Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 12 additions & 20 deletions src/verify_cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ pub struct PathBuilder<'a, 'p> {
impl<'a, 'p: 'a> PathBuilder<'a, 'p> {
/// Build a new [`PathBuilder`] with the given parameters.
///
/// * `intermediate_certs` is the list of intermediate certificates to use for path building.
/// These certificates should be sent by the peer. They are not trusted, but can be used to
/// build a path to a trusted root.
/// * `revocation` provides the revocation options to use for path building. If `None`, no
/// revocation checks will be performed.
/// * `eku` is the intended usage of the certificate, indicating what kind
/// of usage we're verifying the certificate for. The default [`ExtendedKeyUsageValidator`]
/// implementation is [`ExtendedKeyUsage`].
Expand All @@ -54,6 +59,8 @@ impl<'a, 'p: 'a> PathBuilder<'a, 'p> {
/// public key is not validated against this list.
/// * `trust_anchors` is the list of root CAs to trust in the built path.
pub fn new(
intermediate_certs: &'p [CertificateDer<'p>],
Comment thread
djc marked this conversation as resolved.
revocation: Option<RevocationOptions<'a>>,
eku: &'p dyn ExtendedKeyUsageValidator,
supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
trust_anchors: &'p [TrustAnchor<'p>],
Expand All @@ -62,28 +69,12 @@ impl<'a, 'p: 'a> PathBuilder<'a, 'p> {
eku,
supported_sig_algs,
trust_anchors,
intermediate_certs: &[],
revocation: None,
intermediate_certs,
revocation,
verify_path: None,
}
}

/// Set the sequence of intermediate certificates to use for path building.
///
/// These should be sent by the peer. Defaults to empty.
pub fn with_intermediate_certs(mut self, intermediate_certs: &'p [CertificateDer<'p>]) -> Self {
self.intermediate_certs = intermediate_certs;
self
}

/// Set the revocation options to use for path building.
///
/// By default, revocation checking is disabled.
pub fn with_revocation(mut self, revocation: RevocationOptions<'a>) -> Self {
self.revocation = Some(revocation);
self
}

/// Set a path verification function to use for path building.
///
/// `verify()` will only be called for potentially verified paths, that is, paths that
Expand Down Expand Up @@ -1509,11 +1500,12 @@ mod tests {
let mut path = PartialPath::new(ee_cert);

let builder = PathBuilder::new(
intermediate_certs,
None,
&ExtendedKeyUsage::SERVER_AUTH,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
trust_anchors,
)
.with_intermediate_certs(intermediate_certs);
);
let builder = match verify_path {
Some(verify) => builder.with_path_verification(verify),
None => builder,
Expand Down
61 changes: 21 additions & 40 deletions tests/amazon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,58 +237,42 @@ pub fn amazon() {
Some(&all_crls),
] {
let builder = PathBuilder::new(
&intermediates,
crls.map(|c| revocation_options_for_test(c)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(&intermediates);

let builder = match crls {
Some(crls) => builder.with_revocation(revocation_options_for_test(crls)),
None => builder,
};
);

assert!(builder.build(&cert, time).is_ok());

let builder = PathBuilder::new(
&intermediates_legacy,
crls.map(|c| revocation_options_for_test(c)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&legacy_anchors,
)
.with_intermediate_certs(&intermediates_legacy);

let builder = match crls {
Some(crls) => builder.with_revocation(revocation_options_for_test(crls)),
None => builder,
};
);

assert!(builder.build(&cert, time).is_ok());

let builder = PathBuilder::new(
&intermediates_legacy,
crls.map(|c| revocation_options_for_test(c)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&all_anchors,
)
.with_intermediate_certs(&intermediates_legacy);

let builder = match crls {
Some(crls) => builder.with_revocation(revocation_options_for_test(crls)),
None => builder,
};
);

assert!(builder.build(&cert, time).is_ok());

let builder = PathBuilder::new(
&intermediates_legacy,
crls.map(|c| revocation_options_for_test(c)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&all_anchors,
)
.with_intermediate_certs(&intermediates_legacy);

let builder = match crls {
Some(crls) => builder.with_revocation(revocation_options_for_test(crls)),
None => builder,
};
);

// verify should find shortest path
let path = builder.build(&cert, time).unwrap();
Expand All @@ -302,28 +286,24 @@ pub fn amazon() {

for &crls in &[None, Some(&roots_crls)] {
let builder = PathBuilder::new(
&intermediates,
crls.map(|c| revocation_options_for_test(c)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(&intermediates);

let builder = match crls {
Some(crls) => builder.with_revocation(revocation_options_for_test(crls)),
None => builder,
};
);

assert!(builder.build(&cert, time).is_ok());
}

for &crls in &[&intermediates_crls, &all_crls] {
let builder = PathBuilder::new(
&intermediates,
Some(revocation_options_for_test(crls)),
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(&intermediates)
.with_revocation(revocation_options_for_test(crls));
);

assert!(
builder
Expand All @@ -335,11 +315,12 @@ pub fn amazon() {

for &(cert, _dns_name) in expired_certs {
let builder = PathBuilder::new(
&intermediates,
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(&intermediates);
);

let cert = CertificateDer::from(cert);
let cert = EndEntityCert::try_from(&cert).unwrap();
Expand Down
2 changes: 2 additions & 0 deletions tests/client_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ fn cert_with_serverauth_eku_rejected_for_client_auth() {
fn check_cert(ee: &[u8], ca: CertificateDer<'static>) -> Result<(), webpki::Error> {
let anchors = &[anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(
&[],
None,
&ExtendedKeyUsage::CLIENT_AUTH,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
anchors,
Expand Down
14 changes: 7 additions & 7 deletions tests/client_auth_revocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ fn check_cert(
.map(|cert| CertificateDer::from(*cert))
.collect::<Vec<_>>();

let builder = PathBuilder::new(&ExtendedKeyUsage::CLIENT_AUTH, ALGS, anchors)
.with_intermediate_certs(&intermediates);

let builder = match revocation {
Some(crls) => builder.with_revocation(crls),
None => builder,
};
let builder = PathBuilder::new(
&intermediates,
revocation,
&ExtendedKeyUsage::CLIENT_AUTH,
ALGS,
anchors,
);

let ee = CertificateDer::from(ee);
let cert = webpki::EndEntityCert::try_from(&ee).unwrap();
Expand Down
8 changes: 7 additions & 1 deletion tests/custom_ekus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ fn check_cert(
) {
let ca = CertificateDer::from(ca);
let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(eku, rustls_aws_lc_rs::ALL_VERIFICATION_ALGS, &anchors);
let builder = PathBuilder::new(
&[],
None,
eku,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
&anchors,
);

let ee = CertificateDer::from(ee);
let cert = webpki::EndEntityCert::try_from(&ee).unwrap();
Expand Down
31 changes: 21 additions & 10 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ fn netflix() {
let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let intermediates = &[inter];
let builder = PathBuilder::new(
intermediates,
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(intermediates);
);

let time = UnixTime::since_unix_epoch(Duration::from_secs(1_492_441_716)); // 2017-04-17T15:08:36Z
let ee = CertificateDer::from(ee);
Expand All @@ -56,11 +57,12 @@ fn sanofi_rsa_signature_with_absent_algorithm_params() {
let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let intermediates = &[inter];
let builder = PathBuilder::new(
intermediates,
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(intermediates);
);

let time = UnixTime::since_unix_epoch(Duration::from_secs(1_746_549_566)); // 2025-05-06T17:39:26Z
let ee = CertificateDer::from(ee);
Expand All @@ -81,11 +83,12 @@ fn cloudflare_dns() {
let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let intermediates = &[inter];
let builder = PathBuilder::new(
intermediates,
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(intermediates);
);

let time = UnixTime::since_unix_epoch(Duration::from_secs(1_663_495_771));
let ee = CertificateDer::from(ee);
Expand Down Expand Up @@ -131,6 +134,8 @@ fn wpt() {

let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(
&[],
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
Expand All @@ -148,6 +153,8 @@ fn ed25519() {

let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(
&[],
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
Expand All @@ -167,11 +174,12 @@ fn critical_extensions() {
let anchors = [anchor_from_trusted_cert(&root).unwrap()];
let intermediates = &[ca];
let builder = PathBuilder::new(
intermediates,
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(intermediates);
);

let time = UnixTime::since_unix_epoch(Duration::from_secs(1_670_779_098));
let ee = CertificateDer::from(
Expand Down Expand Up @@ -215,6 +223,8 @@ fn read_ee_with_neg_serial() {

let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(
&[],
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
Expand Down Expand Up @@ -380,11 +390,12 @@ fn cert_time_validity() {

let anchors = [anchor_from_trusted_cert(&ca).unwrap()];
let builder = PathBuilder::new(
slice::from_ref(&inter),
None,
&ExtendedKeyUsage::SERVER_AUTH,
ALL_VERIFICATION_ALGS,
&anchors,
)
.with_intermediate_certs(slice::from_ref(&inter));
);

let not_before = UnixTime::since_unix_epoch(Duration::from_secs(1_478_563_200));
let not_after = UnixTime::since_unix_epoch(Duration::from_secs(1_541_203_199));
Expand Down
2 changes: 2 additions & 0 deletions tests/tls_server_certs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ fn check_cert(
let ca_cert_der = CertificateDer::from(ca);
let anchors = [anchor_from_trusted_cert(&ca_cert_der).unwrap()];
let builder = PathBuilder::new(
&[],
None,
&ExtendedKeyUsage::SERVER_AUTH,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
&anchors,
Expand Down
23 changes: 9 additions & 14 deletions tests/x509_limbo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,6 @@ fn run_validation(tc: &Testcase) -> Result<(), String> {
.map(|ic| cert_der_from_pem(ic))
.collect::<Vec<_>>();

let builder = PathBuilder::new(
&ExtendedKeyUsage::SERVER_AUTH,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
&trust_anchors,
)
.with_intermediate_certs(&intermediates);

let crls = tc
.crls
.iter()
Expand All @@ -134,18 +127,20 @@ fn run_validation(tc: &Testcase) -> Result<(), String> {
.collect::<Result<Vec<_>, _>>()?;
let crls = crls.iter().collect::<Vec<_>>();

let builder = if !crls.is_empty() {
builder.with_revocation(
let builder = PathBuilder::new(
&intermediates,
(!crls.is_empty()).then(|| {
RevocationOptionsBuilder::new(crls.as_slice())
.unwrap()
.with_depth(RevocationCheckDepth::Chain)
.with_status_policy(UnknownStatusPolicy::Deny)
.with_expiration_policy(ExpirationPolicy::Enforce)
.build(),
)
} else {
builder
};
.build()
}),
&ExtendedKeyUsage::SERVER_AUTH,
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
&trust_anchors,
);

let leaf_der = cert_der_from_pem(&tc.peer_certificate);
let leaf =
Expand Down