@@ -17,6 +17,7 @@ use crate::{
17
17
der, signed_data, subject_name, time, Error , SignatureAlgorithm , TrustAnchor ,
18
18
} ;
19
19
20
+ #[ allow( clippy:: too_many_arguments) ]
20
21
pub ( crate ) fn build_chain (
21
22
required_eku_if_present : KeyPurposeId ,
22
23
supported_sig_algs : & [ & SignatureAlgorithm ] ,
@@ -25,6 +26,7 @@ pub(crate) fn build_chain(
25
26
cert : & Cert ,
26
27
time : time:: Time ,
27
28
sub_ca_count : usize ,
29
+ signatures : & mut usize ,
28
30
) -> Result < ( ) , Error > {
29
31
let used_as_ca = used_as_ca ( & cert. ee_or_ca ) ;
30
32
@@ -79,15 +81,17 @@ pub(crate) fn build_chain(
79
81
80
82
// TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
81
83
82
- check_signatures ( supported_sig_algs, cert, trust_anchor_spki) ?;
84
+ check_signatures ( supported_sig_algs, cert, trust_anchor_spki, signatures ) ?;
83
85
84
86
Ok ( ( ) )
85
87
} ) ;
86
88
87
89
// If the error is not fatal, then keep going.
88
- if result. is_ok ( ) {
89
- return Ok ( ( ) ) ;
90
- }
90
+ match result {
91
+ Ok ( ( ) ) => return Ok ( ( ) ) ,
92
+ err @ Err ( Error :: MaximumSignatureChecksExceeded ) => return err,
93
+ _ => { }
94
+ } ;
91
95
92
96
loop_while_non_fatal_error ( intermediate_certs, |cert_der| {
93
97
let potential_issuer =
@@ -132,6 +136,7 @@ pub(crate) fn build_chain(
132
136
& potential_issuer,
133
137
time,
134
138
next_sub_ca_count,
139
+ signatures,
135
140
)
136
141
} )
137
142
}
@@ -140,10 +145,16 @@ fn check_signatures(
140
145
supported_sig_algs : & [ & SignatureAlgorithm ] ,
141
146
cert_chain : & Cert ,
142
147
trust_anchor_key : untrusted:: Input ,
148
+ signatures : & mut usize ,
143
149
) -> Result < ( ) , Error > {
144
150
let mut spki_value = trust_anchor_key;
145
151
let mut cert = cert_chain;
146
152
loop {
153
+ * signatures += 1 ;
154
+ if * signatures > 100 {
155
+ return Err ( Error :: MaximumSignatureChecksExceeded ) ;
156
+ }
157
+
147
158
signed_data:: verify_signed_data ( supported_sig_algs, spki_value, & cert. signed_data ) ?;
148
159
149
160
// TODO: check revocation
@@ -341,16 +352,85 @@ fn check_eku(
341
352
342
353
fn loop_while_non_fatal_error < V > (
343
354
values : V ,
344
- f : impl Fn ( V :: Item ) -> Result < ( ) , Error > ,
355
+ mut f : impl FnMut ( V :: Item ) -> Result < ( ) , Error > ,
345
356
) -> Result < ( ) , Error >
346
357
where
347
358
V : IntoIterator ,
348
359
{
349
360
for v in values {
350
361
// If the error is not fatal, then keep going.
351
- if f ( v) . is_ok ( ) {
352
- return Ok ( ( ) ) ;
362
+ match f ( v) {
363
+ Ok ( ( ) ) => return Ok ( ( ) ) ,
364
+ err @ Err ( Error :: MaximumSignatureChecksExceeded ) => return err,
365
+ _ => { }
353
366
}
354
367
}
355
368
Err ( Error :: UnknownIssuer )
356
369
}
370
+
371
+ #[ cfg( test) ]
372
+ mod tests {
373
+ use super :: * ;
374
+
375
+ #[ test]
376
+ #[ cfg( feature = "alloc" ) ]
377
+ fn test_too_many_signatures ( ) {
378
+ use std:: convert:: TryFrom ;
379
+
380
+ use crate :: { EndEntityCert , Time , ECDSA_P256_SHA256 } ;
381
+
382
+ let alg = & rcgen:: PKCS_ECDSA_P256_SHA256 ;
383
+
384
+ let make_issuer = || {
385
+ let mut ca_params = rcgen:: CertificateParams :: new ( Vec :: new ( ) ) ;
386
+ ca_params
387
+ . distinguished_name
388
+ . push ( rcgen:: DnType :: OrganizationName , "Bogus Subject" ) ;
389
+ ca_params. is_ca = rcgen:: IsCa :: Ca ( rcgen:: BasicConstraints :: Unconstrained ) ;
390
+ ca_params. key_usages = vec ! [
391
+ rcgen:: KeyUsagePurpose :: KeyCertSign ,
392
+ rcgen:: KeyUsagePurpose :: DigitalSignature ,
393
+ rcgen:: KeyUsagePurpose :: CrlSign ,
394
+ ] ;
395
+ ca_params. alg = alg;
396
+ rcgen:: Certificate :: from_params ( ca_params) . unwrap ( )
397
+ } ;
398
+
399
+ let ca_cert = make_issuer ( ) ;
400
+ let ca_cert_der = ca_cert. serialize_der ( ) . unwrap ( ) ;
401
+
402
+ let mut intermediates = Vec :: with_capacity ( 101 ) ;
403
+ let mut issuer = ca_cert;
404
+ for _ in 0 ..101 {
405
+ let intermediate = make_issuer ( ) ;
406
+ let intermediate_der = intermediate. serialize_der_with_signer ( & issuer) . unwrap ( ) ;
407
+ intermediates. push ( intermediate_der) ;
408
+ issuer = intermediate;
409
+ }
410
+
411
+ let mut ee_params = rcgen:: CertificateParams :: new ( vec ! [ "example.com" . to_string( ) ] ) ;
412
+ ee_params. is_ca = rcgen:: IsCa :: ExplicitNoCa ;
413
+ ee_params. alg = alg;
414
+ let ee_cert = rcgen:: Certificate :: from_params ( ee_params) . unwrap ( ) ;
415
+ let ee_cert_der = ee_cert. serialize_der_with_signer ( & issuer) . unwrap ( ) ;
416
+
417
+ let anchors = & [ TrustAnchor :: try_from_cert_der ( & ca_cert_der) . unwrap ( ) ] ;
418
+ let time = Time :: from_seconds_since_unix_epoch ( 0x1fed_f00d ) ;
419
+ let cert = EndEntityCert :: try_from ( & ee_cert_der[ ..] ) . unwrap ( ) ;
420
+ let intermediates_der: Vec < & [ u8 ] > = intermediates. iter ( ) . map ( |x| x. as_ref ( ) ) . collect ( ) ;
421
+ let intermediate_certs: & [ & [ u8 ] ] = intermediates_der. as_ref ( ) ;
422
+
423
+ let result = build_chain (
424
+ EKU_SERVER_AUTH ,
425
+ & [ & ECDSA_P256_SHA256 ] ,
426
+ anchors,
427
+ intermediate_certs,
428
+ cert. inner ( ) ,
429
+ time,
430
+ 0 ,
431
+ & mut 0_usize ,
432
+ ) ;
433
+
434
+ assert ! ( matches!( result, Err ( Error :: MaximumSignatureChecksExceeded ) ) ) ;
435
+ }
436
+ }
0 commit comments