@@ -149,7 +149,7 @@ func isPrecertificate(cert *x509.Certificate) (bool, error) {
149
149
// supplied in the chain. Then applies the RFC requirement that the path must involve all
150
150
// the submitted chain in the order of submission.
151
151
// TODO(phboneff): make this a method func([][]byte) ([]*x509.Certificate, error)
152
- func validateChain (rawChain [][]byte , validationOpts ChainValidationOpts ) ([]* x509.Certificate , error ) {
152
+ func ( opts ChainValidationOpts ) validateChain (rawChain [][]byte ) ([]* x509.Certificate , error ) {
153
153
if len (rawChain ) == 0 {
154
154
return nil , errors .New ("empty certificate chain" )
155
155
}
@@ -172,8 +172,8 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
172
172
}
173
173
}
174
174
175
- naStart := validationOpts .notAfterStart
176
- naLimit := validationOpts .notAfterLimit
175
+ naStart := opts .notAfterStart
176
+ naLimit := opts .notAfterLimit
177
177
cert := chain [0 ]
178
178
179
179
// Check whether the expiry date of the cert is within the acceptable range.
@@ -184,24 +184,24 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
184
184
return nil , fmt .Errorf ("certificate NotAfter (%v) >= %v" , cert .NotAfter , * naLimit )
185
185
}
186
186
187
- now := validationOpts .currentTime
187
+ now := opts .currentTime
188
188
if now .IsZero () {
189
189
now = time .Now ()
190
190
}
191
191
expired := now .After (cert .NotAfter )
192
- if validationOpts .rejectExpired && expired {
192
+ if opts .rejectExpired && expired {
193
193
return nil , errors .New ("rejecting expired certificate" )
194
194
}
195
- if validationOpts .rejectUnexpired && ! expired {
195
+ if opts .rejectUnexpired && ! expired {
196
196
return nil , errors .New ("rejecting unexpired certificate" )
197
197
}
198
198
199
199
// Check for unwanted extension types, if required.
200
200
// TODO(al): Refactor CertValidationOpts c'tor to a builder pattern and
201
201
// pre-calc this in there
202
- if len (validationOpts .rejectExtIds ) != 0 {
202
+ if len (opts .rejectExtIds ) != 0 {
203
203
badIDs := make (map [string ]bool )
204
- for _ , id := range validationOpts .rejectExtIds {
204
+ for _ , id := range opts .rejectExtIds {
205
205
badIDs [id .String ()] = true
206
206
}
207
207
for idx , ext := range cert .Extensions {
@@ -214,9 +214,9 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
214
214
215
215
// TODO(al): Refactor CertValidationOpts c'tor to a builder pattern and
216
216
// pre-calc this in there too.
217
- if len (validationOpts .extKeyUsages ) > 0 {
217
+ if len (opts .extKeyUsages ) > 0 {
218
218
acceptEKUs := make (map [x509.ExtKeyUsage ]bool )
219
- for _ , eku := range validationOpts .extKeyUsages {
219
+ for _ , eku := range opts .extKeyUsages {
220
220
acceptEKUs [eku ] = true
221
221
}
222
222
good := false
@@ -227,7 +227,7 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
227
227
}
228
228
}
229
229
if ! good {
230
- return nil , fmt .Errorf ("rejecting certificate without EKU in %v" , validationOpts .extKeyUsages )
230
+ return nil , fmt .Errorf ("rejecting certificate without EKU in %v" , opts .extKeyUsages )
231
231
}
232
232
}
233
233
@@ -237,9 +237,9 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
237
237
// - allow certificate without policing them since this is not CT's responsibility
238
238
// See /internal/lax509/README.md for further information.
239
239
verifyOpts := lax509.VerifyOptions {
240
- Roots : validationOpts .trustedRoots .CertPool (),
240
+ Roots : opts .trustedRoots .CertPool (),
241
241
Intermediates : intermediatePool .CertPool (),
242
- KeyUsages : validationOpts .extKeyUsages ,
242
+ KeyUsages : opts .extKeyUsages ,
243
243
}
244
244
245
245
verifiedChains , err := lax509 .Verify (cert , verifyOpts )
@@ -263,6 +263,36 @@ func validateChain(rawChain [][]byte, validationOpts ChainValidationOpts) ([]*x5
263
263
return nil , errors .New ("no RFC compliant path to root found when trying to validate chain" )
264
264
}
265
265
266
+ // verifyAddChain is used by add-chain and add-pre-chain. It does the checks that the supplied
267
+ // cert is of the correct type and chains to a trusted root.
268
+ // TODO(phbnf): add tests
269
+ func (opts ChainValidationOpts ) verifyAddChain (req rfc6962.AddChainRequest , expectingPrecert bool ) ([]* x509.Certificate , error ) {
270
+ // We already checked that the chain is not empty so can move on to verification
271
+ validPath , err := opts .validateChain (req .Chain )
272
+ if err != nil {
273
+ // We rejected it because the cert failed checks or we could not find a path to a root etc.
274
+ // Lots of possible causes for errors
275
+ return nil , fmt .Errorf ("chain failed to verify: %s" , err )
276
+ }
277
+
278
+ isPrecert , err := isPrecertificate (validPath [0 ])
279
+ if err != nil {
280
+ return nil , fmt .Errorf ("precert test failed: %s" , err )
281
+ }
282
+
283
+ // The type of the leaf must match the one the handler expects
284
+ if isPrecert != expectingPrecert {
285
+ if expectingPrecert {
286
+ klog .Warningf ("Cert (or precert with invalid CT ext) submitted as precert chain: %q" , req .Chain )
287
+ } else {
288
+ klog .Warningf ("Precert (or cert with invalid CT ext) submitted as cert chain: %q" , req .Chain )
289
+ }
290
+ return nil , fmt .Errorf ("cert / precert mismatch: %T" , expectingPrecert )
291
+ }
292
+
293
+ return validPath , nil
294
+ }
295
+
266
296
func chainsEquivalent (inChain []* x509.Certificate , verifiedChain []* x509.Certificate ) bool {
267
297
// The verified chain includes a root, but the input chain may or may not include a
268
298
// root (RFC 6962 s4.1/ s4.2 "the last [certificate] is either the root certificate
0 commit comments