diff --git a/src/crl.rs b/src/crl.rs index 816e67df..da2bea77 100644 --- a/src/crl.rs +++ b/src/crl.rs @@ -17,6 +17,7 @@ use crate::der::{self, DerIterator, FromDer, Tag, CONSTRUCTED, CONTEXT_SPECIFIC} use crate::error::{DerTypeId, Error}; use crate::signed_data::{self, SignedData}; use crate::subject_name::GeneralName; +use crate::verify_cert::Budget; use crate::x509::{remember_extension, set_extension_once, DistributionPointName, Extension}; use crate::{SignatureVerificationAlgorithm, Time}; use core::fmt::Debug; @@ -50,6 +51,7 @@ pub trait CertRevocationList: Sealed + Debug { &self, supported_sig_algs: &[&dyn SignatureVerificationAlgorithm], issuer_spki: &[u8], + budget: &mut Budget, ) -> Result<(), Error>; } @@ -97,11 +99,13 @@ impl CertRevocationList for OwnedCertRevocationList { &self, supported_sig_algs: &[&dyn SignatureVerificationAlgorithm], issuer_spki: &[u8], + budget: &mut Budget, ) -> Result<(), Error> { signed_data::verify_signed_data( supported_sig_algs, untrusted::Input::from(issuer_spki), &self.signed_data.borrow(), + budget, ) } } @@ -239,11 +243,13 @@ impl CertRevocationList for BorrowedCertRevocationList<'_> { &self, supported_sig_algs: &[&dyn SignatureVerificationAlgorithm], issuer_spki: &[u8], + budget: &mut Budget, ) -> Result<(), Error> { signed_data::verify_signed_data( supported_sig_algs, untrusted::Input::from(issuer_spki), &self.signed_data, + budget, ) } } diff --git a/src/ring_algs.rs b/src/ring_algs.rs index 5e861863..54079b5b 100644 --- a/src/ring_algs.rs +++ b/src/ring_algs.rs @@ -151,6 +151,7 @@ mod tests { use base64::{engine::general_purpose, Engine as _}; use crate::error::{DerTypeId, Error}; + use crate::verify_cert::Budget; use crate::{der, signed_data}; use alloc::{string::String, vec::Vec}; @@ -215,7 +216,8 @@ mod tests { signed_data::verify_signed_data( SUPPORTED_ALGORITHMS_IN_TESTS, spki_value, - &signed_data + &signed_data, + &mut Budget::default(), ) ); } diff --git a/src/signed_data.rs b/src/signed_data.rs index a4143fda..de599170 100644 --- a/src/signed_data.rs +++ b/src/signed_data.rs @@ -14,6 +14,7 @@ use crate::der::{self, FromDer}; use crate::error::{DerTypeId, Error}; +use crate::verify_cert::Budget; #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -153,7 +154,10 @@ pub(crate) fn verify_signed_data( supported_algorithms: &[&dyn SignatureVerificationAlgorithm], spki_value: untrusted::Input, signed_data: &SignedData, + budget: &mut Budget, ) -> Result<(), Error> { + budget.consume_signature()?; + // We need to verify the signature in `signed_data` using the public key // in `public_key`. In order to know which *ring* signature verification // algorithm to use, we need to know the public key algorithm (ECDSA, diff --git a/src/verify_cert.rs b/src/verify_cert.rs index 5c70ae0d..b609e60a 100644 --- a/src/verify_cert.rs +++ b/src/verify_cert.rs @@ -12,6 +12,8 @@ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +use core::default::Default; + use pki_types::{CertificateDer, TrustAnchor}; use crate::cert::{Cert, EndEntityOrCa}; @@ -260,8 +262,7 @@ fn check_signatures( let mut issuer_key_usage = None; // TODO(XXX): Consider whether to track TrustAnchor KU. let mut cert = cert_chain; loop { - budget.consume_signature()?; - signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?; + signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data, budget)?; if let Some(revocation_opts) = &revocation { check_crls( @@ -271,6 +272,7 @@ fn check_signatures( spki_value, issuer_key_usage, revocation_opts, + budget, )?; } @@ -290,14 +292,14 @@ fn check_signatures( Ok(()) } -struct Budget { +pub struct Budget { signatures: usize, build_chain_calls: usize, } impl Budget { #[inline] - fn consume_signature(&mut self) -> Result<(), Error> { + pub(crate) fn consume_signature(&mut self) -> Result<(), Error> { self.signatures = self .signatures .checked_sub(1) @@ -315,7 +317,7 @@ impl Budget { } } -impl core::default::Default for Budget { +impl Default for Budget { fn default() -> Self { Self { // This limit is taken from the remediation for golang CVE-2018-16875. However, @@ -326,7 +328,7 @@ impl core::default::Default for Budget { // This limit is taken from NSS libmozpkix, see: // - build_chain_calls: 200000, + build_chain_calls: 200_000, } } } @@ -349,6 +351,7 @@ fn check_crls( issuer_spki: untrusted::Input, issuer_ku: Option, revocation: &RevocationOptions, + budget: &mut Budget, ) -> Result, Error> { assert_eq!(cert.issuer, issuer_subject); @@ -379,7 +382,7 @@ fn check_crls( // TODO(XXX): consider whether we can refactor so this happens once up-front, instead // of per-lookup. // https://github.com/rustls/webpki/issues/81 - crl.verify_signature(supported_sig_algs, issuer_spki.as_slice_less_safe()) + crl.verify_signature(supported_sig_algs, issuer_spki.as_slice_less_safe(), budget) .map_err(crl_signature_err)?; // Verify that if the issuer has a KeyUsage bitstring it asserts cRLSign.