@@ -27,14 +27,15 @@ pub(crate) struct ChainOptions<'a> {
2727}
2828
2929pub ( 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 )
3131}
3232
3333fn build_chain_inner (
3434 opts : & ChainOptions ,
3535 cert : & Cert ,
3636 time : time:: Time ,
3737 sub_ca_count : usize ,
38+ signatures : & mut usize ,
3839) -> Result < ( ) , Error > {
3940 let used_as_ca = used_as_ca ( & cert. ee_or_ca ) ;
4041
@@ -87,7 +88,13 @@ fn build_chain_inner(
8788
8889 // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?;
8990
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+ ) ?;
9198
9299 Ok ( ( ) )
93100 } ,
@@ -133,7 +140,7 @@ fn build_chain_inner(
133140 UsedAsCa :: Yes => sub_ca_count + 1 ,
134141 } ;
135142
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 )
137144 } )
138145}
139146
@@ -142,12 +149,17 @@ fn check_signatures(
142149 cert_chain : & Cert ,
143150 trust_anchor : & TrustAnchor ,
144151 crls : & [ & dyn CertRevocationList ] ,
152+ signatures : & mut usize ,
145153) -> Result < ( ) , Error > {
146154 let mut spki_value = untrusted:: Input :: from ( trust_anchor. spki ) ;
147155 let mut issuer_subject = untrusted:: Input :: from ( trust_anchor. subject ) ;
148156 let mut issuer_key_usage = None ; // TODO(XXX): Consider whether to track TrustAnchor KU.
149157 let mut cert = cert_chain;
150158 loop {
159+ * signatures += 1 ;
160+ if * signatures > 100 {
161+ return Err ( Error :: MaximumSignatureChecksExceeded ) ;
162+ }
151163 signed_data:: verify_signed_data ( supported_sig_algs, spki_value, & cert. signed_data ) ?;
152164
153165 if !crls. is_empty ( ) {
@@ -487,7 +499,7 @@ impl KeyUsageMode {
487499fn loop_while_non_fatal_error < V > (
488500 default_error : Error ,
489501 values : V ,
490- f : impl Fn ( V :: Item ) -> Result < ( ) , Error > ,
502+ mut f : impl FnMut ( V :: Item ) -> Result < ( ) , Error > ,
491503) -> Result < ( ) , Error >
492504where
493505 V : IntoIterator ,
@@ -496,6 +508,7 @@ where
496508 for v in values {
497509 match f ( v) {
498510 Ok ( ( ) ) => return Ok ( ( ) ) ,
511+ err @ Err ( Error :: MaximumSignatureChecksExceeded ) => return err,
499512 Err ( new_error) => error = error. most_specific ( new_error) ,
500513 }
501514 }
@@ -511,4 +524,66 @@ mod tests {
511524 assert ! ( ExtendedKeyUsage :: RequiredIfPresent ( EKU_SERVER_AUTH )
512525 . key_purpose_id_equals( EKU_SERVER_AUTH . oid_value) )
513526 }
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+ }
514589}
0 commit comments