From 7af5c004f58066e0e0c4501bb5d874bcc9d40270 Mon Sep 17 00:00:00 2001 From: Florian Uekermann Date: Sat, 10 Feb 2024 15:52:11 +0100 Subject: [PATCH] fixes for aws-lc-rs/ring feature switches --- .github/workflows/rust.yml | 5 +++-- src/acceptor.rs | 9 +++++++-- src/acme.rs | 8 ++++---- src/caches/dir.rs | 2 +- src/config.rs | 18 +++++++++++++++--- src/incoming.rs | 21 +++++++++++++++++++-- src/jose.rs | 8 ++++---- src/lib.rs | 23 +++++++++++++++++++++-- src/state.rs | 29 ++++++++++++++++++++++++----- 9 files changed, 98 insertions(+), 25 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c6915ed..3c91054 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,10 +15,11 @@ jobs: strategy: matrix: toolchain: ["stable", "beta", "nightly"] + no-default: ["", "--no-default-features"] crypto: ["ring", "aws-lc-rs", "ring,aws-lc-rs", ""] tokio: ["tokio", "tokio,axum", ""] steps: - uses: actions/checkout@v3 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - - run: cargo build --verbose --features ${{ matrix.crypto }},${{ matrix.tokio }} - - run: cargo test --verbose --features ${{ matrix.crypto }},${{ matrix.tokio }} + - run: cargo build --verbose ${{no-default}} --features ${{ matrix.crypto }},${{ matrix.tokio }} + - run: cargo test --verbose ${{no-default}} --features ${{ matrix.crypto }},${{ matrix.tokio }} diff --git a/src/acceptor.rs b/src/acceptor.rs index a553af1..9c664f6 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -1,5 +1,5 @@ use crate::acme::ACME_TLS_ALPN_NAME; -use crate::{is_tls_alpn_challenge, ResolvesServerCertAcme}; +use crate::{crypto_provider, is_tls_alpn_challenge, ResolvesServerCertAcme}; use core::fmt; use futures::prelude::*; use futures_rustls::rustls::server::Acceptor; @@ -16,9 +16,14 @@ pub struct AcmeAcceptor { } impl AcmeAcceptor { + #[cfg(any(feature = "ring", feature = "aws-lc-rs"))] #[deprecated(note = "please use high-level API via `AcmeState::incoming()` instead or refer to updated low-level API examples")] pub(crate) fn new(resolver: Arc) -> Self { - let mut config = ServerConfig::builder().with_no_client_auth().with_cert_resolver(resolver.clone()); + let mut config = ServerConfig::builder_with_provider(crypto_provider().into()) + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_cert_resolver(resolver.clone()); config.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec()); Self { config: Arc::new(config) } } diff --git a/src/acme.rs b/src/acme.rs index 93bbbd0..c3747b6 100644 --- a/src/acme.rs +++ b/src/acme.rs @@ -1,11 +1,11 @@ use std::sync::Arc; use crate::any_ecdsa_type; +use crate::crypto::error::{KeyRejected, Unspecified}; +use crate::crypto::rand::SystemRandom; +use crate::crypto::signature::{EcdsaKeyPair, EcdsaSigningAlgorithm, ECDSA_P256_SHA256_FIXED_SIGNING}; use crate::https_helper::{https, HttpsRequestError}; use crate::jose::{key_authorization_sha256, sign, JoseError}; -use crate::ring::error::{KeyRejected, Unspecified}; -use crate::ring::rand::SystemRandom; -use crate::ring::signature::{EcdsaKeyPair, EcdsaSigningAlgorithm, ECDSA_P256_SHA256_FIXED_SIGNING}; use base64::prelude::*; use futures_rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use futures_rustls::rustls::{sign::CertifiedKey, ClientConfig}; @@ -57,7 +57,7 @@ impl Account { ALG, key_pair, // ring 0.17 has a third argument here; aws-lc-rs doesn't. - #[cfg(feature = "ring")] + #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] &SystemRandom::new(), )?; let contact: Vec<&'a str> = contact.into_iter().map(AsRef::::as_ref).collect(); diff --git a/src/caches/dir.rs b/src/caches/dir.rs index 1d1cd55..18add36 100644 --- a/src/caches/dir.rs +++ b/src/caches/dir.rs @@ -1,4 +1,4 @@ -use crate::ring::digest::{Context, SHA256}; +use crate::crypto::digest::{Context, SHA256}; use crate::{AccountCache, CertCache}; use async_trait::async_trait; use base64::prelude::*; diff --git a/src/config.rs b/src/config.rs index a9b57b5..4b32c38 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,10 +1,11 @@ use crate::acme::{LETS_ENCRYPT_PRODUCTION_DIRECTORY, LETS_ENCRYPT_STAGING_DIRECTORY}; use crate::caches::{BoxedErrCache, CompositeCache, NoCache}; -use crate::{AccountCache, Cache, CertCache}; +use crate::{crypto_provider, AccountCache, Cache, CertCache}; use crate::{AcmeState, Incoming}; use core::fmt; use futures::{AsyncRead, AsyncWrite, Stream}; use futures_rustls::pki_types::TrustAnchor; +use futures_rustls::rustls::crypto::CryptoProvider; use futures_rustls::rustls::{ClientConfig, RootCertStore}; use std::convert::Infallible; use std::fmt::Debug; @@ -48,8 +49,13 @@ impl AcmeConfig { /// # type EA = EC; /// let config: AcmeConfig = AcmeConfig::new(["example.com"]).cache(NoCache::new()); /// ``` - /// + #[cfg(any(feature = "ring", feature = "aws-lc-rs"))] pub fn new(domains: impl IntoIterator>) -> Self { + Self::new_with_provider(domains, crypto_provider().into()) + } + + /// Same as [AcmeConfig::new], with a specific [CryptoProvider]. + pub fn new_with_provider(domains: impl IntoIterator>, provider: Arc) -> Self { let mut root_store = RootCertStore::empty(); root_store.extend(TLS_SERVER_ROOTS.iter().map(|ta| { let ta = ta.to_owned(); @@ -59,7 +65,13 @@ impl AcmeConfig { name_constraints: ta.name_constraints.map(Into::into), } })); - let client_config = Arc::new(ClientConfig::builder().with_root_certificates(root_store).with_no_client_auth()); + let client_config = Arc::new( + ClientConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .with_root_certificates(root_store) + .with_no_client_auth(), + ); AcmeConfig { client_config, directory_url: LETS_ENCRYPT_STAGING_DIRECTORY.into(), diff --git a/src/incoming.rs b/src/incoming.rs index 2c03516..4e20be5 100644 --- a/src/incoming.rs +++ b/src/incoming.rs @@ -1,8 +1,9 @@ use crate::acceptor::{AcmeAccept, AcmeAcceptor}; -use crate::AcmeState; +use crate::{crypto_provider, AcmeState}; use core::fmt; use futures::stream::{FusedStream, FuturesUnordered}; use futures::{AsyncRead, AsyncWrite, Stream}; +use futures_rustls::rustls::crypto::CryptoProvider; use futures_rustls::rustls::ServerConfig; use futures_rustls::server::TlsStream; use futures_rustls::Accept; @@ -47,8 +48,24 @@ impl> + Unpin, EC: Debug + 'static, EA: Debug + 'static> Incoming { + #[cfg(any(feature = "ring", feature = "aws-lc-rs"))] pub fn new(tcp_incoming: ITCP, state: AcmeState, acceptor: AcmeAcceptor, alpn_protocols: Vec>) -> Self { - let mut config = ServerConfig::builder().with_no_client_auth().with_cert_resolver(state.resolver()); + Self::new_with_provider(tcp_incoming, state, acceptor, alpn_protocols, crypto_provider().into()) + } + + /// Same as [Incoming::new], with a specific [CryptoProvider]. + pub fn new_with_provider( + tcp_incoming: ITCP, + state: AcmeState, + acceptor: AcmeAcceptor, + alpn_protocols: Vec>, + provider: Arc, + ) -> Self { + let mut config = ServerConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_cert_resolver(state.resolver()); config.alpn_protocols = alpn_protocols; Self { state, diff --git a/src/jose.rs b/src/jose.rs index bceb014..eb519ba 100644 --- a/src/jose.rs +++ b/src/jose.rs @@ -1,6 +1,6 @@ -use crate::ring::digest::{digest, Digest, SHA256}; -use crate::ring::rand::SystemRandom; -use crate::ring::signature::{EcdsaKeyPair, KeyPair}; +use crate::crypto::digest::{digest, Digest, SHA256}; +use crate::crypto::rand::SystemRandom; +use crate::crypto::signature::{EcdsaKeyPair, KeyPair}; use base64::prelude::*; use serde::Serialize; use thiserror::Error; @@ -110,5 +110,5 @@ pub enum JoseError { #[error("json serialization failed: {0}")] Json(#[from] serde_json::Error), #[error("crypto error: {0}")] - Crypto(#[from] crate::ring::error::Unspecified), + Crypto(#[from] crate::crypto::error::Unspecified), } diff --git a/src/lib.rs b/src/lib.rs index e233812..748bcdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,9 +134,28 @@ pub use resolver::*; pub use state::*; #[cfg(feature = "aws-lc-rs")] -use ::{aws_lc_rs as ring, futures_rustls::rustls::crypto::aws_lc_rs::sign::any_ecdsa_type}; +use ::aws_lc_rs as crypto; #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] -use ::{futures_rustls::rustls::crypto::ring::sign::any_ecdsa_type, ring}; +use ::ring as crypto; +// TODO: Can we use something like CryptoProvider for rustls, but for ring to drop this requirement? #[cfg(not(any(feature = "ring", feature = "aws-lc-rs")))] compile_error!("rustls-acme requires either the ring or aws-lc-rs feature enabled"); + +#[cfg(any(feature = "ring", feature = "aws-lc-rs"))] +pub(crate) fn any_ecdsa_type( + der: &futures_rustls::pki_types::PrivateKeyDer, +) -> Result, futures_rustls::rustls::Error> { + #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] + return futures_rustls::rustls::crypto::ring::sign::any_ecdsa_type(&der); + #[cfg(feature = "aws-lc-rs")] + return futures_rustls::rustls::crypto::aws_lc_rs::sign::any_ecdsa_type(&der); +} + +#[cfg(any(feature = "ring", feature = "aws-lc-rs"))] +pub(crate) fn crypto_provider() -> futures_rustls::rustls::crypto::CryptoProvider { + #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] + return futures_rustls::rustls::crypto::ring::default_provider(); + #[cfg(feature = "aws-lc-rs")] + return futures_rustls::rustls::crypto::aws_lc_rs::default_provider(); +} diff --git a/src/state.rs b/src/state.rs index 9c85efe..01b2cc2 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,6 @@ use crate::acceptor::AcmeAcceptor; use crate::acme::{Account, AcmeError, Auth, AuthStatus, Directory, Identifier, Order, OrderStatus, ACME_TLS_ALPN_NAME}; -use crate::{AcmeConfig, Incoming, ResolvesServerCertAcme}; +use crate::{any_ecdsa_type, crypto_provider, AcmeConfig, Incoming, ResolvesServerCertAcme}; use async_io::Timer; use chrono::{DateTime, TimeZone, Utc}; use core::fmt; @@ -8,8 +8,9 @@ use futures::future::try_join_all; use futures::prelude::*; use futures::ready; use futures_rustls::pki_types::{CertificateDer as RustlsCertificate, PrivateKeyDer, PrivatePkcs8KeyDer}; +use futures_rustls::rustls::crypto::CryptoProvider; use futures_rustls::rustls::sign::CertifiedKey; -use futures_rustls::rustls::{crypto::ring::sign::any_ecdsa_type, ServerConfig}; +use futures_rustls::rustls::ServerConfig; use rcgen::{CertificateParams, DistinguishedName, PKCS_ECDSA_P256_SHA256}; use std::convert::Infallible; use std::fmt::Debug; @@ -139,16 +140,34 @@ impl AcmeState { self.resolver.clone() } /// Creates a [rustls::ServerConfig] for tls-alpn-01 challenge connections. Use this if [crate::is_tls_alpn_challenge] returns `true`. + #[cfg(any(feature = "ring", feature = "aws-lc-rs"))] pub fn challenge_rustls_config(&self) -> Arc { - let mut rustls_config = ServerConfig::builder().with_no_client_auth().with_cert_resolver(self.resolver()); + self.challenge_rustls_config_with_provider(crypto_provider().into()) + } + /// Same as [AcmeState::challenge_rustls_config], with a specific [CryptoProvider]. + pub fn challenge_rustls_config_with_provider(&self, provider: Arc) -> Arc { + let mut rustls_config = ServerConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_cert_resolver(self.resolver()); rustls_config.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec()); return Arc::new(rustls_config); } /// Creates a default [rustls::ServerConfig] for accepting regular tls connections. Use this if [crate::is_tls_alpn_challenge] returns `false`. /// If you need a [rustls::ServerConfig], which uses the certificates acquired by this [AcmeState], /// you may build your own using the output of [AcmeState::resolver]. + #[cfg(any(feature = "ring", feature = "aws-lc-rs"))] pub fn default_rustls_config(&self) -> Arc { - let rustls_config = ServerConfig::builder().with_no_client_auth().with_cert_resolver(self.resolver()); + self.default_rustls_config_with_provider(crypto_provider().into()) + } + /// Same as [AcmeState::default_rustls_config], with a specific [CryptoProvider]. + pub fn default_rustls_config_with_provider(&self, provider: Arc) -> Arc { + let rustls_config = ServerConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_cert_resolver(self.resolver()); return Arc::new(rustls_config); } pub fn new(config: AcmeConfig) -> Self { @@ -171,7 +190,7 @@ impl AcmeState { wait: None, } } - fn parse_cert(pem: &[u8]) -> Result<(futures_rustls::rustls::sign::CertifiedKey, [DateTime; 2]), CertParseError> { + fn parse_cert(pem: &[u8]) -> Result<(CertifiedKey, [DateTime; 2]), CertParseError> { let mut pems = pem::parse_many(&pem)?; if pems.len() < 2 { return Err(CertParseError::TooFewPem(pems.len()));