From 875fcef52e64e9643e66c3994392f9c95414abd7 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 24 Jul 2023 22:43:20 +0200 Subject: [PATCH] Unify high-level API to make key usage explicit --- src/end_entity.rs | 36 +++++++++----- src/lib.rs | 4 +- src/trust_anchor.rs | 6 +-- tests/better_tls.rs | 9 ++-- tests/client_auth.rs | 15 ++++-- tests/client_auth_revocation.rs | 8 +-- tests/custom_ekus.rs | 5 +- tests/integration.rs | 87 +++++++++++++++++++++++++-------- tests/tls_server_certs.rs | 14 ++++-- 9 files changed, 126 insertions(+), 58 deletions(-) diff --git a/src/end_entity.rs b/src/end_entity.rs index 486b0559..d5b75475 100644 --- a/src/end_entity.rs +++ b/src/end_entity.rs @@ -16,9 +16,10 @@ use crate::subject_name::GeneralDnsNameRef; use crate::{ cert, signed_data, subject_name, verify_cert, CertRevocationList, Error, KeyUsage, - NonTlsTrustAnchors, SignatureAlgorithm, SubjectNameRef, Time, TlsClientTrustAnchors, - TlsServerTrustAnchors, TrustAnchor, + SignatureAlgorithm, SubjectNameRef, Time, TrustAnchor, }; +#[allow(deprecated)] +use crate::{TlsClientTrustAnchors, TlsServerTrustAnchors}; /// An end-entity certificate. /// @@ -100,20 +101,25 @@ impl<'a> EndEntityCert<'a> { /// 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( + /// * `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). + /// * `usage` is the intended usage of the certificate, indicating what kind + /// of usage we're verifying the certificate for. + /// * `crls` is the list of certificate revocation lists to check + /// the certificate against. + pub fn verify_for_usage( &self, supported_sig_algs: &[&SignatureAlgorithm], - &NonTlsTrustAnchors(trust_anchors): &NonTlsTrustAnchors, + trust_anchors: &[TrustAnchor], intermediate_certs: &[&[u8]], time: Time, - eku: KeyUsage, + usage: KeyUsage, crls: &[&dyn CertRevocationList], ) -> Result<(), Error> { self.verify_is_valid_cert( @@ -121,7 +127,7 @@ impl<'a> EndEntityCert<'a> { trust_anchors, intermediate_certs, time, - eku, + usage, crls, ) } @@ -136,6 +142,8 @@ impl<'a> EndEntityCert<'a> { /// intermediate certificates that the server sent in the TLS handshake. /// `time` is the time for which the validation is effective (usually the /// current time). + #[allow(deprecated)] + #[deprecated(since = "0.101.2", note = "Use `verify_for_usage` instead")] pub fn verify_is_valid_tls_server_cert( &self, supported_sig_algs: &[&SignatureAlgorithm], @@ -164,6 +172,8 @@ impl<'a> EndEntityCert<'a> { /// `cert` is the purported end-entity certificate of the client. `time` is /// the time for which the validation is effective (usually the current /// time). + #[allow(deprecated)] + #[deprecated(since = "0.101.2", note = "Use `verify_for_usage` instead")] pub fn verify_is_valid_tls_client_cert( &self, supported_sig_algs: &[&SignatureAlgorithm], diff --git a/src/lib.rs b/src/lib.rs index a5345f0a..617b43bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,8 @@ mod crl; mod verify_cert; mod x509; +#[allow(deprecated)] +pub use trust_anchor::{TlsClientTrustAnchors, TlsServerTrustAnchors}; pub use { cert::{Cert, EndEntityOrCa}, crl::{BorrowedCertRevocationList, BorrowedRevokedCert, CertRevocationList, RevocationReason}, @@ -72,7 +74,7 @@ pub use { SubjectNameRef, }, time::Time, - trust_anchor::{NonTlsTrustAnchors, TlsClientTrustAnchors, TlsServerTrustAnchors, TrustAnchor}, + trust_anchor::TrustAnchor, verify_cert::KeyUsage, }; diff --git a/src/trust_anchor.rs b/src/trust_anchor.rs index 0ee37ee6..32e4a5b3 100644 --- a/src/trust_anchor.rs +++ b/src/trust_anchor.rs @@ -23,15 +23,13 @@ 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. +#[deprecated(since = "0.101.2")] #[derive(Debug)] pub struct TlsServerTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); /// Trust anchors which may be used for authenticating clients. +#[deprecated(since = "0.101.2")] #[derive(Debug)] pub struct TlsClientTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); diff --git a/tests/better_tls.rs b/tests/better_tls.rs index ccf59867..306b283b 100644 --- a/tests/better_tls.rs +++ b/tests/better_tls.rs @@ -1,7 +1,7 @@ use base64::{engine::general_purpose, Engine as _}; use serde::Deserialize; use std::collections::HashMap; -use webpki::TrustAnchor; +use webpki::{KeyUsage, TrustAnchor}; #[test] pub fn path_building() { @@ -11,7 +11,6 @@ pub fn path_building() { let root_der = &better_tls.root_der(); let roots = &[TrustAnchor::try_from_cert_der(root_der).expect("invalid trust anchor")]; - let trust_anchors = &webpki::TlsServerTrustAnchors(roots); let path_building_suite = better_tls .suites @@ -35,11 +34,13 @@ pub fn path_building() { // certificates won't expire. let now = webpki::Time::from_seconds_since_unix_epoch(1_688_651_734); - let result = ee_cert.verify_is_valid_tls_server_cert( + let result = ee_cert.verify_for_usage( &[&webpki::ECDSA_P256_SHA256], // All of the BetterTLS testcases use P256 keys. - trust_anchors, + roots, intermediates, now, + KeyUsage::server_auth(), + &[], ); match testcase.expected { diff --git a/tests/client_auth.rs b/tests/client_auth.rs index bffcb4f4..dd84e6d4 100644 --- a/tests/client_auth.rs +++ b/tests/client_auth.rs @@ -12,7 +12,8 @@ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -extern crate webpki; +#[cfg(feature = "alloc")] +use webpki::KeyUsage; #[cfg(feature = "alloc")] static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ @@ -29,12 +30,18 @@ static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ #[cfg(feature = "alloc")] fn check_cert(ee: &[u8], ca: &[u8]) -> Result<(), webpki::Error> { - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsClientTrustAnchors(&anchors); + let anchors = &[webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); let cert = webpki::EndEntityCert::try_from(ee).unwrap(); - cert.verify_is_valid_tls_client_cert(ALL_SIGALGS, &anchors, &[], time, &[]) + cert.verify_for_usage( + ALL_SIGALGS, + anchors, + &[], + time, + KeyUsage::client_auth(), + &[], + ) } // DO NOT EDIT BELOW: generated by tests/generate.py diff --git a/tests/client_auth_revocation.rs b/tests/client_auth_revocation.rs index c943f6fe..ea6ee216 100644 --- a/tests/client_auth_revocation.rs +++ b/tests/client_auth_revocation.rs @@ -12,7 +12,7 @@ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -extern crate webpki; +use webpki::KeyUsage; fn check_cert( ee: &[u8], @@ -21,15 +21,15 @@ fn check_cert( crls: &[&dyn webpki::CertRevocationList], ) -> Result<(), webpki::Error> { let anchors = &[webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsClientTrustAnchors(anchors.as_slice()); let cert = webpki::EndEntityCert::try_from(ee).unwrap(); let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); - cert.verify_is_valid_tls_client_cert( + cert.verify_for_usage( &[&webpki::ECDSA_P256_SHA256], - &anchors, + anchors, intermediates, time, + KeyUsage::client_auth(), crls, ) } diff --git a/tests/custom_ekus.rs b/tests/custom_ekus.rs index ed745059..0fc094df 100644 --- a/tests/custom_ekus.rs +++ b/tests/custom_ekus.rs @@ -9,8 +9,7 @@ fn check_cert( time: webpki::Time, result: Result<(), webpki::Error>, ) { - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::NonTlsTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let algs = &[ &webpki::RSA_PKCS1_2048_8192_SHA256, &webpki::ECDSA_P256_SHA256, @@ -19,7 +18,7 @@ fn check_cert( let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( - cert.verify_is_valid_cert_with_eku(algs, &anchors, &[], time, eku, &[]), + cert.verify_for_usage(algs, &anchors, &[], time, eku, &[]), result ); } diff --git a/tests/integration.rs b/tests/integration.rs index 9f18f744..85d6e0e6 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -12,7 +12,7 @@ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -extern crate webpki; +use webpki::KeyUsage; static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ &webpki::ECDSA_P256_SHA256, @@ -39,15 +39,21 @@ pub fn netflix() { let inter = include_bytes!("netflix/inter.der"); let ca = include_bytes!("netflix/ca.der"); - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(1_492_441_716); // 2017-04-17T15:08:36Z let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( Ok(()), - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[inter], time) + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[inter], + time, + KeyUsage::server_auth(), + &[] + ) ); } @@ -59,15 +65,21 @@ pub fn cloudflare_dns() { let inter = include_bytes!("cloudflare_dns/inter.der"); let ca = include_bytes!("cloudflare_dns/ca.der"); - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(1_663_495_771); let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( Ok(()), - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[inter], time) + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[inter], + time, + KeyUsage::server_auth(), + &[] + ) ); let check_name = |name: &str| { @@ -107,15 +119,21 @@ pub fn wpt() { let ee: &[u8] = include_bytes!("wpt/ee.der"); let ca = include_bytes!("wpt/ca.der"); - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(1_619_256_684); // 2021-04-24T09:31:24Z let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( Ok(()), - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time) + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[], + time, + KeyUsage::server_auth(), + &[] + ) ); } @@ -124,15 +142,21 @@ pub fn ed25519() { let ee: &[u8] = include_bytes!("ed25519/ee.der"); let ca = include_bytes!("ed25519/ca.der"); - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(1_547_363_522); // 2019-01-13T07:12:02Z let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( Ok(()), - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time) + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[], + time, + KeyUsage::server_auth(), + &[] + ) ); } @@ -144,16 +168,31 @@ fn critical_extensions() { let time = webpki::Time::from_seconds_since_unix_epoch(1_670_779_098); let anchors = [webpki::TrustAnchor::try_from_cert_der(root).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); let ee = include_bytes!("critical_extensions/ee-cert-noncrit-unknown-ext.der"); - let res = webpki::EndEntityCert::try_from(&ee[..]) - .and_then(|cert| cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[ca], time)); + let res = webpki::EndEntityCert::try_from(&ee[..]).and_then(|cert| { + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[ca], + time, + KeyUsage::server_auth(), + &[], + ) + }); assert_eq!(res, Ok(()), "accept non-critical unknown extension"); let ee = include_bytes!("critical_extensions/ee-cert-crit-unknown-ext.der"); - let res = webpki::EndEntityCert::try_from(&ee[..]) - .and_then(|cert| cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[ca], time)); + let res = webpki::EndEntityCert::try_from(&ee[..]).and_then(|cert| { + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[ca], + time, + KeyUsage::server_auth(), + &[], + ) + }); assert_eq!( res, Err(webpki::Error::UnsupportedCriticalExtension), @@ -180,15 +219,21 @@ fn read_ee_with_neg_serial() { let ca: &[u8] = include_bytes!("misc/serial_neg_ca.der"); let ee: &[u8] = include_bytes!("misc/serial_neg_ee.der"); - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(1_667_401_500); // 2022-11-02T15:05:00Z let cert = webpki::EndEntityCert::try_from(ee).unwrap(); assert_eq!( Ok(()), - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time) + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[], + time, + KeyUsage::server_auth(), + &[] + ) ); } diff --git a/tests/tls_server_certs.rs b/tests/tls_server_certs.rs index b59d9999..e0d8f2ef 100644 --- a/tests/tls_server_certs.rs +++ b/tests/tls_server_certs.rs @@ -13,7 +13,7 @@ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #![cfg(feature = "alloc")] -extern crate webpki; +use webpki::KeyUsage; static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ &webpki::ECDSA_P256_SHA256, @@ -33,12 +33,18 @@ fn check_cert( valid_names: &[&str], invalid_names: &[&str], ) -> Result<(), webpki::Error> { - let anchors = vec![webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; - let anchors = webpki::TlsServerTrustAnchors(&anchors); + let anchors = [webpki::TrustAnchor::try_from_cert_der(ca).unwrap()]; let time = webpki::Time::from_seconds_since_unix_epoch(0x1fed_f00d); let cert = webpki::EndEntityCert::try_from(ee).unwrap(); - cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time)?; + cert.verify_for_usage( + ALL_SIGALGS, + &anchors, + &[], + time, + KeyUsage::server_auth(), + &[], + )?; for valid in valid_names { let name = webpki::SubjectNameRef::try_from_ascii_str(valid).unwrap();