diff --git a/Cargo.toml b/Cargo.toml index 2063466a7f..5e4678b03d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ arbitrary = { version = "1.0.1", features = ["derive"] } async-io = "2" async-std = "1.11" assert_matches = "1.1" +aws-lc-rs = { version = "1.8.1", default-features = false } bencher = "0.1.5" bytes = "1" clap = { version = "4", features = ["derive"] } @@ -33,7 +34,7 @@ rand = "0.8" rcgen = "0.13" ring = "0.17" rustc-hash = "2" -rustls = { version = "0.23.5", default-features = false, features = ["ring", "std"] } +rustls = { version = "0.23.5", default-features = false, features = ["std"] } rustls-pemfile = "2" rustls-platform-verifier = "0.3" serde = { version = "1.0", features = ["derive"] } diff --git a/deny.toml b/deny.toml index 43038b9add..3313d4a6aa 100644 --- a/deny.toml +++ b/deny.toml @@ -6,9 +6,10 @@ allow = [ "ISC", "MIT", "MPL-2.0", + "OpenSSL", "Unicode-DFS-2016", ] -exceptions = [{ allow = ["ISC", "MIT", "OpenSSL"], name = "ring" }] +exceptions = [{ name = "ring" }] private = { ignore = true } [[licenses.clarify]] diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 191569e24f..e9470b2814 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -15,7 +15,10 @@ all-features = true [features] default = ["rustls", "log"] -rustls = ["dep:rustls", "ring"] +aws-lc-rs = ["dep:aws-lc-rs", "aws-lc-rs/aws-lc-sys"] +rustls = ["rustls-ring"] +rustls-aws-lc-rs = ["dep:rustls", "rustls/aws-lc-rs", "aws-lc-rs"] +rustls-ring = ["dep:rustls", "rustls/ring", "ring"] ring = ["dep:ring"] # Enable rustls ring provider and direct ring usage # Provides `ClientConfig::with_platform_verifier()` convenience method @@ -25,6 +28,7 @@ log = ["tracing/log"] [dependencies] arbitrary = { workspace = true, optional = true } +aws-lc-rs = { workspace = true, optional = true } bytes = { workspace = true } rustc-hash = { workspace = true } rand = { workspace = true } diff --git a/quinn-proto/src/cid_generator.rs b/quinn-proto/src/cid_generator.rs index 6173e96f91..c59fb4102f 100644 --- a/quinn-proto/src/cid_generator.rs +++ b/quinn-proto/src/cid_generator.rs @@ -171,7 +171,6 @@ mod tests { use super::*; #[test] - #[cfg(feature = "ring")] fn validate_keyed_cid() { let mut generator = HashedConnectionIdGenerator::new(); let cid = generator.generate_cid(); diff --git a/quinn-proto/src/config.rs b/quinn-proto/src/config.rs index d4c8e63855..f174e0ffda 100644 --- a/quinn-proto/src/config.rs +++ b/quinn-proto/src/config.rs @@ -6,8 +6,6 @@ use std::{ time::Duration, }; -#[cfg(feature = "ring")] -use rand::RngCore; #[cfg(feature = "rustls")] use rustls::client::WebPkiServerVerifier; #[cfg(feature = "rustls")] @@ -759,16 +757,19 @@ impl fmt::Debug for EndpointConfig { } } -#[cfg(feature = "ring")] +#[cfg(any(feature = "aws-lc-rs", feature = "ring"))] impl Default for EndpointConfig { fn default() -> Self { + #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] + use aws_lc_rs::hmac; + use rand::RngCore; + #[cfg(feature = "ring")] + use ring::hmac; + let mut reset_key = [0; 64]; rand::thread_rng().fill_bytes(&mut reset_key); - Self::new(Arc::new(ring::hmac::Key::new( - ring::hmac::HMAC_SHA256, - &reset_key, - ))) + Self::new(Arc::new(hmac::Key::new(hmac::HMAC_SHA256, &reset_key))) } } @@ -934,16 +935,22 @@ impl ServerConfig { } } -#[cfg(feature = "ring")] +#[cfg(any(feature = "aws-lc-rs", feature = "ring"))] impl ServerConfig { /// Create a server config with the given [`crypto::ServerConfig`] /// /// Uses a randomized handshake token key. pub fn with_crypto(crypto: Arc) -> Self { + #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] + use aws_lc_rs::hkdf; + use rand::RngCore; + #[cfg(feature = "ring")] + use ring::hkdf; + let rng = &mut rand::thread_rng(); let mut master_key = [0u8; 64]; rng.fill_bytes(&mut master_key); - let master_key = ring::hkdf::Salt::new(ring::hkdf::HKDF_SHA256, &[]).extract(&master_key); + let master_key = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]).extract(&master_key); Self::new(crypto, Arc::new(master_key)) } diff --git a/quinn-proto/src/crypto.rs b/quinn-proto/src/crypto.rs index 17229708a1..f3c89b930c 100644 --- a/quinn-proto/src/crypto.rs +++ b/quinn-proto/src/crypto.rs @@ -18,8 +18,8 @@ use crate::{ }; /// Cryptography interface based on *ring* -#[cfg(feature = "ring")] -pub(crate) mod ring; +#[cfg(any(feature = "aws-lc-rs", feature = "ring"))] +pub(crate) mod ring_like; /// TLS interface based on rustls #[cfg(feature = "rustls")] pub mod rustls; diff --git a/quinn-proto/src/crypto/ring.rs b/quinn-proto/src/crypto/ring_like.rs similarity index 92% rename from quinn-proto/src/crypto/ring.rs rename to quinn-proto/src/crypto/ring_like.rs index aaeaaafbb0..1b5f301bfe 100644 --- a/quinn-proto/src/crypto/ring.rs +++ b/quinn-proto/src/crypto/ring_like.rs @@ -1,3 +1,6 @@ +#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] +use aws_lc_rs::{aead, error, hkdf, hmac}; +#[cfg(feature = "ring")] use ring::{aead, error, hkdf, hmac}; use crate::crypto::{self, CryptoError}; diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index aad4d0d3cf..aae2f41183 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -1,6 +1,9 @@ use std::{any::Any, io, str, sync::Arc}; +#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] +use aws_lc_rs::aead; use bytes::BytesMut; +#[cfg(feature = "ring")] use ring::aead; pub use rustls::Error; use rustls::{ @@ -307,14 +310,17 @@ impl QuicClientConfig { } pub(crate) fn inner(verifier: Arc) -> rustls::ClientConfig { - let mut config = rustls::ClientConfig::builder_with_provider( - rustls::crypto::ring::default_provider().into(), - ) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() // The *ring* default provider supports TLS 1.3 - .dangerous() - .with_custom_certificate_verifier(verifier) - .with_no_client_auth(); + #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] + let provider = rustls::crypto::aws_lc_rs::default_provider(); + #[cfg(feature = "ring")] + let provider = rustls::crypto::ring::default_provider(); + + let mut config = rustls::ClientConfig::builder_with_provider(Arc::new(provider)) + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap() // The default providers support TLS 1.3 + .dangerous() + .with_custom_certificate_verifier(verifier) + .with_no_client_auth(); config.enable_early_data = true; config diff --git a/quinn-proto/src/lib.rs b/quinn-proto/src/lib.rs index bb39101b78..02a9d22438 100644 --- a/quinn-proto/src/lib.rs +++ b/quinn-proto/src/lib.rs @@ -32,7 +32,7 @@ mod cid_queue; pub mod coding; mod constant_time; mod range_set; -#[cfg(all(test, feature = "rustls"))] +#[cfg(all(test, any(feature = "rustls-aws-lc-rs", feature = "rustls-ring")))] mod tests; pub mod transport_parameters; mod varint; diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index f67ab75ab2..e0a5d48f6f 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -7,9 +7,12 @@ use std::{ }; use assert_matches::assert_matches; +#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] +use aws_lc_rs::hmac; use bytes::Bytes; use hex_literal::hex; use rand::RngCore; +#[cfg(feature = "ring")] use ring::hmac; use rustls::{ pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}, diff --git a/quinn-proto/src/token.rs b/quinn-proto/src/token.rs index 8b63d43ea5..4fa6032951 100644 --- a/quinn-proto/src/token.rs +++ b/quinn-proto/src/token.rs @@ -164,9 +164,13 @@ impl fmt::Display for ResetToken { } } -#[cfg(test)] +#[cfg(all(test, any(feature = "aws-lc-rs", feature = "ring")))] mod test { + #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] + use aws_lc_rs::hkdf; #[cfg(feature = "ring")] + use ring::hkdf; + #[test] fn token_sanity() { use super::*; @@ -184,7 +188,7 @@ mod test { let mut master_key = [0; 64]; rng.fill_bytes(&mut master_key); - let prk = ring::hkdf::Salt::new(ring::hkdf::HKDF_SHA256, &[]).extract(&master_key); + let prk = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]).extract(&master_key); let addr = SocketAddr::new(Ipv6Addr::LOCALHOST.into(), 4433); let retry_src_cid = RandomConnectionIdGenerator::new(MAX_CID_SIZE).generate_cid(); @@ -200,7 +204,6 @@ mod test { assert_eq!(token.issued, decoded.issued); } - #[cfg(feature = "ring")] #[test] fn invalid_token_returns_err() { use super::*; @@ -214,7 +217,7 @@ mod test { let mut master_key = [0; 64]; rng.fill_bytes(&mut master_key); - let prk = ring::hkdf::Salt::new(ring::hkdf::HKDF_SHA256, &[]).extract(&master_key); + let prk = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]).extract(&master_key); let addr = SocketAddr::new(Ipv6Addr::LOCALHOST.into(), 4433); let retry_src_cid = RandomConnectionIdGenerator::new(MAX_CID_SIZE).generate_cid(); diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 15838f84e3..1a5630d6f5 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -16,11 +16,14 @@ all-features = true [features] default = ["log", "platform-verifier", "ring", "runtime-tokio", "rustls"] +aws-lc-rs = ["proto/aws-lc-rs"] # Records how long locks are held, and warns if they are held >= 1ms lock_tracking = [] # Provides `ClientConfig::with_platform_verifier()` convenience method platform-verifier = ["proto/platform-verifier"] -rustls = ["dep:rustls", "proto/rustls", "proto/ring"] +rustls = ["rustls-ring"] +rustls-aws-lc-rs = ["dep:rustls", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"] +rustls-ring = ["dep:rustls", "proto/rustls-ring", "proto/ring"] # Enables `Endpoint::client` and `Endpoint::server` conveniences ring = ["proto/ring"] runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] diff --git a/quinn/src/endpoint.rs b/quinn/src/endpoint.rs index 816be05454..7dd2035707 100644 --- a/quinn/src/endpoint.rs +++ b/quinn/src/endpoint.rs @@ -12,7 +12,7 @@ use std::{ time::Instant, }; -#[cfg(feature = "ring")] +#[cfg(any(feature = "aws-lc-rs", feature = "ring"))] use crate::runtime::default_runtime; use crate::{ runtime::{AsyncUdpSocket, Runtime}, @@ -25,7 +25,7 @@ use proto::{ EndpointEvent, ServerConfig, }; use rustc_hash::FxHashMap; -#[cfg(feature = "ring")] +#[cfg(any(feature = "aws-lc-rs", feature = "ring"))] use socket2::{Domain, Protocol, Socket, Type}; use tokio::sync::{futures::Notified, mpsc, Notify}; use tracing::{Instrument, Span}; @@ -67,7 +67,7 @@ impl Endpoint { /// /// Some environments may not allow creation of dual-stack sockets, in which case an IPv6 /// client will only be able to connect to IPv6 servers. An IPv4 client is never dual-stack. - #[cfg(feature = "ring")] + #[cfg(any(feature = "aws-lc-rs", feature = "ring"))] // `EndpointConfig::default()` is only available with these pub fn client(addr: SocketAddr) -> io::Result { let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?; if addr.is_ipv6() { @@ -97,7 +97,7 @@ impl Endpoint { /// IPv6 address on Windows will not by default be able to communicate with IPv4 /// addresses. Portable applications should bind an address that matches the family they wish to /// communicate within. - #[cfg(feature = "ring")] + #[cfg(any(feature = "aws-lc-rs", feature = "ring"))] // `EndpointConfig::default()` is only available with these pub fn server(config: ServerConfig, addr: SocketAddr) -> io::Result { let socket = std::net::UdpSocket::bind(addr)?; let runtime = default_runtime()