@@ -17,12 +17,16 @@ package config
17
17
18
18
import (
19
19
"context"
20
- "encoding/json "
20
+ "encoding/pem "
21
21
"fmt"
22
22
23
+ "github.com/sigstore/cosign/v2/pkg/cosign"
23
24
"github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1"
25
+ pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
26
+ pbtrustroot "github.com/sigstore/protobuf-specs/gen/pb-go/trustroot/v1"
27
+ "github.com/sigstore/sigstore/pkg/cryptoutils"
28
+ "google.golang.org/protobuf/encoding/protojson"
24
29
corev1 "k8s.io/api/core/v1"
25
- "knative.dev/pkg/apis"
26
30
"sigs.k8s.io/yaml"
27
31
)
28
32
@@ -33,81 +37,24 @@ const (
33
37
SigstoreKeysConfigName = "config-sigstore-keys"
34
38
)
35
39
36
- // Note that these are 1:1 mapped to public API SigstoreKeys. Reasoning
37
- // being that we may choose to serialize these differently, or use the protos
38
- // that are defined upstream, so want to keep the public/private distinction, so
39
- // that we can change things independend of breaking the API. Time will tell
40
- // if this is the right call, but we can always reunify them later if we so
41
- // want.
42
- // TODO(vaikas): See about replacing these with the protos here once they land
43
- // and see how easy it is to replace with protos instead of our custom defs
44
- // above.
45
- // https://github.com/sigstore/protobuf-specs/pull/5
46
- // And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70
47
-
48
- // TransparencyLogInstance describes the immutable parameters from a
49
- // transparency log.
50
- // See https://www.rfc-editor.org/rfc/rfc9162.html#name-log-parameters
51
- // for more details.
52
- // The incluced parameters are the minimal set required to identify a log,
53
- // and verify an inclusion promise.
54
- type TransparencyLogInstance struct {
55
- BaseURL apis.URL `json:"baseURL"`
56
- HashAlgorithm string `json:"hashAlgorithm"`
57
- // PEM encoded public key
58
- PublicKey []byte `json:"publicKey"`
59
- LogID string `json:"logID"`
60
- }
61
-
62
- type DistinguishedName struct {
63
- Organization string `json:"organization"`
64
- CommonName string `json:"commonName"`
65
- }
66
-
67
- type CertificateAuthority struct {
68
- // The root certificate MUST be self-signed, and so the subject and
69
- // issuer are the same.
70
- Subject DistinguishedName `json:"subject"`
71
- // The URI at which the CA can be accessed.
72
- URI apis.URL `json:"uri"`
73
- // The certificate chain for this CA.
74
- // CertChain is in PEM format.
75
- CertChain []byte `json:"certChain"`
76
-
77
- // TODO(vaikas): How to best represent this
78
- // The time the *entire* chain was valid. This is at max the
79
- // longest interval when *all* certificates in the chain where valid,
80
- // but it MAY be shorter.
81
- // dev.sigstore.common.v1.TimeRange valid_for = 4;
82
- }
40
+ // Type aliases for types from protobuf-specs. TODO: Consider just importing
41
+ // the protobuf-specs types directly from each package as needed.
83
42
84
43
// SigstoreKeys contains all the necessary Keys and Certificates for validating
85
44
// against a specific instance of Sigstore.
86
- // TODO(vaikas): See about replacing these with the protos here once they land
87
- // and see how easy it is to replace with protos instead of our custom defs
88
- // above.
89
- // https://github.com/sigstore/protobuf-specs/pull/5
90
- // And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70
91
- // Well, not the multi-root, but one instance of that is exactly the
92
- // SigstoreKeys.
93
- type SigstoreKeys struct {
94
- // Trusted certificate authorities (e.g Fulcio).
95
- CertificateAuthorities []CertificateAuthority `json:"certificateAuthorities,omitempty"`
96
- // Rekor log specifications
97
- TLogs []TransparencyLogInstance `json:"tLogs,omitempty"`
98
- // Certificate Transparency Log
99
- CTLogs []TransparencyLogInstance `json:"ctLogs,omitempty"`
100
- // Trusted timestamping authorities
101
- TimeStampAuthorities []CertificateAuthority `json:"timestampAuthorities"`
102
- }
45
+ type SigstoreKeys = pbtrustroot.TrustedRoot
46
+ type CertificateAuthority = pbtrustroot.CertificateAuthority
47
+ type TransparencyLogInstance = pbtrustroot.TransparencyLogInstance
48
+ type DistinguishedName = pbcommon.DistinguishedName
49
+ type LogId = pbcommon.LogId
103
50
104
51
type SigstoreKeysMap struct {
105
- SigstoreKeys map [string ]SigstoreKeys
52
+ SigstoreKeys map [string ]* SigstoreKeys
106
53
}
107
54
108
55
// NewSigstoreKeysFromMap creates a map of SigstoreKeys to use for validation.
109
56
func NewSigstoreKeysFromMap (data map [string ]string ) (* SigstoreKeysMap , error ) {
110
- ret := make (map [string ]SigstoreKeys , len (data ))
57
+ ret := make (map [string ]* SigstoreKeys , len (data ))
111
58
// Spin through the ConfigMap. Each entry will have a serialized form of
112
59
// necessary validation keys in the form of SigstoreKeys.
113
60
for k , v := range data {
@@ -123,7 +70,7 @@ func NewSigstoreKeysFromMap(data map[string]string) (*SigstoreKeysMap, error) {
123
70
if err := parseSigstoreKeys (v , sigstoreKeys ); err != nil {
124
71
return nil , fmt .Errorf ("failed to parse the entry %q : %q : %w" , k , v , err )
125
72
}
126
- ret [k ] = * sigstoreKeys
73
+ ret [k ] = sigstoreKeys
127
74
}
128
75
return & SigstoreKeysMap {SigstoreKeys : ret }, nil
129
76
}
@@ -133,56 +80,121 @@ func NewSigstoreKeysFromConfigMap(config *corev1.ConfigMap) (*SigstoreKeysMap, e
133
80
return NewSigstoreKeysFromMap (config .Data )
134
81
}
135
82
136
- func parseSigstoreKeys (entry string , out interface {} ) error {
83
+ func parseSigstoreKeys (entry string , out * pbtrustroot. TrustedRoot ) error {
137
84
j , err := yaml .YAMLToJSON ([]byte (entry ))
138
85
if err != nil {
139
86
return fmt .Errorf ("config's value could not be converted to JSON: %w : %s" , err , entry )
140
87
}
141
- return json .Unmarshal (j , & out )
88
+ return protojson .Unmarshal (j , out )
142
89
}
143
90
144
- // ConvertFrom takes a source and converts into a SigstoreKeys suitable
91
+ // ConvertSigstoreKeys takes a source and converts into a SigstoreKeys suitable
145
92
// for serialization into a ConfigMap entry.
146
- func (sk * SigstoreKeys ) ConvertFrom (_ context.Context , source * v1alpha1.SigstoreKeys ) {
147
- sk .CertificateAuthorities = make ([]CertificateAuthority , len (source .CertificateAuthorities ))
93
+ func ConvertSigstoreKeys (_ context.Context , source * v1alpha1.SigstoreKeys ) * SigstoreKeys {
94
+ sk := & SigstoreKeys {}
95
+ sk .CertificateAuthorities = make ([]* pbtrustroot.CertificateAuthority , len (source .CertificateAuthorities ))
148
96
for i := range source .CertificateAuthorities {
149
97
sk .CertificateAuthorities [i ] = ConvertCertificateAuthority (source .CertificateAuthorities [i ])
150
98
}
151
99
152
- sk .TLogs = make ([]TransparencyLogInstance , len (source .TLogs ))
100
+ sk .Tlogs = make ([]* pbtrustroot. TransparencyLogInstance , len (source .TLogs ))
153
101
for i := range source .TLogs {
154
- sk .TLogs [i ] = ConvertTransparencyLogInstance (source .TLogs [i ])
102
+ sk .Tlogs [i ] = ConvertTransparencyLogInstance (source .TLogs [i ])
155
103
}
156
104
157
- sk .CTLogs = make ([]TransparencyLogInstance , len (source .CTLogs ))
105
+ sk .Ctlogs = make ([]* pbtrustroot. TransparencyLogInstance , len (source .CTLogs ))
158
106
for i := range source .CTLogs {
159
- sk .CTLogs [i ] = ConvertTransparencyLogInstance (source .CTLogs [i ])
107
+ sk .Ctlogs [i ] = ConvertTransparencyLogInstance (source .CTLogs [i ])
160
108
}
161
109
162
- sk .TimeStampAuthorities = make ([]CertificateAuthority , len (source .TimeStampAuthorities ))
110
+ sk .TimestampAuthorities = make ([]* pbtrustroot. CertificateAuthority , len (source .TimeStampAuthorities ))
163
111
for i := range source .TimeStampAuthorities {
164
- sk .TimeStampAuthorities [i ] = ConvertCertificateAuthority (source .TimeStampAuthorities [i ])
112
+ sk .TimestampAuthorities [i ] = ConvertCertificateAuthority (source .TimeStampAuthorities [i ])
165
113
}
114
+ return sk
166
115
}
167
116
168
117
// ConvertCertificateAuthority converts public into private CertificateAuthority
169
- func ConvertCertificateAuthority (source v1alpha1.CertificateAuthority ) CertificateAuthority {
170
- return CertificateAuthority {
171
- Subject : DistinguishedName {
118
+ func ConvertCertificateAuthority (source v1alpha1.CertificateAuthority ) * pbtrustroot. CertificateAuthority {
119
+ return & pbtrustroot. CertificateAuthority {
120
+ Subject : & pbcommon. DistinguishedName {
172
121
Organization : source .Subject .Organization ,
173
122
CommonName : source .Subject .CommonName ,
174
123
},
175
- URI : * source .URI .DeepCopy (),
176
- CertChain : source .CertChain ,
124
+ Uri : source .URI .String (),
125
+ CertChain : DeserializeCertChain ( source .CertChain ) ,
177
126
}
178
127
}
179
128
180
129
// ConvertTransparencyLogInstance converts public into private
181
130
// TransparencyLogInstance.
182
- func ConvertTransparencyLogInstance (source v1alpha1.TransparencyLogInstance ) TransparencyLogInstance {
183
- return TransparencyLogInstance {
184
- BaseURL : * source .BaseURL .DeepCopy (),
185
- HashAlgorithm : source .HashAlgorithm ,
186
- PublicKey : source .PublicKey ,
131
+ func ConvertTransparencyLogInstance (source v1alpha1.TransparencyLogInstance ) * pbtrustroot.TransparencyLogInstance {
132
+ pk , err := cryptoutils .UnmarshalPEMToPublicKey (source .PublicKey )
133
+ if err != nil {
134
+ return nil // TODO: log error? Add return error?
135
+ }
136
+ logID , err := cosign .GetTransparencyLogID (pk )
137
+ if err != nil {
138
+ return nil // TODO: log error? Add return error?
139
+ }
140
+
141
+ var hashAlgorithm pbcommon.HashAlgorithm
142
+ switch source .HashAlgorithm {
143
+ case "sha256" :
144
+ hashAlgorithm = pbcommon .HashAlgorithm_SHA2_256
145
+ case "sha384" :
146
+ hashAlgorithm = pbcommon .HashAlgorithm_SHA2_384
147
+ case "sha512" :
148
+ hashAlgorithm = pbcommon .HashAlgorithm_SHA2_512
149
+ default :
150
+ hashAlgorithm = pbcommon .HashAlgorithm_HASH_ALGORITHM_UNSPECIFIED
151
+ }
152
+
153
+ return & pbtrustroot.TransparencyLogInstance {
154
+ BaseUrl : source .BaseURL .String (),
155
+ HashAlgorithm : hashAlgorithm ,
156
+ PublicKey : DeserializePublicKey (source .PublicKey ),
157
+ LogId : & pbcommon.LogId {
158
+ KeyId : []byte (logID ),
159
+ },
187
160
}
188
161
}
162
+
163
+ func SerializeCertChain (certChain * pbcommon.X509CertificateChain ) []byte {
164
+ var chain []byte
165
+ for _ , cert := range certChain .Certificates {
166
+ bytes := cert .RawBytes
167
+ block := & pem.Block {
168
+ Type : "CERTIFICATE" ,
169
+ Bytes : bytes ,
170
+ }
171
+ chain = append (chain , pem .EncodeToMemory (block )... )
172
+ }
173
+ return chain
174
+ }
175
+
176
+ func SerializePublicKey (publicKey * pbcommon.PublicKey ) []byte {
177
+ block := & pem.Block {
178
+ Type : "PUBLIC KEY" ,
179
+ Bytes : publicKey .RawBytes ,
180
+ }
181
+ return pem .EncodeToMemory (block )
182
+ }
183
+
184
+ func DeserializeCertChain (chain []byte ) * pbcommon.X509CertificateChain {
185
+ var certs []* pbcommon.X509Certificate
186
+ for {
187
+ var block * pem.Block
188
+ block , chain = pem .Decode (chain )
189
+ if block == nil {
190
+ break
191
+ }
192
+ certs = append (certs , & pbcommon.X509Certificate {RawBytes : block .Bytes })
193
+ }
194
+ return & pbcommon.X509CertificateChain {Certificates : certs }
195
+ }
196
+
197
+ func DeserializePublicKey (publicKey []byte ) * pbcommon.PublicKey {
198
+ block , _ := pem .Decode (publicKey )
199
+ return & pbcommon.PublicKey {RawBytes : block .Bytes }
200
+ }
0 commit comments