diff --git a/provider-example/examples/client.rs b/provider-example/examples/client.rs index 01462af2..6bb24c5f 100644 --- a/provider-example/examples/client.rs +++ b/provider-example/examples/client.rs @@ -2,7 +2,7 @@ use std::io::{stdout, Read, Write}; use std::net::TcpStream; use std::sync::Arc; -use rustls_provider_example::{certificate_verifier, PROVIDER}; +use rustls_provider_example::PROVIDER; fn main() { env_logger::init(); @@ -16,8 +16,7 @@ fn main() { let config = rustls::ClientConfig::builder_with_provider(PROVIDER) .with_safe_defaults() - .dangerous() - .with_custom_certificate_verifier(certificate_verifier(root_store)) + .with_root_certificates(root_store) .with_no_client_auth(); let server_name = "www.rust-lang.org".try_into().unwrap(); diff --git a/provider-example/src/lib.rs b/provider-example/src/lib.rs index 720f8a7a..2018665d 100644 --- a/provider-example/src/lib.rs +++ b/provider-example/src/lib.rs @@ -36,6 +36,10 @@ impl rustls::crypto::CryptoProvider for Provider { ) -> Result, rustls::Error> { unimplemented!() } + + fn signature_verification_algorithms(&self) -> rustls::WebPkiSupportedAlgorithms { + verify::ALGORITHMS + } } static ALL_CIPHER_SUITES: &[rustls::SupportedCipherSuite] = &[ @@ -67,12 +71,3 @@ pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: rustls::SupportedCipherS prf_provider: &rustls::crypto::tls12::PrfUsingHmac(&hmac::Sha256Hmac), aead_alg: &aead::Chacha20Poly1305, }); - -pub fn certificate_verifier( - roots: rustls::RootCertStore, -) -> Arc { - rustls::client::WebPkiServerVerifier::builder(roots.into()) - .with_signature_verification_algorithms(verify::ALGORITHMS) - .build() - .unwrap() -} diff --git a/rustls/src/client/builder.rs b/rustls/src/client/builder.rs index 5f81edd7..e46cdf5f 100644 --- a/rustls/src/client/builder.rs +++ b/rustls/src/client/builder.rs @@ -5,7 +5,6 @@ use crate::crypto::{CryptoProvider, SupportedKxGroup}; use crate::error::Error; use crate::key_log::NoKeyLog; use crate::suites::SupportedCipherSuite; -#[cfg(feature = "ring")] use crate::webpki; use crate::{verify, versions}; @@ -15,11 +14,9 @@ use pki_types::{CertificateDer, PrivateKeyDer}; use alloc::sync::Arc; use alloc::vec::Vec; -#[cfg(any(feature = "dangerous_configuration", feature = "ring"))] use core::marker::PhantomData; impl ConfigBuilder { - #[cfg(feature = "ring")] /// Choose how to verify server certificates. pub fn with_root_certificates( self, @@ -33,6 +30,9 @@ impl ConfigBuilder { versions: self.state.versions, verifier: Arc::new(webpki::WebPkiServerVerifier::new_without_revocation( root_store, + self.state + .provider + .signature_verification_algorithms(), )), }, side: PhantomData, diff --git a/rustls/src/crypto/mod.rs b/rustls/src/crypto/mod.rs index 2ceb805d..bd43307d 100644 --- a/rustls/src/crypto/mod.rs +++ b/rustls/src/crypto/mod.rs @@ -1,5 +1,6 @@ use crate::sign::SigningKey; use crate::suites; +use crate::webpki::WebPkiSupportedAlgorithms; use crate::{Error, NamedGroup}; use alloc::boxed::Box; @@ -54,6 +55,11 @@ pub trait CryptoProvider: Send + Sync + Debug + 'static { &self, key_der: PrivateKeyDer<'static>, ) -> Result, Error>; + + /// Return the signature verification algorithms for use with webpki. + /// + /// These are used for both certificate chain verification and handshake signature verification. + fn signature_verification_algorithms(&self) -> WebPkiSupportedAlgorithms; } /// A supported key exchange group. diff --git a/rustls/src/crypto/ring/mod.rs b/rustls/src/crypto/ring/mod.rs index ef0cee7f..f06b41fb 100644 --- a/rustls/src/crypto/ring/mod.rs +++ b/rustls/src/crypto/ring/mod.rs @@ -59,6 +59,10 @@ impl CryptoProvider for Ring { sign::any_supported_type(&key_der) .map_err(|_| Error::General("invalid private key".to_owned())) } + + fn signature_verification_algorithms(&self) -> WebPkiSupportedAlgorithms { + SUPPORTED_SIG_ALGS + } } /// The cipher suite configuration that an application should use by default. @@ -103,7 +107,7 @@ pub mod cipher_suite { /// A `WebPkiSupportedAlgorithms` value that reflects webpki's capabilities when /// compiled against *ring*. -pub(crate) static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { +static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { all: &[ webpki_algs::ECDSA_P256_SHA256, webpki_algs::ECDSA_P256_SHA384, diff --git a/rustls/src/verifybench.rs b/rustls/src/verifybench.rs index 61b3383e..8d6b8d00 100644 --- a/rustls/src/verifybench.rs +++ b/rustls/src/verifybench.rs @@ -9,6 +9,7 @@ use core::time::Duration; use std::time::Instant; +use crate::crypto::ring; use crate::verify::ServerCertVerifier; use crate::webpki::{RootCertStore, WebPkiServerVerifier}; @@ -208,7 +209,10 @@ impl Context { } fn bench(&self, count: usize) { - let verifier = WebPkiServerVerifier::new_without_revocation(self.roots.clone()); + let verifier = WebPkiServerVerifier::new_without_revocation( + self.roots.clone(), + ring::RING.signature_verification_algorithms(), + ); const OCSP_RESPONSE: &[u8] = &[]; let mut times = Vec::new(); diff --git a/rustls/src/webpki/client_verifier.rs b/rustls/src/webpki/client_verifier.rs index 8fc57db7..38bb621d 100644 --- a/rustls/src/webpki/client_verifier.rs +++ b/rustls/src/webpki/client_verifier.rs @@ -5,6 +5,7 @@ use pki_types::{CertificateDer, CertificateRevocationListDer, UnixTime}; use webpki::{CertRevocationList, RevocationCheckDepth, UnknownStatusPolicy}; use super::{pki_error, VerifierBuilderError}; +use crate::crypto::CryptoProvider; use crate::verify::{ ClientCertVerified, ClientCertVerifier, DigitallySignedStruct, HandshakeSignatureValid, NoClientAuth, @@ -24,11 +25,14 @@ pub struct ClientCertVerifierBuilder { revocation_check_depth: RevocationCheckDepth, unknown_revocation_policy: UnknownStatusPolicy, anon_policy: AnonymousClientPolicy, - supported_algs: Option, + supported_algs: WebPkiSupportedAlgorithms, } impl ClientCertVerifierBuilder { - pub(crate) fn new(roots: Arc) -> Self { + pub(crate) fn new( + roots: Arc, + supported_algs: WebPkiSupportedAlgorithms, + ) -> Self { Self { root_hint_subjects: roots.subjects(), roots, @@ -36,7 +40,7 @@ impl ClientCertVerifierBuilder { anon_policy: AnonymousClientPolicy::Deny, revocation_check_depth: RevocationCheckDepth::Chain, unknown_revocation_policy: UnknownStatusPolicy::Deny, - supported_algs: None, + supported_algs, } } @@ -135,7 +139,7 @@ impl ClientCertVerifierBuilder { mut self, supported_algs: WebPkiSupportedAlgorithms, ) -> Self { - self.supported_algs = Some(supported_algs); + self.supported_algs = supported_algs; self } @@ -144,8 +148,8 @@ impl ClientCertVerifierBuilder { /// and to determine what to do with anonymous clients that do not respond to the client /// certificate authentication offer with a client certificate. /// - /// If the `ring` crate feature is supplied, and `with_signature_verification_algorithms` was not - /// called on the builder, a default set of signature verification algorithms is used. + /// If `with_signature_verification_algorithms` was not called on the builder, a default set of + /// signature verification algorithms is used, controlled by the selected [`crate::crypto::CryptoProvider`]. /// /// Once built, the provided `Arc` can be used with a Rustls /// [crate::server::ServerConfig] to configure client certificate validation using @@ -155,22 +159,11 @@ impl ClientCertVerifierBuilder { /// This function will return a `ClientCertVerifierBuilderError` if: /// 1. No trust anchors have been provided. /// 2. DER encoded CRLs have been provided that can not be parsed successfully. - /// 3. No signature verification algorithms were set and the `ring` feature is not enabled. - #[cfg_attr(not(feature = "ring"), allow(unused_mut))] - pub fn build(mut self) -> Result, VerifierBuilderError> { + pub fn build(self) -> Result, VerifierBuilderError> { if self.roots.is_empty() { return Err(VerifierBuilderError::NoRootAnchors); } - #[cfg(feature = "ring")] - if self.supported_algs.is_none() { - self.supported_algs = Some(crate::crypto::ring::SUPPORTED_SIG_ALGS); - } - - let supported_algs = self - .supported_algs - .ok_or(VerifierBuilderError::NoSupportedAlgorithms)?; - Ok(Arc::new(WebPkiClientVerifier::new( self.roots, self.root_hint_subjects, @@ -178,7 +171,7 @@ impl ClientCertVerifierBuilder { self.revocation_check_depth, self.unknown_revocation_policy, self.anon_policy, - supported_algs, + self.supported_algs, ))) } } @@ -246,14 +239,37 @@ pub struct WebPkiClientVerifier { } impl WebPkiClientVerifier { - /// Create builder to build up the `webpki` client certificate verifier configuration. + /// Create a builder for the `webpki` client certificate verifier configuration using + /// the default [`CryptoProvider`]. + /// /// Client certificate authentication will be offered by the server, and client certificates /// will be verified using the trust anchors found in the provided `roots`. If you /// wish to disable client authentication use [WebPkiClientVerifier::no_client_auth()] instead. /// + /// The cryptography used comes from the default [`CryptoProvider`]: [`crate::crypto::ring::RING`]. + /// Use [`Self::builder_with_provider`] if you wish to customize this. + /// /// For more information, see the [`ClientCertVerifierBuilder`] documentation. + #[cfg(feature = "ring")] pub fn builder(roots: Arc) -> ClientCertVerifierBuilder { - ClientCertVerifierBuilder::new(roots) + Self::builder_with_provider(roots, crate::crypto::ring::RING) + } + + /// Create a builder for the `webpki` client certificate verifier configuration using + /// a specified [`CryptoProvider`]. + /// + /// Client certificate authentication will be offered by the server, and client certificates + /// will be verified using the trust anchors found in the provided `roots`. If you + /// wish to disable client authentication use [WebPkiClientVerifier::no_client_auth()] instead. + /// + /// The cryptography used comes from the specified [`CryptoProvider`]. + /// + /// For more information, see the [`ClientCertVerifierBuilder`] documentation. + pub fn builder_with_provider( + roots: Arc, + provider: &'static dyn CryptoProvider, + ) -> ClientCertVerifierBuilder { + ClientCertVerifierBuilder::new(roots, provider.signature_verification_algorithms()) } /// Create a new `WebPkiClientVerifier` that disables client authentication. The server will @@ -563,7 +579,6 @@ mod tests { let all = vec![ VerifierBuilderError::NoRootAnchors, VerifierBuilderError::InvalidCrl(crate::CertRevocationListError::ParseError), - VerifierBuilderError::NoSupportedAlgorithms, ]; for err in all { diff --git a/rustls/src/webpki/mod.rs b/rustls/src/webpki/mod.rs index d72edc23..c00d15b6 100644 --- a/rustls/src/webpki/mod.rs +++ b/rustls/src/webpki/mod.rs @@ -34,11 +34,6 @@ pub enum VerifierBuilderError { NoRootAnchors, /// A provided CRL could not be parsed. InvalidCrl(CertRevocationListError), - /// No supported signature verification algorithms were provided. - /// - /// Call `with_signature_verification_algorithms` on the builder, or compile - /// with the `ring` feature. - NoSupportedAlgorithms, } impl From for VerifierBuilderError { @@ -52,9 +47,6 @@ impl fmt::Display for VerifierBuilderError { match self { Self::NoRootAnchors => write!(f, "no root trust anchors were provided"), Self::InvalidCrl(e) => write!(f, "provided CRL could not be parsed: {:?}", e), - Self::NoSupportedAlgorithms => { - write!(f, "no signature verification algorithms were provided") - } } } } diff --git a/rustls/src/webpki/server_verifier.rs b/rustls/src/webpki/server_verifier.rs index 71aba0a7..2e33c795 100644 --- a/rustls/src/webpki/server_verifier.rs +++ b/rustls/src/webpki/server_verifier.rs @@ -6,8 +6,7 @@ use alloc::vec::Vec; use pki_types::{CertificateDer, CertificateRevocationListDer, UnixTime}; use webpki::{CertRevocationList, RevocationCheckDepth, UnknownStatusPolicy}; -#[cfg(feature = "ring")] -use crate::crypto::ring::SUPPORTED_SIG_ALGS; +use crate::crypto::CryptoProvider; use crate::verify::{ DigitallySignedStruct, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, }; @@ -27,17 +26,20 @@ pub struct ServerCertVerifierBuilder { crls: Vec>, revocation_check_depth: RevocationCheckDepth, unknown_revocation_policy: UnknownStatusPolicy, - supported_algs: Option, + supported_algs: WebPkiSupportedAlgorithms, } impl ServerCertVerifierBuilder { - pub(crate) fn new(roots: Arc) -> Self { + pub(crate) fn new( + roots: Arc, + supported_algs: WebPkiSupportedAlgorithms, + ) -> Self { Self { roots, crls: Vec::new(), revocation_check_depth: RevocationCheckDepth::Chain, unknown_revocation_policy: UnknownStatusPolicy::Deny, - supported_algs: None, + supported_algs, } } @@ -86,15 +88,15 @@ impl ServerCertVerifierBuilder { mut self, supported_algs: WebPkiSupportedAlgorithms, ) -> Self { - self.supported_algs = Some(supported_algs); + self.supported_algs = supported_algs; self } /// Build a server certificate verifier, allowing control over the root certificates to use as /// trust anchors, and to control how server certificate revocation checking is performed. /// - /// If the `ring` crate feature is supplied, and `with_signature_verification_algorithms` was not - /// called on the builder, a default set of signature verification algorithms is used. + /// If `with_signature_verification_algorithms` was not called on the builder, a default set of + /// signature verification algorithms is used, controlled by the selected [`crate::crypto::CryptoProvider`]. /// /// Once built, the provided `Arc` can be used with a Rustls /// [crate::server::ServerConfig] to configure client certificate validation using @@ -104,28 +106,17 @@ impl ServerCertVerifierBuilder { /// This function will return a `CertVerifierBuilderError` if: /// 1. No trust anchors have been provided. /// 2. DER encoded CRLs have been provided that can not be parsed successfully. - /// 3. No signature verification algorithms were set and the `ring` feature is not enabled. - #[cfg_attr(not(feature = "ring"), allow(unused_mut))] - pub fn build(mut self) -> Result, VerifierBuilderError> { + pub fn build(self) -> Result, VerifierBuilderError> { if self.roots.is_empty() { return Err(VerifierBuilderError::NoRootAnchors); } - #[cfg(feature = "ring")] - if self.supported_algs.is_none() { - self.supported_algs = Some(SUPPORTED_SIG_ALGS); - } - - let supported_algs = self - .supported_algs - .ok_or(VerifierBuilderError::NoSupportedAlgorithms)?; - Ok(Arc::new(WebPkiServerVerifier::new( self.roots, parse_crls(self.crls)?, self.revocation_check_depth, self.unknown_revocation_policy, - supported_algs, + self.supported_algs, ))) } } @@ -142,24 +133,47 @@ pub struct WebPkiServerVerifier { #[allow(unreachable_pub)] impl WebPkiServerVerifier { - /// Create builder to build up the `webpki` server certificate verifier configuration. + /// Create a builder for the `webpki` server certificate verifier configuration using + /// the default [`CryptoProvider`]. + /// /// Server certificates will be verified using the trust anchors found in the provided `roots`. /// + /// The cryptography used comes from the default [`CryptoProvider`]: [`crate::crypto::ring::RING`]. + /// Use [`Self::builder_with_provider`] if you wish to customize this. + /// /// For more information, see the [`ServerCertVerifierBuilder`] documentation. + #[cfg(feature = "ring")] pub fn builder(roots: Arc) -> ServerCertVerifierBuilder { - ServerCertVerifierBuilder::new(roots) + Self::builder_with_provider(roots, crate::crypto::ring::RING) + } + + /// Create a builder for the `webpki` server certificate verifier configuration using + /// a specified [`CryptoProvider`]. + /// + /// Server certificates will be verified using the trust anchors found in the provided `roots`. + /// + /// The cryptography used comes from the specified [`CryptoProvider`]. + /// + /// For more information, see the [`ServerCertVerifierBuilder`] documentation. + pub fn builder_with_provider( + roots: Arc, + provider: &'static dyn CryptoProvider, + ) -> ServerCertVerifierBuilder { + ServerCertVerifierBuilder::new(roots, provider.signature_verification_algorithms()) } /// Short-cut for creating a `WebPkiServerVerifier` that does not perform certificate revocation /// checking, avoiding the need to use a builder. - #[cfg(feature = "ring")] - pub(crate) fn new_without_revocation(roots: impl Into>) -> Self { + pub(crate) fn new_without_revocation( + roots: impl Into>, + supported_algs: WebPkiSupportedAlgorithms, + ) -> Self { Self::new( roots, Vec::default(), RevocationCheckDepth::Chain, UnknownStatusPolicy::Allow, - SUPPORTED_SIG_ALGS, + supported_algs, ) } @@ -198,7 +212,12 @@ impl WebPkiServerVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { - verify_signed_struct(message, cert, dss, &SUPPORTED_SIG_ALGS) + verify_signed_struct( + message, + cert, + dss, + &crate::crypto::ring::RING.signature_verification_algorithms(), + ) } /// A full implementation of `ServerCertVerifier::verify_tls13_signature` or @@ -209,14 +228,21 @@ impl WebPkiServerVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { - verify_tls13(message, cert, dss, &SUPPORTED_SIG_ALGS) + verify_tls13( + message, + cert, + dss, + &crate::crypto::ring::RING.signature_verification_algorithms(), + ) } /// A full implementation of `ServerCertVerifier::supported_verify_schemes()` or /// `ClientCertVerifier::supported_verify_schemes()`. #[cfg(feature = "ring")] pub fn default_supported_verify_schemes() -> Vec { - SUPPORTED_SIG_ALGS.supported_schemes() + crate::crypto::ring::RING + .signature_verification_algorithms() + .supported_schemes() } } diff --git a/rustls/src/webpki/verify.rs b/rustls/src/webpki/verify.rs index 95842238..52e567ec 100644 --- a/rustls/src/webpki/verify.rs +++ b/rustls/src/webpki/verify.rs @@ -246,7 +246,7 @@ mod tests { fn webpki_supported_algorithms_is_debug() { assert_eq!( "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [ECDSA_NISTP384_SHA384, ECDSA_NISTP256_SHA256, ED25519, RSA_PSS_SHA512, RSA_PSS_SHA384, RSA_PSS_SHA256, RSA_PKCS1_SHA512, RSA_PKCS1_SHA384, RSA_PKCS1_SHA256] }", - format!("{:?}", crate::crypto::ring::SUPPORTED_SIG_ALGS) + format!("{:?}", crate::crypto::ring::RING.signature_verification_algorithms()) ); } } diff --git a/rustls/tests/api.rs b/rustls/tests/api.rs index be598c15..3b5b3b6d 100644 --- a/rustls/tests/api.rs +++ b/rustls/tests/api.rs @@ -5489,6 +5489,11 @@ impl rustls::crypto::CryptoProvider for FaultyRandomProvider { ) -> Result, Error> { self.parent.load_private_key(key_der) } + + fn signature_verification_algorithms(&self) -> rustls::WebPkiSupportedAlgorithms { + self.parent + .signature_verification_algorithms() + } } #[test]