Skip to content

Commit

Permalink
verify_cert: rework verify_chain helper.
Browse files Browse the repository at this point in the history
This commit updates the verify_chain helper to take references to its
inputs (allowing the same inputs to be used for multiple calls). It also
adds an optional `Budget` argument, allowing testing verification with
a custom budget. When not provided a default budget is used.
  • Loading branch information
cpu committed Sep 7, 2023
1 parent 932ad95 commit 85361f4
Showing 1 changed file with 37 additions and 48 deletions.
85 changes: 37 additions & 48 deletions src/verify_cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ mod tests {
fn build_degenerate_chain(
intermediate_count: usize,
trust_anchor_is_actual_issuer: TrustAnchorIsActualIssuer,
budget: Option<Budget>,
) -> Error {
let ca_cert = make_issuer("Bogus Subject", None);
let ca_cert_der = CertificateDer::from(ca_cert.serialize_der().unwrap());
Expand All @@ -898,14 +899,20 @@ mod tests {
intermediates.pop();
}

verify_chain(ca_cert_der, intermediates, make_end_entity(&issuer)).unwrap_err()
verify_chain(
&ca_cert_der,
&intermediates,
&make_end_entity(&issuer),
budget,
)
.unwrap_err()
}

#[test]
#[cfg(feature = "alloc")]
fn test_too_many_signatures() {
assert_eq!(
build_degenerate_chain(5, TrustAnchorIsActualIssuer::Yes),
build_degenerate_chain(5, TrustAnchorIsActualIssuer::Yes, None),
Error::MaximumSignatureChecksExceeded
);
}
Expand All @@ -914,7 +921,7 @@ mod tests {
#[cfg(feature = "alloc")]
fn test_too_many_path_calls() {
assert_eq!(
build_degenerate_chain(10, TrustAnchorIsActualIssuer::No),
build_degenerate_chain(10, TrustAnchorIsActualIssuer::No, None),
Error::MaximumPathBuildCallsExceeded
);
}
Expand All @@ -933,7 +940,12 @@ mod tests {
issuer = intermediate;
}

verify_chain(ca_cert_der, intermediates, make_end_entity(&issuer))
verify_chain(
&ca_cert_der,
&intermediates,
&make_end_entity(&issuer),
None,
)
}

#[test]
Expand All @@ -956,9 +968,6 @@ mod tests {
#[test]
#[cfg(feature = "alloc")]
fn name_constraint_budget() {
use crate::{extract_trust_anchor, ECDSA_P256_SHA256};
use crate::{EndEntityCert, Time};

// Issue a trust anchor that imposes name constraints. The constraint should match
// the end entity certificate SAN.
let ca_cert = make_issuer(
Expand Down Expand Up @@ -988,18 +997,10 @@ mod tests {
// Create an end-entity cert that is issued by the last of the intermediates.
let ee_cert = make_end_entity(intermediates.last().unwrap());

let anchors = &[extract_trust_anchor(&ca_cert_der).unwrap()];
let time = Time::from_seconds_since_unix_epoch(0x1fed_f00d);
let cert = EndEntityCert::try_from(&ee_cert).unwrap();
let intermediates_der = intermediates_der
.iter()
.map(|x| CertificateDer::from(x.as_ref()))
.collect::<Vec<_>>();

// We use a custom budget to make it easier to write a test, otherwise it is tricky to
// stuff enough names/constraints into the potential chains while staying within the path
// depth limit and the build chain call limit.
let mut passing_budget = Budget {
let passing_budget = Budget {
// One comparison against the intermediate's distinguished name.
// One comparison against the EE's distinguished name.
// One comparison against the EE's SAN.
Expand All @@ -1011,64 +1012,50 @@ mod tests {
// Validation should succeed with the name constraint comparison budget allocated above.
// This shows that we're not consuming budget on unused intermediates: we didn't budget
// enough comparisons for that to pass the overall chain building.
build_chain_inner(
&ChainOptions {
eku: KeyUsage::server_auth(),
supported_sig_algs: &[ECDSA_P256_SHA256],
trust_anchors: anchors,
intermediate_certs: &intermediates_der,
revocation: None,
},
cert.inner(),
time,
0,
&mut passing_budget,
verify_chain(
&ca_cert_der,
&intermediates_der,
&ee_cert,
Some(passing_budget),
)
.unwrap();

let mut failing_budget = Budget {
let failing_budget = Budget {
// See passing_budget: 2 comparisons is not sufficient.
name_constraint_comparisons: 2,
..Budget::default()
};
// Validation should fail when the budget is smaller than the number of comparisons performed
// on the validated path. This demonstrates we properly fail path building when too many
// name constraint comparisons occur.
let result = build_chain_inner(
&ChainOptions {
eku: KeyUsage::server_auth(),
supported_sig_algs: &[ECDSA_P256_SHA256],
trust_anchors: anchors,
intermediate_certs: &intermediates_der,
revocation: None,
},
cert.inner(),
time,
0,
&mut failing_budget,
let result = verify_chain(
&ca_cert_der,
&intermediates_der,
&ee_cert,
Some(failing_budget),
);

assert_eq!(result, Err(Error::MaximumNameConstraintComparisonsExceeded));
}

#[cfg(feature = "alloc")]
fn verify_chain(
trust_anchor: CertificateDer<'_>,
intermediates_der: Vec<Vec<u8>>,
ee_cert: CertificateDer<'_>,
trust_anchor: &CertificateDer<'_>,
intermediates_der: &[Vec<u8>],
ee_cert: &CertificateDer<'_>,
budget: Option<Budget>,
) -> Result<(), Error> {
use crate::{extract_trust_anchor, ECDSA_P256_SHA256};
use crate::{EndEntityCert, Time};

let anchors = &[extract_trust_anchor(&trust_anchor).unwrap()];
let anchors = &[extract_trust_anchor(trust_anchor).unwrap()];
let time = Time::from_seconds_since_unix_epoch(0x1fed_f00d);
let cert = EndEntityCert::try_from(&ee_cert).unwrap();
let cert = EndEntityCert::try_from(ee_cert).unwrap();
let intermediates_der = intermediates_der
.iter()
.map(|x| CertificateDer::from(x.as_ref()))
.collect::<Vec<_>>();

build_chain(
build_chain_inner(
&ChainOptions {
eku: KeyUsage::server_auth(),
supported_sig_algs: &[ECDSA_P256_SHA256],
Expand All @@ -1078,6 +1065,8 @@ mod tests {
},
cert.inner(),
time,
0,
&mut budget.unwrap_or_default(),
)
}

Expand Down

0 comments on commit 85361f4

Please sign in to comment.