diff --git a/Cargo.lock b/Cargo.lock index 94d7f1c4c5..73e7f8db98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,6 +388,7 @@ dependencies = [ "quinn", "rcgen", "rustls", + "rustls-aws-lc-rs", "tokio", "tracing", "tracing-subscriber", @@ -456,6 +457,7 @@ dependencies = [ "quinn", "rcgen", "rustls", + "rustls-ring", ] [[package]] @@ -1812,6 +1814,8 @@ dependencies = [ "quinn-proto", "rcgen", "rustls", + "rustls-aws-lc-rs", + "rustls-util", "serde", "serde_json", "socket2", @@ -1981,6 +1985,9 @@ dependencies = [ "rcgen", "rustc-hash", "rustls", + "rustls-aws-lc-rs", + "rustls-ring", + "rustls-util", "smol", "socket2", "thiserror 2.0.18", @@ -2011,8 +2018,11 @@ dependencies = [ "ring", "rustc-hash", "rustls", + "rustls-aws-lc-rs", "rustls-pki-types", "rustls-platform-verifier", + "rustls-ring", + "rustls-util", "slab", "thiserror 2.0.18", "tinyvec", @@ -2199,25 +2209,34 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +version = "0.24.0-dev.0" +source = "git+https://github.com/rustls/rustls.git?branch=main#d61b9270adc750375e8fee0cf71c0837c499beac" dependencies = [ - "aws-lc-rs", "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] +[[package]] +name = "rustls-aws-lc-rs" +version = "0.1.0-dev.0" +source = "git+https://github.com/rustls/rustls.git?branch=main#d61b9270adc750375e8fee0cf71c0837c499beac" +dependencies = [ + "aws-lc-rs", + "rustls", + "rustls-pki-types", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2237,9 +2256,8 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +version = "0.8.0" +source = "git+https://github.com/iadev09/rustls-platform-verifier.git?rev=05cefce8d045ca21010f2f9aa952d7a821c1f429#05cefce8d045ca21010f2f9aa952d7a821c1f429" dependencies = [ "core-foundation", "core-foundation-sys", @@ -2253,23 +2271,40 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] name = "rustls-platform-verifier-android" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +source = "git+https://github.com/iadev09/rustls-platform-verifier.git?rev=05cefce8d045ca21010f2f9aa952d7a821c1f429#05cefce8d045ca21010f2f9aa952d7a821c1f429" + +[[package]] +name = "rustls-ring" +version = "0.1.0-dev.0" +source = "git+https://github.com/rustls/rustls.git?branch=main#d61b9270adc750375e8fee0cf71c0837c499beac" +dependencies = [ + "ring", + "rustls", + "rustls-pki-types", + "subtle", +] + +[[package]] +name = "rustls-util" +version = "0.1.0" +source = "git+https://github.com/rustls/rustls.git?branch=main#d61b9270adc750375e8fee0cf71c0837c499beac" +dependencies = [ + "log", + "rustls", +] [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.104.0-alpha.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "bea702cca24d344fc70973022bf7eb920c224e318466eb49784272337dd24b1a" dependencies = [ - "aws-lc-rs", - "ring", "rustls-pki-types", "untrusted", ] @@ -2379,9 +2414,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "serde_core", "serde_with_macros", @@ -2389,9 +2424,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling", "proc-macro2", @@ -2483,9 +2518,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", "windows-sys 0.61.2", diff --git a/Cargo.toml b/Cargo.toml index e7bcdc23dc..779098cf21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,8 +35,11 @@ rand = "0.10.1" rcgen = "0.14" ring = "0.17" rustc-hash = "2" -rustls = { version = "0.23.5", default-features = false, features = ["std"] } -rustls-platform-verifier = "0.7" +rustls = { version = "0.24.0-dev.0", git = "https://github.com/rustls/rustls.git", branch = "main", default-features = false, features = ["webpki"] } +rustls-aws-lc-rs = { version = "0.1.0-dev.0", git = "https://github.com/rustls/rustls.git", branch = "main", default-features = false, features = ["aws-lc-sys", "std"] } +rustls-platform-verifier = { version = "0.8.0", git = "https://github.com/iadev09/rustls-platform-verifier.git", rev = "05cefce8d045ca21010f2f9aa952d7a821c1f429", default-features = false } +rustls-ring = { version = "0.1.0-dev.0", git = "https://github.com/rustls/rustls.git", branch = "main", default-features = false, features = ["std"] } +rustls-util = { version = "0.1.0", git = "https://github.com/rustls/rustls.git", branch = "main" } rustls-pki-types = "1.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1" diff --git a/bench/Cargo.toml b/bench/Cargo.toml index 3712da30d3..3b87b3cdb7 100644 --- a/bench/Cargo.toml +++ b/bench/Cargo.toml @@ -10,9 +10,10 @@ anyhow = { workspace = true } bytes = { workspace = true } clap = { workspace = true } hdrhistogram = { workspace = true } -quinn = { path = "../quinn", features = ["ring"] } +quinn = { path = "../quinn" } rcgen = { workspace = true } rustls = { workspace = true } +rustls-aws-lc-rs = { workspace = true } tokio = { workspace = true, features = ["rt"] } tracing = { workspace = true } tracing-subscriber = { workspace = true } diff --git a/bench/src/lib.rs b/bench/src/lib.rs index 86c30c8c13..5e0420ee80 100644 --- a/bench/src/lib.rs +++ b/bench/src/lib.rs @@ -63,17 +63,12 @@ pub async fn connect_client( let mut roots = RootCertStore::empty(); roots.add(server_cert)?; - let default_provider = rustls::crypto::ring::default_provider(); - let provider = rustls::crypto::CryptoProvider { - cipher_suites: vec![opt.cipher.as_rustls()], - ..default_provider - }; + let mut provider = rustls_aws_lc_rs::DEFAULT_PROVIDER; + provider.tls13_cipher_suites = vec![opt.cipher.as_rustls()].into(); - let crypto = rustls::ClientConfig::builder_with_provider(provider.into()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() + let crypto = rustls::ClientConfig::builder(Arc::new(provider)) .with_root_certificates(roots) - .with_no_client_auth(); + .with_no_client_auth()?; let mut client_config = quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(crypto)?)); client_config.transport_config(Arc::new(transport_config(&opt))); @@ -230,8 +225,8 @@ pub enum CipherSuite { } impl CipherSuite { - pub fn as_rustls(self) -> rustls::SupportedCipherSuite { - use rustls::crypto::ring::cipher_suite; + pub fn as_rustls(self) -> &'static rustls::Tls13CipherSuite { + use rustls_aws_lc_rs::cipher_suite; match self { Self::Aes128 => cipher_suite::TLS13_AES_128_GCM_SHA256, Self::Aes256 => cipher_suite::TLS13_AES_256_GCM_SHA384, diff --git a/docs/book/Cargo.toml b/docs/book/Cargo.toml index 484f57050d..4dbb14b70b 100644 --- a/docs/book/Cargo.toml +++ b/docs/book/Cargo.toml @@ -14,3 +14,4 @@ bytes = { workspace = true } quinn = { version = "0.12.0", path = "../../quinn" } rcgen.workspace = true rustls.workspace = true +rustls-ring.workspace = true diff --git a/docs/book/src/bin/certificate.rs b/docs/book/src/bin/certificate.rs index eb3d83fd41..64f9bcd760 100644 --- a/docs/book/src/bin/certificate.rs +++ b/docs/book/src/bin/certificate.rs @@ -1,16 +1,10 @@ -use std::{error::Error, sync::Arc}; +use std::{error::Error, hash::Hasher, sync::Arc}; -use quinn::{ - ClientConfig, - crypto::rustls::{NoInitialCipherSuite, QuicClientConfig}, -}; +use quinn::{ClientConfig, crypto::rustls::QuicClientConfig}; use rustls::{ - DigitallySignedStruct, SignatureScheme, client::danger, crypto::{CryptoProvider, verify_tls12_signature, verify_tls13_signature}, - pki_types::{ - CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName, UnixTime, pem::PemObject, - }, + pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}, }; #[allow(unused_variables)] @@ -22,69 +16,62 @@ fn main() { } #[allow(dead_code)] // Included in `certificate.md` -fn configure_client() -> Result { - let crypto = rustls::ClientConfig::builder() +fn configure_client() -> Result> { + let crypto = rustls::ClientConfig::builder(Arc::new(rustls_ring::DEFAULT_PROVIDER)) .dangerous() .with_custom_certificate_verifier(SkipServerVerification::new()) - .with_no_client_auth(); + .with_no_client_auth()?; Ok(ClientConfig::new(Arc::new(QuicClientConfig::try_from( crypto, )?))) } -// Implementation of `ServerCertVerifier` that verifies everything as trustworthy. +// Implementation of `ServerVerifier` that verifies everything as trustworthy. #[derive(Debug)] struct SkipServerVerification(Arc); impl SkipServerVerification { fn new() -> Arc { - Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider()))) + Arc::new(Self(Arc::new(rustls_ring::DEFAULT_PROVIDER))) } } -impl danger::ServerCertVerifier for SkipServerVerification { - fn verify_server_cert( +impl danger::ServerVerifier for SkipServerVerification { + fn verify_identity( &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp: &[u8], - _now: UnixTime, - ) -> Result { - Ok(danger::ServerCertVerified::assertion()) + _identity: &danger::ServerIdentity<'_>, + ) -> Result { + Ok(danger::PeerVerified::assertion()) } + fn verify_tls12_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, + input: &danger::SignatureVerificationInput<'_>, ) -> Result { - verify_tls12_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + verify_tls12_signature(input, &self.0.signature_verification_algorithms) } fn verify_tls13_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, + input: &danger::SignatureVerificationInput<'_>, ) -> Result { - verify_tls13_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + verify_tls13_signature(input, &self.0.signature_verification_algorithms) } - fn supported_verify_schemes(&self) -> Vec { + fn supported_verify_schemes(&self) -> Vec { self.0.signature_verification_algorithms.supported_schemes() } + + fn request_ocsp_response(&self) -> bool { + false + } + + fn hash_config(&self, h: &mut dyn Hasher) { + for scheme in self.supported_verify_schemes() { + h.write_u16(scheme.0); + } + } } fn generate_self_signed_cert() diff --git a/docs/book/src/quinn/certificate.md b/docs/book/src/quinn/certificate.md index 1c52a8c694..ff9866658a 100644 --- a/docs/book/src/quinn/certificate.md +++ b/docs/book/src/quinn/certificate.md @@ -7,25 +7,26 @@ As QUIC uses TLS 1.3 for authentication of connections, the server needs to prov ## Insecure Connection For our example use case, the easiest way to allow the client to trust our server is to disable certificate verification (don't do this in production!). -When the [rustls][3] `dangerous_configuration` feature flag is enabled, a client can be configured to trust any server. +With [rustls][3]'s dangerous client configuration API, a client can be configured to trust any server. -Start by adding a [rustls][3] dependency with the `dangerous_configuration` feature flag to your `Cargo.toml` file. +Start by adding [rustls][3] and provider dependencies to your `Cargo.toml` file. ```toml -quinn = "0.11" -rustls = "0.23" +quinn = "0.12" +rustls = "0.24" +rustls-ring = "0.1" ``` -Then, allow the client to skip the certificate validation by implementing [ServerCertVerifier][ServerCertVerifier] and letting it assert verification for any server. +Then, allow the client to skip the certificate validation by implementing [ServerVerifier][ServerVerifier] and letting it assert verification for any server. ```rust -{{#include ../bin/certificate.rs:36:88}} +{{#include ../bin/certificate.rs:30:75}} ``` -After that, modify the [ClientConfig][ClientConfig] to use this [ServerCertVerifier][ServerCertVerifier] implementation. +After that, modify the [ClientConfig][ClientConfig] to use this [ServerVerifier][ServerVerifier] implementation. ```rust -{{#include ../bin/certificate.rs:25:34}} +{{#include ../bin/certificate.rs:19:28}} ``` Finally, if you plug this [ClientConfig][ClientConfig] into the [Endpoint::set_default_client_config()][set_default_client_config] your client endpoint should verify all connections as trustworthy. @@ -45,7 +46,7 @@ This example uses [rcgen][4] to generate a certificate. Let's look at an example: ```rust -{{#include ../bin/certificate.rs:90:96}} +{{#include ../bin/certificate.rs:77:83}} ``` _Note that [generate_simple_self_signed][generate_simple_self_signed] returns a [Certificate][2] that can be serialized to both `.der` and `.pem` formats._ @@ -68,7 +69,7 @@ certbot asks for the required data and writes the certificates to `fullchain.pem These files can then be referenced in code. ```rust -{{#include ../bin/certificate.rs:98:106}} +{{#include ../bin/certificate.rs:85:93}} ``` ### Configuring Certificates @@ -79,7 +80,7 @@ After configuring plug the configuration into the `Endpoint`. **Configure Server** ```rust -{{#include ../bin/certificate.rs:20}} +{{#include ../bin/certificate.rs:14}} ``` This is the only thing you need to do for your server to be secured. @@ -87,7 +88,7 @@ This is the only thing you need to do for your server to be secured. **Configure Client** ```rust -{{#include ../bin/certificate.rs:21}} +{{#include ../bin/certificate.rs:15}} ``` This is the only thing you need to do for your client to trust a server certificate signed by a conventional certificate authority. @@ -104,7 +105,7 @@ This is the only thing you need to do for your client to trust a server certific [6]: https://letsencrypt.org/getting-started/ [7]: https://certbot.eff.org/instructions [ClientConfig]: https://docs.rs/quinn/latest/quinn/struct.ClientConfig.html -[ServerCertVerifier]: https://docs.rs/rustls/latest/rustls/client/trait.ServerCertVerifier.html +[ServerVerifier]: https://docs.rs/rustls/latest/rustls/client/danger/trait.ServerVerifier.html [set_default_client_config]: https://docs.rs/quinn/latest/quinn/struct.Endpoint.html#method.set_default_client_config [generate_simple_self_signed]: https://docs.rs/rcgen/latest/rcgen/fn.generate_simple_self_signed.html [Certificate]: https://docs.rs/rcgen/latest/rcgen/struct.Certificate.html diff --git a/perf/Cargo.toml b/perf/Cargo.toml index 7c6fe7e119..9ce3bed502 100644 --- a/perf/Cargo.toml +++ b/perf/Cargo.toml @@ -34,6 +34,8 @@ quinn = { path = "../quinn" } quinn-proto = { path = "../quinn-proto" } rcgen = { workspace = true } rustls = { workspace = true } +rustls-aws-lc-rs = { workspace = true } +rustls-util = { workspace = true } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } socket2 = { workspace = true } diff --git a/perf/src/client.rs b/perf/src/client.rs index ff25d7d1f3..d4d9bacf26 100644 --- a/perf/src/client.rs +++ b/perf/src/client.rs @@ -1,6 +1,7 @@ #[cfg(feature = "json-output")] use std::path::PathBuf; use std::{ + hash::Hasher, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::Path, sync::Arc, @@ -11,7 +12,7 @@ use anyhow::{Context, Result}; use bytes::Bytes; use clap::Parser; use quinn::{TokioRuntime, crypto::rustls::QuicClientConfig}; -use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use rustls::enums::ApplicationProtocol; use tokio::sync::Semaphore; use tracing::{debug, error, info}; @@ -104,22 +105,18 @@ pub async fn run(opt: Opt) -> Result<()> { let endpoint = quinn::Endpoint::new(endpoint_cfg, None, socket, Arc::new(TokioRuntime))?; - let default_provider = rustls::crypto::ring::default_provider(); - let provider = Arc::new(rustls::crypto::CryptoProvider { - cipher_suites: PERF_CIPHER_SUITES.into(), - ..default_provider - }); + let mut provider = rustls_aws_lc_rs::DEFAULT_PROVIDER; + provider.tls13_cipher_suites = PERF_CIPHER_SUITES.into(); + let provider = Arc::new(provider); - let mut crypto = rustls::ClientConfig::builder_with_provider(provider.clone()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() + let mut crypto = rustls::ClientConfig::builder(provider.clone()) .dangerous() .with_custom_certificate_verifier(SkipServerVerification::new(provider)) - .with_no_client_auth(); - crypto.alpn_protocols = vec![b"perf".to_vec()]; + .with_no_client_auth()?; + crypto.alpn_protocols = vec![ApplicationProtocol::from(b"perf")]; if opt.common.keylog { - crypto.key_log = Arc::new(rustls::KeyLogFile::new()); + crypto.key_log = Arc::new(rustls_util::KeyLogFile::new()); } let transport = opt.common.build_transport_config( @@ -381,47 +378,39 @@ impl SkipServerVerification { } } -impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { - fn verify_server_cert( +impl rustls::client::danger::ServerVerifier for SkipServerVerification { + fn verify_identity( &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp: &[u8], - _now: UnixTime, - ) -> Result { - Ok(rustls::client::danger::ServerCertVerified::assertion()) + _identity: &rustls::client::danger::ServerIdentity<'_>, + ) -> Result { + Ok(rustls::client::danger::PeerVerified::assertion()) } fn verify_tls12_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + input: &rustls::client::danger::SignatureVerificationInput<'_>, ) -> Result { - rustls::crypto::verify_tls12_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + rustls::crypto::verify_tls12_signature(input, &self.0.signature_verification_algorithms) } fn verify_tls13_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + input: &rustls::client::danger::SignatureVerificationInput<'_>, ) -> Result { - rustls::crypto::verify_tls13_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + rustls::crypto::verify_tls13_signature(input, &self.0.signature_verification_algorithms) } - fn supported_verify_schemes(&self) -> Vec { + fn supported_verify_schemes(&self) -> Vec { self.0.signature_verification_algorithms.supported_schemes() } + + fn request_ocsp_response(&self) -> bool { + false + } + + fn hash_config(&self, h: &mut dyn Hasher) { + for scheme in self.supported_verify_schemes() { + h.write_u16(scheme.0); + } + } } diff --git a/perf/src/lib.rs b/perf/src/lib.rs index f547643cb0..1aa95273f4 100644 --- a/perf/src/lib.rs +++ b/perf/src/lib.rs @@ -11,7 +11,7 @@ use quinn::{ congestion::{self, ControllerFactory}, udp::UdpSocketState, }; -use rustls::crypto::ring::cipher_suite; +use rustls_aws_lc_rs::cipher_suite; use socket2::{Domain, Protocol, Socket, Type}; use tracing::warn; @@ -214,7 +214,7 @@ impl CongestionAlgorithm { } } -pub static PERF_CIPHER_SUITES: &[rustls::SupportedCipherSuite] = &[ +pub static PERF_CIPHER_SUITES: &[&rustls::Tls13CipherSuite] = &[ cipher_suite::TLS13_AES_128_GCM_SHA256, cipher_suite::TLS13_AES_256_GCM_SHA384, cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, diff --git a/perf/src/noprotection.rs b/perf/src/noprotection.rs index 37eb118f42..2c4521a517 100644 --- a/perf/src/noprotection.rs +++ b/perf/src/noprotection.rs @@ -120,7 +120,7 @@ impl crypto::Session for NoProtectionSession { } fn export_keying_material( - &self, + &mut self, output: &mut [u8], label: &[u8], context: &[u8], diff --git a/perf/src/server.rs b/perf/src/server.rs index 18d1a4d8ef..0fb64508a8 100644 --- a/perf/src/server.rs +++ b/perf/src/server.rs @@ -4,7 +4,11 @@ use anyhow::{Context, Result}; use bytes::Bytes; use clap::Parser; use quinn::{TokioRuntime, crypto::rustls::QuicServerConfig}; -use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}; +use rustls::{ + crypto::Identity, + enums::ApplicationProtocol, + pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}, +}; use tracing::{debug, error, info}; use crate::{CommonOpt, PERF_CIPHER_SUITES, noprotection::NoProtectionServerConfig}; @@ -44,22 +48,16 @@ pub async fn run(opt: Opt) -> Result<()> { } }; - let default_provider = rustls::crypto::ring::default_provider(); - let provider = rustls::crypto::CryptoProvider { - cipher_suites: PERF_CIPHER_SUITES.into(), - ..default_provider - }; + let mut provider = rustls_aws_lc_rs::DEFAULT_PROVIDER; + provider.tls13_cipher_suites = PERF_CIPHER_SUITES.into(); - let mut crypto = rustls::ServerConfig::builder_with_provider(provider.into()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() + let mut crypto = rustls::ServerConfig::builder(Arc::new(provider)) .with_no_client_auth() - .with_single_cert(cert, key) - .unwrap(); - crypto.alpn_protocols = vec![b"perf".to_vec()]; + .with_single_cert(Arc::new(Identity::from_cert_chain(cert)?), key)?; + crypto.alpn_protocols = vec![ApplicationProtocol::from(b"perf")]; if opt.common.keylog { - crypto.key_log = Arc::new(rustls::KeyLogFile::new()); + crypto.key_log = Arc::new(rustls_util::KeyLogFile::new()); } let transport = opt.common.build_transport_config( diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index c018ef1541..7c43b3f693 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -21,10 +21,10 @@ bloom = ["dep:fastbloom"] # For backwards compatibility, `rustls` forwards to `rustls-ring` rustls = ["rustls-ring"] # Enable rustls with the `aws-lc-rs` crypto provider -rustls-aws-lc-rs = ["dep:rustls", "rustls?/aws-lc-rs", "aws-lc-rs"] -rustls-aws-lc-rs-fips = ["rustls-aws-lc-rs", "aws-lc-rs-fips"] +rustls-aws-lc-rs = ["dep:rustls", "dep:rustls-aws-lc-rs", "aws-lc-rs"] +rustls-aws-lc-rs-fips = ["rustls-aws-lc-rs", "aws-lc-rs-fips", "rustls-aws-lc-rs?/fips"] # Enable rustls with the `ring` crypto provider -rustls-ring = ["dep:rustls", "rustls?/ring", "ring"] +rustls-ring = ["dep:rustls", "dep:rustls-ring", "ring"] ring = ["dep:ring"] # Enable rustls ring provider and direct ring usage # Provides `ClientConfig::with_platform_verifier()` convenience method @@ -32,7 +32,7 @@ platform-verifier = ["dep:rustls-platform-verifier"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. tracing-log = ["tracing/log"] # Enable rustls logging -rustls-log = ["rustls?/logging"] +rustls-log = ["rustls?/log"] # Enable qlog support qlog = ["dep:qlog"] @@ -53,7 +53,9 @@ rand = { workspace = true } rand_pcg = "0.10" ring = { workspace = true, optional = true } rustls = { workspace = true, optional = true } +rustls-aws-lc-rs = { workspace = true, optional = true } rustls-platform-verifier = { workspace = true, optional = true } +rustls-ring = { workspace = true, optional = true } slab = { workspace = true } thiserror = { workspace = true } tinyvec = { workspace = true, features = ["alloc"] } @@ -71,6 +73,7 @@ web-time = { workspace = true } assert_matches = { workspace = true } hex-literal = { workspace = true } rcgen = { workspace = true } +rustls-util = { workspace = true } tracing-subscriber = { workspace = true } wasm-bindgen-test = { workspace = true } diff --git a/quinn-proto/src/config/mod.rs b/quinn-proto/src/config/mod.rs index 129ee1dbaa..58b46df2b5 100644 --- a/quinn-proto/src/config/mod.rs +++ b/quinn-proto/src/config/mod.rs @@ -632,8 +632,9 @@ impl ClientConfig { pub fn with_root_certificates( roots: Arc, ) -> Result { + let provider = configured_provider(); Ok(Self::new(Arc::new(crypto::rustls::QuicClientConfig::new( - WebPkiServerVerifier::builder_with_provider(roots, configured_provider()).build()?, + Arc::new(WebPkiServerVerifier::builder(roots, &provider).build()?), )))) } } diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 69c175689e..28b8c51313 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1300,6 +1300,11 @@ impl Connection { &*self.crypto } + /// Get a mutable session reference + pub fn crypto_session_mut(&mut self) -> &mut dyn crypto::Session { + &mut *self.crypto + } + /// Whether the connection is in the process of being established /// /// If this returns `false`, the connection may be either established or closed, signaled by the diff --git a/quinn-proto/src/crypto.rs b/quinn-proto/src/crypto.rs index 2ac40fc1ee..86917ad450 100644 --- a/quinn-proto/src/crypto.rs +++ b/quinn-proto/src/crypto.rs @@ -86,7 +86,7 @@ pub trait Session: Send + Sync + 'static { /// This function will fail, returning [ExportKeyingMaterialError], /// if the requested output length is too large. fn export_keying_material( - &self, + &mut self, output: &mut [u8], label: &[u8], context: &[u8], diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index b1fd9da1e4..9f14ff9e6a 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -1,31 +1,34 @@ use std::{any::Any, io, str, sync::Arc}; -#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))] -use aws_lc_rs::aead; +use crate::{ + ConnectError, ConnectionId, Side, TransportError, TransportErrorCode, + crypto::{ + self, CryptoError, ExportKeyingMaterialError, HeaderKey, KeyPair, Keys, UnsupportedVersion, + }, + transport_parameters::TransportParameters, +}; use bytes::BytesMut; -#[cfg(feature = "ring")] -use ring::aead; pub use rustls::Error; #[cfg(feature = "__rustls-post-quantum-test")] -use rustls::NamedGroup; +use rustls::crypto::kx::NamedGroup; use rustls::{ - self, CipherSuite, - client::danger::ServerCertVerifier, + self, + client::danger::ServerVerifier, + crypto::{ + CipherSuite, CryptoProvider, Identity, + cipher::{AeadKey, Iv}, + }, + error::AlertDescription, pki_types::{CertificateDer, PrivateKeyDer, ServerName}, - quic::{Connection, HeaderProtectionKey, KeyChange, PacketKey, Secrets, Suite, Version}, + quic::{ + ClientConnection, Connection as _, DirectionalKeys, HeaderProtectionKey, KeyChange, + PacketKey, Secrets, ServerConnection, Side as QuicSide, Suite, Version, + }, }; #[cfg(feature = "platform-verifier")] use rustls_platform_verifier::BuilderVerifierExt; -use crate::{ - ConnectError, ConnectionId, Side, TransportError, TransportErrorCode, - crypto::{ - self, CryptoError, ExportKeyingMaterialError, HeaderKey, KeyPair, Keys, UnsupportedVersion, - }, - transport_parameters::TransportParameters, -}; - -impl From for rustls::Side { +impl From for QuicSide { fn from(s: Side) -> Self { match s { Side::Client => Self::Client, @@ -39,16 +42,14 @@ pub struct TlsSession { version: Version, got_handshake_data: bool, next_secrets: Option, - inner: Connection, + exporter: Option, + inner: QuicConnection, suite: Suite, } impl TlsSession { fn side(&self) -> Side { - match self.inner { - Connection::Client(_) => Side::Client, - Connection::Server(_) => Side::Server, - } + self.inner.side() } } @@ -63,38 +64,31 @@ impl crypto::Session for TlsSession { } Some(Box::new(HandshakeData { protocol: self.inner.alpn_protocol().map(|x| x.into()), - server_name: match &self.inner { - Connection::Client(_) => None, - Connection::Server(session) => session.server_name().map(|x| x.into()), - }, + server_name: self.inner.server_name().map(str::to_owned), protocol_version: match &self.inner { - Connection::Client(session) => session.protocol_version(), - Connection::Server(session) => session.protocol_version(), + QuicConnection::Client(session) => session.protocol_version(), + QuicConnection::Server(session) => session.protocol_version(), } .map(|x| -> Box { Box::new(x) }), cipher_suite: match &self.inner { - Connection::Client(session) => session.negotiated_cipher_suite(), - Connection::Server(session) => session.negotiated_cipher_suite(), + QuicConnection::Client(session) => session.negotiated_cipher_suite(), + QuicConnection::Server(session) => session.negotiated_cipher_suite(), } .map(|suite| -> Box { Box::new(suite.suite()) }), #[cfg(feature = "__rustls-post-quantum-test")] negotiated_key_exchange_group: self .inner .negotiated_key_exchange_group() - .expect("key exchange group is negotiated") - .name(), + .expect("key exchange group is negotiated"), })) } - /// For the rustls `TlsSession`, the `Any` type is `Vec` + /// For the rustls `TlsSession`, the `Any` type is `rustls::crypto::Identity<'static>` fn peer_identity(&self) -> Option> { - self.inner.peer_certificates().map(|v| -> Box { - Box::new( - v.iter() - .map(|v| v.clone().into_owned()) - .collect::>>(), - ) - }) + self.inner + .peer_identity() + .cloned() + .map(|identity| -> Box { Box::new(identity) }) } fn early_crypto(&self) -> Option<(Box, Box)> { @@ -103,10 +97,7 @@ impl crypto::Session for TlsSession { } fn early_data_accepted(&self) -> Option { - match self.inner { - Connection::Client(ref session) => Some(session.is_early_data_accepted()), - _ => None, - } + self.inner.is_early_data_accepted() } fn is_handshaking(&self) -> bool { @@ -115,7 +106,7 @@ impl crypto::Session for TlsSession { fn read_handshake(&mut self, buf: &[u8]) -> Result { self.inner.read_hs(buf).map_err(|e| { - if let Some(alert) = self.inner.alert() { + if let Ok(alert) = AlertDescription::try_from(&e) { TransportError { code: TransportErrorCode::crypto(alert.into()), frame: None, @@ -130,10 +121,7 @@ impl crypto::Session for TlsSession { // Hack around the lack of an explicit signal from rustls to reflect ClientHello being // ready on incoming connections, or ALPN negotiation completing on outgoing // connections. - let have_server_name = match self.inner { - Connection::Client(_) => false, - Connection::Server(ref session) => session.server_name().is_some(), - }; + let have_server_name = self.inner.server_name().is_some(); if self.inner.alpn_protocol().is_some() || have_server_name || !self.is_handshaking() { self.got_handshake_data = true; return Ok(true); @@ -195,45 +183,128 @@ impl crypto::Session for TlsSession { let tag_start = tag_start + pseudo_packet.len(); pseudo_packet.extend_from_slice(payload); - let (nonce, key) = match self.version { - Version::V1 => (RETRY_INTEGRITY_NONCE_V1, RETRY_INTEGRITY_KEY_V1), - Version::V1Draft => (RETRY_INTEGRITY_NONCE_DRAFT, RETRY_INTEGRITY_KEY_DRAFT), - _ => unreachable!(), - }; - - let nonce = aead::Nonce::assume_unique_for_key(nonce); - let key = aead::LessSafeKey::new(aead::UnboundKey::new(&aead::AES_128_GCM, &key).unwrap()); - let (aad, tag) = pseudo_packet.split_at_mut(tag_start); - key.open_in_place(nonce, aead::Aad::from(aad), tag).is_ok() + retry_key_for_version(self.version, &self.suite) + .decrypt_in_place(0, aad, tag, None) + .is_ok() } fn export_keying_material( - &self, + &mut self, output: &mut [u8], label: &[u8], context: &[u8], ) -> Result<(), ExportKeyingMaterialError> { - self.inner - .export_keying_material(output, label, Some(context)) + if self.exporter.is_none() { + self.exporter = Some( + self.inner + .exporter() + .map_err(|_| ExportKeyingMaterialError)?, + ); + } + + self.exporter + .as_ref() + .expect("exporter is set") + .derive(label, Some(context), output) .map_err(|_| ExportKeyingMaterialError)?; Ok(()) } } -const RETRY_INTEGRITY_KEY_DRAFT: [u8; 16] = [ - 0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1, -]; -const RETRY_INTEGRITY_NONCE_DRAFT: [u8; 12] = [ - 0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c, -]; +enum QuicConnection { + Client(ClientConnection), + Server(ServerConnection), +} -const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [ - 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e, -]; -const RETRY_INTEGRITY_NONCE_V1: [u8; 12] = [ - 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb, -]; +impl QuicConnection { + fn side(&self) -> Side { + match self { + Self::Client(_) => Side::Client, + Self::Server(_) => Side::Server, + } + } + + fn alpn_protocol(&self) -> Option<&[u8]> { + match self { + Self::Client(session) => session.alpn_protocol(), + Self::Server(session) => session.alpn_protocol(), + } + .map(AsRef::as_ref) + } + + fn peer_identity(&self) -> Option<&Identity<'static>> { + match self { + Self::Client(session) => session.peer_identity(), + Self::Server(session) => session.peer_identity(), + } + } + + fn zero_rtt_keys(&self) -> Option { + match self { + Self::Client(session) => session.zero_rtt_keys(), + Self::Server(session) => session.zero_rtt_keys(), + } + } + + fn is_early_data_accepted(&self) -> Option { + match self { + Self::Client(session) => Some(session.is_early_data_accepted()), + Self::Server(_) => None, + } + } + + fn is_handshaking(&self) -> bool { + match self { + Self::Client(session) => session.is_handshaking(), + Self::Server(session) => session.is_handshaking(), + } + } + + fn read_hs(&mut self, buf: &[u8]) -> Result<(), Error> { + match self { + Self::Client(session) => session.read_hs(buf), + Self::Server(session) => session.read_hs(buf), + } + } + + fn write_hs(&mut self, buf: &mut Vec) -> Option { + match self { + Self::Client(session) => session.write_hs(buf), + Self::Server(session) => session.write_hs(buf), + } + } + + fn quic_transport_parameters(&self) -> Option<&[u8]> { + match self { + Self::Client(session) => session.quic_transport_parameters(), + Self::Server(session) => session.quic_transport_parameters(), + } + } + + fn server_name(&self) -> Option<&str> { + match self { + Self::Client(_) => None, + Self::Server(session) => session.server_name().map(AsRef::as_ref), + } + } + + #[cfg(feature = "__rustls-post-quantum-test")] + fn negotiated_key_exchange_group(&self) -> Option { + match self { + Self::Client(session) => session.negotiated_key_exchange_group(), + Self::Server(session) => session.negotiated_key_exchange_group(), + } + .map(|group| group.name()) + } + + fn exporter(&mut self) -> Result { + match self { + Self::Client(session) => session.exporter(), + Self::Server(session) => session.exporter(), + } + } +} impl HeaderKey for Box { fn decrypt(&self, pn_offset: usize, packet: &mut [u8]) { @@ -288,7 +359,8 @@ pub struct HandshakeData { /// A QUIC-compatible TLS client configuration /// /// Quinn implicitly constructs a `QuicClientConfig` with reasonable defaults within -/// [`ClientConfig::with_root_certificates()`][root_certs] and [`ClientConfig::try_with_platform_verifier()`][platform]. +/// [`ClientConfig::with_root_certificates()`][root_certs] and +/// [`ClientConfig::try_with_platform_verifier()`][platform]. /// Alternatively, `QuicClientConfig`'s [`TryFrom`] implementation can be used to wrap around a /// custom [`rustls::ClientConfig`], in which case care should be taken around certain points: /// @@ -311,17 +383,15 @@ pub struct QuicClientConfig { impl QuicClientConfig { #[cfg(feature = "platform-verifier")] pub(crate) fn with_platform_verifier() -> Result { - // Keep in sync with `inner()` below - let mut inner = rustls::ClientConfig::builder_with_provider(configured_provider()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() // The default providers support TLS 1.3 + let mut inner = rustls::ClientConfig::builder(configured_provider()) .with_platform_verifier()? - .with_no_client_auth(); + .with_no_client_auth() + .expect("default providers are valid for QUIC"); inner.enable_early_data = true; Ok(Self { - // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256 - initial: initial_suite_from_provider(inner.crypto_provider()) + // We're confident that the default providers contain TLS13_AES_128_GCM_SHA256 + initial: initial_suite_from_provider(inner.provider()) .expect("no initial cipher suite found"), inner: Arc::new(inner), }) @@ -331,11 +401,11 @@ impl QuicClientConfig { /// /// QUIC requires that TLS 1.3 be enabled. Advanced users can use any [`rustls::ClientConfig`] that /// satisfies this requirement. - pub(crate) fn new(verifier: Arc) -> Self { + pub(crate) fn new(verifier: Arc) -> Self { let inner = Self::inner(verifier); Self { - // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256 - initial: initial_suite_from_provider(inner.crypto_provider()) + // We're confident that the default providers contain TLS13_AES_128_GCM_SHA256 + initial: initial_suite_from_provider(inner.provider()) .expect("no initial cipher suite found"), inner: Arc::new(inner), } @@ -354,14 +424,19 @@ impl QuicClientConfig { } } - pub(crate) fn inner(verifier: Arc) -> rustls::ClientConfig { - // Keep in sync with `with_platform_verifier()` above - let mut config = rustls::ClientConfig::builder_with_provider(configured_provider()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() // The default providers support TLS 1.3 + pub(crate) fn inner(verifier: Arc) -> rustls::ClientConfig { + Self::inner_with_provider(verifier, configured_provider()) + } + + pub(crate) fn inner_with_provider( + verifier: Arc, + provider: Arc, + ) -> rustls::ClientConfig { + let mut config = rustls::ClientConfig::builder(provider) .dangerous() .with_custom_certificate_verifier(verifier) - .with_no_client_auth(); + .with_no_client_auth() + .expect("default providers are valid for QUIC"); config.enable_early_data = true; config @@ -380,8 +455,9 @@ impl crypto::ClientConfig for QuicClientConfig { version, got_handshake_data: false, next_secrets: None, - inner: Connection::Client( - rustls::quic::ClientConnection::new( + exporter: None, + inner: QuicConnection::Client( + ClientConnection::new( self.inner.clone(), version, ServerName::try_from(server_name) @@ -409,7 +485,7 @@ impl TryFrom> for QuicClientConfig { fn try_from(inner: Arc) -> Result { Ok(Self { - initial: initial_suite_from_provider(inner.crypto_provider()) + initial: initial_suite_from_provider(inner.provider()) .ok_or(NoInitialCipherSuite { specific: false })?, inner, }) @@ -420,9 +496,7 @@ impl TryFrom> for QuicClientConfig { /// /// When the cipher suite is supplied `with_initial()`, it must be /// [`CipherSuite::TLS13_AES_128_GCM_SHA256`]. When the cipher suite is derived from a config's -/// [`CryptoProvider`][provider], that provider must reference a cipher suite with the same ID. -/// -/// [provider]: rustls::crypto::CryptoProvider +/// [`CryptoProvider`], that provider must reference a cipher suite with the same ID. #[derive(Clone, Debug)] pub struct NoInitialCipherSuite { /// Whether the initial cipher suite was supplied by the caller @@ -464,7 +538,7 @@ impl QuicServerConfig { ) -> Result { let inner = Self::inner(cert_chain, key)?; Ok(Self { - // We're confident that the *ring* default provider contains TLS13_AES_128_GCM_SHA256 + // We're confident that the default providers contain TLS13_AES_128_GCM_SHA256 initial: initial_suite_from_provider(inner.crypto_provider()) .expect("no initial cipher suite found"), inner: Arc::new(inner), @@ -493,11 +567,17 @@ impl QuicServerConfig { cert_chain: Vec>, key: PrivateKeyDer<'static>, ) -> Result { - 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 + Self::inner_with_provider(cert_chain, key, configured_provider()) + } + + pub(crate) fn inner_with_provider( + cert_chain: Vec>, + key: PrivateKeyDer<'static>, + provider: Arc, + ) -> Result { + let mut inner = rustls::ServerConfig::builder(provider) .with_no_client_auth() - .with_single_cert(cert_chain, key)?; + .with_single_cert(Arc::new(Identity::from_cert_chain(cert_chain)?), key)?; inner.max_early_data_size = u32::MAX; Ok(inner) @@ -536,9 +616,9 @@ impl crypto::ServerConfig for QuicServerConfig { version, got_handshake_data: false, next_secrets: None, - inner: Connection::Server( - rustls::quic::ServerConnection::new(self.inner.clone(), version, to_vec(params)) - .unwrap(), + exporter: None, + inner: QuicConnection::Server( + ServerConnection::new(self.inner.clone(), version, to_vec(params)).unwrap(), ), suite: self.initial, }) @@ -556,22 +636,13 @@ impl crypto::ServerConfig for QuicServerConfig { fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16] { // Safe: `start_session()` is never called if `initial_keys()` rejected `version` let version = interpret_version(version).unwrap(); - let (nonce, key) = match version { - Version::V1 => (RETRY_INTEGRITY_NONCE_V1, RETRY_INTEGRITY_KEY_V1), - Version::V1Draft => (RETRY_INTEGRITY_NONCE_DRAFT, RETRY_INTEGRITY_KEY_DRAFT), - _ => unreachable!(), - }; - let mut pseudo_packet = Vec::with_capacity(packet.len() + orig_dst_cid.len() + 1); pseudo_packet.push(orig_dst_cid.len() as u8); pseudo_packet.extend_from_slice(&orig_dst_cid); pseudo_packet.extend_from_slice(packet); - let nonce = aead::Nonce::assume_unique_for_key(nonce); - let key = aead::LessSafeKey::new(aead::UnboundKey::new(&aead::AES_128_GCM, &key).unwrap()); - - let tag = key - .seal_in_place_separate_tag(nonce, aead::Aad::from(pseudo_packet), &mut []) + let tag = retry_key_for_version(version, &self.initial) + .encrypt_in_place(0, &pseudo_packet, &mut [], None) .unwrap(); let mut result = [0; 16]; result.copy_from_slice(tag.as_ref()); @@ -579,24 +650,39 @@ impl crypto::ServerConfig for QuicServerConfig { } } -pub(crate) fn initial_suite_from_provider( - provider: &Arc, -) -> Option { +fn retry_key_for_version(version: Version, initial_suite: &Suite) -> Box { + let (nonce, key) = match version { + Version::V1 => (RETRY_INTEGRITY_NONCE_V1, RETRY_INTEGRITY_KEY_V1), + _ => unreachable!(), + }; + + initial_suite + .quic + .packet_key(AeadKey::from(key), Iv::from(nonce)) +} + +const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [ + 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e, +]; +const RETRY_INTEGRITY_NONCE_V1: [u8; 12] = [ + 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb, +]; + +pub(crate) fn initial_suite_from_provider(provider: &Arc) -> Option { provider - .cipher_suites + .tls13_cipher_suites .iter() - .find_map(|cs| match (cs.suite(), cs.tls13()) { - (CipherSuite::TLS13_AES_128_GCM_SHA256, Some(suite)) => Some(suite.quic_suite()), + .find_map(|&suite| match suite.common.suite { + CipherSuite::TLS13_AES_128_GCM_SHA256 => suite.quic_suite(), _ => None, }) - .flatten() } -pub(crate) fn configured_provider() -> Arc { +pub(crate) fn configured_provider() -> Arc { #[cfg(all(feature = "rustls-aws-lc-rs", not(feature = "rustls-ring")))] - let provider = rustls::crypto::aws_lc_rs::default_provider(); + let provider = rustls_aws_lc_rs::DEFAULT_PROVIDER; #[cfg(feature = "rustls-ring")] - let provider = rustls::crypto::ring::default_provider(); + let provider = rustls_ring::DEFAULT_PROVIDER; Arc::new(provider) } @@ -629,7 +715,9 @@ impl crypto::PacketKey for Box { fn encrypt(&self, packet: u64, buf: &mut [u8], header_len: usize) { let (header, payload_tag) = buf.split_at_mut(header_len); let (payload, tag_storage) = payload_tag.split_at_mut(payload_tag.len() - self.tag_len()); - let tag = self.encrypt_in_place(packet, &*header, payload).unwrap(); + let tag = self + .encrypt_in_place(packet, &*header, payload, None) + .unwrap(); tag_storage.copy_from_slice(tag.as_ref()); } @@ -640,7 +728,7 @@ impl crypto::PacketKey for Box { payload: &mut BytesMut, ) -> Result<(), CryptoError> { let plain = self - .decrypt_in_place(packet, header, payload.as_mut()) + .decrypt_in_place(packet, header, payload.as_mut(), None) .map_err(|_| CryptoError)?; let plain_len = plain.len(); payload.truncate(plain_len); @@ -662,7 +750,6 @@ impl crypto::PacketKey for Box { fn interpret_version(version: u32) -> Result { match version { - 0xff00_001d..=0xff00_0020 => Ok(Version::V1Draft), 0x0000_0001 | 0xff00_0021..=0xff00_0022 => Ok(Version::V1), _ => Err(UnsupportedVersion), } diff --git a/quinn-proto/src/lib.rs b/quinn-proto/src/lib.rs index 5982b69033..0e3cff8c30 100644 --- a/quinn-proto/src/lib.rs +++ b/quinn-proto/src/lib.rs @@ -157,15 +157,7 @@ pub mod fuzzing { } /// The QUIC protocol version implemented. -pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[ - 0x00000001, - 0xff00_001d, - 0xff00_001e, - 0xff00_001f, - 0xff00_0020, - 0xff00_0021, - 0xff00_0022, -]; +pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[0x00000001, 0xff00_0021, 0xff00_0022]; /// Whether an endpoint was the initiator of a connection #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] diff --git a/quinn-proto/src/packet.rs b/quinn-proto/src/packet.rs index e8ab1aabb5..797a4c49d5 100644 --- a/quinn-proto/src/packet.rs +++ b/quinn-proto/src/packet.rs @@ -938,17 +938,15 @@ mod tests { #[test] fn header_encoding() { use crate::Side; - use crate::crypto::rustls::{initial_keys, initial_suite_from_provider}; - #[cfg(all(feature = "rustls-aws-lc-rs", not(feature = "rustls-ring")))] - use rustls::crypto::aws_lc_rs::default_provider; - #[cfg(feature = "rustls-ring")] - use rustls::crypto::ring::default_provider; + use crate::crypto::rustls::{ + configured_provider, initial_keys, initial_suite_from_provider, + }; use rustls::quic::Version; let dcid = ConnectionId::new(&hex!("06b858ec6f80452b")); - let provider = default_provider(); + let provider = configured_provider(); - let suite = initial_suite_from_provider(&std::sync::Arc::new(provider)).unwrap(); + let suite = initial_suite_from_provider(&provider).unwrap(); let client = initial_keys(Version::V1, dcid, Side::Client, &suite); let mut buf = Vec::new(); let header = Header::Initial(InitialHeader { diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index 2f684260e5..386cd00ee9 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -13,12 +13,11 @@ use hex_literal::hex; use rand::Rng; #[cfg(feature = "ring")] use ring::hmac; -#[cfg(all(feature = "rustls-aws-lc-rs", not(feature = "rustls-ring")))] -use rustls::crypto::aws_lc_rs::default_provider; -#[cfg(feature = "rustls-ring")] -use rustls::crypto::ring::default_provider; use rustls::{ - AlertDescription, RootCertStore, + RootCertStore, + crypto::Identity, + enums::{ApplicationProtocol, ProtocolVersion}, + error::AlertDescription, pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}, server::WebPkiClientVerifier, }; @@ -146,11 +145,11 @@ fn lifecycle() { } #[test] -fn draft_version_compat() { +fn compatible_version() { let _guard = subscribe(); let mut client_config = client_config(); - client_config.version(0xff00_0020); + client_config.version(0xff00_0022); let mut pair = Pair::default(); let (client_ch, server_ch) = pair.connect_with(client_config); @@ -296,14 +295,14 @@ fn export_keying_material() { // client keying material let mut client_buf = [0u8; 64]; pair.client_conn_mut(client_ch) - .crypto_session() + .crypto_session_mut() .export_keying_material(&mut client_buf, LABEL, CONTEXT) .unwrap(); // server keying material let mut server_buf = [0u8; 64]; pair.server_conn_mut(server_ch) - .crypto_session() + .crypto_session_mut() .export_keying_material(&mut server_buf, LABEL, CONTEXT) .unwrap(); @@ -436,7 +435,7 @@ fn reject_self_signed_server_cert() { assert_matches!(pair.client_conn_mut(client_ch).poll(), Some(Event::ConnectionLost { reason: ConnectionError::TransportError(ref error)}) - if error.code == TransportErrorCode::crypto(AlertDescription::UnknownCA.into())); + if error.code == TransportErrorCode::crypto(AlertDescription::UnknownCa.into())); } #[test] @@ -451,16 +450,17 @@ fn reject_missing_client_cert() { let key = PrivatePkcs8KeyDer::from(CERTIFIED_KEY.signing_key.serialize_der()); let cert = CERTIFIED_KEY.cert.der().clone(); - let provider = Arc::new(default_provider()); - let config = rustls::ServerConfig::builder_with_provider(provider.clone()) - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap() - .with_client_cert_verifier( - WebPkiClientVerifier::builder_with_provider(Arc::new(store), provider) + let provider = crypto::rustls::configured_provider(); + let config = rustls::ServerConfig::builder(provider.clone()) + .with_client_cert_verifier(Arc::new( + WebPkiClientVerifier::builder(Arc::new(store), &provider) .build() .unwrap(), + )) + .with_single_cert( + Arc::new(Identity::from_cert_chain(vec![cert]).unwrap()), + PrivateKeyDer::from(key), ) - .with_single_cert(vec![cert], PrivateKeyDer::from(key)) .unwrap(); let config = QuicServerConfig::try_from(config).unwrap(); @@ -647,7 +647,7 @@ fn zero_rtt_rejection() { // the existing `ClientConfig` and change the ALPN protocols to make that happen. let this = Arc::get_mut(&mut client_crypto).expect("QuicClientConfig is shared"); let inner = Arc::get_mut(&mut this.inner).expect("QuicClientConfig.inner is shared"); - inner.alpn_protocols = vec!["bar".into()]; + inner.alpn_protocols = vec![ApplicationProtocol::from(b"bar")]; // Changing protocols invalidates 0-RTT let client_config = ClientConfig::new(client_crypto); @@ -845,13 +845,13 @@ fn alpn_success() { assert_eq!( hd.protocol_version .unwrap() - .downcast_ref::(), - Some(&rustls::ProtocolVersion::TLSv1_3) + .downcast_ref::(), + Some(&ProtocolVersion::TLSv1_3) ); assert!( hd.cipher_suite .unwrap() - .downcast_ref::() + .downcast_ref::() .is_some() ); } diff --git a/quinn-proto/src/tests/util.rs b/quinn-proto/src/tests/util.rs index 24c13d2a47..7932c398c3 100644 --- a/quinn-proto/src/tests/util.rs +++ b/quinn-proto/src/tests/util.rs @@ -13,13 +13,15 @@ use std::{ use assert_matches::assert_matches; use bytes::BytesMut; use rustls::{ - KeyLogFile, client::WebPkiServerVerifier, + crypto::CryptoProvider, + enums::ApplicationProtocol, pki_types::{CertificateDer, PrivateKeyDer}, }; +use rustls_util::KeyLogFile; use tracing::{info_span, trace}; -use super::crypto::rustls::{QuicClientConfig, QuicServerConfig, configured_provider}; +use super::crypto::rustls::{QuicClientConfig, QuicServerConfig}; use super::*; use crate::{Duration, Instant}; @@ -610,9 +612,10 @@ fn server_crypto_inner( ) }); - let mut config = QuicServerConfig::inner(vec![cert], key).unwrap(); + let mut config = + QuicServerConfig::inner_with_provider(vec![cert], key, test_provider()).unwrap(); if let Some(alpn) = alpn { - config.alpn_protocols = alpn; + config.alpn_protocols = alpn.into_iter().map(ApplicationProtocol::from).collect(); } config.try_into().unwrap() @@ -651,19 +654,44 @@ fn client_crypto_inner( roots.add(cert).unwrap(); } - let mut inner = QuicClientConfig::inner( - WebPkiServerVerifier::builder_with_provider(Arc::new(roots), configured_provider()) - .build() - .unwrap(), - ); + let provider = test_provider(); + let verifier = WebPkiServerVerifier::builder(Arc::new(roots), &provider) + .build() + .unwrap(); + let mut inner = QuicClientConfig::inner_with_provider(Arc::new(verifier), provider); inner.key_log = Arc::new(KeyLogFile::new()); if let Some(alpn) = alpn { - inner.alpn_protocols = alpn; + inner.alpn_protocols = alpn.into_iter().map(ApplicationProtocol::from).collect(); } inner.try_into().unwrap() } +#[cfg(all(feature = "rustls-aws-lc-rs-fips", not(feature = "rustls-ring")))] +fn test_provider() -> Arc { + Arc::new(CryptoProvider { + kx_groups: std::borrow::Cow::Owned(vec![rustls_aws_lc_rs::kx_group::SECP256R1]), + ..rustls_aws_lc_rs::DEFAULT_FIPS_PROVIDER + }) +} + +#[cfg(all( + feature = "rustls-aws-lc-rs", + not(feature = "rustls-aws-lc-rs-fips"), + not(feature = "rustls-ring") +))] +fn test_provider() -> Arc { + Arc::new(CryptoProvider { + kx_groups: std::borrow::Cow::Owned(vec![rustls_aws_lc_rs::kx_group::X25519]), + ..rustls_aws_lc_rs::DEFAULT_PROVIDER + }) +} + +#[cfg(feature = "rustls-ring")] +fn test_provider() -> Arc { + Arc::new(rustls_ring::DEFAULT_PROVIDER) +} + pub(super) fn min_opt(x: Option, y: Option) -> Option { match (x, y) { (Some(x), Some(y)) => Some(cmp::min(x, y)), diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 5d873965f3..d33927e515 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -28,10 +28,10 @@ platform-verifier = ["proto/platform-verifier"] # For backwards compatibility, `rustls` forwards to `rustls-ring` rustls = ["rustls-ring"] # Enable rustls with the `aws-lc-rs` crypto provider -rustls-aws-lc-rs = ["dep:rustls", "aws-lc-rs", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"] -rustls-aws-lc-rs-fips = ["dep:rustls", "aws-lc-rs-fips", "proto/rustls-aws-lc-rs-fips", "proto/aws-lc-rs-fips"] +rustls-aws-lc-rs = ["__rustls", "dep:rustls-aws-lc-rs", "aws-lc-rs", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"] +rustls-aws-lc-rs-fips = ["rustls-aws-lc-rs", "aws-lc-rs-fips", "proto/rustls-aws-lc-rs-fips", "proto/aws-lc-rs-fips"] # Enable rustls with the `ring` crypto provider -rustls-ring = ["dep:rustls", "ring", "proto/rustls-ring", "proto/ring"] +rustls-ring = ["__rustls", "dep:rustls-ring", "ring", "proto/rustls-ring", "proto/ring"] # Enable the `ring` crypto provider. # Outside wasm*-unknown-unknown targets, this enables `Endpoint::client` and `Endpoint::server` conveniences. ring = ["proto/ring"] @@ -41,14 +41,15 @@ runtime-smol = ["dep:async-io", "dep:smol"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. tracing-log = ["tracing/log", "proto/tracing-log", "udp/tracing-log"] # Enable rustls logging -rustls-log = ["rustls?/logging"] +rustls-log = ["rustls?/log"] # Enable qlog support qlog = ["proto/qlog"] # Internal (PRIVATE!) features used to aid testing. # Don't rely on these whatsoever. They may disappear at any time. -__rustls-post-quantum-test = ["rustls/prefer-post-quantum", "rustls-aws-lc-rs", "proto/__rustls-post-quantum-test"] +__rustls-post-quantum-test = ["rustls-aws-lc-rs", "proto/__rustls-post-quantum-test"] +__rustls = ["dep:rustls"] [dependencies] async-io = { workspace = true, optional = true } @@ -59,6 +60,8 @@ rustc-hash = { workspace = true } pin-project-lite = { workspace = true } proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.12.0", default-features = false } rustls = { workspace = true, optional = true } +rustls-aws-lc-rs = { workspace = true, optional = true } +rustls-ring = { workspace = true, optional = true } smol = { workspace = true, optional = true } thiserror = { workspace = true } tracing = { workspace = true } @@ -78,6 +81,7 @@ bencher = { workspace = true } directories-next = { workspace = true } rand = { workspace = true } rcgen = { workspace = true } +rustls-util = { workspace = true } clap = { workspace = true } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time", "macros", "test-util"] } tracing-subscriber = { workspace = true } @@ -92,23 +96,23 @@ workspace = true [[example]] name = "server" -required-features = ["rustls-ring"] +required-features = ["__rustls"] [[example]] name = "client" -required-features = ["rustls-ring"] +required-features = ["__rustls"] [[example]] name = "insecure_connection" -required-features = ["rustls-ring"] +required-features = ["__rustls"] [[example]] name = "single_socket" -required-features = ["rustls-ring"] +required-features = ["__rustls"] [[example]] name = "connection" -required-features = ["rustls-ring"] +required-features = ["__rustls"] [[test]] name = "post_quantum" @@ -117,8 +121,8 @@ required-features = ["__rustls-post-quantum-test"] [[bench]] name = "bench" harness = false -required-features = ["rustls-ring"] +required-features = ["__rustls"] [package.metadata.docs.rs] # all non-default features except fips (cannot build on docs.rs environment) -features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "runtime-tokio", "runtime-smol", "tracing-log", "rustls-log"] +features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "platform-verifier", "runtime-tokio", "runtime-smol", "tracing-log", "rustls-log"] diff --git a/quinn/examples/client.rs b/quinn/examples/client.rs index 40d29c9dbe..40763534ac 100644 --- a/quinn/examples/client.rs +++ b/quinn/examples/client.rs @@ -20,6 +20,16 @@ use url::Url; mod common; +#[cfg(feature = "rustls-aws-lc-rs")] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_aws_lc_rs::DEFAULT_PROVIDER +} + +#[cfg(all(not(feature = "rustls-aws-lc-rs"), feature = "rustls-ring"))] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_ring::DEFAULT_PROVIDER +} + /// HTTP/0.9 over QUIC client #[derive(Parser, Debug)] #[clap(name = "client")] @@ -92,13 +102,13 @@ async fn run(options: Opt) -> Result<()> { } } } - let mut client_crypto = rustls::ClientConfig::builder() + let mut client_crypto = rustls::ClientConfig::builder(Arc::new(default_provider())) .with_root_certificates(roots) - .with_no_client_auth(); + .with_no_client_auth()?; client_crypto.alpn_protocols = common::ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect(); if options.keylog { - client_crypto.key_log = Arc::new(rustls::KeyLogFile::new()); + client_crypto.key_log = Arc::new(rustls_util::KeyLogFile::new()); } let client_config = diff --git a/quinn/examples/insecure_connection.rs b/quinn/examples/insecure_connection.rs index 39fa5ba231..3f704aa2a2 100644 --- a/quinn/examples/insecure_connection.rs +++ b/quinn/examples/insecure_connection.rs @@ -4,17 +4,27 @@ use std::{ error::Error, + hash::Hasher, net::{IpAddr, Ipv4Addr, SocketAddr}, sync::Arc, }; use proto::crypto::rustls::QuicClientConfig; use quinn::{ClientConfig, Endpoint}; -use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; mod common; use common::make_server_endpoint; +#[cfg(feature = "rustls-aws-lc-rs")] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_aws_lc_rs::DEFAULT_PROVIDER +} + +#[cfg(all(not(feature = "rustls-aws-lc-rs"), feature = "rustls-ring"))] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_ring::DEFAULT_PROVIDER +} + #[tokio::main] async fn main() -> Result<(), Box> { // server and client are running on the same thread asynchronously @@ -40,10 +50,10 @@ async fn run_client(server_addr: SocketAddr) -> Result<(), Box); impl SkipServerVerification { fn new() -> Arc { - Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider()))) + Arc::new(Self(Arc::new(default_provider()))) } } -impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { - fn verify_server_cert( +impl rustls::client::danger::ServerVerifier for SkipServerVerification { + fn verify_identity( &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp: &[u8], - _now: UnixTime, - ) -> Result { - Ok(rustls::client::danger::ServerCertVerified::assertion()) + _identity: &rustls::client::danger::ServerIdentity<'_>, + ) -> Result { + Ok(rustls::client::danger::PeerVerified::assertion()) } fn verify_tls12_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + input: &rustls::client::danger::SignatureVerificationInput<'_>, ) -> Result { - rustls::crypto::verify_tls12_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + rustls::crypto::verify_tls12_signature(input, &self.0.signature_verification_algorithms) } fn verify_tls13_signature( &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + input: &rustls::client::danger::SignatureVerificationInput<'_>, ) -> Result { - rustls::crypto::verify_tls13_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) + rustls::crypto::verify_tls13_signature(input, &self.0.signature_verification_algorithms) } - fn supported_verify_schemes(&self) -> Vec { + fn supported_verify_schemes(&self) -> Vec { self.0.signature_verification_algorithms.supported_schemes() } + + fn request_ocsp_response(&self) -> bool { + false + } + + fn hash_config(&self, h: &mut dyn Hasher) { + for scheme in self.supported_verify_schemes() { + h.write_u16(scheme.0); + } + } } diff --git a/quinn/examples/server.rs b/quinn/examples/server.rs index 3f0b6740f5..bb8a8bf8ab 100644 --- a/quinn/examples/server.rs +++ b/quinn/examples/server.rs @@ -13,12 +13,25 @@ use std::{ use anyhow::{Context, Result, anyhow, bail}; use clap::Parser; use proto::crypto::rustls::QuicServerConfig; -use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}; +use rustls::{ + crypto::Identity, + pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}, +}; use tracing::{error, info, info_span}; use tracing_futures::Instrument as _; mod common; +#[cfg(feature = "rustls-aws-lc-rs")] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_aws_lc_rs::DEFAULT_PROVIDER +} + +#[cfg(all(not(feature = "rustls-aws-lc-rs"), feature = "rustls-ring"))] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_ring::DEFAULT_PROVIDER +} + #[derive(Parser, Debug)] #[clap(name = "server")] struct Opt { @@ -119,12 +132,12 @@ async fn run(options: Opt) -> Result<()> { (vec![cert], key) }; - let mut server_crypto = rustls::ServerConfig::builder() + let mut server_crypto = rustls::ServerConfig::builder(Arc::new(default_provider())) .with_no_client_auth() - .with_single_cert(certs, key)?; + .with_single_cert(Arc::new(Identity::from_cert_chain(certs)?), key)?; server_crypto.alpn_protocols = common::ALPN_QUIC_HTTP.iter().map(|&x| x.into()).collect(); if options.keylog { - server_crypto.key_log = Arc::new(rustls::KeyLogFile::new()); + server_crypto.key_log = Arc::new(rustls_util::KeyLogFile::new()); } let mut server_config = diff --git a/quinn/src/connection.rs b/quinn/src/connection.rs index 274c784b4e..82de52059b 100644 --- a/quinn/src/connection.rs +++ b/quinn/src/connection.rs @@ -627,7 +627,7 @@ impl Connection { /// /// The dynamic type returned is determined by the configured /// [`Session`](proto::crypto::Session). For the default `rustls` session, the return value can - /// be [`downcast`](Box::downcast) to a Vec<[rustls::pki_types::CertificateDer]> + /// be [`downcast`](Box::downcast) to rustls::crypto::Identity<'static>. pub fn peer_identity(&self) -> Option> { self.0 .state @@ -674,7 +674,7 @@ impl Connection { .state .lock("export_keying_material") .inner - .crypto_session() + .crypto_session_mut() .export_keying_material(output, label, context) } diff --git a/quinn/src/tests.rs b/quinn/src/tests.rs index 6d964bd4fe..478afdb253 100755 --- a/quinn/src/tests.rs +++ b/quinn/src/tests.rs @@ -1,10 +1,5 @@ #![cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))] -#[cfg(all(feature = "rustls-aws-lc-rs", not(feature = "rustls-ring")))] -use rustls::crypto::aws_lc_rs::default_provider; -#[cfg(feature = "rustls-ring")] -use rustls::crypto::ring::default_provider; - use std::{ convert::TryInto, future::Future, @@ -26,6 +21,7 @@ use proto::{RandomConnectionIdGenerator, crypto::rustls::QuicClientConfig}; use rand::{Rng, SeedableRng, rngs::StdRng}; use rustls::{ RootCertStore, + crypto::Identity, pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}, }; use tokio::time::{sleep, timeout}; @@ -39,6 +35,31 @@ use tracing_subscriber::EnvFilter; use super::{ClientConfig, Endpoint, EndpointConfig, RecvStream, SendStream, TransportConfig}; +#[cfg(all(feature = "rustls-aws-lc-rs-fips", not(feature = "rustls-ring")))] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls::crypto::CryptoProvider { + kx_groups: std::borrow::Cow::Owned(vec![rustls_aws_lc_rs::kx_group::SECP256R1]), + ..rustls_aws_lc_rs::DEFAULT_FIPS_PROVIDER + } +} + +#[cfg(all( + feature = "rustls-aws-lc-rs", + not(feature = "rustls-aws-lc-rs-fips"), + not(feature = "rustls-ring") +))] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls::crypto::CryptoProvider { + kx_groups: std::borrow::Cow::Owned(vec![rustls_aws_lc_rs::kx_group::X25519]), + ..rustls_aws_lc_rs::DEFAULT_PROVIDER + } +} + +#[cfg(feature = "rustls-ring")] +fn default_provider() -> rustls::crypto::CryptoProvider { + rustls_ring::DEFAULT_PROVIDER +} + #[test] fn handshake_timeout() { let _guard = subscribe(); @@ -291,14 +312,24 @@ impl EndpointFactory { } fn endpoint_with_config(&self, transport_config: TransportConfig) -> Endpoint { + let cert = self.cert.cert.der().clone(); let key = PrivateKeyDer::Pkcs8(self.cert.signing_key.serialize_der().into()); let transport_config = Arc::new(transport_config); - let mut server_config = - crate::ServerConfig::with_single_cert(vec![self.cert.cert.der().clone()], key).unwrap(); + let mut server_crypto = rustls::ServerConfig::builder(Arc::new(default_provider())) + .with_no_client_auth() + .with_single_cert( + Arc::new(Identity::from_cert_chain(vec![cert.clone()]).unwrap()), + key, + ) + .unwrap(); + server_crypto.max_early_data_size = u32::MAX; + let mut server_config = crate::ServerConfig::with_crypto(Arc::new( + crate::crypto::rustls::QuicServerConfig::try_from(server_crypto).unwrap(), + )); server_config.transport_config(transport_config.clone()); let mut roots = RootCertStore::empty(); - roots.add(self.cert.cert.der().clone()).unwrap(); + roots.add(cert).unwrap(); let endpoint = Endpoint::new( self.endpoint_config.clone(), Some(server_config), @@ -306,7 +337,13 @@ impl EndpointFactory { Arc::new(TokioRuntime), ) .unwrap(); - let mut client_config = ClientConfig::with_root_certificates(Arc::new(roots)).unwrap(); + let mut client_crypto = rustls::ClientConfig::builder(Arc::new(default_provider())) + .with_root_certificates(roots) + .with_no_client_auth() + .unwrap(); + client_crypto.enable_early_data = true; + let mut client_config = + ClientConfig::new(Arc::new(QuicClientConfig::try_from(client_crypto).unwrap())); client_config.transport_config(transport_config); endpoint.set_default_client_config(client_config); @@ -528,13 +565,11 @@ fn run_echo(args: EchoArgs) { let mut roots = RootCertStore::empty(); roots.add(cert).unwrap(); - let mut client_crypto = - rustls::ClientConfig::builder_with_provider(default_provider().into()) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(roots) - .with_no_client_auth(); - client_crypto.key_log = Arc::new(rustls::KeyLogFile::new()); + let mut client_crypto = rustls::ClientConfig::builder(Arc::new(default_provider())) + .with_root_certificates(roots) + .with_no_client_auth() + .unwrap(); + client_crypto.key_log = Arc::new(rustls_util::KeyLogFile::new()); let client = { let _guard = runtime.enter(); diff --git a/quinn/tests/post_quantum.rs b/quinn/tests/post_quantum.rs index 1d2970971b..93e70d3fef 100644 --- a/quinn/tests/post_quantum.rs +++ b/quinn/tests/post_quantum.rs @@ -7,7 +7,7 @@ use std::{ }; use rustls::{ - NamedGroup, + crypto::{Identity, kx::NamedGroup}, pki_types::{CertificateDer, PrivatePkcs8KeyDer}, }; use tracing::info; @@ -79,13 +79,10 @@ fn make_client_endpoint( ) -> Result> { let mut certs = rustls::RootCertStore::empty(); certs.add(server_cert)?; - let rustls_config = rustls::ClientConfig::builder_with_provider(Arc::new( - rustls::crypto::aws_lc_rs::default_provider(), - )) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(certs) - .with_no_client_auth(); + let rustls_config = rustls::ClientConfig::builder(Arc::new(rustls_aws_lc_rs::DEFAULT_PROVIDER)) + .with_root_certificates(certs) + .with_no_client_auth() + .unwrap(); let client_cfg = quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap())); @@ -103,14 +100,13 @@ fn make_server_endpoint( let cert = CertificateDer::from(cert.cert); let mut server_config = quinn::ServerConfig::with_crypto(Arc::new( QuicServerConfig::try_from( - rustls::ServerConfig::builder_with_provider(Arc::new( - rustls::crypto::aws_lc_rs::default_provider(), - )) - .with_safe_default_protocol_versions() - .unwrap() - .with_no_client_auth() - .with_single_cert(vec![cert.clone()], key.into()) - .unwrap(), + rustls::ServerConfig::builder(Arc::new(rustls_aws_lc_rs::DEFAULT_PROVIDER)) + .with_no_client_auth() + .with_single_cert( + Arc::new(Identity::from_cert_chain(vec![cert.clone()]).unwrap()), + key.into(), + ) + .unwrap(), ) .unwrap(), ));