Skip to content

Commit

Permalink
Enable use of aws-lc-rs instead of ring
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed Sep 16, 2024
1 parent e1a244e commit 424502f
Show file tree
Hide file tree
Showing 17 changed files with 90 additions and 50 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ jobs:
- run: cargo test --manifest-path fuzz/Cargo.toml
if: ${{ matrix.rust }} == "stable"

test-aws-lc-rs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
# Prevent feature unification from selecting *ring* as the crypto provider
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn-proto/Cargo.toml --no-default-features --features rustls-aws-lc-rs
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs,runtime-tokio

msrv:
runs-on: ubuntu-latest
steps:
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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"] }
Expand Down
2 changes: 1 addition & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ allow = [
"ISC",
"MIT",
"MPL-2.0",
"OpenSSL",
"Unicode-DFS-2016",
]
exceptions = [{ allow = ["ISC", "MIT", "OpenSSL"], name = "ring" }]
private = { ignore = true }

[[licenses.clarify]]
Expand Down
8 changes: 6 additions & 2 deletions quinn-proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,14 +28,15 @@ 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 }
ring = { workspace = true, optional = true }
rustls = { workspace = true, optional = true }
rustls-platform-verifier = { workspace = true, optional = true }
slab = { workspace = true }
thiserror = { workspace= true }
thiserror = { workspace = true }
tinyvec = { workspace = true, features = ["alloc"] }
tracing = { workspace = true }

Expand Down
1 change: 0 additions & 1 deletion quinn-proto/src/cid_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
31 changes: 19 additions & 12 deletions quinn-proto/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use std::{
time::Duration,
};

#[cfg(feature = "ring")]
use rand::RngCore;
#[cfg(feature = "rustls")]
use rustls::client::WebPkiServerVerifier;
#[cfg(feature = "rustls")]
Expand All @@ -19,7 +17,7 @@ use crate::crypto::rustls::QuicServerConfig;
use crate::{
cid_generator::{ConnectionIdGenerator, HashedConnectionIdGenerator},
congestion,
crypto::{self, HandshakeTokenKey, HmacKey},
crypto::{self, rustls::configured_provider, HandshakeTokenKey, HmacKey},
shared::ConnectionId,
RandomConnectionIdGenerator, VarInt, VarIntBoundsExceeded, DEFAULT_SUPPORTED_VERSIONS,
INITIAL_MTU, MAX_CID_SIZE, MAX_UDP_PAYLOAD,
Expand Down Expand Up @@ -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)))
}
}

Expand Down Expand Up @@ -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<dyn crypto::ServerConfig>) -> 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))
}
Expand Down Expand Up @@ -1030,7 +1037,7 @@ impl ClientConfig {
}
}

#[cfg(feature = "rustls")]
#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
impl ClientConfig {
/// Create a client configuration that trusts the platform's native roots
#[cfg(feature = "platform-verifier")]
Expand All @@ -1045,7 +1052,7 @@ impl ClientConfig {
roots: Arc<rustls::RootCertStore>,
) -> Result<Self, rustls::client::VerifierBuilderError> {
Ok(Self::new(Arc::new(crypto::rustls::QuicClientConfig::new(
WebPkiServerVerifier::builder(roots).build()?,
WebPkiServerVerifier::builder_with_provider(roots, configured_provider()).build()?,
))))
}
}
Expand Down
6 changes: 3 additions & 3 deletions quinn-proto/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ 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")]
#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
pub mod rustls;

/// A cryptographic session (commonly TLS)
Expand Down
Original file line number Diff line number Diff line change
@@ -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};
Expand Down
37 changes: 22 additions & 15 deletions quinn-proto/src/crypto/rustls.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -307,14 +310,12 @@ impl QuicClientConfig {
}

pub(crate) fn inner(verifier: Arc<dyn ServerCertVerifier>) -> 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();
let mut config = rustls::ClientConfig::builder_with_provider(configured_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
Expand Down Expand Up @@ -446,13 +447,11 @@ impl QuicServerConfig {
cert_chain: Vec<CertificateDer<'static>>,
key: PrivateKeyDer<'static>,
) -> Result<rustls::ServerConfig, rustls::Error> {
let mut inner = rustls::ServerConfig::builder_with_provider(
rustls::crypto::ring::default_provider().into(),
)
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap() // The *ring* default provider supports TLS 1.3
.with_no_client_auth()
.with_single_cert(cert_chain, key)?;
let mut inner = rustls::ServerConfig::builder_with_provider(configured_provider())
.with_protocol_versions(&[&rustls::version::TLS13])
.unwrap() // The *ring* default provider supports TLS 1.3
.with_no_client_auth()
.with_single_cert(cert_chain, key)?;

inner.max_early_data_size = u32::MAX;
Ok(inner)
Expand Down Expand Up @@ -549,6 +548,14 @@ pub(crate) fn initial_suite_from_provider(
.flatten()
}

pub(crate) fn configured_provider() -> Arc<rustls::crypto::CryptoProvider> {
#[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();
Arc::new(provider)
}

fn to_vec(params: &TransportParameters) -> Vec<u8> {
let mut bytes = Vec::new();
params.write(&mut bytes);
Expand Down
2 changes: 1 addition & 1 deletion quinn-proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions quinn-proto/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, BytesMut};
use hex_literal::hex;
use rand::RngCore;
#[cfg(feature = "ring")]
use ring::hmac;
use rustls::{
pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer},
Expand Down
4 changes: 2 additions & 2 deletions quinn-proto/src/tests/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustls::{
};
use tracing::{info_span, trace};

use super::crypto::rustls::{QuicClientConfig, QuicServerConfig};
use super::crypto::rustls::{configured_provider, QuicClientConfig, QuicServerConfig};
use super::*;

pub(super) const DEFAULT_MTU: usize = 1452;
Expand Down Expand Up @@ -640,7 +640,7 @@ fn client_crypto_inner(
}

let mut inner = QuicClientConfig::inner(
WebPkiServerVerifier::builder(Arc::new(roots))
WebPkiServerVerifier::builder_with_provider(Arc::new(roots), configured_provider())
.build()
.unwrap(),
);
Expand Down
11 changes: 7 additions & 4 deletions quinn-proto/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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();
Expand All @@ -200,7 +204,6 @@ mod test {
assert_eq!(token.issued, decoded.issued);
}

#[cfg(feature = "ring")]
#[test]
fn invalid_token_returns_err() {
use super::*;
Expand All @@ -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();
Expand Down
7 changes: 5 additions & 2 deletions quinn/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ rust-version.workspace = true
all-features = true

[features]
default = ["log", "platform-verifier", "ring", "runtime-tokio", "rustls"]
default = ["log", "platform-verifier", "runtime-tokio", "rustls-ring"]
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", "aws-lc-rs", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"]
rustls-ring = ["dep:rustls", "ring", "proto/rustls-ring", "proto/ring"]
# Enables `Endpoint::client` and `Endpoint::server` conveniences
ring = ["proto/ring"]
runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"]
Expand Down
8 changes: 4 additions & 4 deletions quinn/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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};
Expand Down Expand Up @@ -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<Self> {
let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?;
if addr.is_ipv6() {
Expand Down Expand Up @@ -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<Self> {
let socket = std::net::UdpSocket::bind(addr)?;
let runtime = default_runtime()
Expand Down
2 changes: 1 addition & 1 deletion quinn/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "rustls")]
#![cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]

use std::{
convert::TryInto,
Expand Down
Loading

0 comments on commit 424502f

Please sign in to comment.