@@ -27,14 +27,15 @@ pub(crate) struct ChainOptions<'a> {
27
27
}
28
28
29
29
pub ( crate ) fn build_chain ( opts : & ChainOptions , cert : & Cert , time : time:: Time ) -> Result < ( ) , Error > {
30
- build_chain_inner ( opts, cert, time, 0 )
30
+ build_chain_inner ( opts, cert, time, 0 , & mut 0_usize )
31
31
}
32
32
33
33
fn build_chain_inner (
34
34
opts : & ChainOptions ,
35
35
cert : & Cert ,
36
36
time : time:: Time ,
37
37
sub_ca_count : usize ,
38
+ signatures : & mut usize ,
38
39
) -> Result < ( ) , Error > {
39
40
let used_as_ca = used_as_ca ( & cert. ee_or_ca ) ;
40
41
@@ -87,7 +88,13 @@ fn build_chain_inner(
87
88
88
89
// TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
89
90
90
- check_signatures ( opts. supported_sig_algs , cert, trust_anchor, opts. crls ) ?;
91
+ check_signatures (
92
+ opts. supported_sig_algs ,
93
+ cert,
94
+ trust_anchor,
95
+ opts. crls ,
96
+ signatures,
97
+ ) ?;
91
98
92
99
Ok ( ( ) )
93
100
} ,
@@ -133,7 +140,7 @@ fn build_chain_inner(
133
140
UsedAsCa :: Yes => sub_ca_count + 1 ,
134
141
} ;
135
142
136
- build_chain_inner ( opts, & potential_issuer, time, next_sub_ca_count)
143
+ build_chain_inner ( opts, & potential_issuer, time, next_sub_ca_count, signatures )
137
144
} )
138
145
}
139
146
@@ -142,12 +149,17 @@ fn check_signatures(
142
149
cert_chain : & Cert ,
143
150
trust_anchor : & TrustAnchor ,
144
151
crls : & [ & dyn CertRevocationList ] ,
152
+ signatures : & mut usize ,
145
153
) -> Result < ( ) , Error > {
146
154
let mut spki_value = untrusted:: Input :: from ( trust_anchor. spki ) ;
147
155
let mut issuer_subject = untrusted:: Input :: from ( trust_anchor. subject ) ;
148
156
let mut issuer_key_usage = None ; // TODO(XXX): Consider whether to track TrustAnchor KU.
149
157
let mut cert = cert_chain;
150
158
loop {
159
+ * signatures += 1 ;
160
+ if * signatures > 100 {
161
+ return Err ( Error :: MaximumSignatureChecksExceeded ) ;
162
+ }
151
163
signed_data:: verify_signed_data ( supported_sig_algs, spki_value, & cert. signed_data ) ?;
152
164
153
165
if !crls. is_empty ( ) {
@@ -487,7 +499,7 @@ impl KeyUsageMode {
487
499
fn loop_while_non_fatal_error < V > (
488
500
default_error : Error ,
489
501
values : V ,
490
- f : impl Fn ( V :: Item ) -> Result < ( ) , Error > ,
502
+ mut f : impl FnMut ( V :: Item ) -> Result < ( ) , Error > ,
491
503
) -> Result < ( ) , Error >
492
504
where
493
505
V : IntoIterator ,
@@ -496,6 +508,7 @@ where
496
508
for v in values {
497
509
match f ( v) {
498
510
Ok ( ( ) ) => return Ok ( ( ) ) ,
511
+ err @ Err ( Error :: MaximumSignatureChecksExceeded ) => return err,
499
512
Err ( new_error) => error = error. most_specific ( new_error) ,
500
513
}
501
514
}
@@ -511,4 +524,66 @@ mod tests {
511
524
assert ! ( ExtendedKeyUsage :: RequiredIfPresent ( EKU_SERVER_AUTH )
512
525
. key_purpose_id_equals( EKU_SERVER_AUTH . oid_value) )
513
526
}
527
+
528
+ #[ test]
529
+ #[ cfg( feature = "alloc" ) ]
530
+ fn test_too_many_signatures ( ) {
531
+ use crate :: ECDSA_P256_SHA256 ;
532
+ use crate :: { EndEntityCert , Time } ;
533
+
534
+ let alg = & rcgen:: PKCS_ECDSA_P256_SHA256 ;
535
+
536
+ let make_issuer = || {
537
+ let mut ca_params = rcgen:: CertificateParams :: new ( Vec :: new ( ) ) ;
538
+ ca_params
539
+ . distinguished_name
540
+ . push ( rcgen:: DnType :: OrganizationName , "Bogus Subject" ) ;
541
+ ca_params. is_ca = rcgen:: IsCa :: Ca ( rcgen:: BasicConstraints :: Unconstrained ) ;
542
+ ca_params. key_usages = vec ! [
543
+ rcgen:: KeyUsagePurpose :: KeyCertSign ,
544
+ rcgen:: KeyUsagePurpose :: DigitalSignature ,
545
+ rcgen:: KeyUsagePurpose :: CrlSign ,
546
+ ] ;
547
+ ca_params. alg = alg;
548
+ rcgen:: Certificate :: from_params ( ca_params) . unwrap ( )
549
+ } ;
550
+
551
+ let ca_cert = make_issuer ( ) ;
552
+ let ca_cert_der = ca_cert. serialize_der ( ) . unwrap ( ) ;
553
+
554
+ let mut intermediates = Vec :: with_capacity ( 101 ) ;
555
+ let mut issuer = ca_cert;
556
+ for _ in 0 ..101 {
557
+ let intermediate = make_issuer ( ) ;
558
+ let intermediate_der = intermediate. serialize_der_with_signer ( & issuer) . unwrap ( ) ;
559
+ intermediates. push ( intermediate_der) ;
560
+ issuer = intermediate;
561
+ }
562
+
563
+ let mut ee_params = rcgen:: CertificateParams :: new ( vec ! [ "example.com" . to_string( ) ] ) ;
564
+ ee_params. is_ca = rcgen:: IsCa :: ExplicitNoCa ;
565
+ ee_params. alg = alg;
566
+ let ee_cert = rcgen:: Certificate :: from_params ( ee_params) . unwrap ( ) ;
567
+ let ee_cert_der = ee_cert. serialize_der_with_signer ( & issuer) . unwrap ( ) ;
568
+
569
+ let anchors = & [ TrustAnchor :: try_from_cert_der ( & ca_cert_der) . unwrap ( ) ] ;
570
+ let time = Time :: from_seconds_since_unix_epoch ( 0x1fed_f00d ) ;
571
+ let cert = EndEntityCert :: try_from ( & ee_cert_der[ ..] ) . unwrap ( ) ;
572
+ let intermediates_der: Vec < & [ u8 ] > = intermediates. iter ( ) . map ( |x| x. as_ref ( ) ) . collect ( ) ;
573
+ let intermediate_certs: & [ & [ u8 ] ] = intermediates_der. as_ref ( ) ;
574
+
575
+ let result = build_chain (
576
+ & ChainOptions {
577
+ eku : KeyUsage :: server_auth ( ) ,
578
+ supported_sig_algs : & [ & ECDSA_P256_SHA256 ] ,
579
+ trust_anchors : anchors,
580
+ intermediate_certs,
581
+ crls : & [ ] ,
582
+ } ,
583
+ cert. inner ( ) ,
584
+ time,
585
+ ) ;
586
+
587
+ assert ! ( matches!( result, Err ( Error :: MaximumSignatureChecksExceeded ) ) ) ;
588
+ }
514
589
}
0 commit comments