From 597aef7899d122a2487a809b4653fb2b39f0c683 Mon Sep 17 00:00:00 2001 From: Sietse Ringers Date: Fri, 14 Jul 2023 09:57:25 +0200 Subject: [PATCH 1/3] verify_cert: add ExtendedKeyUsage enum for EKU --- src/end_entity.rs | 4 +- src/verify_cert.rs | 93 ++++++++++++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/end_entity.rs b/src/end_entity.rs index 6c1247c4..c25f2f13 100644 --- a/src/end_entity.rs +++ b/src/end_entity.rs @@ -93,7 +93,7 @@ impl<'a> EndEntityCert<'a> { ) -> Result<(), Error> { verify_cert::build_chain( &verify_cert::ChainOptions { - required_eku_if_present: verify_cert::EKU_SERVER_AUTH, + eku: verify_cert::ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_SERVER_AUTH), supported_sig_algs, trust_anchors, intermediate_certs, @@ -125,7 +125,7 @@ impl<'a> EndEntityCert<'a> { ) -> Result<(), Error> { verify_cert::build_chain( &verify_cert::ChainOptions { - required_eku_if_present: verify_cert::EKU_CLIENT_AUTH, + eku: verify_cert::ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_CLIENT_AUTH), supported_sig_algs, trust_anchors, intermediate_certs, diff --git a/src/verify_cert.rs b/src/verify_cert.rs index 894f4259..e8ca21d2 100644 --- a/src/verify_cert.rs +++ b/src/verify_cert.rs @@ -19,7 +19,7 @@ use crate::{ }; pub(crate) struct ChainOptions<'a> { - pub(crate) required_eku_if_present: KeyPurposeId, + pub(crate) eku: ExtendedKeyUsage, pub(crate) supported_sig_algs: &'a [&'a SignatureAlgorithm], pub(crate) trust_anchors: &'a [TrustAnchor<'a>], pub(crate) intermediate_certs: &'a [&'a [u8]], @@ -38,13 +38,7 @@ fn build_chain_inner( ) -> Result<(), Error> { let used_as_ca = used_as_ca(&cert.ee_or_ca); - check_issuer_independent_properties( - cert, - time, - used_as_ca, - sub_ca_count, - opts.required_eku_if_present, - )?; + check_issuer_independent_properties(cert, time, used_as_ca, sub_ca_count, opts.eku)?; // TODO: HPKP checks. @@ -65,12 +59,13 @@ fn build_chain_inner( // for the purpose of name constraints checking, only end-entity server certificates // could plausibly have a DNS name as a subject commonName that could contribute to // path validity - let subject_common_name_contents = - if opts.required_eku_if_present == EKU_SERVER_AUTH && used_as_ca == UsedAsCa::No { - subject_name::SubjectCommonNameContents::DnsName - } else { - subject_name::SubjectCommonNameContents::Ignore - }; + let subject_common_name_contents = if opts.eku.key_purpose_id_equals(EKU_SERVER_AUTH.oid_value) + && used_as_ca == UsedAsCa::No + { + subject_name::SubjectCommonNameContents::DnsName + } else { + subject_name::SubjectCommonNameContents::Ignore + }; let result = loop_while_non_fatal_error( Error::UnknownIssuer, @@ -245,7 +240,7 @@ fn check_issuer_independent_properties( time: time::Time, used_as_ca: UsedAsCa, sub_ca_count: usize, - required_eku_if_present: KeyPurposeId, + eku: ExtendedKeyUsage, ) -> Result<(), Error> { // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?; // TODO: Check signature algorithm like mozilla::pkix. @@ -263,9 +258,7 @@ fn check_issuer_independent_properties( untrusted::read_all_optional(cert.basic_constraints, Error::BadDer, |value| { check_basic_constraints(value, used_as_ca, sub_ca_count) })?; - untrusted::read_all_optional(cert.eku, Error::BadDer, |value| { - check_eku(value, required_eku_if_present) - })?; + untrusted::read_all_optional(cert.eku, Error::BadDer, |value| check_eku(value, eku))?; Ok(()) } @@ -341,42 +334,65 @@ fn check_basic_constraints( } } +/// Extended Key Usage (EKU) of a certificate. +#[derive(Clone, Copy)] +pub(crate) enum ExtendedKeyUsage { + /// If the certificate has EKUs, then the specified [`KeyPurposeId`] must be included. + RequiredIfPresent(KeyPurposeId), +} + +impl ExtendedKeyUsage { + fn key_purpose_id_equals(&self, value: untrusted::Input<'_>) -> bool { + match self { + ExtendedKeyUsage::RequiredIfPresent(eku) => *eku, + } + .oid_value + == value + } +} + +/// An OID value indicating an Extended Key Usage (EKU) key purpose. #[derive(Clone, Copy, PartialEq, Eq)] pub(crate) struct KeyPurposeId { oid_value: untrusted::Input<'static>, } +impl KeyPurposeId { + /// Construct a new [`KeyPurposeId`]. + /// + /// `oid` is the OBJECT IDENTIFIER in bytes. + const fn new(oid: &'static [u8]) -> Self { + Self { + oid_value: untrusted::Input::from(oid), + } + } +} + // id-pkix OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 } // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } #[allow(clippy::identity_op)] // TODO: Make this clearer -pub(crate) static EKU_SERVER_AUTH: KeyPurposeId = KeyPurposeId { - oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 1]), -}; +pub(crate) static EKU_SERVER_AUTH: KeyPurposeId = + KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 1]); // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } #[allow(clippy::identity_op)] // TODO: Make this clearer -pub(crate) static EKU_CLIENT_AUTH: KeyPurposeId = KeyPurposeId { - oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 2]), -}; +pub(crate) static EKU_CLIENT_AUTH: KeyPurposeId = + KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 2]); // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } #[allow(clippy::identity_op)] // TODO: Make this clearer -pub(crate) static EKU_OCSP_SIGNING: KeyPurposeId = KeyPurposeId { - oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 9]), -}; +pub(crate) static EKU_OCSP_SIGNING: KeyPurposeId = + KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 9]); // https://tools.ietf.org/html/rfc5280#section-4.2.1.12 -fn check_eku( - input: Option<&mut untrusted::Reader>, - required_eku_if_present: KeyPurposeId, -) -> Result<(), Error> { +fn check_eku(input: Option<&mut untrusted::Reader>, eku: ExtendedKeyUsage) -> Result<(), Error> { match input { Some(input) => { loop { let value = der::expect_tag_and_get_value(input, der::Tag::OID)?; - if value == required_eku_if_present.oid_value { + if eku.key_purpose_id_equals(value) { input.skip_to_end(); break; } @@ -396,7 +412,7 @@ fn check_eku( // important that id-kp-OCSPSigning is explicit so that a normal // end-entity certificate isn't able to sign trusted OCSP responses // for itself or for other certificates issued by its issuing CA. - if required_eku_if_present.oid_value == EKU_OCSP_SIGNING.oid_value { + if eku.key_purpose_id_equals(EKU_OCSP_SIGNING.oid_value) { return Err(Error::RequiredEkuNotFound); } @@ -457,3 +473,14 @@ where } Err(error) } + +#[cfg(test)] +mod tests { + use crate::verify_cert::{ExtendedKeyUsage, EKU_SERVER_AUTH}; + + #[test] + fn eku_key_purpose_id() { + assert!(ExtendedKeyUsage::RequiredIfPresent(EKU_SERVER_AUTH) + .key_purpose_id_equals(EKU_SERVER_AUTH.oid_value)) + } +} From 9d374c9569e45393b9d1b57a9a5047bb470bca12 Mon Sep 17 00:00:00 2001 From: Sietse Ringers Date: Fri, 14 Jul 2023 09:59:26 +0200 Subject: [PATCH 2/3] end_entity: add method to verify an EndEntityCert with a custom EKU The new method is similar to verify_is_valid_tls_server_cert() and verify_is_valid_tls_client_cert(), but allows the caller to specify its own EKU. Using the new ExtendedKeyUsage enum, the caller can choose if the EKU is required to be present, or if verification also passes if no EKUs are present (normal behaviour for server and client certificates). --- src/end_entity.rs | 86 +++++++++++++++++++++++++++++++++----------- src/lib.rs | 3 +- src/trust_anchor.rs | 4 +++ src/verify_cert.rs | 15 +++++--- tests/custom_ekus.rs | 68 +++++++++++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 25 deletions(-) create mode 100644 tests/custom_ekus.rs diff --git a/src/end_entity.rs b/src/end_entity.rs index c25f2f13..aad4e7e6 100644 --- a/src/end_entity.rs +++ b/src/end_entity.rs @@ -15,8 +15,9 @@ #[cfg(feature = "alloc")] use crate::subject_name::GeneralDnsNameRef; use crate::{ - cert, signed_data, subject_name, verify_cert, CertRevocationList, Error, SignatureAlgorithm, - SubjectNameRef, Time, TlsClientTrustAnchors, TlsServerTrustAnchors, + cert, signed_data, subject_name, verify_cert, CertRevocationList, Error, ExtendedKeyUsage, + NonTlsTrustAnchors, SignatureAlgorithm, SubjectNameRef, Time, TlsClientTrustAnchors, + TlsServerTrustAnchors, TrustAnchor, }; /// An end-entity certificate. @@ -74,6 +75,57 @@ impl<'a> EndEntityCert<'a> { &self.inner } + fn verify_is_valid_cert( + &self, + supported_sig_algs: &[&SignatureAlgorithm], + trust_anchors: &[TrustAnchor], + intermediate_certs: &[&[u8]], + time: Time, + eku: ExtendedKeyUsage, + crls: &[&dyn CertRevocationList], + ) -> Result<(), Error> { + verify_cert::build_chain( + &verify_cert::ChainOptions { + eku, + supported_sig_algs, + trust_anchors, + intermediate_certs, + crls, + }, + &self.inner, + time, + ) + } + + /// Verifies that the end-entity certificate is valid for use against the + /// specified Extended Key Usage (EKU). + /// + /// `supported_sig_algs` is the list of signature algorithms that are + /// trusted for use in certificate signatures; the end-entity certificate's + /// public key is not validated against this list. `trust_anchors` is the + /// list of root CAs to trust. `intermediate_certs` is the sequence of + /// intermediate certificates that the server sent in the TLS handshake. + /// `time` is the time for which the validation is effective (usually the + /// current time). + pub fn verify_is_valid_cert_with_eku( + &self, + supported_sig_algs: &[&SignatureAlgorithm], + &NonTlsTrustAnchors(trust_anchors): &NonTlsTrustAnchors, + intermediate_certs: &[&[u8]], + time: Time, + eku: ExtendedKeyUsage, + crls: &[&dyn CertRevocationList], + ) -> Result<(), Error> { + self.verify_is_valid_cert( + supported_sig_algs, + trust_anchors, + intermediate_certs, + time, + eku, + crls, + ) + } + /// Verifies that the end-entity certificate is valid for use by a TLS /// server. /// @@ -91,16 +143,13 @@ impl<'a> EndEntityCert<'a> { intermediate_certs: &[&[u8]], time: Time, ) -> Result<(), Error> { - verify_cert::build_chain( - &verify_cert::ChainOptions { - eku: verify_cert::ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_SERVER_AUTH), - supported_sig_algs, - trust_anchors, - intermediate_certs, - crls: &[], - }, - &self.inner, + self.verify_is_valid_cert( + supported_sig_algs, + trust_anchors, + intermediate_certs, time, + ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_SERVER_AUTH), + &[], ) } @@ -123,16 +172,13 @@ impl<'a> EndEntityCert<'a> { time: Time, crls: &[&dyn CertRevocationList], ) -> Result<(), Error> { - verify_cert::build_chain( - &verify_cert::ChainOptions { - eku: verify_cert::ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_CLIENT_AUTH), - supported_sig_algs, - trust_anchors, - intermediate_certs, - crls, - }, - &self.inner, + self.verify_is_valid_cert( + supported_sig_algs, + trust_anchors, + intermediate_certs, time, + ExtendedKeyUsage::RequiredIfPresent(verify_cert::EKU_CLIENT_AUTH), + crls, ) } diff --git a/src/lib.rs b/src/lib.rs index 982a93f7..57ca13e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,8 @@ pub use { SubjectNameRef, }, time::Time, - trust_anchor::{TlsClientTrustAnchors, TlsServerTrustAnchors, TrustAnchor}, + trust_anchor::{NonTlsTrustAnchors, TlsClientTrustAnchors, TlsServerTrustAnchors, TrustAnchor}, + verify_cert::{ExtendedKeyUsage, KeyPurposeId}, }; #[cfg(feature = "alloc")] diff --git a/src/trust_anchor.rs b/src/trust_anchor.rs index 87506b47..129b4587 100644 --- a/src/trust_anchor.rs +++ b/src/trust_anchor.rs @@ -26,6 +26,10 @@ pub struct TrustAnchor<'a> { pub name_constraints: Option<&'a [u8]>, } +/// Trust anchors which may be used for authenticating certificates of any kind. +#[derive(Debug)] +pub struct NonTlsTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); + /// Trust anchors which may be used for authenticating servers. #[derive(Debug)] pub struct TlsServerTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); diff --git a/src/verify_cert.rs b/src/verify_cert.rs index e8ca21d2..5374d9a4 100644 --- a/src/verify_cert.rs +++ b/src/verify_cert.rs @@ -336,7 +336,10 @@ fn check_basic_constraints( /// Extended Key Usage (EKU) of a certificate. #[derive(Clone, Copy)] -pub(crate) enum ExtendedKeyUsage { +pub enum ExtendedKeyUsage { + /// The certificate must contain the specified [`KeyPurposeId`] as EKU. + Required(KeyPurposeId), + /// If the certificate has EKUs, then the specified [`KeyPurposeId`] must be included. RequiredIfPresent(KeyPurposeId), } @@ -344,6 +347,7 @@ pub(crate) enum ExtendedKeyUsage { impl ExtendedKeyUsage { fn key_purpose_id_equals(&self, value: untrusted::Input<'_>) -> bool { match self { + ExtendedKeyUsage::Required(eku) => *eku, ExtendedKeyUsage::RequiredIfPresent(eku) => *eku, } .oid_value @@ -353,7 +357,7 @@ impl ExtendedKeyUsage { /// An OID value indicating an Extended Key Usage (EKU) key purpose. #[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) struct KeyPurposeId { +pub struct KeyPurposeId { oid_value: untrusted::Input<'static>, } @@ -361,7 +365,7 @@ impl KeyPurposeId { /// Construct a new [`KeyPurposeId`]. /// /// `oid` is the OBJECT IDENTIFIER in bytes. - const fn new(oid: &'static [u8]) -> Self { + pub const fn new(oid: &'static [u8]) -> Self { Self { oid_value: untrusted::Input::from(oid), } @@ -403,6 +407,9 @@ fn check_eku(input: Option<&mut untrusted::Reader>, eku: ExtendedKeyUsage) -> Re Ok(()) } None => { + if matches!(eku, ExtendedKeyUsage::Required(_)) { + return Err(Error::RequiredEkuNotFound); + } // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: // "OCSP signing delegation SHALL be designated by the inclusion of // id-kp-OCSPSigning in an extended key usage certificate extension @@ -476,7 +483,7 @@ where #[cfg(test)] mod tests { - use crate::verify_cert::{ExtendedKeyUsage, EKU_SERVER_AUTH}; + use crate::{verify_cert::EKU_SERVER_AUTH, ExtendedKeyUsage}; #[test] fn eku_key_purpose_id() { diff --git a/tests/custom_ekus.rs b/tests/custom_ekus.rs new file mode 100644 index 00000000..62f71861 --- /dev/null +++ b/tests/custom_ekus.rs @@ -0,0 +1,68 @@ +#[cfg(feature = "alloc")] +fn check_cert( + ee: &[u8], + ca: &[u8], + eku: webpki::ExtendedKeyUsage, + result: Result<(), webpki::Error>, +) { + let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; + let anchors = webpki::NonTlsTrustAnchors(&anchors); + + let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); + let cert = webpki::EndEntityCert::try_from(ee).unwrap(); + + assert_eq!( + cert.verify_is_valid_cert_with_eku( + eku, + &[&webpki::RSA_PKCS1_2048_8192_SHA256], + &anchors, + &[], + time, + &[], + ), + result + ); +} + +#[cfg(feature = "alloc")] +#[allow(clippy::identity_op)] +static EKU_CLIENT_AUTH: webpki::KeyPurposeId = + webpki::KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 2]); + +#[cfg(feature = "alloc")] +#[allow(clippy::identity_op)] +static EKU_SERVER_AUTH: webpki::KeyPurposeId = + webpki::KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 1]); + +#[cfg(feature = "alloc")] +#[test] +pub fn verify_custom_eku() { + use webpki::ExtendedKeyUsage::Required; + use webpki::ExtendedKeyUsage::RequiredIfPresent; + + let err = Err(webpki::Error::RequiredEkuNotFound); + + let ee = include_bytes!("client_auth/cert_with_clientauth_eku_accepted_for_client_auth.ee.der"); + let ca = include_bytes!("client_auth/cert_with_clientauth_eku_accepted_for_client_auth.ca.der"); + check_cert(ee, ca, Required(EKU_CLIENT_AUTH), Ok(())); + check_cert(ee, ca, Required(EKU_SERVER_AUTH), err); + check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); + check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), err); + + let ee = include_bytes!("client_auth/cert_with_no_eku_accepted_for_client_auth.ee.der"); + let ca = include_bytes!("client_auth/cert_with_no_eku_accepted_for_client_auth.ca.der"); + check_cert(ee, ca, Required(EKU_CLIENT_AUTH), err); + check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); + + let ee = include_bytes!("client_auth/cert_with_both_ekus_accepted_for_client_auth.ee.der"); + let ca = include_bytes!("client_auth/cert_with_both_ekus_accepted_for_client_auth.ca.der"); + check_cert(ee, ca, Required(EKU_CLIENT_AUTH), Ok(())); + check_cert(ee, ca, Required(EKU_SERVER_AUTH), Ok(())); + check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); + check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), Ok(())); +} + +#[test] +fn key_purpose_id() { + webpki::KeyPurposeId::new(&[1, 2, 3]); +} From 091588a805ebf9deb895960f36a02ebd4a26d752 Mon Sep 17 00:00:00 2001 From: Sietse Ringers Date: Sat, 22 Jul 2023 10:51:36 +0200 Subject: [PATCH 3/3] tests: add certificates with custom eku --- tests/custom_ekus.rs | 66 +++++++++++++++++++++++-------------- tests/misc/mdoc_eku.ca.der | Bin 0 -> 466 bytes tests/misc/mdoc_eku.ee.der | Bin 0 -> 499 bytes 3 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 tests/misc/mdoc_eku.ca.der create mode 100644 tests/misc/mdoc_eku.ee.der diff --git a/tests/custom_ekus.rs b/tests/custom_ekus.rs index 62f71861..d3d322ac 100644 --- a/tests/custom_ekus.rs +++ b/tests/custom_ekus.rs @@ -1,25 +1,25 @@ +#[cfg(feature = "alloc")] +use webpki::ExtendedKeyUsage::{Required, RequiredIfPresent}; + #[cfg(feature = "alloc")] fn check_cert( ee: &[u8], ca: &[u8], eku: webpki::ExtendedKeyUsage, + time: webpki::Time, result: Result<(), webpki::Error>, ) { let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let anchors = webpki::NonTlsTrustAnchors(&anchors); + let algs = &[ + &webpki::RSA_PKCS1_2048_8192_SHA256, + &webpki::ECDSA_P256_SHA256, + ]; - let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( - cert.verify_is_valid_cert_with_eku( - eku, - &[&webpki::RSA_PKCS1_2048_8192_SHA256], - &anchors, - &[], - time, - &[], - ), + cert.verify_is_valid_cert_with_eku(algs, &anchors, &[], time, eku, &[]), result ); } @@ -35,31 +35,47 @@ static EKU_SERVER_AUTH: webpki::KeyPurposeId = webpki::KeyPurposeId::new(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 1]); #[cfg(feature = "alloc")] -#[test] -pub fn verify_custom_eku() { - use webpki::ExtendedKeyUsage::Required; - use webpki::ExtendedKeyUsage::RequiredIfPresent; +#[allow(clippy::identity_op)] +static EKU_MDOC_ISSUER_AUTH: webpki::KeyPurposeId = + webpki::KeyPurposeId::new(&[(40 * 1) + 0, 129, 140, 93, 5, 1, 2]); +#[cfg(feature = "alloc")] +#[test] +pub fn verify_custom_eku_mdoc() { let err = Err(webpki::Error::RequiredEkuNotFound); + let time = webpki::Time::from_seconds_since_unix_epoch(1609459200); // Jan 1 01:00:00 CET 2021 - let ee = include_bytes!("client_auth/cert_with_clientauth_eku_accepted_for_client_auth.ee.der"); - let ca = include_bytes!("client_auth/cert_with_clientauth_eku_accepted_for_client_auth.ca.der"); - check_cert(ee, ca, Required(EKU_CLIENT_AUTH), Ok(())); - check_cert(ee, ca, Required(EKU_SERVER_AUTH), err); - check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); - check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), err); + let ee = include_bytes!("misc/mdoc_eku.ee.der"); + let ca = include_bytes!("misc/mdoc_eku.ca.der"); + check_cert(ee, ca, Required(EKU_MDOC_ISSUER_AUTH), time, Ok(())); + check_cert(ee, ca, Required(EKU_SERVER_AUTH), time, err); + check_cert( + ee, + ca, + RequiredIfPresent(EKU_MDOC_ISSUER_AUTH), + time, + Ok(()), + ); + check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), time, err); +} + +#[cfg(feature = "alloc")] +#[test] +pub fn verify_custom_eku_client() { + let err = Err(webpki::Error::RequiredEkuNotFound); + let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); let ee = include_bytes!("client_auth/cert_with_no_eku_accepted_for_client_auth.ee.der"); let ca = include_bytes!("client_auth/cert_with_no_eku_accepted_for_client_auth.ca.der"); - check_cert(ee, ca, Required(EKU_CLIENT_AUTH), err); - check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); + check_cert(ee, ca, Required(EKU_CLIENT_AUTH), time, err); + check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), time, Ok(())); let ee = include_bytes!("client_auth/cert_with_both_ekus_accepted_for_client_auth.ee.der"); let ca = include_bytes!("client_auth/cert_with_both_ekus_accepted_for_client_auth.ca.der"); - check_cert(ee, ca, Required(EKU_CLIENT_AUTH), Ok(())); - check_cert(ee, ca, Required(EKU_SERVER_AUTH), Ok(())); - check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), Ok(())); - check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), Ok(())); + check_cert(ee, ca, Required(EKU_CLIENT_AUTH), time, Ok(())); + check_cert(ee, ca, Required(EKU_SERVER_AUTH), time, Ok(())); + check_cert(ee, ca, RequiredIfPresent(EKU_CLIENT_AUTH), time, Ok(())); + check_cert(ee, ca, RequiredIfPresent(EKU_SERVER_AUTH), time, Ok(())); } #[test] diff --git a/tests/misc/mdoc_eku.ca.der b/tests/misc/mdoc_eku.ca.der new file mode 100644 index 0000000000000000000000000000000000000000..7a5c21361902ffb540de661f9979ecd2fd532b91 GIT binary patch literal 466 zcmXqLVmxQi#8|w5nTe5!NknVQ+Y3RPBJ_Q-ZYH+fEBJCR%5sVU7aNCGo5wj@7G@>` zWkV4IAvWev7G@sq(vtjw%tVFE#NdUQv4ibpVuU(?nUS5@iGfAOPQZ2#`=*$va;|sxm)_Vb>R4x&p6KKzRZ;qQ zi$s@_;xi}HnHO(Mu6m#LQ~C0gZQ`6Ev(FuRmH&Zt2U8X|wiq-v8pr`1EGxt! zZXntyoLZ5XTac6L0HyVk^K%VkK=Se|q6WeSf(!T;@HTNH%gTae`B=nQL_&TkH!twf zcyQC8QYrBSk4NLB1Kb9DAZdO^#{Vq9P-A2RhncJ}h|gib2Ber68IZ%3*^|M*jY*N= zO=mrK*HZxvjm}VJ`8I~k)Y+voW_=f$zl`&c)6AvE+kr|hblfPBk7eDQ@IJ4V$!@}Z VS;M<>>5MD-{>>_6W|E(g0|0ZVi}3&e literal 0 HcmV?d00001 diff --git a/tests/misc/mdoc_eku.ee.der b/tests/misc/mdoc_eku.ee.der new file mode 100644 index 0000000000000000000000000000000000000000..c1d9ab4491db479da673a21e30d1fe8e4458b7bd GIT binary patch literal 499 zcmXqLVtjAV#5i>UGZP~dlZcIr*t_d3pSK7<=@0u*y82gc`|B11E;bIWHji_*EX+&> z%7!8aLTt>TEX+LIr6u_VnTZOSiOGqE+yLjw>3fhZu?5Q%G` zXeeYL05OCUYDh{ksu7U}!ffndTbUT4)-yA*GdnS`ta-k=*x~8Tl%A-fmCL@SyB=S4 z#cY9<^ZQrjTYpt|e2}aSzcIs3+WhiT%P&_u%;GFg?~k5xttX^9`b4qpS$&c0#f>Wr z8kZW#0qvI+Vi7kGZ4^$eNX#wBNp*nIddc~@1~MRdc@|LvVFSSh{0n%SxRGULL9%=- zVk{yek0yvOI~=C?|M;@D?b~%X`{LE3-%#h&70W{8DaS;G^;2ra`4r;t3v) z#!Cmd4fsF`_!$}hvj78?y}>{f#8(CJK>^9G(byBq%E*Kq^2{C#2Chts4ATp%b~2_r zoVdQ{){-g9bXcwTzBwn{d~nTjtqZ+-SWa(ZQm|gzI!Ab!O|I0n+D2dJM@}*8CtOi- P(qUQgj+y1aA9%Fm$r literal 0 HcmV?d00001