diff --git a/Cargo.lock b/Cargo.lock index fc9a5ca..7a24f95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -918,12 +918,11 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "reqwest 0.12.23", - "ring 0.17.14", + "ring", "rusqlite", "rust-ini", "rust_tokio_kcp", "rustls", - "rustls-fork-shadow-tls", "rustls-pemfile 2.2.0", "schemars 0.8.22", "serde", @@ -937,7 +936,6 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-rustls-fork-shadow-tls", "tokio-snappy", "tokio-stream", "tokio-util", @@ -2846,7 +2844,7 @@ dependencies = [ "ipnet", "once_cell", "rand 0.9.2", - "ring 0.17.14", + "ring", "thiserror 2.0.16", "tinyvec", "tokio", @@ -4852,7 +4850,7 @@ dependencies = [ "getrandom 0.3.3", "lru-slab", "rand 0.9.2", - "ring 0.17.14", + "ring", "rustc-hash 2.1.1", "rustls", "rustls-pki-types", @@ -5468,21 +5466,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.14" @@ -5493,7 +5476,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -5507,7 +5490,7 @@ dependencies = [ "ed25519", "generic-array", "pkcs8", - "ring 0.17.14", + "ring", ] [[package]] @@ -5663,23 +5646,13 @@ dependencies = [ "aws-lc-rs", "log", "once_cell", - "ring 0.17.14", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-fork-shadow-tls" -version = "0.20.8" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -5715,9 +5688,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", - "ring 0.17.14", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -5848,16 +5821,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "sealed" version = "0.6.0" @@ -6388,12 +6351,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e14297decde697ddf377c25752aead0927d5cfc89c2684d2af96901a4ceeea" -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -6848,16 +6805,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls-fork-shadow-tls" -version = "0.0.8" -dependencies = [ - "bytes", - "rustls-fork-shadow-tls", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "tokio-snappy" version = "0.2.0" @@ -8358,12 +8305,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -8629,8 +8570,8 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9c99d53..362ba2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,6 @@ members = ["burrow", "tun"] resolver = "2" exclude = ["burrow-gtk"] -[patch.crates-io] -rustls-fork-shadow-tls = { path = "third_party/rustls-fork-shadow-tls" } -tokio-rustls-fork-shadow-tls = { path = "third_party/tokio-rustls-fork-shadow-tls" } - [profile.release] lto = true panic = "abort" diff --git a/burrow/Cargo.toml b/burrow/Cargo.toml index f3cccb9..a7d5cea 100644 --- a/burrow/Cargo.toml +++ b/burrow/Cargo.toml @@ -98,13 +98,9 @@ rustls = { version = "0.23", default-features = false, features = [ "std", "tls12", ] } -rustls-fork-shadow-tls = { version = "0.20.8", features = ["dangerous_configuration"] } rustls-pemfile = "2" sha2 = "0.10" tokio-rustls = "0.26" -tokio-rustls-fork-shadow-tls = { version = "0.0.8", features = [ - "dangerous_configuration", -] } rama-tls-boring = { version = "0.3.0-alpha.4", default-features = false, optional = true } rama-ua = { version = "0.3.0-alpha.4", default-features = false, optional = true, features = [ "embed-profiles", diff --git a/burrow/src/proxy_runtime.rs b/burrow/src/proxy_runtime.rs index 09e49f9..7eacdda 100644 --- a/burrow/src/proxy_runtime.rs +++ b/burrow/src/proxy_runtime.rs @@ -120,7 +120,6 @@ use rustls::{ version, ClientConfig, DigitallySignedStruct, Error as RustlsError, RootCertStore, SignatureScheme, }; -use rustls_fork_shadow_tls as shadow_rustls; use sha2::{Digest, Sha224, Sha256}; use shadowsocks::{ config::{ @@ -148,7 +147,6 @@ use tokio::{ #[cfg(target_vendor = "apple")] use tokio_native_tls::TlsConnector as TokioNativeTlsConnector; use tokio_rustls::TlsConnector; -use tokio_rustls_fork_shadow_tls::TlsConnector as ShadowTlsV3TlsConnector; use tokio_snappy::SnappyIO; use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt}; use tun::tokio::TunInterface; @@ -407,7 +405,6 @@ enum ShadowsocksPluginTransport { WebSocket(ShadowsocksWebSocketTransport), ShadowTls(ShadowsocksShadowTlsTransport), Kcptun(ShadowsocksKcptunTransport), - Restls(ShadowsocksRestlsTransport), } #[derive(Debug, Clone, PartialEq, Eq)] @@ -2227,9 +2224,6 @@ impl ShadowsocksOutbound { Some(ShadowsocksPluginTransport::ShadowTls(config)) => { shadow_tls_connect(Box::new(tcp), config).await? } - Some(ShadowsocksPluginTransport::Restls(config)) => { - restls_connect(Box::new(tcp), config).await? - } Some(ShadowsocksPluginTransport::Kcptun(_)) => { bail!("internal Shadowsocks kcptun transport dispatch error") } @@ -7178,34 +7172,6 @@ fn load_rustls_client_identity( Ok((certificate_chain, private_key)) } -fn load_shadow_rustls_client_identity( - identity: &TlsClientIdentity, -) -> Result<(Vec, shadow_rustls::PrivateKey)> { - let certificate = tls_material_bytes(&identity.certificate, "client certificate")?; - let private_key = tls_material_bytes(&identity.private_key, "client private key")?; - - let mut certificate_reader = io::Cursor::new(certificate); - let certificate_chain = rustls_pemfile::certs(&mut certificate_reader) - .collect::, _>>() - .context("failed to parse TLS client certificate PEM")? - .into_iter() - .map(|certificate| shadow_rustls::Certificate(certificate.as_ref().to_vec())) - .collect::>(); - if certificate_chain.is_empty() { - bail!("TLS client certificate PEM did not contain any certificates"); - } - - let mut private_key_reader = io::Cursor::new(private_key); - let private_key = rustls_pemfile::private_key(&mut private_key_reader) - .context("failed to parse TLS client private key PEM")? - .ok_or_else(|| anyhow!("TLS client private key PEM did not contain a private key"))?; - - Ok(( - certificate_chain, - shadow_rustls::PrivateKey(private_key.secret_der().to_vec()), - )) -} - #[cfg(feature = "boring-browser-fingerprints")] fn load_boring_client_identity( identity: &TlsClientIdentity, @@ -7330,10 +7296,6 @@ impl MihomoClientFingerprint { ) } - #[cfg_attr(not(feature = "boring-browser-fingerprints"), allow(dead_code))] - fn shadow_tls_v3_boring_supported(self) -> bool { - self.shadow_tls_v2_boring_supported() - } } fn hex_nibble(byte: u8) -> Option { @@ -7454,72 +7416,6 @@ fn supported_verify_schemes() -> Vec { ] } -#[derive(Debug)] -struct ShadowPinnedCertificateVerifier { - fingerprint: CertificateFingerprint, -} - -impl shadow_rustls::client::ServerCertVerifier for ShadowPinnedCertificateVerifier { - fn verify_server_cert( - &self, - end_entity: &shadow_rustls::Certificate, - intermediates: &[shadow_rustls::Certificate], - _server_name: &shadow_rustls::ServerName, - _scts: &mut dyn Iterator, - _ocsp_response: &[u8], - _now: SystemTime, - ) -> std::result::Result { - let mut certificates = std::iter::once(end_entity).chain(intermediates.iter()); - if certificates.any(|certificate| { - let digest = Sha256::digest(&certificate.0); - digest[..] == self.fingerprint.0[..] - }) { - Ok(shadow_rustls::client::ServerCertVerified::assertion()) - } else { - Err(shadow_rustls::Error::General( - "certificate chain does not match pinned fingerprint".to_owned(), - )) - } - } -} - -#[derive(Debug)] -struct ShadowNoCertificateVerifier; - -impl shadow_rustls::client::ServerCertVerifier for ShadowNoCertificateVerifier { - fn verify_server_cert( - &self, - _end_entity: &shadow_rustls::Certificate, - _intermediates: &[shadow_rustls::Certificate], - _server_name: &shadow_rustls::ServerName, - _scts: &mut dyn Iterator, - _ocsp_response: &[u8], - _now: SystemTime, - ) -> std::result::Result { - Ok(shadow_rustls::client::ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &shadow_rustls::Certificate, - _dss: &shadow_rustls::DigitallySignedStruct, - ) -> std::result::Result - { - Ok(shadow_rustls::client::HandshakeSignatureValid::assertion()) - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &shadow_rustls::Certificate, - _dss: &shadow_rustls::DigitallySignedStruct, - ) -> std::result::Result - { - Ok(shadow_rustls::client::HandshakeSignatureValid::assertion()) - } -} - async fn write_trojan_header( writer: &mut W, password: &str, diff --git a/burrow/src/proxy_runtime/shadowsocks_plugins.rs b/burrow/src/proxy_runtime/shadowsocks_plugins.rs index cd253e1..7f765d9 100644 --- a/burrow/src/proxy_runtime/shadowsocks_plugins.rs +++ b/burrow/src/proxy_runtime/shadowsocks_plugins.rs @@ -540,17 +540,6 @@ async fn shadow_tls_connect( let (stream, prefix) = hashed.finish(); Ok(Box::new(ShadowTlsV2Stream::new(stream, prefix))) } - 3 => { - if config.client_fingerprint.is_some() { - #[cfg(feature = "boring-browser-fingerprints")] - return shadow_tls_v3_boring_connect(stream, config).await; - #[cfg(not(feature = "boring-browser-fingerprints"))] - bail!( - "unsupported ShadowTLS v3 client-fingerprint: browser TLS profiles require the boring-browser-fingerprints feature" - ); - } - shadow_tls_v3_connect(stream, config).await - } version => bail!("unsupported ShadowTLS version {version}"), } } @@ -798,210 +787,6 @@ fn boring_certificate_fingerprint_matches( Ok(&*digest == fingerprint.0) } -#[cfg(feature = "boring-browser-fingerprints")] -async fn shadow_tls_v3_boring_connect( - stream: Box, - config: &ShadowsocksShadowTlsTransport, -) -> Result> { - let fingerprint = config - .client_fingerprint - .ok_or_else(|| anyhow!("missing ShadowTLS v3 client fingerprint"))?; - let profile = mihomo_browser_tls_profile(fingerprint)?; - let domain = RamaDomain::try_from(config.host.clone()) - .with_context(|| format!("invalid ShadowTLS host {}", config.host))?; - let mut builder = BoringTlsConnectorDataBuilder::try_from(profile.client_config.as_ref()) - .with_context(|| { - format!( - "failed to build browser TLS profile for client-fingerprint {}", - fingerprint.mihomo_name() - ) - })?; - builder = builder - .with_server_name(domain) - .with_alpn_protos(Bytes::from(alpn_wire_protocols(&config.alpn)?)); - if config.skip_cert_verify || config.certificate_fingerprint.is_some() { - builder = builder.with_server_verify_mode(RamaServerVerifyMode::Disable); - } - if let Some(identity) = &config.client_identity { - builder = builder.with_client_auth(load_boring_client_identity(identity)?); - } - let data = builder.build().with_context(|| { - format!( - "failed to configure ShadowTLS v3 browser TLS profile for {}", - config.host - ) - })?; - let handshake_stream = ShadowTlsV3HandshakeStream::new(stream, &config.password); - let signed_stream = DetachableStream::new(ShadowTlsV3SignedClientHelloStream::new( - handshake_stream, - &config.password, - )); - let mut tls = - rama_tls_boring::core::tokio::connect(data.config, config.host.as_str(), signed_stream) - .await - .map_err(|err| { - anyhow!( - "ShadowTLS v3 browser-profile handshake failed for {} using client-fingerprint {}: {err}", - config.host, - fingerprint.mihomo_name() - ) - })?; - if let Some(certificate_fingerprint) = config.certificate_fingerprint.as_ref() { - verify_boring_tls_peer_certificate( - &tls, - certificate_fingerprint, - "ShadowTLS v3 browser-profile", - )?; - } - let signed_stream = tls - .get_mut() - .take() - .context("failed to recover ShadowTLS v3 browser-profile transport")?; - let (handshake_stream, client_hello_signed) = signed_stream.into_inner(); - if !client_hello_signed { - bail!("ShadowTLS v3 browser-profile handshake did not sign the ClientHello session ID"); - } - let (stream, state) = handshake_stream.into_inner(); - if !state.authorized { - bail!("ShadowTLS v3 server authorization failed"); - } - let server_random = state - .server_random - .ok_or_else(|| anyhow!("ShadowTLS v3 handshake did not expose server random"))?; - if !state.is_tls13 { - tracing::debug!( - "ShadowTLS v3 completed without TLS 1.3; continuing like Mihomo non-strict mode" - ); - } - Ok(Box::new(ShadowTlsV3Stream::new( - stream, - &config.password, - server_random, - state.read_hmac, - ))) -} - -async fn shadow_tls_v3_connect( - stream: Box, - config: &ShadowsocksShadowTlsTransport, -) -> Result> { - let tls_config = shadow_tls_v3_client_config(config)?; - let connector = ShadowTlsV3TlsConnector::from(Arc::new(tls_config)); - let name = shadow_rustls::ServerName::try_from(config.host.as_str()) - .map_err(|_| anyhow!("invalid ShadowTLS host {}", config.host))?; - let password = config.password.clone(); - let handshake_stream = ShadowTlsV3HandshakeStream::new(stream, &config.password); - let tls = connector - .connect_with_session_id_generator(name, handshake_stream, move |client_hello| { - shadow_tls_v3_generate_session_id(&password, client_hello) - }) - .await - .with_context(|| format!("ShadowTLS v3 handshake failed for {}", config.host))?; - let (handshake_stream, _) = tls.into_parts(); - let (stream, state) = handshake_stream.into_inner(); - if !state.authorized { - bail!("ShadowTLS v3 server authorization failed"); - } - let server_random = state - .server_random - .ok_or_else(|| anyhow!("ShadowTLS v3 handshake did not expose server random"))?; - if !state.is_tls13 { - tracing::debug!( - "ShadowTLS v3 completed without TLS 1.3; continuing like Mihomo non-strict mode" - ); - } - Ok(Box::new(ShadowTlsV3Stream::new( - stream, - &config.password, - server_random, - state.read_hmac, - ))) -} - -async fn restls_connect( - stream: Box, - config: &ShadowsocksRestlsTransport, -) -> Result> { - #[cfg(feature = "boring-browser-fingerprints")] - if config.version_hint == RestlsVersionHint::Tls13 { - return restls_boring_connect(stream, config).await; - } - - let tls_config = restls_client_config(config)?; - let connector = ShadowTlsV3TlsConnector::from(Arc::new(tls_config)); - let name = shadow_rustls::ServerName::try_from(config.host.as_str()) - .map_err(|_| anyhow!("invalid Restls host {}", config.host))?; - let secret = config.secret; - let tls12 = config.version_hint == RestlsVersionHint::Tls12; - let handshake_stream = RestlsHandshakeStream::new(stream, config.secret, tls12); - let session_id_error = Arc::new(StdMutex::new(None::)); - let session_id_error_for_generator = Arc::clone(&session_id_error); - let tls_result = if tls12 { - connector - .connect_with_session_id_generators( - name, - handshake_stream, - shadow_rustls::ClientSessionIdGenerators { - tls13: None, - tls12: Some(Arc::new(move |client_hello, materials| { - restls_tls12_session_id_for_client_hello( - &secret, - client_hello, - materials, - &session_id_error_for_generator, - ) - })), - }, - ) - .await - } else { - connector - .connect_with_session_id_generator(name, handshake_stream, move |client_hello| { - restls_tls13_session_id_for_client_hello( - &secret, - client_hello, - &session_id_error_for_generator, - ) - }) - .await - }; - let tls = match tls_result { - Ok(tls) => tls, - Err(err) => { - if let Some(session_id_err) = take_restls_session_id_error(&session_id_error) { - return Err(err).with_context(|| { - format!( - "{session_id_err}; Restls handshake failed for {}", - config.host - ) - }); - } - return Err(err) - .with_context(|| format!("Restls handshake failed for {}", config.host)); - } - }; - if let Some(session_id_err) = take_restls_session_id_error(&session_id_error) { - bail!("{session_id_err}"); - } - let (handshake_stream, session) = tls.into_parts(); - let tls12_gcm = restls_tls12_gcm_suite(session.negotiated_cipher_suite()); - let (stream, handshake) = handshake_stream.into_inner(); - if !handshake.server_auth_unmasked { - bail!("Restls server authentication record was not observed"); - } - let server_random = handshake - .server_random - .ok_or_else(|| anyhow!("Restls handshake did not expose server random"))?; - let client_finished = handshake - .client_finished_auth - .ok_or_else(|| anyhow!("Restls handshake did not capture ClientFinished record"))?; - let mut codec = RestlsApplicationCodec::new(config.secret, server_random, tls12_gcm); - codec.set_client_finished_auth(client_finished); - codec.set_tls12_gcm_to_client_disable_counter(handshake.tls12_gcm_server_disable_counter); - let state = RestlsStreamState::new(codec, config.script.clone()); - Ok(Box::new(RestlsStream::new(stream, state))) -} - #[cfg(feature = "boring-browser-fingerprints")] async fn restls_boring_connect( stream: Box, @@ -1065,46 +850,6 @@ async fn restls_boring_connect( Ok(Box::new(RestlsStream::new(stream, state))) } -fn restls_client_config( - config: &ShadowsocksRestlsTransport, -) -> Result { - let mut root_store = shadow_rustls::RootCertStore::empty(); - root_store.add_server_trust_anchors(webpki_roots_legacy::TLS_SERVER_ROOTS.0.iter().map( - |anchor| { - shadow_rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( - anchor.subject, - anchor.spki, - anchor.name_constraints, - ) - }, - )); - let versions = match config.version_hint { - RestlsVersionHint::Tls12 => &[&shadow_rustls::version::TLS12][..], - RestlsVersionHint::Tls13 => &[&shadow_rustls::version::TLS13][..], - }; - let mut tls_config = shadow_rustls::ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(versions) - .context("failed to configure Restls TLS protocol versions")? - .with_root_certificates(root_store) - .with_no_client_auth(); - tls_config.enable_tickets = !config.session_tickets_disabled; - Ok(tls_config) -} - -fn restls_tls12_gcm_suite(suite: Option) -> bool { - matches!( - suite.map(|suite| suite.suite()), - Some( - shadow_rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - | shadow_rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - | shadow_rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - | shadow_rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - ) - ) -} - fn shadow_tls_client_config(config: &ShadowsocksShadowTlsTransport) -> Result { install_rustls_crypto_provider(); let mut root_store = RootCertStore::empty(); @@ -1143,49 +888,6 @@ fn shadow_tls_client_config(config: &ShadowsocksShadowTlsTransport) -> Result Result { - let mut root_store = shadow_rustls::RootCertStore::empty(); - root_store.add_server_trust_anchors(webpki_roots_legacy::TLS_SERVER_ROOTS.0.iter().map( - |anchor| { - shadow_rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( - anchor.subject, - anchor.spki, - anchor.name_constraints, - ) - }, - )); - let builder = shadow_rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(root_store); - let mut tls_config = if let Some(identity) = config.client_identity.as_ref() { - let (cert_chain, private_key) = load_shadow_rustls_client_identity(identity)?; - builder - .with_single_cert(cert_chain, private_key) - .context("failed to configure ShadowTLS v3 client certificate")? - } else { - builder.with_no_client_auth() - }; - tls_config.alpn_protocols = config - .alpn - .iter() - .map(|value| value.as_bytes().to_vec()) - .collect(); - if let Some(fingerprint) = config.certificate_fingerprint.as_ref() { - tls_config.dangerous().set_certificate_verifier(Arc::new( - ShadowPinnedCertificateVerifier { - fingerprint: fingerprint.clone(), - }, - )); - } else if config.skip_cert_verify { - tls_config - .dangerous() - .set_certificate_verifier(Arc::new(ShadowNoCertificateVerifier)); - } - Ok(tls_config) -} - async fn read_http_upgrade_response(stream: &mut Box) -> Result { let mut response = Vec::with_capacity(1024); let mut byte = [0u8; 1]; @@ -1492,26 +1194,12 @@ fn shadowsocks_plugin_transport( .to_owned(); let version = plugin_u8_opt(&plugin.opts, "version").unwrap_or(2); match version { - 1 | 2 | 3 => {} + 1 | 2 => {} other => bail!("unsupported Shadowsocks shadow-tls version {other}"), } let parsed_client_fingerprint = client_fingerprint.and_then(MihomoClientFingerprint::from_mihomo_name); if let Some(client_fingerprint) = parsed_client_fingerprint { - if version == 3 { - #[cfg(not(feature = "boring-browser-fingerprints"))] - bail!( - "unsupported Shadowsocks {name} client-fingerprint {}: uTLS-style ClientHello impersonation for ShadowTLS v3 requires the boring-browser-fingerprints feature", - client_fingerprint.mihomo_name() - ); - #[cfg(feature = "boring-browser-fingerprints")] - if !client_fingerprint.shadow_tls_v3_boring_supported() { - bail!( - "unsupported Shadowsocks {name} client-fingerprint {}: no matching browser TLS profile with ShadowTLS session ID signing is available yet", - client_fingerprint.mihomo_name() - ); - } - } if version == 2 && !client_fingerprint.shadow_tls_v2_boring_supported() { bail!( "unsupported Shadowsocks {name} client-fingerprint {}: no matching browser TLS profile is available yet", @@ -1553,20 +1241,6 @@ fn shadowsocks_plugin_transport( }, ))); } - if name == "restls" { - if let Some(client_fingerprint) = unsupported_client_fingerprint_value(client_fingerprint) { - #[cfg(not(feature = "boring-browser-fingerprints"))] - bail!( - "unsupported Shadowsocks {name} client-fingerprint {client_fingerprint}: uTLS ClientHello impersonation is not implemented" - ); - #[cfg(feature = "boring-browser-fingerprints")] - { - let _ = client_fingerprint; - } - } - let transport = restls_transport(plugin, client_fingerprint)?; - return Ok(Some(ShadowsocksPluginTransport::Restls(transport))); - } if name == "kcptun" { let mut transport = ShadowsocksKcptunTransport::empty(); if let Some(value) = plugin.opts.get("key") { diff --git a/burrow/src/proxy_runtime/tests.rs b/burrow/src/proxy_runtime/tests.rs index dbe5bca..9eb046b 100644 --- a/burrow/src/proxy_runtime/tests.rs +++ b/burrow/src/proxy_runtime/tests.rs @@ -1201,40 +1201,6 @@ mod tests { assert!(outbound.udp_over_tcp); } - #[test] - fn runtime_support_accepts_tls13_and_tls12_restls() { - fn restls_node(version_hint: &str) -> ProxyNode { - ProxyNode { - ordinal: 0, - name: format!("ss-restls-{version_hint}"), - protocol: crate::proxy_subscription::ProxyProtocol::Shadowsocks, - server: "proxy.example".to_owned(), - port: 443, - warnings: Vec::new(), - config: ProxyNodeConfig::Shadowsocks(ShadowsocksNode { - cipher: "aes-128-gcm".to_owned(), - password: "ss-secret".to_owned(), - udp: true, - udp_over_tcp: false, - udp_over_tcp_version: UOT_VERSION, - client_fingerprint: None, - plugin: Some(ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("password".to_owned(), "restls-secret".to_owned()), - ("version-hint".to_owned(), version_hint.to_owned()), - ]), - }), - smux: None, - }), - } - } - - assert!(runtime_support_error(&restls_node("tls13")).is_none()); - assert!(runtime_support_error(&restls_node("tls12")).is_none()); - } - #[test] fn runtime_support_rejects_shadowsocks_tls_client_fingerprint() { fn tls_plugin_node(plugin: ShadowsocksPlugin) -> ProxyNode { @@ -1263,23 +1229,12 @@ mod tests { opts: HashMap::from([ ("host".to_owned(), "cover.example".to_owned()), ("password".to_owned(), "secret".to_owned()), - ("version".to_owned(), "3".to_owned()), - ]), - }; - let restls = ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("password".to_owned(), "restls-secret".to_owned()), - ("version-hint".to_owned(), "tls13".to_owned()), + ("version".to_owned(), "2".to_owned()), ]), }; #[cfg(not(feature = "boring-browser-fingerprints"))] - let rejected_nodes = [ - tls_plugin_node(shadow_tls.clone()), - tls_plugin_node(restls.clone()), - ]; + let rejected_nodes = [tls_plugin_node(shadow_tls.clone())]; #[cfg(feature = "boring-browser-fingerprints")] let rejected_nodes: [ProxyNode; 0] = []; @@ -1287,11 +1242,9 @@ mod tests { let err = runtime_support_error(&node) .expect("uTLS client-fingerprint is not runtime-supported yet"); assert!(err.contains("client-fingerprint firefox"), "{err}"); - assert!(err.contains("uTLS"), "{err}"); + assert!(err.contains("browser TLS profile"), "{err}"); } - #[cfg(feature = "boring-browser-fingerprints")] - assert!(runtime_support_error(&tls_plugin_node(restls)).is_none()); #[cfg(feature = "boring-browser-fingerprints")] assert!(runtime_support_error(&tls_plugin_node(shadow_tls)).is_none()); @@ -1309,7 +1262,7 @@ mod tests { opts: HashMap::from([ ("host".to_owned(), "cover.example".to_owned()), ("password".to_owned(), "secret".to_owned()), - ("version".to_owned(), "3".to_owned()), + ("version".to_owned(), "2".to_owned()), ]), }); if let ProxyNodeConfig::Shadowsocks(shadowsocks) = &mut none_node.config { @@ -1834,29 +1787,7 @@ OW4mfN8jmXq6wTtOv85mBGE= ("version".to_owned(), "3".to_owned()), ]), }; - let Some(ShadowsocksPluginTransport::ShadowTls(shadow_tls_v3)) = - shadowsocks_plugin_transport(Some(&shadow_tls_v3_plugin), None).unwrap() - else { - panic!("expected shadow-tls plugin transport"); - }; - assert_eq!(shadow_tls_v3.version, 3); - #[cfg(feature = "boring-browser-fingerprints")] - { - let Some(ShadowsocksPluginTransport::ShadowTls(shadow_tls_v3_with_fingerprint)) = - shadowsocks_plugin_transport(Some(&shadow_tls_v3_plugin), Some("firefox")).unwrap() - else { - panic!("expected shadow-tls plugin transport"); - }; - assert_eq!(shadow_tls_v3_with_fingerprint.version, 3); - assert_eq!( - shadow_tls_v3_with_fingerprint.client_fingerprint, - Some(MihomoClientFingerprint::Firefox) - ); - } - #[cfg(not(feature = "boring-browser-fingerprints"))] - assert!( - shadowsocks_plugin_transport(Some(&shadow_tls_v3_plugin), Some("firefox")).is_err() - ); + assert!(shadowsocks_plugin_transport(Some(&shadow_tls_v3_plugin), None).is_err()); let kcptun = ShadowsocksPlugin { name: "kcptun".to_owned(), @@ -1894,115 +1825,6 @@ OW4mfN8jmXq6wTtOv85mBGE= assert_eq!(kcptun.frame_size, 4096); assert_eq!(kcptun_ipv4_dscp_tos(kcptun.dscp), 184); - let restls = ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("password".to_owned(), "secret".to_owned()), - ("version-hint".to_owned(), "tls13".to_owned()), - ( - "restls-script".to_owned(), - "600~100,300~200<2,300".to_owned(), - ), - ]), - }; - let restls = restls_transport(&restls, Some("firefox")).unwrap(); - assert_eq!(restls.host, "cover.example"); - assert_eq!(restls.version_hint, RestlsVersionHint::Tls13); - assert_eq!(restls.client_fingerprint, RestlsClientFingerprint::Firefox); - assert!(restls.session_tickets_disabled); - assert_eq!( - restls.secret, - blake3::derive_key("restls-traffic-key", b"secret") - ); - assert_eq!( - restls.script, - vec![ - RestlsScriptLine { - target_len: RestlsTargetLength { base: 600, random_range: 100 }, - command: RestlsCommand::Noop, - }, - RestlsScriptLine { - target_len: RestlsTargetLength { base: 300, random_range: 200 }, - command: RestlsCommand::Response(2), - }, - RestlsScriptLine { - target_len: RestlsTargetLength { base: 300, random_range: 0 }, - command: RestlsCommand::Noop, - }, - ] - ); - } - - #[test] - fn restls_plugin_supports_tls13_and_tls12_runtime() { - let restls_tls12 = ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("password".to_owned(), "secret".to_owned()), - ("version-hint".to_owned(), "tls12".to_owned()), - ]), - }; - let Some(ShadowsocksPluginTransport::Restls(restls_tls12_transport)) = - shadowsocks_plugin_transport(Some(&restls_tls12), None).unwrap() - else { - panic!("expected TLS 1.2 restls plugin transport"); - }; - assert_eq!( - restls_tls12_transport.version_hint, - RestlsVersionHint::Tls12 - ); - assert_eq!( - restls_tls12_transport.client_fingerprint, - RestlsClientFingerprint::Chrome - ); - assert!(!restls_tls12_transport.session_tickets_disabled); - let tls12_config = restls_client_config(&restls_tls12_transport).unwrap(); - assert!(tls12_config.enable_tickets); - - let parsed = restls_transport(&restls_tls12, Some("safari")).unwrap(); - assert_eq!(parsed.version_hint, RestlsVersionHint::Tls12); - assert_eq!(parsed.client_fingerprint, RestlsClientFingerprint::Safari); - assert!(!parsed.session_tickets_disabled); - - let case_mismatch = restls_transport(&restls_tls12, Some("Safari")).unwrap(); - assert_eq!( - case_mismatch.client_fingerprint, - RestlsClientFingerprint::Chrome, - "Mihomo's restls clientIDMap is case-sensitive and falls back to Chrome" - ); - - let restls_tls13 = ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("password".to_owned(), "secret".to_owned()), - ("version-hint".to_owned(), "tls13".to_owned()), - ]), - }; - let Some(ShadowsocksPluginTransport::Restls(restls_tls13)) = - shadowsocks_plugin_transport(Some(&restls_tls13), None).unwrap() - else { - panic!("expected TLS 1.3 restls plugin transport"); - }; - assert_eq!(restls_tls13.version_hint, RestlsVersionHint::Tls13); - assert_eq!( - restls_tls13.client_fingerprint, - RestlsClientFingerprint::Chrome - ); - assert!(restls_tls13.session_tickets_disabled); - let tls_config = restls_client_config(&restls_tls13).unwrap(); - assert!(!tls_config.enable_tickets); - - let invalid = ShadowsocksPlugin { - name: "restls".to_owned(), - opts: HashMap::from([ - ("host".to_owned(), "cover.example".to_owned()), - ("version-hint".to_owned(), "tls14".to_owned()), - ]), - }; - assert!(restls_transport(&invalid, None).is_err()); } #[test] diff --git a/third_party/rustls-fork-shadow-tls/Cargo.lock b/third_party/rustls-fork-shadow-tls/Cargo.lock deleted file mode 100644 index 16aefc7..0000000 --- a/third_party/rustls-fork-shadow-tls/Cargo.lock +++ /dev/null @@ -1,729 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap", - "unicode-width", -] - -[[package]] -name = "criterion" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "env_logger" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.135" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "proc-macro2" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rayon" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustls-fork-shadow-tls" -version = "0.20.8" -dependencies = [ - "base64", - "criterion", - "env_logger", - "log", - "ring", - "rustls-pemfile", - "rustversion", - "sct", - "webpki", - "webpki-roots", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" -dependencies = [ - "base64", -] - -[[package]] -name = "rustversion" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "serde" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" -dependencies = [ - "itoa 1.0.5", - "ryu", - "serde", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "syn" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" -dependencies = [ - "webpki", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rustls-fork-shadow-tls/Cargo.toml b/third_party/rustls-fork-shadow-tls/Cargo.toml deleted file mode 100644 index de79f4a..0000000 --- a/third_party/rustls-fork-shadow-tls/Cargo.toml +++ /dev/null @@ -1,107 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -rust-version = "1.57" -name = "rustls-fork-shadow-tls" -version = "0.20.8" -build = "build.rs" -autobenches = false -description = "Rustls is a modern TLS library written in Rust." -homepage = "https://github.com/rustls/rustls" -readme = "README.md" -categories = [ - "network-programming", - "cryptography", -] -license = "Apache-2.0/ISC/MIT" -repository = "https://github.com/rustls/rustls" -resolver = "2" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = [ - "--cfg", - "docsrs", -] - -[[example]] -name = "bogo_shim" -path = "examples/internal/bogo_shim.rs" -required-features = [ - "dangerous_configuration", - "quic", -] - -[[example]] -name = "trytls_shim" -path = "examples/internal/trytls_shim.rs" - -[[example]] -name = "bench" -path = "examples/internal/bench.rs" - -[[bench]] -name = "benchmarks" -path = "benches/benchmarks.rs" -harness = false - -[dependencies.log] -version = "0.4.4" -optional = true - -[dependencies.ring] -version = "0.16.20" - -[dependencies.sct] -version = "0.7.0" - -[dependencies.webpki] -version = "0.22.0" -features = [ - "alloc", - "std", -] - -[dev-dependencies.base64] -version = "0.13.0" - -[dev-dependencies.criterion] -version = "0.3.0" - -[dev-dependencies.env_logger] -version = "0.9.0" - -[dev-dependencies.log] -version = "0.4.4" - -[dev-dependencies.rustls-pemfile] -version = "1.0.0" - -[dev-dependencies.webpki-roots] -version = "0.22.0" - -[build-dependencies.rustversion] -version = "1.0.6" -optional = true - -[features] -dangerous_configuration = [] -default = [ - "logging", - "tls12", -] -logging = ["log"] -quic = [] -read_buf = ["rustversion"] -secret_extraction = [] -tls12 = [] diff --git a/third_party/rustls-fork-shadow-tls/Cargo.toml.orig b/third_party/rustls-fork-shadow-tls/Cargo.toml.orig deleted file mode 100644 index 86d90c7..0000000 --- a/third_party/rustls-fork-shadow-tls/Cargo.toml.orig +++ /dev/null @@ -1,62 +0,0 @@ -[package] -name = "rustls-fork-shadow-tls" -version = "0.20.8" -edition = "2018" -rust-version = "1.57" -license = "Apache-2.0/ISC/MIT" -readme = "../README.md" -description = "Rustls is a modern TLS library written in Rust." -homepage = "https://github.com/rustls/rustls" -repository = "https://github.com/rustls/rustls" -categories = ["network-programming", "cryptography"] -autobenches = false -build = "build.rs" -resolver = "2" - -[build-dependencies] -rustversion = { version = "1.0.6", optional = true } - -[dependencies] -log = { version = "0.4.4", optional = true } -ring = "0.16.20" -sct = "0.7.0" -webpki = { version = "0.22.0", features = ["alloc", "std"] } - -[features] -default = ["logging", "tls12"] -logging = ["log"] -dangerous_configuration = [] -secret_extraction = [] -quic = [] -tls12 = [] -read_buf = ["rustversion"] - -[dev-dependencies] -env_logger = "0.9.0" -log = "0.4.4" -webpki-roots = "0.22.0" -criterion = "0.3.0" -rustls-pemfile = "1.0.0" -base64 = "0.13.0" - -[[example]] -name = "bogo_shim" -path = "examples/internal/bogo_shim.rs" -required-features = ["dangerous_configuration", "quic"] - -[[example]] -name = "trytls_shim" -path = "examples/internal/trytls_shim.rs" - -[[example]] -name = "bench" -path = "examples/internal/bench.rs" - -[[bench]] -name = "benchmarks" -path = "benches/benchmarks.rs" -harness = false - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] diff --git a/third_party/rustls-fork-shadow-tls/LICENSE-APACHE b/third_party/rustls-fork-shadow-tls/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/third_party/rustls-fork-shadow-tls/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/third_party/rustls-fork-shadow-tls/LICENSE-ISC b/third_party/rustls-fork-shadow-tls/LICENSE-ISC deleted file mode 100644 index 03acf1b..0000000 --- a/third_party/rustls-fork-shadow-tls/LICENSE-ISC +++ /dev/null @@ -1,15 +0,0 @@ -ISC License (ISC) -Copyright (c) 2016, Joseph Birr-Pixton - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/third_party/rustls-fork-shadow-tls/LICENSE-MIT b/third_party/rustls-fork-shadow-tls/LICENSE-MIT deleted file mode 100644 index ef480e6..0000000 --- a/third_party/rustls-fork-shadow-tls/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Joseph Birr-Pixton - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/third_party/rustls-fork-shadow-tls/README.md b/third_party/rustls-fork-shadow-tls/README.md deleted file mode 100644 index 5ddb46d..0000000 --- a/third_party/rustls-fork-shadow-tls/README.md +++ /dev/null @@ -1,298 +0,0 @@ -

- -

- -

-Rustls is a modern TLS library written in Rust. It uses ring for cryptography and webpki for certificate -verification. -

- -# Status -Rustls is ready for use. There are no major breaking interface changes -envisioned after the set included in the 0.20 release. - -If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md). - -[![Build Status](https://github.com/rustls/rustls/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/rustls/rustls/actions/workflows/build.yml?query=branch%3Amain) -[![Coverage Status (codecov.io)](https://codecov.io/gh/rustls/rustls/branch/main/graph/badge.svg)](https://codecov.io/gh/rustls/rustls/) -[![Documentation](https://docs.rs/rustls/badge.svg)](https://docs.rs/rustls/) -[![Chat](https://img.shields.io/discord/976380008299917365?logo=discord)](https://discord.gg/MCSB76RU96) - -## Release history - -* Next release - - Planned: removal of unused signature verification schemes at link-time. -* 0.20.8 (2023-01-12) - - Yield an error from `ConnectionCommon::read_tls()` if buffers are full. - Both a full deframer buffer and a full incoming plaintext buffer will - now cause an error to be returned. Callers should call `process_new_packets()` - and read out the plaintext data from `reader()` after each successful call to `read_tls()`. - - The minimum supported Rust version is now 1.57.0 due to some dependencies - requiring it. -* 0.20.7 (2022-10-18) - - Expose secret extraction API under the `secret_extraction` cargo feature. - This is designed to enable switching from rustls to kTLS (kernel TLS - offload) after a successful TLS 1.2/1.3 handshake, for example. - - Move filtering of signature schemes after config selection, avoiding the need - for linking in encryption/decryption code for all cipher suites at the cost of - exposing more signature schemes in the `ClientHello` emitted by the `Acceptor`. - - Expose AlertDescription, ContentType, and HandshakeType, - SignatureAlgorithm, and NamedGroup as part of the stable API. Previously they - were part of the unstable internals API, but were referenced by parts of the - stable API. - - We now have a [Discord channel](https://discord.gg/MCSB76RU96) for community - discussions. - - The minimum supported Rust version is now 1.56.0 due to several dependencies - requiring it. -* 0.20.6 (2022-05-18) - - 0.20.5 included a change to track more context for the `Error::CorruptMessage` - which made API-incompatible changes to the `Error` type. We yanked 0.20.5 - and have reverted that change as part of 0.20.6. -* 0.20.5 (2022-05-14) - - Correct compatbility with servers which return no TLS extensions and take - advantage of a special case encoding. - - Remove spurious warn-level logging introduced in 0.20.3. - - Expose cipher suites in `ClientHello` type. - - Allow verification of IP addresses with `dangerous_config` enabled. - - Retry I/O operations in `ConnectionCommon::complete_io()` when interrupted. - - Fix server::ResolvesServerCertUsingSni case sensitivity. -* 0.20.4 (2022-02-19) - - Correct regression in QUIC 0-RTT support. -* 0.20.3 (2022-02-13) - - Support loading ECDSA keys in SEC1 format. - - Support receipt of 0-RTT "early data" in TLS1.3 servers. It is not enabled - by default; opt in by setting `ServerConfig::max_early_data_size` to a non-zero - value. - - Support sending of data with the first server flight. This is also not - enabled by default either: opt in by setting `ServerConfig::send_half_rtt_data`. - - Support `read_buf` interface when compiled with nightly. This means - data can be safely read out of a rustls connection into a buffer without - the buffer requiring initialisation first. Set the `read_buf` feature to - use this. - - Improve efficiency when writing vectors of TLS types. - - Reduce copying and improve efficiency in TLS1.2 handshake. -* 0.20.2 (2021-11-21) - - Fix `CipherSuite::as_str()` value (as introduced in 0.20.1). -* 0.20.1 (2021-11-14) - - Allow cipher suite enum items to be stringified. - - Improve documentation of configuration builder types. - - Ensure unused cipher suites can be removed at link-time. - - Ensure single-use error types implement `std::error::Error`, and are public. - -See [RELEASE_NOTES.md](RELEASE_NOTES.md) for further change history. - -# Documentation -Lives here: https://docs.rs/rustls/ - -# Approach -Rustls is a TLS library that aims to provide a good level of cryptographic security, -requires no configuration to achieve that security, and provides no unsafe features or -obsolete cryptography. - -## Current features - -* TLS1.2 and TLS1.3. -* ECDSA, Ed25519 or RSA server authentication by clients. -* ECDSA, Ed25519 or RSA server authentication by servers. -* Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. -* AES128-GCM and AES256-GCM bulk encryption, with safe nonces. -* ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). -* ALPN support. -* SNI support. -* Tunable fragment size to make TLS messages match size of underlying transport. -* Optional use of vectored IO to minimise system calls. -* TLS1.2 session resumption. -* TLS1.2 resumption via tickets ([RFC5077](https://tools.ietf.org/html/rfc5077)). -* TLS1.3 resumption via tickets or session storage. -* TLS1.3 0-RTT data for clients. -* TLS1.3 0-RTT data for servers. -* Client authentication by clients. -* Client authentication by servers. -* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)). -* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)). -* OCSP stapling by servers. -* SCT stapling by servers. -* SCT verification by clients. - -## Possible future features - -* PSK support. -* OCSP verification by clients. -* Certificate pinning. - -## Non-features - -For reasons [explained in the manual](https://docs.rs/rustls/latest/rustls/manual/_02_tls_vulnerabilities/index.html), -rustls does not and will not support: - -* SSL1, SSL2, SSL3, TLS1 or TLS1.1. -* RC4. -* DES or triple DES. -* EXPORT ciphersuites. -* MAC-then-encrypt ciphersuites. -* Ciphersuites without forward secrecy. -* Renegotiation. -* Kerberos. -* Compression. -* Discrete-log Diffie-Hellman. -* Automatic protocol version downgrade. - -There are plenty of other libraries that provide these features should you -need them. - -### Platform support - -Rustls uses [`ring`](https://crates.io/crates/ring) for implementing the -cryptography in TLS. As a result, rustls only runs on platforms -[supported by `ring`](https://github.com/briansmith/ring#online-automated-testing). -At the time of writing this means x86, x86-64, armv7, and aarch64. - -Rustls requires Rust 1.56 or later. - -# Example code -There are two example programs which use -[mio](https://github.com/carllerche/mio) to do asynchronous IO. - -## Client example program -The client example program is named `tlsclient-mio`. The interface looks like: - -```tlsclient-mio -Connects to the TLS server at hostname:PORT. The default PORT -is 443. By default, this reads a request from stdin (to EOF) -before making the connection. --http replaces this with a -basic HTTP GET request for /. - -If --cafile is not supplied, a built-in set of CA certificates -are used from the webpki-roots crate. - -Usage: - tlsclient-mio [options] [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] - tlsclient-mio (--version | -v) - tlsclient-mio (--help | -h) - -Options: - -p, --port PORT Connect to PORT [default: 443]. - --http Send a basic HTTP GET request for /. - --cafile CAFILE Read root certificates from CAFILE. - --auth-key KEY Read client authentication key from KEY. - --auth-certs CERTS Read client authentication certificates from CERTS. - CERTS must match up with KEY. - --protover VERSION Disable default TLS version list, and use - VERSION instead. May be used multiple times. - --suite SUITE Disable default cipher suite list, and use - SUITE instead. May be used multiple times. - --proto PROTOCOL Send ALPN extension containing PROTOCOL. - May be used multiple times to offer several protocols. - --cache CACHE Save session cache to file CACHE. - --no-tickets Disable session ticket support. - --no-sni Disable server name indication support. - --insecure Disable certificate verification. - --verbose Emit log output. - --max-frag-size M Limit outgoing messages to M bytes. - --version, -v Show tool version. - --help, -h Show this screen. -``` - -Some sample runs: - -``` -$ cargo run --bin tlsclient-mio -- --http mozilla-modern.badssl.com -HTTP/1.1 200 OK -Server: nginx/1.6.2 (Ubuntu) -Date: Wed, 01 Jun 2016 18:44:00 GMT -Content-Type: text/html -Content-Length: 644 -(...) -``` - -or - -``` -$ cargo run --bin tlsclient-mio -- --http expired.badssl.com -TLS error: WebPkiError(CertExpired, ValidateServerCert) -Connection closed -``` - -## Server example program -The server example program is named `tlsserver-mio`. The interface looks like: - -```tlsserver-mio -Runs a TLS server on :PORT. The default PORT is 443. - -`echo' mode means the server echoes received data on each connection. - -`http' mode means the server blindly sends a HTTP response on each -connection. - -`forward' means the server forwards plaintext to a connection made to -localhost:fport. - -`--certs' names the full certificate chain, `--key' provides the -RSA private key. - -Usage: - tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] echo - tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] http - tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] forward - tlsserver-mio (--version | -v) - tlsserver-mio (--help | -h) - -Options: - -p, --port PORT Listen on PORT [default: 443]. - --certs CERTFILE Read server certificates from CERTFILE. - This should contain PEM-format certificates - in the right order (the first certificate should - certify KEYFILE, the last should be a root CA). - --key KEYFILE Read private key from KEYFILE. This should be a RSA - private key or PKCS8-encoded private key, in PEM format. - --ocsp OCSPFILE Read DER-encoded OCSP response from OCSPFILE and staple - to certificate. Optional. - --auth CERTFILE Enable client authentication, and accept certificates - signed by those roots provided in CERTFILE. - --require-auth Send a fatal alert if the client does not complete client - authentication. - --resumption Support session resumption. - --tickets Support tickets. - --protover VERSION Disable default TLS version list, and use - VERSION instead. May be used multiple times. - --suite SUITE Disable default cipher suite list, and use - SUITE instead. May be used multiple times. - --proto PROTOCOL Negotiate PROTOCOL using ALPN. - May be used multiple times. - --verbose Emit log output. - --version, -v Show tool version. - --help, -h Show this screen. -``` - -Here's a sample run; we start a TLS echo server, then connect to it with -`openssl` and `tlsclient-mio`: - -``` -$ cargo run --bin tlsserver-mio -- --certs test-ca/rsa/end.fullchain --key test-ca/rsa/end.rsa -p 8443 echo & -$ echo hello world | openssl s_client -ign_eof -quiet -connect localhost:8443 -depth=2 CN = ponytown RSA CA -verify error:num=19:self signed certificate in certificate chain -hello world -^C -$ echo hello world | cargo run --bin tlsclient-mio -- --cafile test-ca/rsa/ca.cert -p 8443 localhost -hello world -^C -``` - -# License - -Rustls is distributed under the following three licenses: - -- Apache License version 2.0. -- MIT license. -- ISC license. - -These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC -respectively. You may use this software under the terms of any -of these licenses, at your option. - -# Code of conduct - -This project adopts the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). -Please email rustls-mod@googlegroups.com to report any instance of misconduct, or if you -have any comments or questions on the Code of Conduct. diff --git a/third_party/rustls-fork-shadow-tls/benches/benchmarks.rs b/third_party/rustls-fork-shadow-tls/benches/benchmarks.rs deleted file mode 100644 index 08191be..0000000 --- a/third_party/rustls-fork-shadow-tls/benches/benchmarks.rs +++ /dev/null @@ -1,26 +0,0 @@ -use criterion::criterion_group; -use criterion::criterion_main; -/// Microbenchmarks go here. Larger benchmarks of (e.g..) protocol -/// performance go in examples/internal/bench.rs. -use criterion::Criterion; - -#[path = "../tests/common/mod.rs"] -mod test_utils; -use test_utils::*; - -use rustls::ServerConnection; - -use std::io; -use std::sync::Arc; - -fn bench_ewouldblock(c: &mut Criterion) { - let server_config = make_server_config(KeyType::Rsa); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - let mut read_ewouldblock = FailsReads::new(io::ErrorKind::WouldBlock); - c.bench_function("read_tls with EWOULDBLOCK", move |b| { - b.iter(|| server.read_tls(&mut read_ewouldblock)) - }); -} - -criterion_group!(benches, bench_ewouldblock); -criterion_main!(benches); diff --git a/third_party/rustls-fork-shadow-tls/build.rs b/third_party/rustls-fork-shadow-tls/build.rs deleted file mode 100644 index 9c73252..0000000 --- a/third_party/rustls-fork-shadow-tls/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// This build script allows us to enable the `read_buf` language feature only -/// for Rust Nightly. -/// -/// See the comment in lib.rs to understand why we need this. - -#[cfg_attr(feature = "read_buf", rustversion::not(nightly))] -fn main() {} - -#[cfg(feature = "read_buf")] -#[rustversion::nightly] -fn main() { - println!("cargo:rustc-cfg=read_buf"); -} diff --git a/third_party/rustls-fork-shadow-tls/examples/internal/bench.rs b/third_party/rustls-fork-shadow-tls/examples/internal/bench.rs deleted file mode 100644 index 5ef69d0..0000000 --- a/third_party/rustls-fork-shadow-tls/examples/internal/bench.rs +++ /dev/null @@ -1,664 +0,0 @@ -// This program does assorted benchmarking of rustls. -// -// Note: we don't use any of the standard 'cargo bench', 'test::Bencher', -// etc. because it's unstable at the time of writing. - -use std::convert::TryInto; -use std::env; -use std::fs; -use std::io::{self, Read, Write}; -use std::ops::Deref; -use std::ops::DerefMut; -use std::sync::Arc; -use std::time::{Duration, Instant}; - -use rustls::client::{ClientSessionMemoryCache, NoClientSessionStorage}; -use rustls::server::{ - AllowAnyAuthenticatedClient, NoClientAuth, NoServerSessionStorage, ServerSessionMemoryCache, -}; -use rustls::RootCertStore; -use rustls::Ticketer; -use rustls::{ClientConfig, ClientConnection}; -use rustls::{ConnectionCommon, SideData}; -use rustls::{ServerConfig, ServerConnection}; - -fn duration_nanos(d: Duration) -> f64 { - (d.as_secs() as f64) + f64::from(d.subsec_nanos()) / 1e9 -} - -fn _bench(count: usize, name: &'static str, f_setup: Fsetup, f_test: Ftest) -where - Fsetup: Fn() -> S, - Ftest: Fn(S), -{ - let mut times = Vec::new(); - - for _ in 0..count { - let state = f_setup(); - let start = Instant::now(); - f_test(state); - times.push(duration_nanos(Instant::now().duration_since(start))); - } - - println!("{}", name); - println!("{:?}", times); -} - -fn time(mut f: F) -> f64 -where - F: FnMut(), -{ - let start = Instant::now(); - f(); - let end = Instant::now(); - duration_nanos(end.duration_since(start)) -} - -fn transfer(left: &mut L, right: &mut R, expect_data: Option) -> f64 -where - L: DerefMut + Deref>, - R: DerefMut + Deref>, - LS: SideData, - RS: SideData, -{ - let mut tls_buf = [0u8; 262144]; - let mut read_time = 0f64; - let mut data_left = expect_data; - let mut data_buf = [0u8; 8192]; - - loop { - let mut sz = 0; - - while left.wants_write() { - let written = left - .write_tls(&mut tls_buf[sz..].as_mut()) - .unwrap(); - if written == 0 { - break; - } - - sz += written; - } - - if sz == 0 { - return read_time; - } - - let mut offs = 0; - loop { - let start = Instant::now(); - match right.read_tls(&mut tls_buf[offs..sz].as_ref()) { - Ok(read) => { - right.process_new_packets().unwrap(); - offs += read; - } - Err(err) => { - panic!("error on transfer {}..{}: {}", offs, sz, err); - } - } - - if let Some(left) = &mut data_left { - loop { - let sz = match right.reader().read(&mut data_buf) { - Ok(sz) => sz, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Err(err) => panic!("failed to read data: {}", err), - }; - - *left -= sz; - if *left == 0 { - break; - } - } - } - - let end = Instant::now(); - read_time += duration_nanos(end.duration_since(start)); - if sz == offs { - break; - } - } - } -} - -#[derive(PartialEq, Clone, Copy)] -enum ClientAuth { - No, - Yes, -} - -#[derive(PartialEq, Clone, Copy)] -enum Resumption { - No, - SessionID, - Tickets, -} - -impl Resumption { - fn label(&self) -> &'static str { - match *self { - Resumption::No => "no-resume", - Resumption::SessionID => "sessionid", - Resumption::Tickets => "tickets", - } - } -} - -// copied from tests/api.rs -#[derive(PartialEq, Clone, Copy, Debug)] -enum KeyType { - Rsa, - Ecdsa, - Ed25519, -} - -struct BenchmarkParam { - key_type: KeyType, - ciphersuite: rustls::SupportedCipherSuite, - version: &'static rustls::SupportedProtocolVersion, -} - -impl BenchmarkParam { - const fn new( - key_type: KeyType, - ciphersuite: rustls::SupportedCipherSuite, - version: &'static rustls::SupportedProtocolVersion, - ) -> BenchmarkParam { - BenchmarkParam { - key_type, - ciphersuite, - version, - } - } -} - -static ALL_BENCHMARKS: &[BenchmarkParam] = &[ - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - &rustls::version::TLS12, - ), - #[cfg(feature = "tls12")] - BenchmarkParam::new( - KeyType::Ecdsa, - rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - &rustls::version::TLS12, - ), - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Rsa, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Ecdsa, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, - &rustls::version::TLS13, - ), - BenchmarkParam::new( - KeyType::Ed25519, - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, - &rustls::version::TLS13, - ), -]; - -impl KeyType { - fn path_for(&self, part: &str) -> String { - match self { - KeyType::Rsa => format!("test-ca/rsa/{}", part), - KeyType::Ecdsa => format!("test-ca/ecdsa/{}", part), - KeyType::Ed25519 => format!("test-ca/eddsa/{}", part), - } - } - - fn get_chain(&self) -> Vec { - rustls_pemfile::certs(&mut io::BufReader::new( - fs::File::open(self.path_for("end.fullchain")).unwrap(), - )) - .unwrap() - .iter() - .map(|v| rustls::Certificate(v.clone())) - .collect() - } - - fn get_key(&self) -> rustls::PrivateKey { - rustls::PrivateKey( - rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( - fs::File::open(self.path_for("end.key")).unwrap(), - )) - .unwrap()[0] - .clone(), - ) - } - - fn get_client_chain(&self) -> Vec { - rustls_pemfile::certs(&mut io::BufReader::new( - fs::File::open(self.path_for("client.fullchain")).unwrap(), - )) - .unwrap() - .iter() - .map(|v| rustls::Certificate(v.clone())) - .collect() - } - - fn get_client_key(&self) -> rustls::PrivateKey { - rustls::PrivateKey( - rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( - fs::File::open(self.path_for("client.key")).unwrap(), - )) - .unwrap()[0] - .clone(), - ) - } -} - -fn make_server_config( - params: &BenchmarkParam, - client_auth: ClientAuth, - resume: Resumption, - max_fragment_size: Option, -) -> ServerConfig { - let client_auth = match client_auth { - ClientAuth::Yes => { - let roots = params.key_type.get_chain(); - let mut client_auth_roots = RootCertStore::empty(); - for root in roots { - client_auth_roots.add(&root).unwrap(); - } - AllowAnyAuthenticatedClient::new(client_auth_roots) - } - ClientAuth::No => NoClientAuth::new(), - }; - - let mut cfg = ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(&[params.version]) - .unwrap() - .with_client_cert_verifier(client_auth) - .with_single_cert(params.key_type.get_chain(), params.key_type.get_key()) - .expect("bad certs/private key?"); - - if resume == Resumption::SessionID { - cfg.session_storage = ServerSessionMemoryCache::new(128); - } else if resume == Resumption::Tickets { - cfg.ticketer = Ticketer::new().unwrap(); - } else { - cfg.session_storage = Arc::new(NoServerSessionStorage {}); - } - - cfg.max_fragment_size = max_fragment_size; - cfg -} - -fn make_client_config( - params: &BenchmarkParam, - clientauth: ClientAuth, - resume: Resumption, -) -> ClientConfig { - let mut root_store = RootCertStore::empty(); - let mut rootbuf = - io::BufReader::new(fs::File::open(params.key_type.path_for("ca.cert")).unwrap()); - root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); - - let cfg = ClientConfig::builder() - .with_cipher_suites(&[params.ciphersuite]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[params.version]) - .unwrap() - .with_root_certificates(root_store); - - let mut cfg = if clientauth == ClientAuth::Yes { - cfg.with_single_cert( - params.key_type.get_client_chain(), - params.key_type.get_client_key(), - ) - .unwrap() - } else { - cfg.with_no_client_auth() - }; - - if resume != Resumption::No { - cfg.session_storage = ClientSessionMemoryCache::new(128); - } else { - cfg.session_storage = Arc::new(NoClientSessionStorage {}); - } - - cfg -} - -fn apply_work_multiplier(work: u64) -> u64 { - let mul = match env::var("BENCH_MULTIPLIER") { - Ok(val) => val - .parse::() - .expect("invalid BENCH_MULTIPLIER value"), - Err(_) => 1., - }; - - ((work as f64) * mul).round() as u64 -} - -fn bench_handshake(params: &BenchmarkParam, clientauth: ClientAuth, resume: Resumption) { - let client_config = Arc::new(make_client_config(params, clientauth, resume)); - let server_config = Arc::new(make_server_config(params, clientauth, resume, None)); - - assert!(params.ciphersuite.version() == params.version); - - let rounds = apply_work_multiplier(if resume == Resumption::No { 512 } else { 4096 }); - let mut client_time = 0f64; - let mut server_time = 0f64; - - for _ in 0..rounds { - let server_name = "localhost".try_into().unwrap(); - let mut client = ClientConnection::new(Arc::clone(&client_config), server_name).unwrap(); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - - server_time += time(|| { - transfer(&mut client, &mut server, None); - }); - client_time += time(|| { - transfer(&mut server, &mut client, None); - }); - server_time += time(|| { - transfer(&mut client, &mut server, None); - }); - client_time += time(|| { - transfer(&mut server, &mut client, None); - }); - } - - println!( - "handshakes\t{:?}\t{:?}\t{:?}\tclient\t{}\t{}\t{:.2}\thandshake/s", - params.version, - params.key_type, - params.ciphersuite.suite(), - if clientauth == ClientAuth::Yes { - "mutual" - } else { - "server-auth" - }, - resume.label(), - (rounds as f64) / client_time - ); - println!( - "handshakes\t{:?}\t{:?}\t{:?}\tserver\t{}\t{}\t{:.2}\thandshake/s", - params.version, - params.key_type, - params.ciphersuite.suite(), - if clientauth == ClientAuth::Yes { - "mutual" - } else { - "server-auth" - }, - resume.label(), - (rounds as f64) / server_time - ); -} - -fn do_handshake_step(client: &mut ClientConnection, server: &mut ServerConnection) -> bool { - if server.is_handshaking() || client.is_handshaking() { - transfer(client, server, None); - transfer(server, client, None); - true - } else { - false - } -} - -fn do_handshake(client: &mut ClientConnection, server: &mut ServerConnection) { - while do_handshake_step(client, server) {} -} - -fn bench_bulk(params: &BenchmarkParam, plaintext_size: u64, max_fragment_size: Option) { - let client_config = Arc::new(make_client_config(params, ClientAuth::No, Resumption::No)); - let server_config = Arc::new(make_server_config( - params, - ClientAuth::No, - Resumption::No, - max_fragment_size, - )); - - let server_name = "localhost".try_into().unwrap(); - let mut client = ClientConnection::new(client_config, server_name).unwrap(); - client.set_buffer_limit(None); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - server.set_buffer_limit(None); - - do_handshake(&mut client, &mut server); - - let mut buf = Vec::new(); - buf.resize(plaintext_size as usize, 0u8); - - let total_data = apply_work_multiplier(if plaintext_size < 8192 { - 64 * 1024 * 1024 - } else { - 1024 * 1024 * 1024 - }); - let rounds = total_data / plaintext_size; - let mut time_send = 0f64; - let mut time_recv = 0f64; - - for _ in 0..rounds { - time_send += time(|| { - server.writer().write_all(&buf).unwrap(); - }); - - time_recv += transfer(&mut server, &mut client, Some(buf.len())); - } - - let mfs_str = format!( - "max_fragment_size:{}", - max_fragment_size - .map(|v| v.to_string()) - .unwrap_or_else(|| "default".to_string()) - ); - let total_mbs = ((plaintext_size * rounds) as f64) / (1024. * 1024.); - println!( - "bulk\t{:?}\t{:?}\t{}\tsend\t{:.2}\tMB/s", - params.version, - params.ciphersuite.suite(), - mfs_str, - total_mbs / time_send - ); - println!( - "bulk\t{:?}\t{:?}\t{}\trecv\t{:.2}\tMB/s", - params.version, - params.ciphersuite.suite(), - mfs_str, - total_mbs / time_recv - ); -} - -fn bench_memory(params: &BenchmarkParam, conn_count: u64) { - let client_config = Arc::new(make_client_config(params, ClientAuth::No, Resumption::No)); - let server_config = Arc::new(make_server_config( - params, - ClientAuth::No, - Resumption::No, - None, - )); - - // The target here is to end up with conn_count post-handshake - // server and client sessions. - let conn_count = (conn_count / 2) as usize; - let mut servers = Vec::with_capacity(conn_count); - let mut clients = Vec::with_capacity(conn_count); - - for _i in 0..conn_count { - servers.push(ServerConnection::new(Arc::clone(&server_config)).unwrap()); - let server_name = "localhost".try_into().unwrap(); - clients.push(ClientConnection::new(Arc::clone(&client_config), server_name).unwrap()); - } - - for _step in 0..5 { - for (client, server) in clients - .iter_mut() - .zip(servers.iter_mut()) - { - do_handshake_step(client, server); - } - } - - for client in clients.iter_mut() { - client - .writer() - .write_all(&[0u8; 1024]) - .unwrap(); - } - - for (client, server) in clients - .iter_mut() - .zip(servers.iter_mut()) - { - transfer(client, server, Some(1024)); - } -} - -fn lookup_matching_benches(name: &str) -> Vec<&BenchmarkParam> { - let r: Vec<&BenchmarkParam> = ALL_BENCHMARKS - .iter() - .filter(|params| { - format!("{:?}", params.ciphersuite.suite()).to_lowercase() == name.to_lowercase() - }) - .collect(); - - if r.is_empty() { - panic!("unknown suite {:?}", name); - } - - r -} - -fn selected_tests(mut args: env::Args) { - let mode = args - .next() - .expect("first argument must be mode"); - - match mode.as_ref() { - "bulk" => match args.next() { - Some(suite) => { - let len = args - .next() - .map(|arg| { - arg.parse::() - .expect("3rd arg must be plaintext size integer") - }) - .unwrap_or(1048576); - let mfs = args.next().map(|arg| { - arg.parse::() - .expect("4th arg must be max_fragment_size integer") - }); - for param in lookup_matching_benches(&suite).iter() { - bench_bulk(param, len, mfs); - } - } - None => { - panic!("bulk needs ciphersuite argument"); - } - }, - - "handshake" | "handshake-resume" | "handshake-ticket" => match args.next() { - Some(suite) => { - let resume = if mode == "handshake" { - Resumption::No - } else if mode == "handshake-resume" { - Resumption::SessionID - } else { - Resumption::Tickets - }; - - for param in lookup_matching_benches(&suite).iter() { - bench_handshake(param, ClientAuth::No, resume); - } - } - None => { - panic!("handshake* needs ciphersuite argument"); - } - }, - - "memory" => match args.next() { - Some(suite) => { - let count = args - .next() - .map(|arg| { - arg.parse::() - .expect("3rd arg must be connection count integer") - }) - .unwrap_or(1000000); - for param in lookup_matching_benches(&suite).iter() { - bench_memory(param, count); - } - } - None => { - panic!("memory needs ciphersuite argument"); - } - }, - - _ => { - panic!("unsupported mode {:?}", mode); - } - } -} - -fn all_tests() { - for test in ALL_BENCHMARKS.iter() { - bench_bulk(test, 1024 * 1024, None); - bench_bulk(test, 1024 * 1024, Some(10000)); - bench_handshake(test, ClientAuth::No, Resumption::No); - bench_handshake(test, ClientAuth::Yes, Resumption::No); - bench_handshake(test, ClientAuth::No, Resumption::SessionID); - bench_handshake(test, ClientAuth::Yes, Resumption::SessionID); - bench_handshake(test, ClientAuth::No, Resumption::Tickets); - bench_handshake(test, ClientAuth::Yes, Resumption::Tickets); - } -} - -fn main() { - let mut args = env::args(); - if args.len() > 1 { - args.next(); - selected_tests(args); - } else { - all_tests(); - } -} diff --git a/third_party/rustls-fork-shadow-tls/examples/internal/bogo_shim.rs b/third_party/rustls-fork-shadow-tls/examples/internal/bogo_shim.rs deleted file mode 100644 index 6e4de62..0000000 --- a/third_party/rustls-fork-shadow-tls/examples/internal/bogo_shim.rs +++ /dev/null @@ -1,1195 +0,0 @@ -// This is a test shim for the BoringSSL-Go ('bogo') TLS -// test suite. See bogo/ for this in action. -// -// https://boringssl.googlesource.com/boringssl/+/master/ssl/test -// - -use base64; -use env_logger; -use rustls; - -use rustls::internal::msgs::codec::{Codec, Reader}; -use rustls::internal::msgs::persist; -use rustls::quic::{self, ClientQuicExt, QuicExt, ServerQuicExt}; -use rustls::server::ClientHello; -use rustls::{CipherSuite, ProtocolVersion}; -use rustls::{ClientConnection, Connection, ServerConnection}; - -use std::convert::TryInto; -use std::env; -use std::fs; -use std::io; -use std::io::BufReader; -use std::io::{Read, Write}; -use std::net; -use std::process; -use std::sync::Arc; -use std::time::SystemTime; - -static BOGO_NACK: i32 = 89; - -macro_rules! println_err( - ($($arg:tt)*) => { { - writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap(); - } } -); - -#[derive(Debug)] -struct Options { - port: u16, - server: bool, - max_fragment: Option, - resumes: usize, - verify_peer: bool, - require_any_client_cert: bool, - offer_no_client_cas: bool, - tickets: bool, - resume_with_tickets_disabled: bool, - queue_data: bool, - queue_data_on_resume: bool, - only_write_one_byte_after_handshake: bool, - only_write_one_byte_after_handshake_on_resume: bool, - shut_down_after_handshake: bool, - check_close_notify: bool, - host_name: String, - use_sni: bool, - send_sct: bool, - key_file: String, - cert_file: String, - protocols: Vec, - support_tls13: bool, - support_tls12: bool, - min_version: Option, - max_version: Option, - server_ocsp_response: Vec, - server_sct_list: Vec, - use_signing_scheme: u16, - curves: Option>, - export_keying_material: usize, - export_keying_material_label: String, - export_keying_material_context: String, - export_keying_material_context_used: bool, - read_size: usize, - quic_transport_params: Vec, - expect_quic_transport_params: Vec, - enable_early_data: bool, - expect_ticket_supports_early_data: bool, - expect_accept_early_data: bool, - expect_reject_early_data: bool, - expect_version: u16, - resumption_delay: u32, -} - -impl Options { - fn new() -> Self { - Options { - port: 0, - server: false, - max_fragment: None, - resumes: 0, - verify_peer: false, - tickets: true, - resume_with_tickets_disabled: false, - host_name: "example.com".to_string(), - use_sni: false, - send_sct: false, - queue_data: false, - queue_data_on_resume: false, - only_write_one_byte_after_handshake: false, - only_write_one_byte_after_handshake_on_resume: false, - shut_down_after_handshake: false, - check_close_notify: false, - require_any_client_cert: false, - offer_no_client_cas: false, - key_file: "".to_string(), - cert_file: "".to_string(), - protocols: vec![], - support_tls13: true, - support_tls12: true, - min_version: None, - max_version: None, - server_ocsp_response: vec![], - server_sct_list: vec![], - use_signing_scheme: 0, - curves: None, - export_keying_material: 0, - export_keying_material_label: "".to_string(), - export_keying_material_context: "".to_string(), - export_keying_material_context_used: false, - read_size: 512, - quic_transport_params: vec![], - expect_quic_transport_params: vec![], - enable_early_data: false, - expect_ticket_supports_early_data: false, - expect_accept_early_data: false, - expect_reject_early_data: false, - expect_version: 0, - resumption_delay: 0, - } - } - - fn version_allowed(&self, vers: ProtocolVersion) -> bool { - (self.min_version.is_none() || vers.get_u16() >= self.min_version.unwrap().get_u16()) - && (self.max_version.is_none() || vers.get_u16() <= self.max_version.unwrap().get_u16()) - } - - fn tls13_supported(&self) -> bool { - self.support_tls13 && self.version_allowed(ProtocolVersion::TLSv1_3) - } - - fn tls12_supported(&self) -> bool { - self.support_tls12 && self.version_allowed(ProtocolVersion::TLSv1_2) - } - - fn supported_versions(&self) -> Vec<&'static rustls::SupportedProtocolVersion> { - let mut versions = vec![]; - - if self.tls12_supported() { - versions.push(&rustls::version::TLS12); - } - - if self.tls13_supported() { - versions.push(&rustls::version::TLS13); - } - versions - } -} - -fn load_cert(filename: &str) -> Vec { - let certfile = fs::File::open(filename).expect("cannot open certificate file"); - let mut reader = BufReader::new(certfile); - rustls_pemfile::certs(&mut reader) - .unwrap() - .iter() - .map(|v| rustls::Certificate(v.clone())) - .collect() -} - -fn load_key(filename: &str) -> rustls::PrivateKey { - let keyfile = fs::File::open(filename).expect("cannot open private key file"); - let mut reader = BufReader::new(keyfile); - let keys = rustls_pemfile::pkcs8_private_keys(&mut reader).unwrap(); - assert!(keys.len() == 1); - rustls::PrivateKey(keys[0].clone()) -} - -fn split_protocols(protos: &str) -> Vec { - let mut ret = Vec::new(); - - let mut offs = 0; - while offs < protos.len() { - let len = protos.as_bytes()[offs] as usize; - let item = protos[offs + 1..offs + 1 + len].to_string(); - ret.push(item); - offs += 1 + len; - } - - ret -} - -struct DummyClientAuth { - mandatory: bool, -} - -impl rustls::server::ClientCertVerifier for DummyClientAuth { - fn offer_client_auth(&self) -> bool { - true - } - - fn client_auth_mandatory(&self) -> Option { - Some(self.mandatory) - } - - fn client_auth_root_subjects(&self) -> Option { - Some(rustls::DistinguishedNames::new()) - } - - fn verify_client_cert( - &self, - _end_entity: &rustls::Certificate, - _intermediates: &[rustls::Certificate], - _now: SystemTime, - ) -> Result { - Ok(rustls::server::ClientCertVerified::assertion()) - } -} - -struct DummyServerAuth { - send_sct: bool, -} - -impl rustls::client::ServerCertVerifier for DummyServerAuth { - fn verify_server_cert( - &self, - _end_entity: &rustls::Certificate, - _certs: &[rustls::Certificate], - _hostname: &rustls::ServerName, - _scts: &mut dyn Iterator, - _ocsp: &[u8], - _now: SystemTime, - ) -> Result { - Ok(rustls::client::ServerCertVerified::assertion()) - } - - fn request_scts(&self) -> bool { - self.send_sct - } -} - -struct FixedSignatureSchemeSigningKey { - key: Arc, - scheme: rustls::SignatureScheme, -} - -impl rustls::sign::SigningKey for FixedSignatureSchemeSigningKey { - fn choose_scheme( - &self, - offered: &[rustls::SignatureScheme], - ) -> Option> { - if offered.contains(&self.scheme) { - self.key.choose_scheme(&[self.scheme]) - } else { - self.key.choose_scheme(&[]) - } - } - fn algorithm(&self) -> rustls::SignatureAlgorithm { - self.key.algorithm() - } -} - -struct FixedSignatureSchemeServerCertResolver { - resolver: Arc, - scheme: rustls::SignatureScheme, -} - -impl rustls::server::ResolvesServerCert for FixedSignatureSchemeServerCertResolver { - fn resolve(&self, client_hello: ClientHello) -> Option> { - let mut certkey = self.resolver.resolve(client_hello)?; - Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey { - key: certkey.key.clone(), - scheme: self.scheme, - }); - Some(certkey) - } -} - -struct FixedSignatureSchemeClientCertResolver { - resolver: Arc, - scheme: rustls::SignatureScheme, -} - -impl rustls::client::ResolvesClientCert for FixedSignatureSchemeClientCertResolver { - fn resolve( - &self, - acceptable_issuers: &[&[u8]], - sigschemes: &[rustls::SignatureScheme], - ) -> Option> { - if !sigschemes.contains(&self.scheme) { - quit(":NO_COMMON_SIGNATURE_ALGORITHMS:"); - } - let mut certkey = self - .resolver - .resolve(acceptable_issuers, sigschemes)?; - Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey { - key: certkey.key.clone(), - scheme: self.scheme, - }); - Some(certkey) - } - - fn has_certs(&self) -> bool { - self.resolver.has_certs() - } -} - -fn lookup_scheme(scheme: u16) -> rustls::SignatureScheme { - match scheme { - 0x0401 => rustls::SignatureScheme::RSA_PKCS1_SHA256, - 0x0501 => rustls::SignatureScheme::RSA_PKCS1_SHA384, - 0x0601 => rustls::SignatureScheme::RSA_PKCS1_SHA512, - 0x0403 => rustls::SignatureScheme::ECDSA_NISTP256_SHA256, - 0x0503 => rustls::SignatureScheme::ECDSA_NISTP384_SHA384, - 0x0804 => rustls::SignatureScheme::RSA_PSS_SHA256, - 0x0805 => rustls::SignatureScheme::RSA_PSS_SHA384, - 0x0806 => rustls::SignatureScheme::RSA_PSS_SHA512, - 0x0807 => rustls::SignatureScheme::ED25519, - // TODO: add support for Ed448 - // 0x0808 => rustls::SignatureScheme::ED448, - _ => { - println_err!("Unsupported signature scheme {:04x}", scheme); - process::exit(BOGO_NACK); - } - } -} - -fn lookup_kx_group(group: u16) -> &'static rustls::SupportedKxGroup { - match group { - 0x001d => &rustls::kx_group::X25519, - 0x0017 => &rustls::kx_group::SECP256R1, - 0x0018 => &rustls::kx_group::SECP384R1, - _ => { - println_err!("Unsupported kx group {:04x}", group); - process::exit(BOGO_NACK); - } - } -} - -struct ServerCacheWithResumptionDelay { - delay: u32, - storage: Arc, -} - -impl ServerCacheWithResumptionDelay { - fn new(delay: u32) -> Arc { - Arc::new(Self { - delay, - storage: rustls::server::ServerSessionMemoryCache::new(32), - }) - } -} - -fn align_time() { - /* we don't have an injectable clock source in rustls' public api, and - * resumption timing is in seconds resolution, so tests that use - * resumption_delay tend to be flickery if the seconds time ticks - * during this. - * - * this function delays until a fresh second ticks, which alleviates - * this. gross! - */ - use std::{thread, time}; - - fn sample() -> u64 { - time::SystemTime::now() - .duration_since(time::SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs() - } - - let start_secs = sample(); - while start_secs == sample() { - thread::sleep(time::Duration::from_millis(20)); - } -} - -impl rustls::server::StoresServerSessions for ServerCacheWithResumptionDelay { - fn put(&self, key: Vec, value: Vec) -> bool { - let mut ssv = persist::ServerSessionValue::read_bytes(&value).unwrap(); - ssv.creation_time_sec -= self.delay as u64; - - self.storage - .put(key, ssv.get_encoding()) - } - - fn get(&self, key: &[u8]) -> Option> { - self.storage.get(key) - } - - fn take(&self, key: &[u8]) -> Option> { - self.storage.take(key) - } - - fn can_cache(&self) -> bool { - self.storage.can_cache() - } -} - -fn make_server_cfg(opts: &Options) -> Arc { - let client_auth = - if opts.verify_peer || opts.offer_no_client_cas || opts.require_any_client_cert { - Arc::new(DummyClientAuth { - mandatory: opts.require_any_client_cert, - }) - } else { - rustls::server::NoClientAuth::new() - }; - - let cert = load_cert(&opts.cert_file); - let key = load_key(&opts.key_file); - - let kx_groups = if let Some(curves) = &opts.curves { - curves - .iter() - .map(|curveid| lookup_kx_group(*curveid)) - .collect() - } else { - rustls::ALL_KX_GROUPS.to_vec() - }; - - let mut cfg = rustls::ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(&kx_groups) - .with_protocol_versions(&opts.supported_versions()) - .unwrap() - .with_client_cert_verifier(client_auth) - .with_single_cert_with_ocsp_and_sct( - cert.clone(), - key, - opts.server_ocsp_response.clone(), - opts.server_sct_list.clone(), - ) - .unwrap(); - - cfg.session_storage = ServerCacheWithResumptionDelay::new(opts.resumption_delay); - cfg.max_fragment_size = opts.max_fragment; - - if opts.use_signing_scheme > 0 { - let scheme = lookup_scheme(opts.use_signing_scheme); - cfg.cert_resolver = Arc::new(FixedSignatureSchemeServerCertResolver { - resolver: cfg.cert_resolver.clone(), - scheme, - }); - } - - if opts.tickets { - cfg.ticketer = rustls::Ticketer::new().unwrap(); - } else if opts.resumes == 0 { - cfg.session_storage = Arc::new(rustls::server::NoServerSessionStorage {}); - } - - if !opts.protocols.is_empty() { - cfg.alpn_protocols = opts - .protocols - .iter() - .map(|proto| proto.as_bytes().to_vec()) - .collect::>(); - } - - if opts.enable_early_data { - // see kMaxEarlyDataAccepted in boringssl, which bogo validates - cfg.max_early_data_size = 14336; - cfg.send_half_rtt_data = true; - } - - Arc::new(cfg) -} - -struct ClientCacheWithoutKxHints { - delay: u32, - storage: Arc, -} - -impl ClientCacheWithoutKxHints { - fn new(delay: u32) -> Arc { - Arc::new(ClientCacheWithoutKxHints { - delay, - storage: rustls::client::ClientSessionMemoryCache::new(32), - }) - } -} - -impl rustls::client::StoresClientSessions for ClientCacheWithoutKxHints { - fn put(&self, key: Vec, value: Vec) -> bool { - if key.len() > 2 && key[0] == b'k' && key[1] == b'x' { - return true; - } - - let mut reader = Reader::init(&value[2..]); - let csv = CipherSuite::read_bytes(&value[..2]) - .and_then(|suite| { - persist::ClientSessionValue::read(&mut reader, suite, &rustls::ALL_CIPHER_SUITES) - }) - .unwrap(); - - let value = match csv { - persist::ClientSessionValue::Tls13(mut tls13) => { - tls13.common.rewind_epoch(self.delay); - tls13.get_encoding() - } - persist::ClientSessionValue::Tls12(mut tls12) => { - tls12.common.rewind_epoch(self.delay); - tls12.get_encoding() - } - }; - - self.storage.put(key, value) - } - - fn get(&self, key: &[u8]) -> Option> { - self.storage.get(key) - } -} - -fn make_client_cfg(opts: &Options) -> Arc { - let kx_groups = if let Some(curves) = &opts.curves { - curves - .iter() - .map(|curveid| lookup_kx_group(*curveid)) - .collect() - } else { - rustls::ALL_KX_GROUPS.to_vec() - }; - - let cfg = rustls::ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(&kx_groups) - .with_protocol_versions(&opts.supported_versions()) - .expect("inconsistent settings") - .with_custom_certificate_verifier(Arc::new(DummyServerAuth { - send_sct: opts.send_sct, - })); - - let mut cfg = if !opts.cert_file.is_empty() && !opts.key_file.is_empty() { - let cert = load_cert(&opts.cert_file); - let key = load_key(&opts.key_file); - cfg.with_single_cert(cert, key).unwrap() - } else { - cfg.with_no_client_auth() - }; - - if !opts.cert_file.is_empty() && opts.use_signing_scheme > 0 { - let scheme = lookup_scheme(opts.use_signing_scheme); - cfg.client_auth_cert_resolver = Arc::new(FixedSignatureSchemeClientCertResolver { - resolver: cfg.client_auth_cert_resolver.clone(), - scheme, - }); - } - - let persist = ClientCacheWithoutKxHints::new(opts.resumption_delay); - cfg.session_storage = persist; - cfg.enable_sni = opts.use_sni; - cfg.max_fragment_size = opts.max_fragment; - - if !opts.protocols.is_empty() { - cfg.alpn_protocols = opts - .protocols - .iter() - .map(|proto| proto.as_bytes().to_vec()) - .collect(); - } - - if opts.enable_early_data { - cfg.enable_early_data = true; - } - - Arc::new(cfg) -} - -fn quit(why: &str) -> ! { - println_err!("{}", why); - process::exit(0) -} - -fn quit_err(why: &str) -> ! { - println_err!("{}", why); - process::exit(1) -} - -fn handle_err(err: rustls::Error) -> ! { - use rustls::Error; - use rustls::{AlertDescription, ContentType}; - use std::{thread, time}; - - println!("TLS error: {:?}", err); - thread::sleep(time::Duration::from_millis(100)); - - match err { - Error::InappropriateHandshakeMessage { .. } | Error::InappropriateMessage { .. } => { - quit(":UNEXPECTED_MESSAGE:") - } - Error::AlertReceived(AlertDescription::RecordOverflow) => { - quit(":TLSV1_ALERT_RECORD_OVERFLOW:") - } - Error::AlertReceived(AlertDescription::HandshakeFailure) => quit(":HANDSHAKE_FAILURE:"), - Error::AlertReceived(AlertDescription::ProtocolVersion) => quit(":WRONG_VERSION:"), - Error::AlertReceived(AlertDescription::InternalError) => { - quit(":PEER_ALERT_INTERNAL_ERROR:") - } - Error::CorruptMessagePayload(ContentType::Alert) => quit(":BAD_ALERT:"), - Error::CorruptMessagePayload(ContentType::ChangeCipherSpec) => { - quit(":BAD_CHANGE_CIPHER_SPEC:") - } - Error::CorruptMessagePayload(ContentType::Handshake) => quit(":BAD_HANDSHAKE_MSG:"), - Error::CorruptMessagePayload(ContentType::Unknown(42)) => quit(":GARBAGE:"), - Error::CorruptMessage => quit(":GARBAGE:"), - Error::DecryptError => quit(":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"), - Error::PeerIncompatibleError(_) => quit(":INCOMPATIBLE:"), - Error::PeerMisbehavedError(s) if s == "too much early_data received" => { - quit(":TOO_MUCH_READ_EARLY_DATA:") - } - Error::PeerMisbehavedError(_) => quit(":PEER_MISBEHAVIOUR:"), - Error::NoCertificatesPresented => quit(":NO_CERTS:"), - Error::AlertReceived(AlertDescription::UnexpectedMessage) => quit(":BAD_ALERT:"), - Error::AlertReceived(AlertDescription::DecompressionFailure) => { - quit_err(":SSLV3_ALERT_DECOMPRESSION_FAILURE:") - } - Error::InvalidCertificateEncoding => quit(":CANNOT_PARSE_LEAF_CERT:"), - Error::InvalidCertificateSignature => quit(":BAD_SIGNATURE:"), - Error::InvalidCertificateSignatureType => quit(":WRONG_SIGNATURE_TYPE:"), - Error::PeerSentOversizedRecord => quit(":DATA_LENGTH_TOO_LONG:"), - _ => { - println_err!("unhandled error: {:?}", err); - quit(":FIXME:") - } - } -} - -fn flush(sess: &mut Connection, conn: &mut net::TcpStream) { - while sess.wants_write() { - match sess.write_tls(conn) { - Err(err) => { - println!("IO error: {:?}", err); - process::exit(0); - } - Ok(_) => {} - } - } - conn.flush().unwrap(); -} - -fn client(conn: &mut Connection) -> &mut ClientConnection { - conn.try_into().unwrap() -} - -fn server(conn: &mut Connection) -> &mut ServerConnection { - match conn { - Connection::Server(s) => s, - _ => panic!("Connection is not a ServerConnection"), - } -} - -fn exec(opts: &Options, mut sess: Connection, count: usize) { - let mut sent_message = false; - - if opts.queue_data || (opts.queue_data_on_resume && count > 0) { - if count > 0 && opts.enable_early_data { - let len = client(&mut sess) - .early_data() - .expect("0rtt not available") - .write(b"hello") - .expect("0rtt write failed"); - sess.writer() - .write_all(&b"hello"[len..]) - .unwrap(); - sent_message = true; - } else if !opts.only_write_one_byte_after_handshake { - let _ = sess.writer().write_all(b"hello"); - sent_message = true; - } - } - - let addrs = [ - net::SocketAddr::from((net::Ipv6Addr::LOCALHOST, opts.port)), - net::SocketAddr::from((net::Ipv4Addr::LOCALHOST, opts.port)), - ]; - let mut conn = net::TcpStream::connect(&addrs[..]).expect("cannot connect"); - let mut sent_shutdown = false; - let mut sent_exporter = false; - let mut quench_writes = false; - - loop { - if !quench_writes { - flush(&mut sess, &mut conn); - } - - if sess.wants_read() { - match sess.read_tls(&mut conn) { - Ok(_) => {} - Err(ref err) if err.kind() == io::ErrorKind::ConnectionReset => {} - Err(err) => panic!("invalid read: {}", err), - }; - - if let Err(err) = sess.process_new_packets() { - flush(&mut sess, &mut conn); /* send any alerts before exiting */ - handle_err(err); - } - } - - if opts.server && opts.enable_early_data { - if let Some(ref mut ed) = server(&mut sess).early_data() { - let mut data = Vec::new(); - let data_len = ed - .read_to_end(&mut data) - .expect("cannot read early_data"); - - for b in data.iter_mut() { - *b ^= 0xff; - } - - sess.writer() - .write_all(&data[..data_len]) - .expect("cannot echo early_data in 1rtt data"); - } - } - - if !sess.is_handshaking() && opts.export_keying_material > 0 && !sent_exporter { - let mut export = Vec::new(); - export.resize(opts.export_keying_material, 0u8); - sess.export_keying_material( - &mut export, - opts.export_keying_material_label - .as_bytes(), - if opts.export_keying_material_context_used { - Some( - opts.export_keying_material_context - .as_bytes(), - ) - } else { - None - }, - ) - .unwrap(); - sess.writer() - .write_all(&export) - .unwrap(); - sent_exporter = true; - } - - if !sess.is_handshaking() && opts.only_write_one_byte_after_handshake && !sent_message { - println!("writing message and then only one byte of its tls frame"); - flush(&mut sess, &mut conn); - - sess.writer() - .write_all(b"hello") - .unwrap(); - sent_message = true; - - let mut one_byte = [0u8]; - let mut cursor = io::Cursor::new(&mut one_byte[..]); - sess.write_tls(&mut cursor).unwrap(); - conn.write(&one_byte).expect("IO error"); - - quench_writes = true; - } - - if opts.enable_early_data && !opts.server && !sess.is_handshaking() && count > 0 { - if opts.expect_accept_early_data && !client(&mut sess).is_early_data_accepted() { - quit_err("Early data was not accepted, but we expect the opposite"); - } else if opts.expect_reject_early_data && client(&mut sess).is_early_data_accepted() { - quit_err("Early data was accepted, but we expect the opposite"); - } - if opts.expect_version == 0x0304 { - match sess.protocol_version() { - Some(ProtocolVersion::TLSv1_3) | Some(ProtocolVersion::Unknown(0x7f17)) => {} - _ => quit_err("wrong protocol version"), - } - } - } - - if !sess.is_handshaking() - && !opts - .expect_quic_transport_params - .is_empty() - { - let their_transport_params = sess - .quic_transport_parameters() - .expect("missing peer quic transport params"); - assert_eq!(opts.expect_quic_transport_params, their_transport_params); - } - - let mut buf = [0u8; 1024]; - let len = match sess - .reader() - .read(&mut buf[..opts.read_size]) - { - Ok(0) => { - if opts.check_close_notify { - println!("close notify ok"); - } - println!("EOF (tls)"); - return; - } - Ok(len) => len, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => 0, - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { - if opts.check_close_notify { - quit_err(":CLOSE_WITHOUT_CLOSE_NOTIFY:"); - } - println!("EOF (tcp)"); - return; - } - Err(err) => panic!("unhandled read error {:?}", err), - }; - - if opts.shut_down_after_handshake && !sent_shutdown && !sess.is_handshaking() { - sess.send_close_notify(); - sent_shutdown = true; - } - - if quench_writes && len > 0 { - println!("unquenching writes after {:?}", len); - quench_writes = false; - } - - for b in buf.iter_mut() { - *b ^= 0xff; - } - - sess.writer() - .write_all(&buf[..len]) - .unwrap(); - } -} - -fn main() { - let mut args: Vec<_> = env::args().collect(); - env_logger::init(); - - args.remove(0); - - if !args.is_empty() && args[0] == "-is-handshaker-supported" { - println!("No"); - process::exit(0); - } - println!("options: {:?}", args); - - let mut opts = Options::new(); - - while !args.is_empty() { - let arg = args.remove(0); - match arg.as_ref() { - "-port" => { - opts.port = args.remove(0).parse::().unwrap(); - } - "-server" => { - opts.server = true; - } - "-key-file" => { - opts.key_file = args.remove(0); - } - "-cert-file" => { - opts.cert_file = args.remove(0); - } - "-resume-count" => { - opts.resumes = args.remove(0).parse::().unwrap(); - } - "-no-tls13" => { - opts.support_tls13 = false; - } - "-no-tls12" => { - opts.support_tls12 = false; - } - "-min-version" => { - let min = args.remove(0).parse::().unwrap(); - opts.min_version = Some(ProtocolVersion::Unknown(min)); - } - "-max-version" => { - let max = args.remove(0).parse::().unwrap(); - opts.max_version = Some(ProtocolVersion::Unknown(max)); - } - "-max-send-fragment" => { - let max_fragment = args.remove(0).parse::().unwrap(); - opts.max_fragment = Some(max_fragment + 5); // ours includes header - } - "-read-size" => { - let rdsz = args.remove(0).parse::().unwrap(); - opts.read_size = rdsz; - } - "-tls13-variant" => { - let variant = args.remove(0).parse::().unwrap(); - if variant != 1 { - println!("NYI TLS1.3 variant selection: {:?} {:?}", arg, variant); - process::exit(BOGO_NACK); - } - } - "-no-ticket" => { - opts.tickets = false; - } - "-on-resume-no-ticket" => { - opts.resume_with_tickets_disabled = true; - } - "-signing-prefs" => { - let alg = args.remove(0).parse::().unwrap(); - opts.use_signing_scheme = alg; - } - "-max-cert-list" | - "-expect-curve-id" | - "-expect-resume-curve-id" | - "-expect-peer-signature-algorithm" | - "-expect-peer-verify-pref" | - "-expect-advertised-alpn" | - "-expect-alpn" | - "-on-initial-expect-alpn" | - "-on-resume-expect-alpn" | - "-on-retry-expect-alpn" | - "-expect-server-name" | - "-expect-ocsp-response" | - "-expect-signed-cert-timestamps" | - "-expect-certificate-types" | - "-expect-client-ca-list" | - "-on-retry-expect-early-data-reason" | - "-on-resume-expect-early-data-reason" | - "-on-initial-expect-early-data-reason" | - "-on-initial-expect-cipher" | - "-on-resume-expect-cipher" | - "-on-retry-expect-cipher" | - "-expect-ticket-age-skew" | - "-handshaker-path" | - "-application-settings" | - "-expect-msg-callback" => { - println!("not checking {} {}; NYI", arg, args.remove(0)); - } - - "-expect-secure-renegotiation" | - "-expect-no-session-id" | - "-enable-ed25519" | - "-expect-hrr" | - "-expect-no-hrr" | - "-on-resume-expect-no-offer-early-data" | - "-key-update" | //< we could implement an API for this - "-expect-tls13-downgrade" | - "-expect-session-id" => { - println!("not checking {}; NYI", arg); - } - - "-export-keying-material" => { - opts.export_keying_material = args.remove(0).parse::().unwrap(); - } - "-export-label" => { - opts.export_keying_material_label = args.remove(0); - } - "-export-context" => { - opts.export_keying_material_context = args.remove(0); - } - "-use-export-context" => { - opts.export_keying_material_context_used = true; - } - "-quic-transport-params" => { - opts.quic_transport_params = base64::decode(args.remove(0).as_bytes()) - .expect("invalid base64"); - } - "-expect-quic-transport-params" => { - opts.expect_quic_transport_params = base64::decode(args.remove(0).as_bytes()) - .expect("invalid base64"); - } - - "-ocsp-response" => { - opts.server_ocsp_response = base64::decode(args.remove(0).as_bytes()) - .expect("invalid base64"); - } - "-signed-cert-timestamps" => { - opts.server_sct_list = base64::decode(args.remove(0).as_bytes()) - .expect("invalid base64"); - - if opts.server_sct_list.len() == 2 && - opts.server_sct_list[0] == 0x00 && - opts.server_sct_list[1] == 0x00 { - quit(":INVALID_SCT_LIST:"); - } - } - "-select-alpn" => { - opts.protocols.push(args.remove(0)); - } - "-require-any-client-certificate" => { - opts.require_any_client_cert = true; - } - "-verify-peer" => { - opts.verify_peer = true; - } - "-shim-writes-first" => { - opts.queue_data = true; - } - "-read-with-unfinished-write" => { - opts.queue_data = true; - opts.only_write_one_byte_after_handshake = true; - } - "-shim-shuts-down" => { - opts.shut_down_after_handshake = true; - } - "-check-close-notify" => { - opts.check_close_notify = true; - } - "-host-name" => { - opts.host_name = args.remove(0); - opts.use_sni = true; - } - "-advertise-alpn" => { - opts.protocols = split_protocols(&args.remove(0)); - } - "-use-null-client-ca-list" => { - opts.offer_no_client_cas = true; - } - "-enable-signed-cert-timestamps" => { - opts.send_sct = true; - } - "-enable-early-data" => { - opts.tickets = false; - opts.enable_early_data = true; - } - "-on-resume-shim-writes-first" => { - opts.queue_data_on_resume = true; - } - "-on-resume-read-with-unfinished-write" => { - opts.queue_data_on_resume = true; - opts.only_write_one_byte_after_handshake_on_resume = true; - } - "-expect-ticket-supports-early-data" => { - opts.expect_ticket_supports_early_data = true; - } - "-expect-accept-early-data" | - "-on-resume-expect-accept-early-data" => { - opts.expect_accept_early_data = true; - } - "-expect-early-data-reason" | - "-on-resume-expect-reject-early-data-reason" => { - let reason = args.remove(0); - match reason.as_str() { - "disabled" | "protocol_version" => { - opts.expect_reject_early_data = true; - } - _ => { - println!("NYI early data reason: {}", reason); - process::exit(1); - } - } - } - "-expect-reject-early-data" | - "-on-resume-expect-reject-early-data" => { - opts.expect_reject_early_data = true; - } - "-expect-version" => { - opts.expect_version = args.remove(0).parse::().unwrap(); - } - "-curves" => { - let curve = args.remove(0).parse::().unwrap(); - if let Some(mut curves) = opts.curves.take() { - curves.push(curve); - } else { - opts.curves = Some(vec![ curve ]); - } - } - "-resumption-delay" => { - opts.resumption_delay = args.remove(0).parse::().unwrap(); - align_time(); - } - - // defaults: - "-enable-all-curves" | - "-renegotiate-ignore" | - "-no-tls11" | - "-no-tls1" | - "-no-ssl3" | - "-handoff" | - "-decline-alpn" | - "-expect-no-session" | - "-expect-session-miss" | - "-expect-extended-master-secret" | - "-expect-ticket-renewal" | - "-enable-ocsp-stapling" | - // internal openssl details: - "-async" | - "-implicit-handshake" | - "-use-old-client-cert-callback" | - "-use-early-callback" => {} - - // Not implemented things - "-dtls" | - "-cipher" | - "-psk" | - "-renegotiate-freely" | - "-false-start" | - "-fallback-scsv" | - "-fail-early-callback" | - "-fail-cert-callback" | - "-install-ddos-callback" | - "-advertise-npn" | - "-verify-fail" | - "-expect-channel-id" | - "-send-channel-id" | - "-select-next-proto" | - "-expect-verify-result" | - "-send-alert" | - "-digest-prefs" | - "-use-exporter-between-reads" | - "-ticket-key" | - "-tls-unique" | - "-enable-server-custom-extension" | - "-enable-client-custom-extension" | - "-expect-dhe-group-size" | - "-use-ticket-callback" | - "-enable-grease" | - "-enable-channel-id" | - "-expect-early-data-info" | - "-expect-cipher-aes" | - "-retain-only-sha256-client-cert-initial" | - "-use-client-ca-list" | - "-expect-draft-downgrade" | - "-allow-unknown-alpn-protos" | - "-on-initial-tls13-variant" | - "-on-initial-expect-curve-id" | - "-on-resume-export-early-keying-material" | - "-on-resume-enable-early-data" | - "-export-early-keying-material" | - "-handshake-twice" | - "-on-resume-verify-fail" | - "-reverify-on-resume" | - "-verify-prefs" | - "-no-op-extra-handshake" | - "-expect-peer-cert-file" | - "-no-rsa-pss-rsae-certs" | - "-ignore-tls13-downgrade" | - "-on-initial-expect-peer-cert-file" => { - println!("NYI option {:?}", arg); - process::exit(BOGO_NACK); - } - - _ => { - println!("unhandled option {:?}", arg); - process::exit(1); - } - } - } - - println!("opts {:?}", opts); - - let mut server_cfg = if opts.server { - Some(make_server_cfg(&opts)) - } else { - None - }; - let client_cfg = if !opts.server { - Some(make_client_cfg(&opts)) - } else { - None - }; - - fn make_session( - opts: &Options, - scfg: &Option>, - ccfg: &Option>, - ) -> Connection { - if opts.server { - let scfg = Arc::clone(scfg.as_ref().unwrap()); - let s = if opts.quic_transport_params.is_empty() { - rustls::ServerConnection::new(scfg).unwrap() - } else { - rustls::ServerConnection::new_quic( - scfg, - quic::Version::V1, - opts.quic_transport_params.clone(), - ) - .unwrap() - }; - s.into() - } else { - let server_name = opts - .host_name - .as_str() - .try_into() - .unwrap(); - let ccfg = Arc::clone(ccfg.as_ref().unwrap()); - let c = if opts.quic_transport_params.is_empty() { - rustls::ClientConnection::new(ccfg, server_name) - } else { - rustls::ClientConnection::new_quic( - ccfg, - quic::Version::V1, - server_name, - opts.quic_transport_params.clone(), - ) - } - .unwrap(); - c.into() - } - } - - for i in 0..opts.resumes + 1 { - let sess = make_session(&opts, &server_cfg, &client_cfg); - exec(&opts, sess, i); - - if opts.resume_with_tickets_disabled { - opts.tickets = false; - server_cfg = Some(make_server_cfg(&opts)); - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/examples/internal/trytls_shim.rs b/third_party/rustls-fork-shadow-tls/examples/internal/trytls_shim.rs deleted file mode 100644 index f47bbd0..0000000 --- a/third_party/rustls-fork-shadow-tls/examples/internal/trytls_shim.rs +++ /dev/null @@ -1,120 +0,0 @@ -// A Rustls stub for TryTLS -// -// Author: Joachim Viide -// See: https://github.com/HowNetWorks/trytls-rustls-stub -// - -use rustls::{ClientConfig, ClientConnection, Error, OwnedTrustAnchor, RootCertStore}; -use std::convert::TryInto; -use std::env; -use std::error::Error as StdError; -use std::fs::File; -use std::io::{BufReader, Read, Write}; -use std::net::TcpStream; -use std::process; -use std::sync::Arc; - -enum Verdict { - Accept, - Reject(Error), -} - -fn parse_args(args: &[String]) -> Result<(String, u16, ClientConfig), Box> { - let mut root_store = RootCertStore::empty(); - match args.len() { - 3 => { - root_store.add_server_trust_anchors( - webpki_roots::TLS_SERVER_ROOTS - .0 - .iter() - .map(|ta| { - OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ) - }), - ); - } - 4 => { - let f = File::open(&args[3])?; - root_store - .add_parsable_certificates(&rustls_pemfile::certs(&mut BufReader::new(f)).unwrap()); - } - _ => { - return Err(From::from("Incorrect number of arguments")); - } - }; - let config = rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(root_store) - .with_no_client_auth(); - - let port = args[2].parse()?; - Ok((args[1].clone(), port, config)) -} - -fn communicate( - host: String, - port: u16, - config: ClientConfig, -) -> Result> { - let server_name = host.as_str().try_into().unwrap(); - let rc_config = Arc::new(config); - let mut client = ClientConnection::new(rc_config, server_name).unwrap(); - let mut stream = TcpStream::connect((&*host, port))?; - - client - .writer() - .write_all(b"GET / HTTP/1.0\r\nConnection: close\r\nContent-Length: 0\r\n\r\n")?; - loop { - while client.wants_write() { - client.write_tls(&mut stream)?; - } - - if client.wants_read() { - if client.read_tls(&mut stream)? == 0 { - return Err(From::from("Connection closed")); - } - - if let Err(err) = client.process_new_packets() { - return match err { - Error::InvalidCertificateData(_) - | Error::InvalidCertificateSignature - | Error::InvalidCertificateSignatureType - | Error::InvalidCertificateEncoding - | Error::AlertReceived(_) => Ok(Verdict::Reject(err)), - _ => Err(From::from(format!("{:?}", err))), - }; - } - - if client.reader().read(&mut [0])? > 0 { - return Ok(Verdict::Accept); - } - } - } -} - -fn main() { - let args: Vec = env::args().collect(); - let (host, port, config) = parse_args(&args).unwrap_or_else(|err| { - println!("Argument error: {}", err); - process::exit(2); - }); - - match communicate(host, port, config) { - Ok(Verdict::Accept) => { - println!("ACCEPT"); - process::exit(0); - } - Ok(Verdict::Reject(reason)) => { - println!("{:?}", reason); - println!("REJECT"); - process::exit(0); - } - Err(err) => { - println!("{}", err); - process::exit(1); - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/anchors.rs b/third_party/rustls-fork-shadow-tls/src/anchors.rs deleted file mode 100644 index 4caf3e7..0000000 --- a/third_party/rustls-fork-shadow-tls/src/anchors.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::key; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::handshake::{DistinguishedName, DistinguishedNames}; -use crate::x509; - -/// A trust anchor, commonly known as a "Root Certificate." -#[derive(Debug, Clone)] -pub struct OwnedTrustAnchor { - subject: Vec, - spki: Vec, - name_constraints: Option>, -} - -impl OwnedTrustAnchor { - /// Get a `webpki::TrustAnchor` by borrowing the owned elements. - pub(crate) fn to_trust_anchor(&self) -> webpki::TrustAnchor { - webpki::TrustAnchor { - subject: &self.subject, - spki: &self.spki, - name_constraints: self.name_constraints.as_deref(), - } - } - - /// Constructs an `OwnedTrustAnchor` from its components. - /// - /// All inputs are DER-encoded. - /// - /// `subject` is the [Subject] field of the trust anchor. - /// - /// `spki` is the [SubjectPublicKeyInfo] field of the trust anchor. - /// - /// `name_constraints` is the [Name Constraints] to - /// apply for this trust anchor, if any. - /// - /// [Subject]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - /// [SubjectPublicKeyInfo]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7 - /// [Name Constraints]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 - pub fn from_subject_spki_name_constraints( - subject: impl Into>, - spki: impl Into>, - name_constraints: Option>>, - ) -> Self { - Self { - subject: subject.into(), - spki: spki.into(), - name_constraints: name_constraints.map(|x| x.into()), - } - } - - /// Return the subject field. - /// - /// This can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/traits/trait.FromDer.html). - /// - /// ```ignore - /// use x509_parser::traits::FromDer; - /// println!("{}", x509_parser::x509::X509Name::from_der(anchor.subject())?.1); - /// ``` - pub fn subject(&self) -> &[u8] { - &self.subject - } -} - -/// A container for root certificates able to provide a root-of-trust -/// for connection authentication. -#[derive(Debug, Clone)] -pub struct RootCertStore { - /// The list of roots. - pub roots: Vec, -} - -impl RootCertStore { - /// Make a new, empty `RootCertStore`. - pub fn empty() -> Self { - Self { roots: Vec::new() } - } - - /// Return true if there are no certificates. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Say how many certificates are in the container. - pub fn len(&self) -> usize { - self.roots.len() - } - - /// Return the Subject Names for certificates in the container. - #[deprecated(since = "0.20.7", note = "Use OwnedTrustAnchor::subject() instead")] - pub fn subjects(&self) -> DistinguishedNames { - let mut r = DistinguishedNames::new(); - - for ota in &self.roots { - let mut name = Vec::new(); - name.extend_from_slice(&ota.subject); - x509::wrap_in_sequence(&mut name); - r.push(DistinguishedName::new(name)); - } - - r - } - - /// Add a single DER-encoded certificate to the store. - pub fn add(&mut self, der: &key::Certificate) -> Result<(), webpki::Error> { - let ta = webpki::TrustAnchor::try_from_cert_der(&der.0)?; - let ota = OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ); - self.roots.push(ota); - Ok(()) - } - - /// Adds all the given TrustAnchors `anchors`. This does not - /// fail. - pub fn add_server_trust_anchors( - &mut self, - trust_anchors: impl Iterator, - ) { - self.roots.extend(trust_anchors) - } - - /// Parse the given DER-encoded certificates and add all that can be parsed - /// in a best-effort fashion. - /// - /// This is because large collections of root certificates often - /// include ancient or syntactically invalid certificates. - /// - /// Returns the number of certificates added, and the number that were ignored. - pub fn add_parsable_certificates(&mut self, der_certs: &[Vec]) -> (usize, usize) { - let mut valid_count = 0; - let mut invalid_count = 0; - - for der_cert in der_certs { - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - match self.add(&key::Certificate(der_cert.clone())) { - Ok(_) => valid_count += 1, - Err(err) => { - trace!("invalid cert der {:?}", der_cert); - debug!("certificate parsing failed: {:?}", err); - invalid_count += 1 - } - } - } - - debug!( - "add_parsable_certificates processed {} valid and {} invalid certs", - valid_count, invalid_count - ); - - (valid_count, invalid_count) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/bs_debug.rs b/third_party/rustls-fork-shadow-tls/src/bs_debug.rs deleted file mode 100644 index ad73ee6..0000000 --- a/third_party/rustls-fork-shadow-tls/src/bs_debug.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::fmt; - -/// Alternative implementation of `fmt::Debug` for byte slice. -/// -/// Standard `Debug` implementation for `[u8]` is comma separated -/// list of numbers. Since large amount of byte strings are in fact -/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP), -/// it is convenient to print strings as ASCII when possible. -/// -/// This struct wraps `&[u8]` just to override `fmt::Debug`. -/// -/// `BsDebug` is not a part of public API of bytes crate. -pub(crate) struct BsDebug<'a>(pub(crate) &'a [u8]); - -impl<'a> fmt::Debug for BsDebug<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(fmt, "b\"")?; - for &c in self.0 { - // https://doc.rust-lang.org/reference.html#byte-escapes - if c == b'\n' { - write!(fmt, "\\n")?; - } else if c == b'\r' { - write!(fmt, "\\r")?; - } else if c == b'\t' { - write!(fmt, "\\t")?; - } else if c == b'\\' || c == b'"' { - write!(fmt, "\\{}", c as char)?; - } else if c == b'\0' { - write!(fmt, "\\0")?; - // ASCII printable - } else if (0x20..0x7f).contains(&c) { - write!(fmt, "{}", c as char)?; - } else { - write!(fmt, "\\x{:02x}", c)?; - } - } - write!(fmt, "\"")?; - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::BsDebug; - - #[test] - fn debug() { - let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect(); - - let expected = "b\"\ - \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\ - \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\ - \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\ - \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\ - \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\ - @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\ - `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ - \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\ - \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ - \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\ - \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ - \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\ - \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ - \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\ - \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ - \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\ - \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ - \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\ - \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ - \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\ - \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ - \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\ - \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\""; - - assert_eq!(expected, format!("{:?}", BsDebug(&vec))); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/builder.rs b/third_party/rustls-fork-shadow-tls/src/builder.rs deleted file mode 100644 index 8b63f8c..0000000 --- a/third_party/rustls-fork-shadow-tls/src/builder.rs +++ /dev/null @@ -1,268 +0,0 @@ -use crate::error::Error; -use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS}; -use crate::suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES}; -use crate::versions; - -use std::fmt; -use std::marker::PhantomData; - -/// Building a [`ServerConfig`] or [`ClientConfig`] in a linker-friendly and -/// complete way. -/// -/// Linker-friendly: meaning unused cipher suites, protocol -/// versions, key exchange mechanisms, etc. can be discarded -/// by the linker as they'll be unreferenced. -/// -/// Complete: the type system ensures all decisions required to run a -/// server or client have been made by the time the process finishes. -/// -/// Example, to make a [`ServerConfig`]: -/// -/// ```no_run -/// # use rustls::ServerConfig; -/// # let certs = vec![]; -/// # let private_key = rustls::PrivateKey(vec![]); -/// ServerConfig::builder() -/// .with_safe_default_cipher_suites() -/// .with_safe_default_kx_groups() -/// .with_safe_default_protocol_versions() -/// .unwrap() -/// .with_no_client_auth() -/// .with_single_cert(certs, private_key) -/// .expect("bad certificate/key"); -/// ``` -/// -/// This may be shortened to: -/// -/// ```no_run -/// # use rustls::ServerConfig; -/// # let certs = vec![]; -/// # let private_key = rustls::PrivateKey(vec![]); -/// ServerConfig::builder() -/// .with_safe_defaults() -/// .with_no_client_auth() -/// .with_single_cert(certs, private_key) -/// .expect("bad certificate/key"); -/// ``` -/// -/// To make a [`ClientConfig`]: -/// -/// ```no_run -/// # use rustls::ClientConfig; -/// # let root_certs = rustls::RootCertStore::empty(); -/// # let certs = vec![]; -/// # let private_key = rustls::PrivateKey(vec![]); -/// ClientConfig::builder() -/// .with_safe_default_cipher_suites() -/// .with_safe_default_kx_groups() -/// .with_safe_default_protocol_versions() -/// .unwrap() -/// .with_root_certificates(root_certs) -/// .with_single_cert(certs, private_key) -/// .expect("bad certificate/key"); -/// ``` -/// -/// This may be shortened to: -/// -/// ``` -/// # use rustls::ClientConfig; -/// # let root_certs = rustls::RootCertStore::empty(); -/// ClientConfig::builder() -/// .with_safe_defaults() -/// .with_root_certificates(root_certs) -/// .with_no_client_auth(); -/// ``` -/// -/// The types used here fit together like this: -/// -/// 1. Call [`ClientConfig::builder()`] or [`ServerConfig::builder()`] to initialize a builder. -/// 1. You must make a decision on which cipher suites to use, typically -/// by calling [`ConfigBuilder::with_safe_default_cipher_suites()`]. -/// 2. Now you must make a decision -/// on key exchange groups: typically by calling -/// [`ConfigBuilder::with_safe_default_kx_groups()`]. -/// 3. Now you must make -/// a decision on which protocol versions to support, typically by calling -/// [`ConfigBuilder::with_safe_default_protocol_versions()`]. -/// 5. Now see [`ConfigBuilder`] or -/// [`ConfigBuilder`] for further steps. -/// -/// [`ServerConfig`]: crate::ServerConfig -/// [`ClientConfig`]: crate::ClientConfig -/// [`ClientConfig::builder()`]: crate::ClientConfig::builder() -/// [`ServerConfig::builder()`]: crate::ServerConfig::builder() -/// [`ConfigBuilder`]: struct.ConfigBuilder.html#impl-3 -/// [`ConfigBuilder`]: struct.ConfigBuilder.html#impl-6 -#[derive(Clone)] -pub struct ConfigBuilder { - pub(crate) state: State, - pub(crate) side: PhantomData, -} - -impl fmt::Debug for ConfigBuilder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let side_name = std::any::type_name::(); - let side_name = side_name - .split("::") - .last() - .unwrap_or(side_name); - f.debug_struct(&format!("ConfigBuilder<{}, _>", side_name)) - .field("state", &self.state) - .finish() - } -} - -/// Config builder state where the caller must supply cipher suites. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsCipherSuites(pub(crate) ()); - -impl ConfigBuilder { - /// Start side-specific config with defaults for underlying cryptography. - /// - /// If used, this will enable all safe supported cipher suites ([`DEFAULT_CIPHER_SUITES`]), all - /// safe supported key exchange groups ([`ALL_KX_GROUPS`]) and all safe supported protocol - /// versions ([`DEFAULT_VERSIONS`]). - /// - /// These are safe defaults, useful for 99% of applications. - /// - /// [`DEFAULT_VERSIONS`]: versions::DEFAULT_VERSIONS - pub fn with_safe_defaults(self) -> ConfigBuilder { - ConfigBuilder { - state: WantsVerifier { - cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(), - kx_groups: ALL_KX_GROUPS.to_vec(), - versions: versions::EnabledVersions::new(versions::DEFAULT_VERSIONS), - }, - side: self.side, - } - } - - /// Choose a specific set of cipher suites. - pub fn with_cipher_suites( - self, - cipher_suites: &[SupportedCipherSuite], - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsKxGroups { - cipher_suites: cipher_suites.to_vec(), - }, - side: self.side, - } - } - - /// Choose the default set of cipher suites ([`DEFAULT_CIPHER_SUITES`]). - /// - /// Note that this default provides only high-quality suites: there is no need - /// to filter out low-, export- or NULL-strength cipher suites: rustls does not - /// implement these. - pub fn with_safe_default_cipher_suites(self) -> ConfigBuilder { - self.with_cipher_suites(DEFAULT_CIPHER_SUITES) - } -} - -/// Config builder state where the caller must supply key exchange groups. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsKxGroups { - cipher_suites: Vec, -} - -impl ConfigBuilder { - /// Choose a specific set of key exchange groups. - pub fn with_kx_groups( - self, - kx_groups: &[&'static SupportedKxGroup], - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsVersions { - cipher_suites: self.state.cipher_suites, - kx_groups: kx_groups.to_vec(), - }, - side: self.side, - } - } - - /// Choose the default set of key exchange groups ([`ALL_KX_GROUPS`]). - /// - /// This is a safe default: rustls doesn't implement any poor-quality groups. - pub fn with_safe_default_kx_groups(self) -> ConfigBuilder { - self.with_kx_groups(&ALL_KX_GROUPS) - } -} - -/// Config builder state where the caller must supply TLS protocol versions. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsVersions { - cipher_suites: Vec, - kx_groups: Vec<&'static SupportedKxGroup>, -} - -impl ConfigBuilder { - /// Accept the default protocol versions: both TLS1.2 and TLS1.3 are enabled. - pub fn with_safe_default_protocol_versions( - self, - ) -> Result, Error> { - self.with_protocol_versions(versions::DEFAULT_VERSIONS) - } - - /// Use a specific set of protocol versions. - pub fn with_protocol_versions( - self, - versions: &[&'static versions::SupportedProtocolVersion], - ) -> Result, Error> { - let mut any_usable_suite = false; - for suite in &self.state.cipher_suites { - if versions.contains(&suite.version()) { - any_usable_suite = true; - break; - } - } - - if !any_usable_suite { - return Err(Error::General("no usable cipher suites configured".into())); - } - - if self.state.kx_groups.is_empty() { - return Err(Error::General("no kx groups configured".into())); - } - - Ok(ConfigBuilder { - state: WantsVerifier { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - versions: versions::EnabledVersions::new(versions), - }, - side: self.side, - }) - } -} - -/// Config builder state where the caller must supply a verifier. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsVerifier { - pub(crate) cipher_suites: Vec, - pub(crate) kx_groups: Vec<&'static SupportedKxGroup>, - pub(crate) versions: versions::EnabledVersions, -} - -/// Helper trait to abstract [`ConfigBuilder`] over building a [`ClientConfig`] or [`ServerConfig`]. -/// -/// [`ClientConfig`]: crate::ClientConfig -/// [`ServerConfig`]: crate::ServerConfig -pub trait ConfigSide: sealed::Sealed {} - -impl ConfigSide for crate::ClientConfig {} -impl ConfigSide for crate::ServerConfig {} - -mod sealed { - pub trait Sealed {} - impl Sealed for crate::ClientConfig {} - impl Sealed for crate::ServerConfig {} -} diff --git a/third_party/rustls-fork-shadow-tls/src/check.rs b/third_party/rustls-fork-shadow-tls/src/check.rs deleted file mode 100644 index d318343..0000000 --- a/third_party/rustls-fork-shadow-tls/src/check.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::error::Error; -#[cfg(feature = "logging")] -use crate::log::warn; -use crate::msgs::enums::{ContentType, HandshakeType}; -use crate::msgs::message::MessagePayload; - -/// For a Message $m, and a HandshakePayload enum member $payload_type, -/// return Ok(payload) if $m is both a handshake message and one that -/// has the given $payload_type. If not, return Err(rustls::Error) quoting -/// $handshake_type as the expected handshake type. -macro_rules! require_handshake_msg( - ( $m:expr, $handshake_type:path, $payload_type:path ) => ( - match &$m.payload { - MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload { - payload: $payload_type(hm), - .. - }, .. } => Ok(hm), - payload => Err($crate::check::inappropriate_handshake_message( - payload, - &[$crate::msgs::enums::ContentType::Handshake], - &[$handshake_type])) - } - ) -); - -/// Like require_handshake_msg, but moves the payload out of $m. -#[cfg(feature = "tls12")] -macro_rules! require_handshake_msg_move( - ( $m:expr, $handshake_type:path, $payload_type:path ) => ( - match $m.payload { - MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload { - payload: $payload_type(hm), - .. - }, .. } => Ok(hm), - payload => - Err($crate::check::inappropriate_handshake_message( - &payload, - &[$crate::msgs::enums::ContentType::Handshake], - &[$handshake_type])) - } - ) -); - -pub(crate) fn inappropriate_message( - payload: &MessagePayload, - content_types: &[ContentType], -) -> Error { - warn!( - "Received a {:?} message while expecting {:?}", - payload.content_type(), - content_types - ); - Error::InappropriateMessage { - expect_types: content_types.to_vec(), - got_type: payload.content_type(), - } -} - -pub(crate) fn inappropriate_handshake_message( - payload: &MessagePayload, - content_types: &[ContentType], - handshake_types: &[HandshakeType], -) -> Error { - match payload { - MessagePayload::Handshake { parsed, .. } => { - warn!( - "Received a {:?} handshake message while expecting {:?}", - parsed.typ, handshake_types - ); - Error::InappropriateHandshakeMessage { - expect_types: handshake_types.to_vec(), - got_type: parsed.typ, - } - } - payload => inappropriate_message(payload, content_types), - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/cipher.rs b/third_party/rustls-fork-shadow-tls/src/cipher.rs deleted file mode 100644 index b595ca6..0000000 --- a/third_party/rustls-fork-shadow-tls/src/cipher.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::error::Error; -use crate::msgs::codec; -use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; - -use ring::{aead, hkdf}; - -/// Objects with this trait can decrypt TLS messages. -pub trait MessageDecrypter: Send + Sync { - /// Perform the decryption over the concerned TLS message. - - fn decrypt(&self, m: OpaqueMessage, seq: u64) -> Result; -} - -/// Objects with this trait can encrypt TLS messages. -pub(crate) trait MessageEncrypter: Send + Sync { - fn encrypt(&self, m: BorrowedPlainMessage, seq: u64) -> Result; -} - -impl dyn MessageEncrypter { - pub(crate) fn invalid() -> Box { - Box::new(InvalidMessageEncrypter {}) - } -} - -impl dyn MessageDecrypter { - pub(crate) fn invalid() -> Box { - Box::new(InvalidMessageDecrypter {}) - } -} - -/// A write or read IV. -#[derive(Default)] -pub(crate) struct Iv(pub(crate) [u8; ring::aead::NONCE_LEN]); - -impl Iv { - #[cfg(feature = "tls12")] - fn new(value: [u8; ring::aead::NONCE_LEN]) -> Self { - Self(value) - } - - #[cfg(feature = "tls12")] - pub(crate) fn copy(value: &[u8]) -> Self { - debug_assert_eq!(value.len(), ring::aead::NONCE_LEN); - let mut iv = Self::new(Default::default()); - iv.0.copy_from_slice(value); - iv - } - - #[cfg(test)] - pub(crate) fn value(&self) -> &[u8; 12] { - &self.0 - } -} - -pub(crate) struct IvLen; - -impl hkdf::KeyType for IvLen { - fn len(&self) -> usize { - aead::NONCE_LEN - } -} - -impl From> for Iv { - fn from(okm: hkdf::Okm) -> Self { - let mut r = Self(Default::default()); - okm.fill(&mut r.0[..]).unwrap(); - r - } -} - -pub(crate) fn make_nonce(iv: &Iv, seq: u64) -> ring::aead::Nonce { - let mut nonce = [0u8; ring::aead::NONCE_LEN]; - codec::put_u64(seq, &mut nonce[4..]); - - nonce - .iter_mut() - .zip(iv.0.iter()) - .for_each(|(nonce, iv)| { - *nonce ^= *iv; - }); - - aead::Nonce::assume_unique_for_key(nonce) -} - -/// A `MessageEncrypter` which doesn't work. -struct InvalidMessageEncrypter {} - -impl MessageEncrypter for InvalidMessageEncrypter { - fn encrypt(&self, _m: BorrowedPlainMessage, _seq: u64) -> Result { - Err(Error::General("encrypt not yet available".to_string())) - } -} - -/// A `MessageDecrypter` which doesn't work. -struct InvalidMessageDecrypter {} - -impl MessageDecrypter for InvalidMessageDecrypter { - fn decrypt(&self, _m: OpaqueMessage, _seq: u64) -> Result { - Err(Error::DecryptError) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/builder.rs b/third_party/rustls-fork-shadow-tls/src/client/builder.rs deleted file mode 100644 index 464bfb9..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/builder.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::anchors; -use crate::builder::{ConfigBuilder, WantsVerifier}; -use crate::client::handy; -use crate::client::{ClientConfig, ResolvesClientCert}; -use crate::error::Error; -use crate::key; -use crate::kx::SupportedKxGroup; -use crate::suites::SupportedCipherSuite; -use crate::verify::{self, CertificateTransparencyPolicy}; -use crate::versions; -use crate::NoKeyLog; - -use std::marker::PhantomData; -use std::sync::Arc; -use std::time::SystemTime; - -impl ConfigBuilder { - /// Choose how to verify client certificates. - pub fn with_root_certificates( - self, - root_store: anchors::RootCertStore, - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsTransparencyPolicyOrClientCert { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - versions: self.state.versions, - root_store, - }, - side: PhantomData::default(), - } - } - - #[cfg(feature = "dangerous_configuration")] - /// Set a custom certificate verifier. - pub fn with_custom_certificate_verifier( - self, - verifier: Arc, - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsClientCert { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - versions: self.state.versions, - verifier, - }, - side: PhantomData::default(), - } - } -} - -/// A config builder state where the caller needs to supply a certificate transparency policy or -/// client certificate resolver. -/// -/// In this state, the caller can optionally enable certificate transparency, or ignore CT and -/// invoke one of the methods related to client certificates (as in the [`WantsClientCert`] state). -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsTransparencyPolicyOrClientCert { - cipher_suites: Vec, - kx_groups: Vec<&'static SupportedKxGroup>, - versions: versions::EnabledVersions, - root_store: anchors::RootCertStore, -} - -impl ConfigBuilder { - /// Set Certificate Transparency logs to use for server certificate validation. - /// - /// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or - /// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will - /// be validated against the configured CT logs until the deadline expires. After the deadline, - /// certificates will no longer be validated, and a warning message will be logged. The deadline - /// may vary depending on how often you deploy builds with updated dependencies. - pub fn with_certificate_transparency_logs( - self, - logs: &'static [&'static sct::Log], - validation_deadline: SystemTime, - ) -> ConfigBuilder { - self.with_logs(Some(CertificateTransparencyPolicy::new( - logs, - validation_deadline, - ))) - } - - /// Sets a single certificate chain and matching private key for use - /// in client authentication. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. - /// - /// This function fails if `key_der` is invalid. - pub fn with_single_cert( - self, - cert_chain: Vec, - key_der: key::PrivateKey, - ) -> Result { - self.with_logs(None) - .with_single_cert(cert_chain, key_der) - } - - /// Do not support client auth. - pub fn with_no_client_auth(self) -> ClientConfig { - self.with_logs(None) - .with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) - } - - /// Sets a custom [`ResolvesClientCert`]. - pub fn with_client_cert_resolver( - self, - client_auth_cert_resolver: Arc, - ) -> ClientConfig { - self.with_logs(None) - .with_client_cert_resolver(client_auth_cert_resolver) - } - - fn with_logs( - self, - ct_policy: Option, - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsClientCert { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - versions: self.state.versions, - verifier: Arc::new(verify::WebPkiVerifier::new( - self.state.root_store, - ct_policy, - )), - }, - side: PhantomData, - } - } -} - -/// A config builder state where the caller needs to supply whether and how to provide a client -/// certificate. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsClientCert { - cipher_suites: Vec, - kx_groups: Vec<&'static SupportedKxGroup>, - versions: versions::EnabledVersions, - verifier: Arc, -} - -impl ConfigBuilder { - /// Sets a single certificate chain and matching private key for use - /// in client authentication. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. - /// - /// This function fails if `key_der` is invalid. - pub fn with_single_cert( - self, - cert_chain: Vec, - key_der: key::PrivateKey, - ) -> Result { - let resolver = handy::AlwaysResolvesClientCert::new(cert_chain, &key_der)?; - Ok(self.with_client_cert_resolver(Arc::new(resolver))) - } - - /// Do not support client auth. - pub fn with_no_client_auth(self) -> ClientConfig { - self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) - } - - /// Sets a custom [`ResolvesClientCert`]. - pub fn with_client_cert_resolver( - self, - client_auth_cert_resolver: Arc, - ) -> ClientConfig { - ClientConfig { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - alpn_protocols: Vec::new(), - session_storage: handy::ClientSessionMemoryCache::new(256), - max_fragment_size: None, - client_auth_cert_resolver, - enable_tickets: true, - versions: self.state.versions, - enable_sni: true, - verifier: self.state.verifier, - key_log: Arc::new(NoKeyLog {}), - #[cfg(feature = "secret_extraction")] - enable_secret_extraction: false, - enable_early_data: false, - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/client_conn.rs b/third_party/rustls-fork-shadow-tls/src/client/client_conn.rs deleted file mode 100644 index 59244a7..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/client_conn.rs +++ /dev/null @@ -1,742 +0,0 @@ -use crate::builder::{ConfigBuilder, WantsCipherSuites}; -use crate::conn::{CommonState, ConnectionCommon, Protocol, Side}; -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::kx; -use crate::kx::SupportedKxGroup; -#[cfg(feature = "logging")] -use crate::log::trace; -#[cfg(feature = "quic")] -use crate::msgs::enums::AlertDescription; -use crate::msgs::handshake::ClientExtension; -use crate::sign; -use crate::suites::SupportedCipherSuite; -use crate::verify; -use crate::versions; -#[cfg(feature = "secret_extraction")] -use crate::ExtractedSecrets; -use crate::KeyLog; - -use super::hs; -#[cfg(feature = "quic")] -use crate::quic; - -use std::convert::TryFrom; -use std::error::Error as StdError; -use std::marker::PhantomData; -use std::net::IpAddr; -use std::ops::{Deref, DerefMut}; -use std::sync::Arc; - -/// Callback used to replace the ClientHello session ID from the encoded ClientHello. -pub type ClientSessionIdGenerator = Arc [u8; 32] + Send + Sync + 'static>; -/// Callback used to replace a TLS 1.2 ClientHello session ID from eager key material. -pub type ClientTls12SessionIdGenerator = - Arc]) -> [u8; 32] + Send + Sync + 'static>; - -/// Session ID generators for custom ClientHello authentication schemes. -#[derive(Clone, Default)] -pub struct ClientSessionIdGenerators { - /// Generator for TLS 1.3 ClientHello authentication. - pub tls13: Option, - /// Generator for TLS 1.2 ClientHello authentication. - pub tls12: Option, -} -use std::{fmt, io, mem}; - -/// A trait for the ability to store client session data. -/// The keys and values are opaque. -/// -/// Both the keys and values should be treated as -/// **highly sensitive data**, containing enough key material -/// to break all security of the corresponding session. -/// -/// `put` is a mutating operation; this isn't expressed -/// in the type system to allow implementations freedom in -/// how to achieve interior mutability. `Mutex` is a common -/// choice. -pub trait StoresClientSessions: Send + Sync { - /// Stores a new `value` for `key`. Returns `true` - /// if the value was stored. - fn put(&self, key: Vec, value: Vec) -> bool; - - /// Returns the latest value for `key`. Returns `None` - /// if there's no such value. - fn get(&self, key: &[u8]) -> Option>; -} - -/// A trait for the ability to choose a certificate chain and -/// private key for the purposes of client authentication. -pub trait ResolvesClientCert: Send + Sync { - /// With the server-supplied acceptable issuers in `acceptable_issuers`, - /// the server's supported signature schemes in `sigschemes`, - /// return a certificate chain and signing key to authenticate. - /// - /// `acceptable_issuers` is undecoded and unverified by the rustls - /// library, but it should be expected to contain a DER encodings - /// of X501 NAMEs. - /// - /// Return None to continue the handshake without any client - /// authentication. The server may reject the handshake later - /// if it requires authentication. - fn resolve( - &self, - acceptable_issuers: &[&[u8]], - sigschemes: &[SignatureScheme], - ) -> Option>; - - /// Return true if any certificates at all are available. - fn has_certs(&self) -> bool; -} - -/// Common configuration for (typically) all connections made by -/// a program. -/// -/// Making one of these can be expensive, and should be -/// once per process rather than once per connection. -/// -/// These must be created via the [`ClientConfig::builder()`] function. -/// -/// # Defaults -/// -/// * [`ClientConfig::max_fragment_size`]: the default is `None`: TLS packets are not fragmented to a specific size. -/// * [`ClientConfig::session_storage`]: the default stores 256 sessions in memory. -/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. -/// * [`ClientConfig::key_log`]: key material is not logged. -#[derive(Clone)] -pub struct ClientConfig { - /// List of ciphersuites, in preference order. - pub(super) cipher_suites: Vec, - - /// List of supported key exchange algorithms, in preference order -- the - /// first element is the highest priority. - /// - /// The first element in this list is the _default key share algorithm_, - /// and in TLS1.3 a key share for it is sent in the client hello. - pub(super) kx_groups: Vec<&'static SupportedKxGroup>, - - /// Which ALPN protocols we include in our client hello. - /// If empty, no ALPN extension is sent. - pub alpn_protocols: Vec>, - - /// How we store session data or tickets. - pub session_storage: Arc, - - /// The maximum size of TLS message we'll emit. If None, we don't limit TLS - /// message lengths except to the 2**16 limit specified in the standard. - /// - /// rustls enforces an arbitrary minimum of 32 bytes for this field. - /// Out of range values are reported as errors from ClientConnection::new. - /// - /// Setting this value to the TCP MSS may improve latency for stream-y workloads. - pub max_fragment_size: Option, - - /// How to decide what client auth certificate/keys to use. - pub client_auth_cert_resolver: Arc, - - /// Whether to support RFC5077 tickets. You must provide a working - /// `session_storage` member for this to have any meaningful - /// effect. - /// - /// The default is true. - pub enable_tickets: bool, - - /// Supported versions, in no particular order. The default - /// is all supported versions. - pub(super) versions: versions::EnabledVersions, - - /// Whether to send the Server Name Indication (SNI) extension - /// during the client handshake. - /// - /// The default is true. - pub enable_sni: bool, - - /// How to verify the server certificate chain. - pub(super) verifier: Arc, - - /// How to output key material for debugging. The default - /// does nothing. - pub key_log: Arc, - - /// Allows traffic secrets to be extracted after the handshake, - /// e.g. for kTLS setup. - #[cfg(feature = "secret_extraction")] - pub enable_secret_extraction: bool, - - /// Whether to send data on the first flight ("early data") in - /// TLS 1.3 handshakes. - /// - /// The default is false. - pub enable_early_data: bool, -} - -impl fmt::Debug for ClientConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ClientConfig") - .field("alpn_protocols", &self.alpn_protocols) - .field("max_fragment_size", &self.max_fragment_size) - .field("enable_tickets", &self.enable_tickets) - .field("enable_sni", &self.enable_sni) - .field("enable_early_data", &self.enable_early_data) - .finish_non_exhaustive() - } -} - -impl ClientConfig { - /// Create a builder to build up the client configuration. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - pub fn builder() -> ConfigBuilder { - ConfigBuilder { - state: WantsCipherSuites(()), - side: PhantomData::default(), - } - } - - #[doc(hidden)] - /// We support a given TLS version if it's quoted in the configured - /// versions *and* at least one ciphersuite for this version is - /// also configured. - pub fn supports_version(&self, v: ProtocolVersion) -> bool { - self.versions.contains(v) - && self - .cipher_suites - .iter() - .any(|cs| cs.version().version == v) - } - - /// Access configuration options whose use is dangerous and requires - /// extra care. - #[cfg(feature = "dangerous_configuration")] - pub fn dangerous(&mut self) -> danger::DangerousClientConfig { - danger::DangerousClientConfig { cfg: self } - } - - pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option { - self.cipher_suites - .iter() - .copied() - .find(|&scs| scs.suite() == suite) - } -} - -/// Encodes ways a client can know the expected name of the server. -/// -/// This currently covers knowing the DNS name of the server, but -/// will be extended in the future to supporting privacy-preserving names -/// for the server ("ECH"). For this reason this enum is `non_exhaustive`. -/// -/// # Making one -/// -/// If you have a DNS name as a `&str`, this type implements `TryFrom<&str>`, -/// so you can do: -/// -/// ``` -/// # use std::convert::{TryInto, TryFrom}; -/// # use rustls::ServerName; -/// ServerName::try_from("example.com").expect("invalid DNS name"); -/// -/// // or, alternatively... -/// -/// let x = "example.com".try_into().expect("invalid DNS name"); -/// # let _: ServerName = x; -/// ``` -#[non_exhaustive] -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub enum ServerName { - /// The server is identified by a DNS name. The name - /// is sent in the TLS Server Name Indication (SNI) - /// extension. - DnsName(verify::DnsName), - - /// The server is identified by an IP address. SNI is not - /// done. - IpAddress(IpAddr), -} - -impl ServerName { - /// Return the name that should go in the SNI extension. - /// If [`None`] is returned, the SNI extension is not included - /// in the handshake. - pub(crate) fn for_sni(&self) -> Option { - match self { - Self::DnsName(dns_name) => Some(dns_name.0.as_ref()), - Self::IpAddress(_) => None, - } - } - - /// Return a prefix-free, unique encoding for the name. - pub(crate) fn encode(&self) -> Vec { - enum UniqueTypeCode { - DnsName = 0x01, - IpAddr = 0x02, - } - - match self { - Self::DnsName(dns_name) => { - let bytes = dns_name.0.as_ref(); - - let mut r = Vec::with_capacity(2 + bytes.as_ref().len()); - r.push(UniqueTypeCode::DnsName as u8); - r.push(bytes.as_ref().len() as u8); - r.extend_from_slice(bytes.as_ref()); - - r - } - Self::IpAddress(address) => { - let string = address.to_string(); - let bytes = string.as_bytes(); - - let mut r = Vec::with_capacity(2 + bytes.len()); - r.push(UniqueTypeCode::IpAddr as u8); - r.push(bytes.len() as u8); - r.extend_from_slice(bytes); - - r - } - } - } -} - -/// Attempt to make a ServerName from a string by parsing -/// it as a DNS name. -impl TryFrom<&str> for ServerName { - type Error = InvalidDnsNameError; - fn try_from(s: &str) -> Result { - match webpki::DnsNameRef::try_from_ascii_str(s) { - Ok(dns) => Ok(Self::DnsName(verify::DnsName(dns.into()))), - Err(webpki::InvalidDnsNameError) => match s.parse() { - Ok(ip) => Ok(Self::IpAddress(ip)), - Err(_) => Err(InvalidDnsNameError), - }, - } - } -} - -/// The provided input could not be parsed because -/// it is not a syntactically-valid DNS Name. -#[derive(Debug)] -pub struct InvalidDnsNameError; - -impl fmt::Display for InvalidDnsNameError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("invalid dns name") - } -} - -impl StdError for InvalidDnsNameError {} - -/// Container for unsafe APIs -#[cfg(feature = "dangerous_configuration")] -pub(super) mod danger { - use std::sync::Arc; - - use super::verify::ServerCertVerifier; - use super::ClientConfig; - - /// Accessor for dangerous configuration options. - #[derive(Debug)] - #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] - pub struct DangerousClientConfig<'a> { - /// The underlying ClientConfig - pub cfg: &'a mut ClientConfig, - } - - impl<'a> DangerousClientConfig<'a> { - /// Overrides the default `ServerCertVerifier` with something else. - pub fn set_certificate_verifier(&mut self, verifier: Arc) { - self.cfg.verifier = verifier; - } - } -} - -#[derive(Debug, PartialEq)] -enum EarlyDataState { - Disabled, - Ready, - Accepted, - AcceptedFinished, - Rejected, -} - -pub(super) struct EarlyData { - state: EarlyDataState, - left: usize, -} - -impl EarlyData { - fn new() -> Self { - Self { - left: 0, - state: EarlyDataState::Disabled, - } - } - - pub(super) fn is_enabled(&self) -> bool { - matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted) - } - - fn is_accepted(&self) -> bool { - matches!( - self.state, - EarlyDataState::Accepted | EarlyDataState::AcceptedFinished - ) - } - - pub(super) fn enable(&mut self, max_data: usize) { - assert_eq!(self.state, EarlyDataState::Disabled); - self.state = EarlyDataState::Ready; - self.left = max_data; - } - - pub(super) fn rejected(&mut self) { - trace!("EarlyData rejected"); - self.state = EarlyDataState::Rejected; - } - - pub(super) fn accepted(&mut self) { - trace!("EarlyData accepted"); - assert_eq!(self.state, EarlyDataState::Ready); - self.state = EarlyDataState::Accepted; - } - - pub(super) fn finished(&mut self) { - trace!("EarlyData finished"); - self.state = match self.state { - EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, - _ => panic!("bad EarlyData state"), - } - } - - fn check_write(&mut self, sz: usize) -> io::Result { - match self.state { - EarlyDataState::Disabled => unreachable!(), - EarlyDataState::Ready | EarlyDataState::Accepted => { - let take = if self.left < sz { - mem::replace(&mut self.left, 0) - } else { - self.left -= sz; - sz - }; - - Ok(take) - } - EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => { - Err(io::Error::from(io::ErrorKind::InvalidInput)) - } - } - } - - fn bytes_left(&self) -> usize { - self.left - } -} - -/// Stub that implements io::Write and dispatches to `write_early_data`. -pub struct WriteEarlyData<'a> { - sess: &'a mut ClientConnection, -} - -impl<'a> WriteEarlyData<'a> { - fn new(sess: &'a mut ClientConnection) -> WriteEarlyData<'a> { - WriteEarlyData { sess } - } - - /// How many bytes you may send. Writes will become short - /// once this reaches zero. - pub fn bytes_left(&self) -> usize { - self.sess - .inner - .data - .early_data - .bytes_left() - } -} - -impl<'a> io::Write for WriteEarlyData<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.sess.write_early_data(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// This represents a single TLS client connection. -pub struct ClientConnection { - inner: ConnectionCommon, -} - -impl fmt::Debug for ClientConnection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ClientConnection") - .finish() - } -} - -impl ClientConnection { - /// Make a new ClientConnection. `config` controls how - /// we behave in the TLS protocol, `name` is the - /// name of the server we want to talk to. - pub fn new( - config: Arc, - name: ServerName, - ) -> Result { - Self::new_inner(config, name, Vec::new(), Protocol::Tcp) - } - - /// Create a new ClientConnection with a generator. - pub fn new_with_session_id_generator( - config: Arc, - name: ServerName, - session_id_generator: F, - ) -> Result - where - F: Fn(&[u8]) -> [u8; 32] + Send + Sync + 'static, - { - Self::new_inner_with_session_id_generators( - config, - name, - Vec::new(), - Protocol::Tcp, - ClientSessionIdGenerators { - tls13: Some(Arc::new(session_id_generator)), - tls12: None, - }, - ) - } - - /// Create a new ClientConnection with TLS session-id generators. - pub fn new_with_session_id_generators( - config: Arc, - name: ServerName, - session_id_generators: ClientSessionIdGenerators, - ) -> Result { - Self::new_inner_with_session_id_generators( - config, - name, - Vec::new(), - Protocol::Tcp, - session_id_generators, - ) - } - - fn new_inner( - config: Arc, - name: ServerName, - extra_exts: Vec, - proto: Protocol, - ) -> Result { - Self::new_inner_with_session_id_generators( - config, - name, - extra_exts, - proto, - ClientSessionIdGenerators::default(), - ) - } - - fn new_inner_with_session_id_generators( - config: Arc, - name: ServerName, - extra_exts: Vec, - proto: Protocol, - session_id_generators: ClientSessionIdGenerators, - ) -> Result { - let mut common_state = CommonState::new(Side::Client); - common_state.set_max_fragment_size(config.max_fragment_size)?; - common_state.protocol = proto; - #[cfg(feature = "secret_extraction")] - { - common_state.enable_secret_extraction = config.enable_secret_extraction; - } - let mut data = ClientConnectionData::new(); - - let mut cx = hs::ClientContext { - common: &mut common_state, - data: &mut data, - }; - - let state = - hs::start_handshake(name, extra_exts, config, &mut cx, session_id_generators)?; - let inner = ConnectionCommon::new(state, data, common_state); - - Ok(Self { inner }) - } - - /// Returns an `io::Write` implementer you can write bytes to - /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. - /// - /// This returns None in many circumstances when the capability to - /// send early data is not available, including but not limited to: - /// - /// - The server hasn't been talked to previously. - /// - The server does not support resumption. - /// - The server does not support early data. - /// - The resumption data for the server has expired. - /// - /// The server specifies a maximum amount of early data. You can - /// learn this limit through the returned object, and writes through - /// it will process only this many bytes. - /// - /// The server can choose not to accept any sent early data -- - /// in this case the data is lost but the connection continues. You - /// can tell this happened using `is_early_data_accepted`. - pub fn early_data(&mut self) -> Option { - if self.inner.data.early_data.is_enabled() { - Some(WriteEarlyData::new(self)) - } else { - None - } - } - - /// Returns True if the server signalled it will process early data. - /// - /// If you sent early data and this returns false at the end of the - /// handshake then the server will not process the data. This - /// is not an error, but you may wish to resend the data. - pub fn is_early_data_accepted(&self) -> bool { - self.inner.data.early_data.is_accepted() - } - - fn write_early_data(&mut self, data: &[u8]) -> io::Result { - self.inner - .data - .early_data - .check_write(data.len()) - .map(|sz| { - self.inner - .common_state - .send_early_plaintext(&data[..sz]) - }) - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - #[cfg(feature = "secret_extraction")] - pub fn extract_secrets(self) -> Result { - self.inner.extract_secrets() - } -} - -impl Deref for ClientConnection { - type Target = ConnectionCommon; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ClientConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -#[doc(hidden)] -impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection { - type Error = (); - - fn try_from(value: &'a mut crate::Connection) -> Result { - use crate::Connection::*; - match value { - Client(conn) => Ok(conn), - Server(_) => Err(()), - } - } -} - -impl From for crate::Connection { - fn from(conn: ClientConnection) -> Self { - Self::Client(conn) - } -} - -/// State associated with a client connection. -pub struct ClientConnectionData { - pub(super) early_data: EarlyData, - pub(super) resumption_ciphersuite: Option, - pub(in crate::client) tls12_eager_key_exchanges: Vec, -} - -impl ClientConnectionData { - fn new() -> Self { - Self { - early_data: EarlyData::new(), - resumption_ciphersuite: None, - tls12_eager_key_exchanges: Vec::new(), - } - } -} - -impl crate::conn::SideData for ClientConnectionData {} - -#[cfg(feature = "quic")] -impl quic::QuicExt for ClientConnection { - fn quic_transport_parameters(&self) -> Option<&[u8]> { - self.inner - .common_state - .quic - .params - .as_ref() - .map(|v| v.as_ref()) - } - - fn zero_rtt_keys(&self) -> Option { - Some(quic::DirectionalKeys::new( - self.inner - .data - .resumption_ciphersuite - .and_then(|suite| suite.tls13())?, - self.inner - .common_state - .quic - .early_secret - .as_ref()?, - )) - } - - fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - self.inner.read_quic_hs(plaintext) - } - - fn write_hs(&mut self, buf: &mut Vec) -> Option { - quic::write_hs(&mut self.inner.common_state, buf) - } - - fn alert(&self) -> Option { - self.inner.common_state.quic.alert - } -} - -/// Methods specific to QUIC client sessions -#[cfg(feature = "quic")] -#[cfg_attr(docsrs, doc(cfg(feature = "quic")))] -pub trait ClientQuicExt { - /// Make a new QUIC ClientConnection. This differs from `ClientConnection::new()` - /// in that it takes an extra argument, `params`, which contains the - /// TLS-encoded transport parameters to send. - fn new_quic( - config: Arc, - quic_version: quic::Version, - name: ServerName, - params: Vec, - ) -> Result { - if !config.supports_version(ProtocolVersion::TLSv1_3) { - return Err(Error::General( - "TLS 1.3 support is required for QUIC".into(), - )); - } - - let ext = match quic_version { - quic::Version::V1Draft => ClientExtension::TransportParametersDraft(params), - quic::Version::V1 => ClientExtension::TransportParameters(params), - }; - - // hack: only a work around, do not use it. - ClientConnection::new_inner(config, name, vec![ext], Protocol::Quic) - } -} - -#[cfg(feature = "quic")] -impl ClientQuicExt for ClientConnection {} diff --git a/third_party/rustls-fork-shadow-tls/src/client/common.rs b/third_party/rustls-fork-shadow-tls/src/client/common.rs deleted file mode 100644 index ac9094d..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/common.rs +++ /dev/null @@ -1,114 +0,0 @@ -use super::ResolvesClientCert; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::enums::ExtensionType; -use crate::msgs::handshake::CertificatePayload; -use crate::msgs::handshake::SCTList; -use crate::msgs::handshake::ServerExtension; -use crate::{sign, DistinguishedNames, SignatureScheme}; - -use std::sync::Arc; - -#[derive(Debug)] -pub(super) struct ServerCertDetails { - pub(super) cert_chain: CertificatePayload, - pub(super) ocsp_response: Vec, - pub(super) scts: Option, -} - -impl ServerCertDetails { - pub(super) fn new( - cert_chain: CertificatePayload, - ocsp_response: Vec, - scts: Option, - ) -> Self { - Self { - cert_chain, - ocsp_response, - scts, - } - } - - pub(super) fn scts(&self) -> impl Iterator { - self.scts - .as_deref() - .unwrap_or(&[]) - .iter() - .map(|payload| payload.0.as_slice()) - } -} - -pub(super) struct ClientHelloDetails { - pub(super) sent_extensions: Vec, -} - -impl ClientHelloDetails { - pub(super) fn new() -> Self { - Self { - sent_extensions: Vec::new(), - } - } - - pub(super) fn server_may_send_sct_list(&self) -> bool { - self.sent_extensions - .contains(&ExtensionType::SCT) - } - - pub(super) fn server_sent_unsolicited_extensions( - &self, - received_exts: &[ServerExtension], - allowed_unsolicited: &[ExtensionType], - ) -> bool { - for ext in received_exts { - let ext_type = ext.get_type(); - if !self.sent_extensions.contains(&ext_type) && !allowed_unsolicited.contains(&ext_type) - { - trace!("Unsolicited extension {:?}", ext_type); - return true; - } - } - - false - } -} - -pub(super) enum ClientAuthDetails { - /// Send an empty `Certificate` and no `CertificateVerify`. - Empty { auth_context_tls13: Option> }, - /// Send a non-empty `Certificate` and a `CertificateVerify`. - Verify { - certkey: Arc, - signer: Box, - auth_context_tls13: Option>, - }, -} - -impl ClientAuthDetails { - pub(super) fn resolve( - resolver: &dyn ResolvesClientCert, - canames: Option<&DistinguishedNames>, - sigschemes: &[SignatureScheme], - auth_context_tls13: Option>, - ) -> Self { - let acceptable_issuers = canames - .map(Vec::as_slice) - .unwrap_or_default() - .iter() - .map(|p| p.0.as_slice()) - .collect::>(); - - if let Some(certkey) = resolver.resolve(&acceptable_issuers, sigschemes) { - if let Some(signer) = certkey.key.choose_scheme(sigschemes) { - debug!("Attempting client auth"); - return Self::Verify { - certkey, - signer, - auth_context_tls13, - }; - } - } - - debug!("Client auth requested but no cert/sigscheme available"); - Self::Empty { auth_context_tls13 } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/handy.rs b/third_party/rustls-fork-shadow-tls/src/client/handy.rs deleted file mode 100644 index 804887a..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/handy.rs +++ /dev/null @@ -1,161 +0,0 @@ -use crate::client; -use crate::enums::SignatureScheme; -use crate::error::Error; -use crate::key; -use crate::limited_cache; -use crate::sign; - -use std::sync::{Arc, Mutex}; - -/// An implementer of `StoresClientSessions` which does nothing. -pub struct NoClientSessionStorage {} - -impl client::StoresClientSessions for NoClientSessionStorage { - fn put(&self, _key: Vec, _value: Vec) -> bool { - false - } - - fn get(&self, _key: &[u8]) -> Option> { - None - } -} - -/// An implementer of `StoresClientSessions` that stores everything -/// in memory. It enforces a limit on the number of entries -/// to bound memory usage. -pub struct ClientSessionMemoryCache { - cache: Mutex, Vec>>, -} - -impl ClientSessionMemoryCache { - /// Make a new ClientSessionMemoryCache. `size` is the - /// maximum number of stored sessions. - pub fn new(size: usize) -> Arc { - debug_assert!(size > 0); - Arc::new(Self { - cache: Mutex::new(limited_cache::LimitedCache::new(size)), - }) - } -} - -impl client::StoresClientSessions for ClientSessionMemoryCache { - fn put(&self, key: Vec, value: Vec) -> bool { - self.cache - .lock() - .unwrap() - .insert(key, value); - true - } - - fn get(&self, key: &[u8]) -> Option> { - self.cache - .lock() - .unwrap() - .get(key) - .cloned() - } -} - -pub(super) struct FailResolveClientCert {} - -impl client::ResolvesClientCert for FailResolveClientCert { - fn resolve( - &self, - _acceptable_issuers: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option> { - None - } - - fn has_certs(&self) -> bool { - false - } -} - -pub(super) struct AlwaysResolvesClientCert(Arc); - -impl AlwaysResolvesClientCert { - pub(super) fn new( - chain: Vec, - priv_key: &key::PrivateKey, - ) -> Result { - let key = sign::any_supported_type(priv_key) - .map_err(|_| Error::General("invalid private key".into()))?; - Ok(Self(Arc::new(sign::CertifiedKey::new(chain, key)))) - } -} - -impl client::ResolvesClientCert for AlwaysResolvesClientCert { - fn resolve( - &self, - _acceptable_issuers: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option> { - Some(Arc::clone(&self.0)) - } - - fn has_certs(&self) -> bool { - true - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::client::StoresClientSessions; - - #[test] - fn test_noclientsessionstorage_drops_put() { - let c = NoClientSessionStorage {}; - assert!(!c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_noclientsessionstorage_denies_gets() { - let c = NoClientSessionStorage {}; - c.put(vec![0x01], vec![0x02]); - assert_eq!(c.get(&[]), None); - assert_eq!(c.get(&[0x01]), None); - assert_eq!(c.get(&[0x02]), None); - } - - #[test] - fn test_clientsessionmemorycache_accepts_put() { - let c = ClientSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_clientsessionmemorycache_persists_put() { - let c = ClientSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - } - - #[test] - fn test_clientsessionmemorycache_overwrites_put() { - let c = ClientSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x01], vec![0x04])); - assert_eq!(c.get(&[0x01]), Some(vec![0x04])); - } - - #[test] - fn test_clientsessionmemorycache_drops_to_maintain_size_invariant() { - let c = ClientSessionMemoryCache::new(2); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x03], vec![0x04])); - assert!(c.put(vec![0x05], vec![0x06])); - assert!(c.put(vec![0x07], vec![0x08])); - assert!(c.put(vec![0x09], vec![0x0a])); - - let count = c.get(&[0x01]).iter().count() - + c.get(&[0x03]).iter().count() - + c.get(&[0x05]).iter().count() - + c.get(&[0x07]).iter().count() - + c.get(&[0x09]).iter().count(); - - assert!(count < 5); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/hs.rs b/third_party/rustls-fork-shadow-tls/src/client/hs.rs deleted file mode 100644 index a4bec64..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/hs.rs +++ /dev/null @@ -1,891 +0,0 @@ -#[cfg(feature = "logging")] -use crate::bs_debug; -use crate::check::inappropriate_handshake_message; -use crate::conn::{CommonState, ConnectionRandoms, State}; -use crate::enums::{CipherSuite, ProtocolVersion}; -use crate::error::Error; -use crate::hash_hs::HandshakeHashBuffer; -use crate::kx; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::base::Payload; -#[cfg(feature = "quic")] -use crate::msgs::base::PayloadU16; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{AlertDescription, Compression, ContentType}; -use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode}; -use crate::msgs::enums::{ExtensionType, HandshakeType}; -use crate::msgs::handshake::{CertificateStatusRequest, ClientSessionTicket, SCTList}; -use crate::msgs::handshake::{ClientExtension, HasServerExtensions}; -use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload}; -use crate::msgs::handshake::{ConvertProtocolNameList, ProtocolNameList}; -use crate::msgs::handshake::{ECPointFormatList, SupportedPointFormats}; -use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry}; -use crate::msgs::handshake::{Random, SessionID}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::ticketer::TimeBase; -use crate::tls13::key_schedule::KeyScheduleEarly; -use crate::SupportedCipherSuite; - -#[cfg(feature = "tls12")] -use super::tls12; -use crate::client::client_conn::{ClientConnectionData, ClientSessionIdGenerators}; -use crate::client::common::ClientHelloDetails; -use crate::client::{tls13, ClientConfig, ServerName}; - -use std::sync::Arc; - -pub(super) type NextState = Box>; -pub(super) type NextStateOrError = Result; -pub(super) type ClientContext<'a> = crate::conn::Context<'a, ClientConnectionData>; - -fn find_session( - server_name: &ServerName, - config: &ClientConfig, - #[cfg(feature = "quic")] cx: &mut ClientContext<'_>, -) -> Option> { - let key = persist::ClientSessionKey::session_for_server_name(server_name); - let key_buf = key.get_encoding(); - - let value = config - .session_storage - .get(&key_buf) - .or_else(|| { - debug!("No cached session for {:?}", server_name); - None - })?; - - #[allow(unused_mut)] - let mut reader = Reader::init(&value[2..]); - #[allow(clippy::bind_instead_of_map)] // https://github.com/rust-lang/rust-clippy/issues/8082 - CipherSuite::read_bytes(&value[..2]) - .and_then(|suite| { - persist::ClientSessionValue::read(&mut reader, suite, &config.cipher_suites) - }) - .and_then(|resuming| { - let retrieved = persist::Retrieved::new(resuming, TimeBase::now().ok()?); - match retrieved.has_expired() { - false => Some(retrieved), - true => None, - } - }) - .and_then(|resuming| { - #[cfg(feature = "quic")] - if cx.common.is_quic() { - let params = PayloadU16::read(&mut reader)?; - cx.common.quic.params = Some(params.0); - } - Some(resuming) - }) -} - -pub(super) fn start_handshake( - server_name: ServerName, - extra_exts: Vec, - config: Arc, - cx: &mut ClientContext<'_>, - session_id_generators: ClientSessionIdGenerators, -) -> NextStateOrError { - let mut transcript_buffer = HandshakeHashBuffer::new(); - if config - .client_auth_cert_resolver - .has_certs() - { - transcript_buffer.set_client_auth_enabled(); - } - - let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3); - - let mut session_id: Option = None; - let mut resuming_session = find_session( - &server_name, - &config, - #[cfg(feature = "quic")] - cx, - ); - - let key_share = if support_tls13 { - Some(tls13::initial_key_share(&config, &server_name)?) - } else { - None - }; - - if let Some(_resuming) = &mut resuming_session { - #[cfg(feature = "tls12")] - if let persist::ClientSessionValue::Tls12(inner) = &mut _resuming.value { - // If we have a ticket, we use the sessionid as a signal that - // we're doing an abbreviated handshake. See section 3.4 in - // RFC5077. - if !inner.ticket().is_empty() { - inner.session_id = SessionID::random()?; - } - session_id = Some(inner.session_id); - } - - debug!("Resuming session"); - } else { - debug!("Not resuming any session"); - } - - // https://tools.ietf.org/html/rfc8446#appendix-D.4 - // https://tools.ietf.org/html/draft-ietf-quic-tls-34#section-8.4 - if session_id.is_none() && !cx.common.is_quic() { - session_id = Some(SessionID::random()?); - } - - let random = Random::new()?; - let hello_details = ClientHelloDetails::new(); - let sent_tls13_fake_ccs = false; - let may_send_sct_list = config.verifier.request_scts(); - Ok(emit_client_hello_for_retry( - config, - cx, - resuming_session, - random, - false, - transcript_buffer, - sent_tls13_fake_ccs, - hello_details, - session_id, - session_id_generators, - None, - server_name, - key_share, - extra_exts, - may_send_sct_list, - None, - )) -} - -struct ExpectServerHello { - config: Arc, - resuming_session: Option>, - server_name: ServerName, - random: Random, - using_ems: bool, - transcript_buffer: HandshakeHashBuffer, - early_key_schedule: Option, - hello: ClientHelloDetails, - offered_key_share: Option, - session_id: SessionID, - sent_tls13_fake_ccs: bool, - suite: Option, -} - -struct ExpectServerHelloOrHelloRetryRequest { - next: ExpectServerHello, - extra_exts: Vec, -} - -fn emit_client_hello_for_retry( - config: Arc, - cx: &mut ClientContext<'_>, - resuming_session: Option>, - random: Random, - using_ems: bool, - mut transcript_buffer: HandshakeHashBuffer, - mut sent_tls13_fake_ccs: bool, - mut hello: ClientHelloDetails, - session_id: Option, - session_id_generators: ClientSessionIdGenerators, - retryreq: Option<&HelloRetryRequest>, - server_name: ServerName, - key_share: Option, - extra_exts: Vec, - may_send_sct_list: bool, - suite: Option, -) -> NextState { - // Do we have a SessionID or ticket cached for this host? - let (ticket, resume_version) = if let Some(resuming) = &resuming_session { - match &resuming.value { - persist::ClientSessionValue::Tls13(inner) => { - (inner.ticket().to_vec(), ProtocolVersion::TLSv1_3) - } - #[cfg(feature = "tls12")] - persist::ClientSessionValue::Tls12(inner) => { - (inner.ticket().to_vec(), ProtocolVersion::TLSv1_2) - } - } - } else { - (Vec::new(), ProtocolVersion::Unknown(0)) - }; - - let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2) && !cx.common.is_quic(); - let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3); - - let mut supported_versions = Vec::new(); - if support_tls13 { - supported_versions.push(ProtocolVersion::TLSv1_3); - } - - if support_tls12 { - supported_versions.push(ProtocolVersion::TLSv1_2); - } - - cx.data.tls12_eager_key_exchanges.clear(); - let tls12_session_id_materials = if retryreq.is_none() - && support_tls12 - && session_id_generators.tls12.is_some() - { - let mut materials = Vec::new(); - for &group in &config.kx_groups { - if let Some(kx) = kx::KeyExchange::start(group) { - materials.push(kx.pubkey.as_ref().to_vec()); - cx.data.tls12_eager_key_exchanges.push(kx); - } - } - if resume_version == ProtocolVersion::TLSv1_2 && !ticket.is_empty() { - materials.push(ticket.clone()); - } - Some(materials) - } else { - None - }; - - // should be unreachable thanks to config builder - assert!(!supported_versions.is_empty()); - - let mut exts = vec![ - ClientExtension::SupportedVersions(supported_versions), - ClientExtension::ECPointFormats(ECPointFormatList::supported()), - ClientExtension::NamedGroups( - config - .kx_groups - .iter() - .map(|skxg| skxg.name) - .collect(), - ), - ClientExtension::SignatureAlgorithms( - config - .verifier - .supported_verify_schemes(), - ), - ClientExtension::ExtendedMasterSecretRequest, - ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()), - ]; - - if let (Some(sni_name), true) = (server_name.for_sni(), config.enable_sni) { - exts.push(ClientExtension::make_sni(sni_name)); - } - - if may_send_sct_list { - exts.push(ClientExtension::SignedCertificateTimestampRequest); - } - - if let Some(key_share) = &key_share { - debug_assert!(support_tls13); - let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref()); - exts.push(ClientExtension::KeyShare(vec![key_share])); - } - - if let Some(cookie) = retryreq.and_then(HelloRetryRequest::get_cookie) { - exts.push(ClientExtension::Cookie(cookie.clone())); - } - - if support_tls13 && config.enable_tickets { - // We could support PSK_KE here too. Such connections don't - // have forward secrecy, and are similar to TLS1.2 resumption. - let psk_modes = vec![PSKKeyExchangeMode::PSK_DHE_KE]; - exts.push(ClientExtension::PresharedKeyModes(psk_modes)); - } - - if !config.alpn_protocols.is_empty() { - exts.push(ClientExtension::Protocols(ProtocolNameList::from_slices( - &config - .alpn_protocols - .iter() - .map(|proto| &proto[..]) - .collect::>(), - ))); - } - - // Extra extensions must be placed before the PSK extension - exts.extend(extra_exts.iter().cloned()); - - let fill_in_binder = if support_tls13 - && config.enable_tickets - && resume_version == ProtocolVersion::TLSv1_3 - && !ticket.is_empty() - { - resuming_session - .as_ref() - .and_then(|resuming| match (suite, resuming.tls13()) { - (Some(suite), Some(resuming)) => { - suite - .tls13()? - .can_resume_from(resuming.suite())?; - Some(resuming) - } - (None, Some(resuming)) => Some(resuming), - _ => None, - }) - .map(|resuming| { - tls13::prepare_resumption( - &config, - cx, - ticket, - &resuming, - &mut exts, - retryreq.is_some(), - ); - resuming - }) - } else if config.enable_tickets { - // If we have a ticket, include it. Otherwise, request one. - if ticket.is_empty() { - exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Request)); - } else { - exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Offer( - Payload::new(ticket), - ))); - } - None - } else { - None - }; - - // Note what extensions we sent. - hello.sent_extensions = exts - .iter() - .map(ClientExtension::get_type) - .collect(); - - let mut session_id = session_id.unwrap_or_else(SessionID::empty); - let mut cipher_suites: Vec<_> = config - .cipher_suites - .iter() - .map(|cs| cs.suite()) - .collect(); - // We don't do renegotiation at all, in fact. - cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - - let mut chp = HandshakeMessagePayload { - typ: HandshakeType::ClientHello, - payload: HandshakePayload::ClientHello(ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_2, - random, - session_id, - cipher_suites, - compression_methods: vec![Compression::Null], - extensions: exts, - }), - }; - - // hack: sign chp and overwrite session id - if session_id_generators.tls13.is_some() || tls12_session_id_materials.is_some() { - let mut buffer = Vec::new(); - match &mut chp.payload { - HandshakePayload::ClientHello(c) => { - c.session_id = SessionID::zero(); - } - _ => unreachable!(), - } - chp.encode(&mut buffer); - let generated_session_id = if let (Some(generator), Some(materials)) = ( - session_id_generators.tls12.as_ref(), - tls12_session_id_materials.as_ref(), - ) { - generator(&buffer, materials) - } else if let Some(generator) = session_id_generators.tls13.as_ref() { - generator(&buffer) - } else { - unreachable!() - }; - session_id = SessionID { - len: 32, - data: generated_session_id, - }; - match &mut chp.payload { - HandshakePayload::ClientHello(c) => { - c.session_id = session_id; - } - _ => unreachable!(), - } - } - - let early_key_schedule = if let Some(resuming) = fill_in_binder { - let schedule = tls13::fill_in_psk_binder(&resuming, &transcript_buffer, &mut chp); - Some((resuming.suite(), schedule)) - } else { - None - }; - - let ch = Message { - // "This value MUST be set to 0x0303 for all records generated - // by a TLS 1.3 implementation other than an initial ClientHello - // (i.e., one not generated after a HelloRetryRequest)" - version: if retryreq.is_some() { - ProtocolVersion::TLSv1_2 - } else { - ProtocolVersion::TLSv1_0 - }, - payload: MessagePayload::handshake(chp), - }; - - if retryreq.is_some() { - // send dummy CCS to fool middleboxes prior - // to second client hello - tls13::emit_fake_ccs(&mut sent_tls13_fake_ccs, cx.common); - } - - trace!("Sending ClientHello {:#?}", ch); - - transcript_buffer.add_message(&ch); - cx.common.send_msg(ch, false); - - // Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret - let early_key_schedule = early_key_schedule.map(|(resuming_suite, schedule)| { - if !cx.data.early_data.is_enabled() { - return schedule; - } - - tls13::derive_early_traffic_secret( - &*config.key_log, - cx, - resuming_suite, - &schedule, - &mut sent_tls13_fake_ccs, - &transcript_buffer, - &random.0, - ); - schedule - }); - - let next = ExpectServerHello { - config, - resuming_session, - server_name, - random, - using_ems, - transcript_buffer, - early_key_schedule, - hello, - offered_key_share: key_share, - session_id, - sent_tls13_fake_ccs, - suite, - }; - - if support_tls13 && retryreq.is_none() { - Box::new(ExpectServerHelloOrHelloRetryRequest { next, extra_exts }) - } else { - Box::new(next) - } -} - -pub(super) fn process_alpn_protocol( - common: &mut CommonState, - config: &ClientConfig, - proto: Option<&[u8]>, -) -> Result<(), Error> { - common.alpn_protocol = proto.map(ToOwned::to_owned); - - if let Some(alpn_protocol) = &common.alpn_protocol { - if !config - .alpn_protocols - .contains(alpn_protocol) - { - return Err(common.illegal_param("server sent non-offered ALPN protocol")); - } - } - - #[cfg(feature = "quic")] - { - // RFC 9001 says: "While ALPN only specifies that servers use this alert, QUIC clients MUST - // use error 0x0178 to terminate a connection when ALPN negotiation fails." We judge that - // the user intended to use ALPN (rather than some out-of-band protocol negotiation - // mechanism) iff any ALPN protocols were configured. This defends against badly-behaved - // servers which accept a connection that requires an application-layer protocol they do not - // understand. - if common.is_quic() && common.alpn_protocol.is_none() && !config.alpn_protocols.is_empty() { - common.send_fatal_alert(AlertDescription::NoApplicationProtocol); - return Err(Error::NoApplicationProtocol); - } - } - - debug!( - "ALPN protocol is {:?}", - common - .alpn_protocol - .as_ref() - .map(|v| bs_debug::BsDebug(v)) - ); - Ok(()) -} - -pub(super) fn sct_list_is_invalid(scts: &SCTList) -> bool { - scts.is_empty() || scts.iter().any(|sct| sct.0.is_empty()) -} - -impl State for ExpectServerHello { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError { - let server_hello = - require_handshake_msg!(m, HandshakeType::ServerHello, HandshakePayload::ServerHello)?; - trace!("We got ServerHello {:#?}", server_hello); - - use crate::ProtocolVersion::{TLSv1_2, TLSv1_3}; - let tls13_supported = self.config.supports_version(TLSv1_3); - - let server_version = if server_hello.legacy_version == TLSv1_2 { - server_hello - .get_supported_versions() - .unwrap_or(server_hello.legacy_version) - } else { - server_hello.legacy_version - }; - - let version = match server_version { - TLSv1_3 if tls13_supported => TLSv1_3, - TLSv1_2 if self.config.supports_version(TLSv1_2) => { - if cx.data.early_data.is_enabled() && cx.common.early_traffic { - // The client must fail with a dedicated error code if the server - // responds with TLS 1.2 when offering 0-RTT. - return Err(Error::PeerMisbehavedError( - "server chose v1.2 when offering 0-rtt".to_string(), - )); - } - - if server_hello - .get_supported_versions() - .is_some() - { - return Err(cx - .common - .illegal_param("server chose v1.2 using v1.3 extension")); - } - - TLSv1_2 - } - _ => { - cx.common - .send_fatal_alert(AlertDescription::ProtocolVersion); - let msg = match server_version { - TLSv1_2 | TLSv1_3 => "server's TLS version is disabled in client", - _ => "server does not support TLS v1.2/v1.3", - }; - return Err(Error::PeerIncompatibleError(msg.to_string())); - } - }; - - if server_hello.compression_method != Compression::Null { - return Err(cx - .common - .illegal_param("server chose non-Null compression")); - } - - if server_hello.has_duplicate_extension() { - cx.common - .send_fatal_alert(AlertDescription::DecodeError); - return Err(Error::PeerMisbehavedError( - "server sent duplicate extensions".to_string(), - )); - } - - let allowed_unsolicited = [ExtensionType::RenegotiationInfo]; - if self - .hello - .server_sent_unsolicited_extensions(&server_hello.extensions, &allowed_unsolicited) - { - cx.common - .send_fatal_alert(AlertDescription::UnsupportedExtension); - return Err(Error::PeerMisbehavedError( - "server sent unsolicited extension".to_string(), - )); - } - - cx.common.negotiated_version = Some(version); - - // Extract ALPN protocol - if !cx.common.is_tls13() { - process_alpn_protocol(cx.common, &self.config, server_hello.get_alpn_protocol())?; - } - - // If ECPointFormats extension is supplied by the server, it must contain - // Uncompressed. But it's allowed to be omitted. - if let Some(point_fmts) = server_hello.get_ecpoints_extension() { - if !point_fmts.contains(&ECPointFormat::Uncompressed) { - cx.common - .send_fatal_alert(AlertDescription::HandshakeFailure); - return Err(Error::PeerMisbehavedError( - "server does not support uncompressed points".to_string(), - )); - } - } - - let suite = self - .config - .find_cipher_suite(server_hello.cipher_suite) - .ok_or_else(|| { - cx.common - .send_fatal_alert(AlertDescription::HandshakeFailure); - Error::PeerMisbehavedError("server chose non-offered ciphersuite".to_string()) - })?; - - if version != suite.version().version { - return Err(cx - .common - .illegal_param("server chose unusable ciphersuite for version")); - } - - match self.suite { - Some(prev_suite) if prev_suite != suite => { - return Err(cx - .common - .illegal_param("server varied selected ciphersuite")); - } - _ => { - debug!("Using ciphersuite {:?}", suite); - self.suite = Some(suite); - cx.common.suite = Some(suite); - } - } - - // Start our handshake hash, and input the server-hello. - let mut transcript = self - .transcript_buffer - .start_hash(suite.hash_algorithm()); - transcript.add_message(&m); - - let randoms = ConnectionRandoms::new(self.random, server_hello.random); - // For TLS1.3, start message encryption using - // handshake_traffic_secret. - match suite { - SupportedCipherSuite::Tls13(suite) => { - let resuming_session = self - .resuming_session - .and_then(|resuming| match resuming.value { - persist::ClientSessionValue::Tls13(inner) => Some(inner), - #[cfg(feature = "tls12")] - persist::ClientSessionValue::Tls12(_) => None, - }); - - tls13::handle_server_hello( - self.config, - cx, - server_hello, - resuming_session, - self.server_name, - randoms, - suite, - transcript, - self.early_key_schedule, - self.hello, - // We always send a key share when TLS 1.3 is enabled. - self.offered_key_share.unwrap(), - self.sent_tls13_fake_ccs, - ) - } - #[cfg(feature = "tls12")] - SupportedCipherSuite::Tls12(suite) => { - let resuming_session = self - .resuming_session - .and_then(|resuming| match resuming.value { - persist::ClientSessionValue::Tls12(inner) => Some(inner), - persist::ClientSessionValue::Tls13(_) => None, - }); - - tls12::CompleteServerHelloHandling { - config: self.config, - resuming_session, - server_name: self.server_name, - randoms, - using_ems: self.using_ems, - transcript, - } - .handle_server_hello(cx, suite, server_hello, tls13_supported) - } - } - } -} - -impl ExpectServerHelloOrHelloRetryRequest { - fn into_expect_server_hello(self) -> NextState { - Box::new(self.next) - } - - fn handle_hello_retry_request( - self, - cx: &mut ClientContext<'_>, - m: Message, - ) -> NextStateOrError { - let hrr = require_handshake_msg!( - m, - HandshakeType::HelloRetryRequest, - HandshakePayload::HelloRetryRequest - )?; - trace!("Got HRR {:?}", hrr); - - cx.common.check_aligned_handshake()?; - - let cookie = hrr.get_cookie(); - let req_group = hrr.get_requested_key_share_group(); - - // We always send a key share when TLS 1.3 is enabled. - let offered_key_share = self.next.offered_key_share.unwrap(); - - // A retry request is illegal if it contains no cookie and asks for - // retry of a group we already sent. - if cookie.is_none() && req_group == Some(offered_key_share.group()) { - return Err(cx - .common - .illegal_param("server requested hrr with our group")); - } - - // Or has an empty cookie. - if let Some(cookie) = cookie { - if cookie.0.is_empty() { - return Err(cx - .common - .illegal_param("server requested hrr with empty cookie")); - } - } - - // Or has something unrecognised - if hrr.has_unknown_extension() { - cx.common - .send_fatal_alert(AlertDescription::UnsupportedExtension); - return Err(Error::PeerIncompatibleError( - "server sent hrr with unhandled extension".to_string(), - )); - } - - // Or has the same extensions more than once - if hrr.has_duplicate_extension() { - return Err(cx - .common - .illegal_param("server send duplicate hrr extensions")); - } - - // Or asks us to change nothing. - if cookie.is_none() && req_group.is_none() { - return Err(cx - .common - .illegal_param("server requested hrr with no changes")); - } - - // Or asks us to talk a protocol we didn't offer, or doesn't support HRR at all. - match hrr.get_supported_versions() { - Some(ProtocolVersion::TLSv1_3) => { - cx.common.negotiated_version = Some(ProtocolVersion::TLSv1_3); - } - _ => { - return Err(cx - .common - .illegal_param("server requested unsupported version in hrr")); - } - } - - // Or asks us to use a ciphersuite we didn't offer. - let maybe_cs = self - .next - .config - .find_cipher_suite(hrr.cipher_suite); - let cs = match maybe_cs { - Some(cs) => cs, - None => { - return Err(cx - .common - .illegal_param("server requested unsupported cs in hrr")); - } - }; - - // HRR selects the ciphersuite. - cx.common.suite = Some(cs); - - // This is the draft19 change where the transcript became a tree - let transcript = self - .next - .transcript_buffer - .start_hash(cs.hash_algorithm()); - let mut transcript_buffer = transcript.into_hrr_buffer(); - transcript_buffer.add_message(&m); - - // Early data is not allowed after HelloRetryrequest - if cx.data.early_data.is_enabled() { - cx.data.early_data.rejected(); - } - - let may_send_sct_list = self - .next - .hello - .server_may_send_sct_list(); - - let key_share = match req_group { - Some(group) if group != offered_key_share.group() => { - let group = kx::KeyExchange::choose(group, &self.next.config.kx_groups) - .ok_or_else(|| { - cx.common - .illegal_param("server requested hrr with bad group") - })?; - kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)? - } - _ => offered_key_share, - }; - - Ok(emit_client_hello_for_retry( - self.next.config, - cx, - self.next.resuming_session, - self.next.random, - self.next.using_ems, - transcript_buffer, - self.next.sent_tls13_fake_ccs, - self.next.hello, - Some(self.next.session_id), - ClientSessionIdGenerators::default(), - Some(hrr), - self.next.server_name, - Some(key_share), - self.extra_exts, - may_send_sct_list, - Some(cs), - )) - } -} - -impl State for ExpectServerHelloOrHelloRetryRequest { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError { - match m.payload { - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::ServerHello(..), - .. - }, - .. - } => self - .into_expect_server_hello() - .handle(cx, m), - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::HelloRetryRequest(..), - .. - }, - .. - } => self.handle_hello_retry_request(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[HandshakeType::ServerHello, HandshakeType::HelloRetryRequest], - )), - } - } -} - -pub(super) fn send_cert_error_alert(common: &mut CommonState, err: Error) -> Error { - match err { - Error::InvalidCertificateEncoding => { - common.send_fatal_alert(AlertDescription::DecodeError); - } - Error::PeerMisbehavedError(_) => { - common.send_fatal_alert(AlertDescription::IllegalParameter); - } - _ => { - common.send_fatal_alert(AlertDescription::BadCertificate); - } - }; - - err -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/tls12.rs b/third_party/rustls-fork-shadow-tls/src/client/tls12.rs deleted file mode 100644 index 2956e28..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/tls12.rs +++ /dev/null @@ -1,1127 +0,0 @@ -use crate::check::{inappropriate_handshake_message, inappropriate_message}; -use crate::conn::{CommonState, ConnectionRandoms, Side, State}; -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::hash_hs::HandshakeHash; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::base::{Payload, PayloadU8}; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::Codec; -use crate::msgs::enums::AlertDescription; -use crate::msgs::enums::{ContentType, HandshakeType}; -use crate::msgs::handshake::{ - CertificatePayload, DecomposedSignatureScheme, DigitallySignedStruct, HandshakeMessagePayload, - HandshakePayload, NewSessionTicketPayload, SCTList, ServerECDHParams, SessionID, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::sign::Signer; -#[cfg(feature = "secret_extraction")] -use crate::suites::PartiallyExtractedSecrets; -use crate::suites::SupportedCipherSuite; -use crate::ticketer::TimeBase; -use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; -use crate::{kx, verify}; - -use super::client_conn::ClientConnectionData; -use super::hs::ClientContext; -use crate::client::common::ClientAuthDetails; -use crate::client::common::ServerCertDetails; -use crate::client::{hs, ClientConfig, ServerName}; - -use ring::agreement::PublicKey; -use ring::constant_time; - -use std::sync::Arc; - -pub(super) use server_hello::CompleteServerHelloHandling; - -mod server_hello { - use crate::msgs::enums::ExtensionType; - use crate::msgs::handshake::HasServerExtensions; - use crate::msgs::handshake::ServerHelloPayload; - - use super::*; - - pub(in crate::client) struct CompleteServerHelloHandling { - pub(in crate::client) config: Arc, - pub(in crate::client) resuming_session: Option, - pub(in crate::client) server_name: ServerName, - pub(in crate::client) randoms: ConnectionRandoms, - pub(in crate::client) using_ems: bool, - pub(in crate::client) transcript: HandshakeHash, - } - - impl CompleteServerHelloHandling { - pub(in crate::client) fn handle_server_hello( - mut self, - cx: &mut ClientContext, - suite: &'static Tls12CipherSuite, - server_hello: &ServerHelloPayload, - tls13_supported: bool, - ) -> hs::NextStateOrError { - server_hello - .random - .write_slice(&mut self.randoms.server); - - // Look for TLS1.3 downgrade signal in server random - // both the server random and TLS12_DOWNGRADE_SENTINEL are - // public values and don't require constant time comparison - let has_downgrade_marker = self.randoms.server[24..] == tls12::DOWNGRADE_SENTINEL; - if tls13_supported && has_downgrade_marker { - return Err(cx - .common - .illegal_param("downgrade to TLS1.2 when TLS1.3 is supported")); - } - - // Doing EMS? - self.using_ems = server_hello.ems_support_acked(); - - // Might the server send a ticket? - let must_issue_new_ticket = if server_hello - .find_extension(ExtensionType::SessionTicket) - .is_some() - { - debug!("Server supports tickets"); - true - } else { - false - }; - - // Might the server send a CertificateStatus between Certificate and - // ServerKeyExchange? - let may_send_cert_status = server_hello - .find_extension(ExtensionType::StatusRequest) - .is_some(); - if may_send_cert_status { - debug!("Server may staple OCSP response"); - } - - // Save any sent SCTs for verification against the certificate. - let server_cert_sct_list = if let Some(sct_list) = server_hello.get_sct_list() { - debug!("Server sent {:?} SCTs", sct_list.len()); - - if hs::sct_list_is_invalid(sct_list) { - let error_msg = "server sent invalid SCT list".to_string(); - return Err(Error::PeerMisbehavedError(error_msg)); - } - Some(sct_list.clone()) - } else { - None - }; - - // See if we're successfully resuming. - if let Some(ref resuming) = self.resuming_session { - if resuming.session_id == server_hello.session_id { - debug!("Server agreed to resume"); - - // Is the server telling lies about the ciphersuite? - if resuming.suite() != suite { - let error_msg = - "abbreviated handshake offered, but with varied cs".to_string(); - return Err(Error::PeerMisbehavedError(error_msg)); - } - - // And about EMS support? - if resuming.extended_ms() != self.using_ems { - let error_msg = "server varied ems support over resume".to_string(); - return Err(Error::PeerMisbehavedError(error_msg)); - } - - let secrets = - ConnectionSecrets::new_resume(self.randoms, suite, resuming.secret()); - self.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Client); - - // Since we're resuming, we verified the certificate and - // proof of possession in the prior session. - cx.common.peer_certificates = Some(resuming.server_cert_chain().to_vec()); - let cert_verified = verify::ServerCertVerified::assertion(); - let sig_verified = verify::HandshakeSignatureValid::assertion(); - - return if must_issue_new_ticket { - Ok(Box::new(ExpectNewTicket { - config: self.config, - secrets, - resuming_session: self.resuming_session, - session_id: server_hello.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - resuming: true, - cert_verified, - sig_verified, - })) - } else { - Ok(Box::new(ExpectCcs { - config: self.config, - secrets, - resuming_session: self.resuming_session, - session_id: server_hello.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - ticket: None, - resuming: true, - cert_verified, - sig_verified, - })) - }; - } - } - - Ok(Box::new(ExpectCertificate { - config: self.config, - resuming_session: self.resuming_session, - session_id: server_hello.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite, - may_send_cert_status, - must_issue_new_ticket, - server_cert_sct_list, - })) - } - } -} - -struct ExpectCertificate { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - pub(super) suite: &'static Tls12CipherSuite, - may_send_cert_status: bool, - must_issue_new_ticket: bool, - server_cert_sct_list: Option, -} - -impl State for ExpectCertificate { - fn handle( - mut self: Box, - _cx: &mut ClientContext<'_>, - m: Message, - ) -> hs::NextStateOrError { - self.transcript.add_message(&m); - let server_cert_chain = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::Certificate - )?; - - if self.may_send_cert_status { - Ok(Box::new(ExpectCertificateStatusOrServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_sct_list: self.server_cert_sct_list, - server_cert_chain, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } else { - let server_cert = - ServerCertDetails::new(server_cert_chain, vec![], self.server_cert_sct_list); - - Ok(Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } - } -} - -struct ExpectCertificateStatusOrServerKx { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert_sct_list: Option, - server_cert_chain: CertificatePayload, - must_issue_new_ticket: bool, -} - -impl State for ExpectCertificateStatusOrServerKx { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::ServerKeyExchange(..), - .. - }, - .. - } => Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: ServerCertDetails::new( - self.server_cert_chain, - vec![], - self.server_cert_sct_list, - ), - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::CertificateStatus(..), - .. - }, - .. - } => Box::new(ExpectCertificateStatus { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_sct_list: self.server_cert_sct_list, - server_cert_chain: self.server_cert_chain, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::ServerKeyExchange, - HandshakeType::CertificateStatus, - ], - )), - } - } -} - -struct ExpectCertificateStatus { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert_sct_list: Option, - server_cert_chain: CertificatePayload, - must_issue_new_ticket: bool, -} - -impl State for ExpectCertificateStatus { - fn handle( - mut self: Box, - _cx: &mut ClientContext<'_>, - m: Message, - ) -> hs::NextStateOrError { - self.transcript.add_message(&m); - let server_cert_ocsp_response = require_handshake_msg_move!( - m, - HandshakeType::CertificateStatus, - HandshakePayload::CertificateStatus - )? - .into_inner(); - - trace!( - "Server stapled OCSP response is {:?}", - &server_cert_ocsp_response - ); - - let server_cert = ServerCertDetails::new( - self.server_cert_chain, - server_cert_ocsp_response, - self.server_cert_sct_list, - ); - - Ok(Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } -} - -struct ExpectServerKx { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails, - must_issue_new_ticket: bool, -} - -impl State for ExpectServerKx { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let opaque_kx = require_handshake_msg!( - m, - HandshakeType::ServerKeyExchange, - HandshakePayload::ServerKeyExchange - )?; - self.transcript.add_message(&m); - - let ecdhe = opaque_kx - .unwrap_given_kxa(&self.suite.kx) - .ok_or_else(|| { - cx.common - .send_fatal_alert(AlertDescription::DecodeError); - Error::CorruptMessagePayload(ContentType::Handshake) - })?; - - // Save the signature and signed parameters for later verification. - let mut kx_params = Vec::new(); - ecdhe.params.encode(&mut kx_params); - let server_kx = ServerKxDetails::new(kx_params, ecdhe.dss); - - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - { - debug!("ECDHE curve is {:?}", ecdhe.params.curve_params); - } - - Ok(Box::new(ExpectServerDoneOrCertReq { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } -} - -fn emit_certificate( - transcript: &mut HandshakeHash, - cert_chain: CertificatePayload, - common: &mut CommonState, -) { - let cert = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::Certificate(cert_chain), - }), - }; - - transcript.add_message(&cert); - common.send_msg(cert, false); -} - -fn emit_clientkx(transcript: &mut HandshakeHash, common: &mut CommonState, pubkey: &PublicKey) { - let mut buf = Vec::new(); - let ecpoint = PayloadU8::new(Vec::from(pubkey.as_ref())); - ecpoint.encode(&mut buf); - let pubkey = Payload::new(buf); - - let ckx = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ClientKeyExchange, - payload: HandshakePayload::ClientKeyExchange(pubkey), - }), - }; - - transcript.add_message(&ckx); - common.send_msg(ckx, false); -} - -fn emit_certverify( - transcript: &mut HandshakeHash, - signer: &dyn Signer, - common: &mut CommonState, -) -> Result<(), Error> { - let message = transcript - .take_handshake_buf() - .ok_or_else(|| Error::General("Expected transcript".to_owned()))?; - - let scheme = signer.scheme(); - let sig = signer.sign(&message)?; - let body = DigitallySignedStruct::new(scheme, sig); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateVerify, - payload: HandshakePayload::CertificateVerify(body), - }), - }; - - transcript.add_message(&m); - common.send_msg(m, false); - Ok(()) -} - -fn emit_ccs(common: &mut CommonState) { - let ccs = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - - common.send_msg(ccs, false); -} - -fn emit_finished( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - common: &mut CommonState, -) { - let vh = transcript.get_current_hash(); - let verify_data = secrets.client_verify_data(&vh); - let verify_data_payload = Payload::new(verify_data); - - let f = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(verify_data_payload), - }), - }; - - transcript.add_message(&f); - common.send_msg(f, true); -} - -struct ServerKxDetails { - kx_params: Vec, - kx_sig: DigitallySignedStruct, -} - -impl ServerKxDetails { - fn new(params: Vec, sig: DigitallySignedStruct) -> Self { - Self { - kx_params: params, - kx_sig: sig, - } - } -} - -// --- Either a CertificateRequest, or a ServerHelloDone. --- -// Existence of the CertificateRequest tells us the server is asking for -// client auth. Otherwise we go straight to ServerHelloDone. -struct ExpectServerDoneOrCertReq { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails, - server_kx: ServerKxDetails, - must_issue_new_ticket: bool, -} - -impl State for ExpectServerDoneOrCertReq { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - if matches!( - m.payload, - MessagePayload::Handshake { - parsed: HandshakeMessagePayload { - payload: HandshakePayload::CertificateRequest(_), - .. - }, - .. - } - ) { - Box::new(ExpectCertificateRequest { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m) - } else { - self.transcript.abandon_client_auth(); - - Box::new(ExpectServerDone { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - client_auth: None, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m) - } - } -} - -struct ExpectCertificateRequest { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails, - server_kx: ServerKxDetails, - must_issue_new_ticket: bool, -} - -impl State for ExpectCertificateRequest { - fn handle( - mut self: Box, - _cx: &mut ClientContext<'_>, - m: Message, - ) -> hs::NextStateOrError { - let certreq = require_handshake_msg!( - m, - HandshakeType::CertificateRequest, - HandshakePayload::CertificateRequest - )?; - self.transcript.add_message(&m); - debug!("Got CertificateRequest {:?}", certreq); - - // The RFC jovially describes the design here as 'somewhat complicated' - // and 'somewhat underspecified'. So thanks for that. - // - // We ignore certreq.certtypes as a result, since the information it contains - // is entirely duplicated in certreq.sigschemes. - - const NO_CONTEXT: Option> = None; // TLS 1.2 doesn't use a context. - let client_auth = ClientAuthDetails::resolve( - self.config - .client_auth_cert_resolver - .as_ref(), - Some(&certreq.canames), - &certreq.sigschemes, - NO_CONTEXT, - ); - - Ok(Box::new(ExpectServerDone { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - client_auth: Some(client_auth), - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } -} - -struct ExpectServerDone { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails, - server_kx: ServerKxDetails, - client_auth: Option, - must_issue_new_ticket: bool, -} - -impl State for ExpectServerDone { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::ServerHelloDone, - .. - }, - .. - } => {} - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[HandshakeType::ServerHelloDone], - )); - } - } - - let mut st = *self; - st.transcript.add_message(&m); - - cx.common.check_aligned_handshake()?; - - trace!("Server cert is {:?}", st.server_cert.cert_chain); - debug!("Server DNS name is {:?}", st.server_name); - - let suite = st.suite; - - // 1. Verify the cert chain. - // 2. Verify any SCTs provided with the certificate. - // 3. Verify that the top certificate signed their kx. - // 4. If doing client auth, send our Certificate. - // 5. Complete the key exchange: - // a) generate our kx pair - // b) emit a ClientKeyExchange containing it - // c) if doing client auth, emit a CertificateVerify - // d) emit a CCS - // e) derive the shared keys, and start encryption - // 6. emit a Finished, our first encrypted message under the new keys. - - // 1. - let (end_entity, intermediates) = st - .server_cert - .cert_chain - .split_first() - .ok_or(Error::NoCertificatesPresented)?; - let now = std::time::SystemTime::now(); - let cert_verified = st - .config - .verifier - .verify_server_cert( - end_entity, - intermediates, - &st.server_name, - &mut st.server_cert.scts(), - &st.server_cert.ocsp_response, - now, - ) - .map_err(|err| hs::send_cert_error_alert(cx.common, err))?; - - // 3. - // Build up the contents of the signed message. - // It's ClientHello.random || ServerHello.random || ServerKeyExchange.params - let sig_verified = { - let mut message = Vec::new(); - message.extend_from_slice(&st.randoms.client); - message.extend_from_slice(&st.randoms.server); - message.extend_from_slice(&st.server_kx.kx_params); - - // Check the signature is compatible with the ciphersuite. - let sig = &st.server_kx.kx_sig; - if !SupportedCipherSuite::from(suite).usable_for_signature_algorithm(sig.scheme.sign()) - { - let error_message = format!( - "peer signed kx with wrong algorithm (got {:?} expect {:?})", - sig.scheme.sign(), - suite.sign - ); - return Err(Error::PeerMisbehavedError(error_message)); - } - - st.config - .verifier - .verify_tls12_signature(&message, &st.server_cert.cert_chain[0], sig) - .map_err(|err| hs::send_cert_error_alert(cx.common, err))? - }; - cx.common.peer_certificates = Some(st.server_cert.cert_chain); - - // 4. - if let Some(client_auth) = &st.client_auth { - let certs = match client_auth { - ClientAuthDetails::Empty { .. } => Vec::new(), - ClientAuthDetails::Verify { certkey, .. } => certkey.cert.clone(), - }; - emit_certificate(&mut st.transcript, certs, cx.common); - } - - // 5a. - let ecdh_params = - tls12::decode_ecdh_params::(cx.common, &st.server_kx.kx_params)?; - let group = - kx::KeyExchange::choose(ecdh_params.curve_params.named_group, &st.config.kx_groups) - .ok_or_else(|| { - Error::PeerMisbehavedError("peer chose an unsupported group".to_string()) - })?; - let eager_key_index = cx - .data - .tls12_eager_key_exchanges - .iter() - .position(|kx| kx.group() == group.name); - let kx = if let Some(index) = eager_key_index { - cx.data.tls12_eager_key_exchanges.swap_remove(index) - } else { - kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)? - }; - - // 5b. - let mut transcript = st.transcript; - emit_clientkx(&mut transcript, cx.common, &kx.pubkey); - // nb. EMS handshake hash only runs up to ClientKeyExchange. - let ems_seed = st - .using_ems - .then(|| transcript.get_current_hash()); - - // 5c. - if let Some(ClientAuthDetails::Verify { signer, .. }) = &st.client_auth { - emit_certverify(&mut transcript, signer.as_ref(), cx.common)?; - } - - // 5d. - emit_ccs(cx.common); - - // 5e. Now commit secrets. - let secrets = ConnectionSecrets::from_key_exchange( - kx, - &ecdh_params.public.0, - ems_seed, - st.randoms, - suite, - )?; - - st.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Client); - cx.common - .record_layer - .start_encrypting(); - - // 6. - emit_finished(&secrets, &mut transcript, cx.common); - - if st.must_issue_new_ticket { - Ok(Box::new(ExpectNewTicket { - config: st.config, - secrets, - resuming_session: st.resuming_session, - session_id: st.session_id, - server_name: st.server_name, - using_ems: st.using_ems, - transcript, - resuming: false, - cert_verified, - sig_verified, - })) - } else { - Ok(Box::new(ExpectCcs { - config: st.config, - secrets, - resuming_session: st.resuming_session, - session_id: st.session_id, - server_name: st.server_name, - using_ems: st.using_ems, - transcript, - ticket: None, - resuming: false, - cert_verified, - sig_verified, - })) - } - } -} - -struct ExpectNewTicket { - config: Arc, - secrets: ConnectionSecrets, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - using_ems: bool, - transcript: HandshakeHash, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl State for ExpectNewTicket { - fn handle( - mut self: Box, - _cx: &mut ClientContext<'_>, - m: Message, - ) -> hs::NextStateOrError { - self.transcript.add_message(&m); - - let nst = require_handshake_msg_move!( - m, - HandshakeType::NewSessionTicket, - HandshakePayload::NewSessionTicket - )?; - - Ok(Box::new(ExpectCcs { - config: self.config, - secrets: self.secrets, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - ticket: Some(nst), - resuming: self.resuming, - cert_verified: self.cert_verified, - sig_verified: self.sig_verified, - })) - } -} - -// -- Waiting for their CCS -- -struct ExpectCcs { - config: Arc, - secrets: ConnectionSecrets, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - using_ems: bool, - transcript: HandshakeHash, - ticket: Option, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl State for ExpectCcs { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ChangeCipherSpec(..) => {} - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ChangeCipherSpec], - )); - } - } - // CCS should not be received interleaved with fragmented handshake-level - // message. - cx.common.check_aligned_handshake()?; - - // nb. msgs layer validates trivial contents of CCS - cx.common - .record_layer - .start_decrypting(); - - Ok(Box::new(ExpectFinished { - config: self.config, - secrets: self.secrets, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - ticket: self.ticket, - resuming: self.resuming, - cert_verified: self.cert_verified, - sig_verified: self.sig_verified, - })) - } -} - -struct ExpectFinished { - config: Arc, - resuming_session: Option, - session_id: SessionID, - server_name: ServerName, - using_ems: bool, - transcript: HandshakeHash, - ticket: Option, - secrets: ConnectionSecrets, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl ExpectFinished { - // -- Waiting for their finished -- - fn save_session(&mut self, cx: &mut ClientContext<'_>) { - // Save a ticket. If we got a new ticket, save that. Otherwise, save the - // original ticket again. - let (mut ticket, lifetime) = match self.ticket.take() { - Some(nst) => (nst.ticket.0, nst.lifetime_hint), - None => (Vec::new(), 0), - }; - - if ticket.is_empty() { - if let Some(resuming_session) = &mut self.resuming_session { - ticket = resuming_session.take_ticket(); - } - } - - if self.session_id.is_empty() && ticket.is_empty() { - debug!("Session not saved: server didn't allocate id or ticket"); - return; - } - - let time_now = match TimeBase::now() { - Ok(time_now) => time_now, - #[allow(unused_variables)] - Err(e) => { - debug!("Session not saved: {}", e); - return; - } - }; - - let key = persist::ClientSessionKey::session_for_server_name(&self.server_name); - let value = persist::Tls12ClientSessionValue::new( - self.secrets.suite(), - self.session_id, - ticket, - self.secrets.get_master_secret(), - cx.common - .peer_certificates - .clone() - .unwrap_or_default(), - time_now, - lifetime, - self.using_ems, - ); - - let worked = self - .config - .session_storage - .put(key.get_encoding(), value.get_encoding()); - - if worked { - debug!("Session saved"); - } else { - debug!("Session not saved"); - } - } -} - -impl State for ExpectFinished { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let mut st = *self; - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - cx.common.check_aligned_handshake()?; - - // Work out what verify_data we expect. - let vh = st.transcript.get_current_hash(); - let expect_verify_data = st.secrets.server_verify_data(&vh); - - // Constant-time verification of this is relatively unimportant: they only - // get one chance. But it can't hurt. - let _fin_verified = - constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) - .map_err(|_| { - cx.common - .send_fatal_alert(AlertDescription::DecryptError); - Error::DecryptError - }) - .map(|_| verify::FinishedMessageVerified::assertion())?; - - // Hash this message too. - st.transcript.add_message(&m); - - st.save_session(cx); - - if st.resuming { - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&st.secrets, &mut st.transcript, cx.common); - } - - cx.common.start_traffic(); - Ok(Box::new(ExpectTraffic { - secrets: st.secrets, - _cert_verified: st.cert_verified, - _sig_verified: st.sig_verified, - _fin_verified, - })) - } -} - -// -- Traffic transit state -- -struct ExpectTraffic { - secrets: ConnectionSecrets, - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} - -impl State for ExpectTraffic { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ApplicationData], - )); - } - } - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.secrets - .export_keying_material(output, label, context); - Ok(()) - } - - #[cfg(feature = "secret_extraction")] - fn extract_secrets(&self) -> Result { - self.secrets - .extract_secrets(Side::Client) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/client/tls13.rs b/third_party/rustls-fork-shadow-tls/src/client/tls13.rs deleted file mode 100644 index 4c118bb..0000000 --- a/third_party/rustls-fork-shadow-tls/src/client/tls13.rs +++ /dev/null @@ -1,1191 +0,0 @@ -use crate::check::inappropriate_handshake_message; -use crate::conn::{CommonState, ConnectionRandoms, State}; -use crate::enums::{ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; -use crate::kx; -#[cfg(feature = "logging")] -use crate::log::{debug, trace, warn}; -use crate::msgs::base::{Payload, PayloadU8}; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::Codec; -use crate::msgs::enums::KeyUpdateRequest; -use crate::msgs::enums::{AlertDescription, NamedGroup}; -use crate::msgs::enums::{ContentType, ExtensionType, HandshakeType}; -use crate::msgs::handshake::ClientExtension; -use crate::msgs::handshake::DigitallySignedStruct; -use crate::msgs::handshake::EncryptedExtensions; -use crate::msgs::handshake::NewSessionTicketPayloadTLS13; -use crate::msgs::handshake::{CertificateEntry, CertificatePayloadTLS13}; -use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; -use crate::msgs::handshake::{HasServerExtensions, ServerHelloPayload}; -use crate::msgs::handshake::{PresharedKeyIdentity, PresharedKeyOffer}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::tls13::key_schedule::{ - KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, KeyScheduleTraffic, -}; -use crate::tls13::Tls13CipherSuite; -use crate::verify; -#[cfg(feature = "quic")] -use crate::{conn::Protocol, msgs::base::PayloadU16, quic}; -#[cfg(feature = "secret_extraction")] -use crate::{conn::Side, suites::PartiallyExtractedSecrets}; -use crate::{sign, KeyLog}; - -use super::client_conn::ClientConnectionData; -use super::hs::ClientContext; -use crate::client::common::ServerCertDetails; -use crate::client::common::{ClientAuthDetails, ClientHelloDetails}; -use crate::client::{hs, ClientConfig, ServerName, StoresClientSessions}; - -use crate::ticketer::TimeBase; -use ring::constant_time; - -use crate::sign::{CertifiedKey, Signer}; -use std::sync::Arc; - -// Extensions we expect in plaintext in the ServerHello. -static ALLOWED_PLAINTEXT_EXTS: &[ExtensionType] = &[ - ExtensionType::KeyShare, - ExtensionType::PreSharedKey, - ExtensionType::SupportedVersions, -]; - -// Only the intersection of things we offer, and those disallowed -// in TLS1.3 -static DISALLOWED_TLS13_EXTS: &[ExtensionType] = &[ - ExtensionType::ECPointFormats, - ExtensionType::SessionTicket, - ExtensionType::RenegotiationInfo, - ExtensionType::ExtendedMasterSecret, -]; - -pub(super) fn handle_server_hello( - config: Arc, - cx: &mut ClientContext, - server_hello: &ServerHelloPayload, - mut resuming_session: Option, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - early_key_schedule: Option, - hello: ClientHelloDetails, - our_key_share: kx::KeyExchange, - mut sent_tls13_fake_ccs: bool, -) -> hs::NextStateOrError { - validate_server_hello(cx.common, server_hello)?; - - let their_key_share = server_hello - .get_key_share() - .ok_or_else(|| { - cx.common - .send_fatal_alert(AlertDescription::MissingExtension); - Error::PeerMisbehavedError("missing key share".to_string()) - })?; - - if our_key_share.group() != their_key_share.group { - return Err(cx - .common - .illegal_param("wrong group for key share")); - } - - let key_schedule_pre_handshake = if let (Some(selected_psk), Some(early_key_schedule)) = - (server_hello.get_psk_index(), early_key_schedule) - { - if let Some(ref resuming) = resuming_session { - let resuming_suite = match suite.can_resume_from(resuming.suite()) { - Some(resuming) => resuming, - None => { - return Err(cx - .common - .illegal_param("server resuming incompatible suite")); - } - }; - - // If the server varies the suite here, we will have encrypted early data with - // the wrong suite. - if cx.data.early_data.is_enabled() && resuming_suite != suite { - return Err(cx - .common - .illegal_param("server varied suite with early data")); - } - - if selected_psk != 0 { - return Err(cx - .common - .illegal_param("server selected invalid psk")); - } - - debug!("Resuming using PSK"); - // The key schedule has been initialized and set in fill_in_psk_binder() - } else { - return Err(Error::PeerMisbehavedError( - "server selected unoffered psk".to_string(), - )); - } - KeySchedulePreHandshake::from(early_key_schedule) - } else { - debug!("Not resuming"); - // Discard the early data key schedule. - cx.data.early_data.rejected(); - cx.common.early_traffic = false; - resuming_session.take(); - KeySchedulePreHandshake::new(suite.hkdf_algorithm) - }; - - let key_schedule = our_key_share.complete(&their_key_share.payload.0, |secret| { - Ok(key_schedule_pre_handshake.into_handshake(secret)) - })?; - - // Remember what KX group the server liked for next time. - save_kx_hint(&config, &server_name, their_key_share.group); - - // If we change keying when a subsequent handshake message is being joined, - // the two halves will have different record layer protections. Disallow this. - cx.common.check_aligned_handshake()?; - - let hash_at_client_recvd_server_hello = transcript.get_current_hash(); - - let (key_schedule, client_key, server_key) = key_schedule.derive_handshake_secrets( - hash_at_client_recvd_server_hello, - &*config.key_log, - &randoms.client, - ); - - // Decrypt with the peer's key, encrypt with our own key - cx.common - .record_layer - .set_message_decrypter(suite.derive_decrypter(&server_key)); - - if !cx.data.early_data.is_enabled() { - // Set the client encryption key for handshakes if early data is not used - cx.common - .record_layer - .set_message_encrypter(suite.derive_encrypter(&client_key)); - } - - #[cfg(feature = "quic")] - if cx.common.is_quic() { - cx.common.quic.hs_secrets = Some(quic::Secrets::new(client_key, server_key, suite, true)); - } - - emit_fake_ccs(&mut sent_tls13_fake_ccs, cx.common); - - Ok(Box::new(ExpectEncryptedExtensions { - config, - resuming_session, - server_name, - randoms, - suite, - transcript, - key_schedule, - hello, - })) -} - -fn validate_server_hello( - common: &mut CommonState, - server_hello: &ServerHelloPayload, -) -> Result<(), Error> { - for ext in &server_hello.extensions { - if !ALLOWED_PLAINTEXT_EXTS.contains(&ext.get_type()) { - common.send_fatal_alert(AlertDescription::UnsupportedExtension); - return Err(Error::PeerMisbehavedError( - "server sent unexpected cleartext ext".to_string(), - )); - } - } - - Ok(()) -} - -pub(super) fn initial_key_share( - config: &ClientConfig, - server_name: &ServerName, -) -> Result { - let key = persist::ClientSessionKey::hint_for_server_name(server_name); - let key_buf = key.get_encoding(); - - let maybe_value = config.session_storage.get(&key_buf); - - let group = maybe_value - .and_then(|enc| NamedGroup::read_bytes(&enc)) - .and_then(|group| kx::KeyExchange::choose(group, &config.kx_groups)) - .unwrap_or_else(|| { - config - .kx_groups - .first() - .expect("No kx groups configured") - }); - - kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes) -} - -fn save_kx_hint(config: &ClientConfig, server_name: &ServerName, group: NamedGroup) { - let key = persist::ClientSessionKey::hint_for_server_name(server_name); - - config - .session_storage - .put(key.get_encoding(), group.get_encoding()); -} - -/// This implements the horrifying TLS1.3 hack where PSK binders have a -/// data dependency on the message they are contained within. -pub(super) fn fill_in_psk_binder( - resuming: &persist::Tls13ClientSessionValue, - transcript: &HandshakeHashBuffer, - hmp: &mut HandshakeMessagePayload, -) -> KeyScheduleEarly { - // We need to know the hash function of the suite we're trying to resume into. - let hkdf_alg = resuming.suite().hkdf_algorithm; - let suite_hash = resuming.suite().hash_algorithm(); - - // The binder is calculated over the clienthello, but doesn't include itself or its - // length, or the length of its container. - let binder_plaintext = hmp.get_encoding_for_binder_signing(); - let handshake_hash = transcript.get_hash_given(suite_hash, &binder_plaintext); - - // Run a fake key_schedule to simulate what the server will do if it chooses - // to resume. - let key_schedule = KeyScheduleEarly::new(hkdf_alg, resuming.secret()); - let real_binder = key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); - - if let HandshakePayload::ClientHello(ref mut ch) = hmp.payload { - ch.set_psk_binder(real_binder.as_ref()); - }; - - key_schedule -} - -pub(super) fn prepare_resumption( - config: &ClientConfig, - cx: &mut ClientContext<'_>, - ticket: Vec, - resuming_session: &persist::Retrieved<&persist::Tls13ClientSessionValue>, - exts: &mut Vec, - doing_retry: bool, -) { - let resuming_suite = resuming_session.suite(); - cx.common.suite = Some(resuming_suite.into()); - cx.data.resumption_ciphersuite = Some(resuming_suite.into()); - // The EarlyData extension MUST be supplied together with the - // PreSharedKey extension. - let max_early_data_size = resuming_session.max_early_data_size(); - if config.enable_early_data && max_early_data_size > 0 && !doing_retry { - cx.data - .early_data - .enable(max_early_data_size as usize); - exts.push(ClientExtension::EarlyData); - } - - // Finally, and only for TLS1.3 with a ticket resumption, include a binder - // for our ticket. This must go last. - // - // Include an empty binder. It gets filled in below because it depends on - // the message it's contained in (!!!). - let obfuscated_ticket_age = resuming_session.obfuscated_ticket_age(); - - let binder_len = resuming_suite - .hash_algorithm() - .output_len; - let binder = vec![0u8; binder_len]; - - let psk_identity = PresharedKeyIdentity::new(ticket, obfuscated_ticket_age); - let psk_ext = PresharedKeyOffer::new(psk_identity, binder); - exts.push(ClientExtension::PresharedKey(psk_ext)); -} - -pub(super) fn derive_early_traffic_secret( - key_log: &dyn KeyLog, - cx: &mut ClientContext<'_>, - resuming_suite: &'static Tls13CipherSuite, - early_key_schedule: &KeyScheduleEarly, - sent_tls13_fake_ccs: &mut bool, - transcript_buffer: &HandshakeHashBuffer, - client_random: &[u8; 32], -) { - // For middlebox compatibility - emit_fake_ccs(sent_tls13_fake_ccs, cx.common); - - let client_hello_hash = transcript_buffer.get_hash_given(resuming_suite.hash_algorithm(), &[]); - let client_early_traffic_secret = - early_key_schedule.client_early_traffic_secret(&client_hello_hash, key_log, client_random); - // Set early data encryption key - cx.common - .record_layer - .set_message_encrypter(resuming_suite.derive_encrypter(&client_early_traffic_secret)); - - #[cfg(feature = "quic")] - if cx.common.is_quic() { - cx.common.quic.early_secret = Some(client_early_traffic_secret); - } - - // Now the client can send encrypted early data - cx.common.early_traffic = true; - trace!("Starting early data traffic"); -} - -pub(super) fn emit_fake_ccs(sent_tls13_fake_ccs: &mut bool, common: &mut CommonState) { - if common.is_quic() { - return; - } - - if std::mem::replace(sent_tls13_fake_ccs, true) { - return; - } - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - common.send_msg(m, false); -} - -fn validate_encrypted_extensions( - common: &mut CommonState, - hello: &ClientHelloDetails, - exts: &EncryptedExtensions, -) -> Result<(), Error> { - if exts.has_duplicate_extension() { - common.send_fatal_alert(AlertDescription::DecodeError); - return Err(Error::PeerMisbehavedError( - "server sent duplicate encrypted extensions".to_string(), - )); - } - - if hello.server_sent_unsolicited_extensions(exts, &[]) { - common.send_fatal_alert(AlertDescription::UnsupportedExtension); - let msg = "server sent unsolicited encrypted extension".to_string(); - return Err(Error::PeerMisbehavedError(msg)); - } - - for ext in exts { - if ALLOWED_PLAINTEXT_EXTS.contains(&ext.get_type()) - || DISALLOWED_TLS13_EXTS.contains(&ext.get_type()) - { - common.send_fatal_alert(AlertDescription::UnsupportedExtension); - let msg = "server sent inappropriate encrypted extension".to_string(); - return Err(Error::PeerMisbehavedError(msg)); - } - } - - Ok(()) -} - -struct ExpectEncryptedExtensions { - config: Arc, - resuming_session: Option, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - hello: ClientHelloDetails, -} - -impl State for ExpectEncryptedExtensions { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let exts = require_handshake_msg!( - m, - HandshakeType::EncryptedExtensions, - HandshakePayload::EncryptedExtensions - )?; - debug!("TLS1.3 encrypted extensions: {:?}", exts); - self.transcript.add_message(&m); - - validate_encrypted_extensions(cx.common, &self.hello, exts)?; - hs::process_alpn_protocol(cx.common, &self.config, exts.get_alpn_protocol())?; - - #[cfg(feature = "quic")] - { - // QUIC transport parameters - if cx.common.is_quic() { - match exts.get_quic_params_extension() { - Some(params) => cx.common.quic.params = Some(params), - None => { - return Err(cx - .common - .missing_extension("QUIC transport parameters not found")); - } - } - } - } - - if let Some(resuming_session) = self.resuming_session { - let was_early_traffic = cx.common.early_traffic; - if was_early_traffic { - if exts.early_data_extension_offered() { - cx.data.early_data.accepted(); - } else { - cx.data.early_data.rejected(); - cx.common.early_traffic = false; - } - } - - if was_early_traffic && !cx.common.early_traffic { - // If no early traffic, set the encryption key for handshakes - cx.common - .record_layer - .set_message_encrypter( - self.suite - .derive_encrypter(self.key_schedule.client_key()), - ); - } - - cx.common.peer_certificates = Some( - resuming_session - .server_cert_chain() - .to_vec(), - ); - - // We *don't* reverify the certificate chain here: resumption is a - // continuation of the previous session in terms of security policy. - let cert_verified = verify::ServerCertVerified::assertion(); - let sig_verified = verify::HandshakeSignatureValid::assertion(); - Ok(Box::new(ExpectFinished { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: None, - cert_verified, - sig_verified, - })) - } else { - if exts.early_data_extension_offered() { - let msg = "server sent early data extension without resumption".to_string(); - return Err(Error::PeerMisbehavedError(msg)); - } - Ok(Box::new(ExpectCertificateOrCertReq { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - may_send_sct_list: self.hello.server_may_send_sct_list(), - })) - } - } -} - -struct ExpectCertificateOrCertReq { - config: Arc, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - may_send_sct_list: bool, -} - -impl State for ExpectCertificateOrCertReq { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::CertificateTLS13(..), - .. - }, - .. - } => Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - may_send_sct_list: self.may_send_sct_list, - client_auth: None, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::CertificateRequestTLS13(..), - .. - }, - .. - } => Box::new(ExpectCertificateRequest { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - may_send_sct_list: self.may_send_sct_list, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::Certificate, - HandshakeType::CertificateRequest, - ], - )), - } - } -} - -// TLS1.3 version of CertificateRequest handling. We then move to expecting the server -// Certificate. Unfortunately the CertificateRequest type changed in an annoying way -// in TLS1.3. -struct ExpectCertificateRequest { - config: Arc, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - may_send_sct_list: bool, -} - -impl State for ExpectCertificateRequest { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let certreq = &require_handshake_msg!( - m, - HandshakeType::CertificateRequest, - HandshakePayload::CertificateRequestTLS13 - )?; - self.transcript.add_message(&m); - debug!("Got CertificateRequest {:?}", certreq); - - // Fortunately the problems here in TLS1.2 and prior are corrected in - // TLS1.3. - - // Must be empty during handshake. - if !certreq.context.0.is_empty() { - warn!("Server sent non-empty certreq context"); - cx.common - .send_fatal_alert(AlertDescription::DecodeError); - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - - let tls13_sign_schemes = sign::supported_sign_tls13(); - let no_sigschemes = Vec::new(); - let compat_sigschemes = certreq - .get_sigalgs_extension() - .unwrap_or(&no_sigschemes) - .iter() - .cloned() - .filter(|scheme| tls13_sign_schemes.contains(scheme)) - .collect::>(); - - if compat_sigschemes.is_empty() { - cx.common - .send_fatal_alert(AlertDescription::HandshakeFailure); - return Err(Error::PeerIncompatibleError( - "server sent bad certreq schemes".to_string(), - )); - } - - let client_auth = ClientAuthDetails::resolve( - self.config - .client_auth_cert_resolver - .as_ref(), - certreq.get_authorities_extension(), - &compat_sigschemes, - Some(certreq.context.0.clone()), - ); - - Ok(Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - may_send_sct_list: self.may_send_sct_list, - client_auth: Some(client_auth), - })) - } -} - -struct ExpectCertificate { - config: Arc, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - may_send_sct_list: bool, - client_auth: Option, -} - -impl State for ExpectCertificate { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let cert_chain = require_handshake_msg!( - m, - HandshakeType::Certificate, - HandshakePayload::CertificateTLS13 - )?; - self.transcript.add_message(&m); - - // This is only non-empty for client auth. - if !cert_chain.context.0.is_empty() { - warn!("certificate with non-empty context during handshake"); - cx.common - .send_fatal_alert(AlertDescription::DecodeError); - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - - if cert_chain.any_entry_has_duplicate_extension() - || cert_chain.any_entry_has_unknown_extension() - { - warn!("certificate chain contains unsolicited/unknown extension"); - cx.common - .send_fatal_alert(AlertDescription::UnsupportedExtension); - return Err(Error::PeerMisbehavedError( - "bad cert chain extensions".to_string(), - )); - } - - let server_cert = ServerCertDetails::new( - cert_chain.convert(), - cert_chain.get_end_entity_ocsp(), - cert_chain.get_end_entity_scts(), - ); - - if let Some(sct_list) = server_cert.scts.as_ref() { - if hs::sct_list_is_invalid(sct_list) { - let error_msg = "server sent invalid SCT list".to_string(); - return Err(Error::PeerMisbehavedError(error_msg)); - } - - if !self.may_send_sct_list { - let error_msg = "server sent unsolicited SCT list".to_string(); - return Err(Error::PeerMisbehavedError(error_msg)); - } - } - - Ok(Box::new(ExpectCertificateVerify { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - server_cert, - client_auth: self.client_auth, - })) - } -} - -// --- TLS1.3 CertificateVerify --- -struct ExpectCertificateVerify { - config: Arc, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - server_cert: ServerCertDetails, - client_auth: Option, -} - -impl State for ExpectCertificateVerify { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let cert_verify = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - - trace!("Server cert is {:?}", self.server_cert.cert_chain); - - // 1. Verify the certificate chain. - let (end_entity, intermediates) = self - .server_cert - .cert_chain - .split_first() - .ok_or(Error::NoCertificatesPresented)?; - let now = std::time::SystemTime::now(); - let cert_verified = self - .config - .verifier - .verify_server_cert( - end_entity, - intermediates, - &self.server_name, - &mut self.server_cert.scts(), - &self.server_cert.ocsp_response, - now, - ) - .map_err(|err| hs::send_cert_error_alert(cx.common, err))?; - - // 2. Verify their signature on the handshake. - let handshake_hash = self.transcript.get_current_hash(); - let sig_verified = self - .config - .verifier - .verify_tls13_signature( - &verify::construct_tls13_server_verify_message(&handshake_hash), - &self.server_cert.cert_chain[0], - cert_verify, - ) - .map_err(|err| hs::send_cert_error_alert(cx.common, err))?; - - cx.common.peer_certificates = Some(self.server_cert.cert_chain); - self.transcript.add_message(&m); - - Ok(Box::new(ExpectFinished { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: self.client_auth, - cert_verified, - sig_verified, - })) - } -} - -fn emit_certificate_tls13( - transcript: &mut HandshakeHash, - certkey: Option<&CertifiedKey>, - auth_context: Option>, - common: &mut CommonState, -) { - let context = auth_context.unwrap_or_default(); - - let mut cert_payload = CertificatePayloadTLS13 { - context: PayloadU8::new(context), - entries: Vec::new(), - }; - - if let Some(certkey) = certkey { - for cert in &certkey.cert { - cert_payload - .entries - .push(CertificateEntry::new(cert.clone())); - } - } - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::CertificateTLS13(cert_payload), - }), - }; - transcript.add_message(&m); - common.send_msg(m, true); -} - -fn emit_certverify_tls13( - transcript: &mut HandshakeHash, - signer: &dyn Signer, - common: &mut CommonState, -) -> Result<(), Error> { - let message = verify::construct_tls13_client_verify_message(&transcript.get_current_hash()); - - let scheme = signer.scheme(); - let sig = signer.sign(&message)?; - let dss = DigitallySignedStruct::new(scheme, sig); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateVerify, - payload: HandshakePayload::CertificateVerify(dss), - }), - }; - - transcript.add_message(&m); - common.send_msg(m, true); - Ok(()) -} - -fn emit_finished_tls13( - transcript: &mut HandshakeHash, - verify_data: ring::hmac::Tag, - common: &mut CommonState, -) { - let verify_data_payload = Payload::new(verify_data.as_ref()); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(verify_data_payload), - }), - }; - - transcript.add_message(&m); - common.send_msg(m, true); -} - -fn emit_end_of_early_data_tls13(transcript: &mut HandshakeHash, common: &mut CommonState) { - if common.is_quic() { - return; - } - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::EndOfEarlyData, - payload: HandshakePayload::EndOfEarlyData, - }), - }; - - transcript.add_message(&m); - common.send_msg(m, true); -} - -struct ExpectFinished { - config: Arc, - server_name: ServerName, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - client_auth: Option, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl State for ExpectFinished { - fn handle(self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let mut st = *self; - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - let handshake_hash = st.transcript.get_current_hash(); - let expect_verify_data = st - .key_schedule - .sign_server_finish(&handshake_hash); - - let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0) - .map_err(|_| { - cx.common - .send_fatal_alert(AlertDescription::DecryptError); - Error::DecryptError - }) - .map(|_| verify::FinishedMessageVerified::assertion())?; - - st.transcript.add_message(&m); - - let hash_after_handshake = st.transcript.get_current_hash(); - /* The EndOfEarlyData message to server is still encrypted with early data keys, - * but appears in the transcript after the server Finished. */ - if cx.common.early_traffic { - emit_end_of_early_data_tls13(&mut st.transcript, cx.common); - cx.common.early_traffic = false; - cx.data.early_data.finished(); - cx.common - .record_layer - .set_message_encrypter( - st.suite - .derive_encrypter(st.key_schedule.client_key()), - ); - } - - /* Send our authentication/finished messages. These are still encrypted - * with our handshake keys. */ - if let Some(client_auth) = st.client_auth { - match client_auth { - ClientAuthDetails::Empty { - auth_context_tls13: auth_context, - } => { - emit_certificate_tls13(&mut st.transcript, None, auth_context, cx.common); - } - ClientAuthDetails::Verify { - certkey, - signer, - auth_context_tls13: auth_context, - } => { - emit_certificate_tls13( - &mut st.transcript, - Some(&certkey), - auth_context, - cx.common, - ); - emit_certverify_tls13(&mut st.transcript, signer.as_ref(), cx.common)?; - } - } - } - - let (key_schedule_finished, client_key, server_key) = st - .key_schedule - .into_traffic_with_client_finished_pending( - hash_after_handshake, - &*st.config.key_log, - &st.randoms.client, - ); - let handshake_hash = st.transcript.get_current_hash(); - let (key_schedule_traffic, verify_data, _) = - key_schedule_finished.sign_client_finish(&handshake_hash); - emit_finished_tls13(&mut st.transcript, verify_data, cx.common); - - /* Now move to our application traffic keys. */ - cx.common.check_aligned_handshake()?; - - cx.common - .record_layer - .set_message_decrypter(st.suite.derive_decrypter(&server_key)); - - cx.common - .record_layer - .set_message_encrypter(st.suite.derive_encrypter(&client_key)); - - cx.common.start_traffic(); - - let st = ExpectTraffic { - session_storage: Arc::clone(&st.config.session_storage), - server_name: st.server_name, - suite: st.suite, - transcript: st.transcript, - key_schedule: key_schedule_traffic, - want_write_key_update: false, - _cert_verified: st.cert_verified, - _sig_verified: st.sig_verified, - _fin_verified: fin, - }; - - #[cfg(feature = "quic")] - { - if cx.common.protocol == Protocol::Quic { - cx.common.quic.traffic_secrets = - Some(quic::Secrets::new(client_key, server_key, st.suite, true)); - return Ok(Box::new(ExpectQuicTraffic(st))); - } - } - - Ok(Box::new(st)) - } -} - -// -- Traffic transit state (TLS1.3) -- -// In this state we can be sent tickets, key updates, -// and application data. -struct ExpectTraffic { - session_storage: Arc, - server_name: ServerName, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleTraffic, - want_write_key_update: bool, - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic { - #[allow(clippy::unnecessary_wraps)] // returns Err for #[cfg(feature = "quic")] - fn handle_new_ticket_tls13( - &mut self, - cx: &mut ClientContext<'_>, - nst: &NewSessionTicketPayloadTLS13, - ) -> Result<(), Error> { - if nst.has_duplicate_extension() { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter); - return Err(Error::PeerMisbehavedError( - "peer sent duplicate NewSessionTicket extensions".into(), - )); - } - - let handshake_hash = self.transcript.get_current_hash(); - let secret = self - .key_schedule - .resumption_master_secret_and_derive_ticket_psk(&handshake_hash, &nst.nonce.0); - - let time_now = match TimeBase::now() { - Ok(t) => t, - #[allow(unused_variables)] - Err(e) => { - debug!("Session not saved: {}", e); - return Ok(()); - } - }; - - let value = persist::Tls13ClientSessionValue::new( - self.suite, - nst.ticket.0.clone(), - secret, - cx.common - .peer_certificates - .clone() - .unwrap_or_default(), - time_now, - nst.lifetime, - nst.age_add, - nst.get_max_early_data_size() - .unwrap_or_default(), - ); - - #[cfg(feature = "quic")] - if let Some(sz) = nst.get_max_early_data_size() { - if cx.common.protocol == Protocol::Quic && sz != 0 && sz != 0xffff_ffff { - return Err(Error::PeerMisbehavedError( - "invalid max_early_data_size".into(), - )); - } - } - - let key = persist::ClientSessionKey::session_for_server_name(&self.server_name); - #[allow(unused_mut)] - let mut ticket = value.get_encoding(); - - #[cfg(feature = "quic")] - if let (Protocol::Quic, Some(ref quic_params)) = - (cx.common.protocol, &cx.common.quic.params) - { - PayloadU16::encode_slice(quic_params, &mut ticket); - } - - let worked = self - .session_storage - .put(key.get_encoding(), ticket); - - if worked { - debug!("Ticket saved"); - } else { - debug!("Ticket not saved"); - } - Ok(()) - } - - fn handle_key_update( - &mut self, - common: &mut CommonState, - kur: &KeyUpdateRequest, - ) -> Result<(), Error> { - #[cfg(feature = "quic")] - { - if let Protocol::Quic = common.protocol { - common.send_fatal_alert(AlertDescription::UnexpectedMessage); - let msg = "KeyUpdate received in QUIC connection".to_string(); - warn!("{}", msg); - return Err(Error::PeerMisbehavedError(msg)); - } - } - - // Mustn't be interleaved with other handshake messages. - common.check_aligned_handshake()?; - - match kur { - KeyUpdateRequest::UpdateNotRequested => {} - KeyUpdateRequest::UpdateRequested => { - self.want_write_key_update = true; - } - _ => { - common.send_fatal_alert(AlertDescription::IllegalParameter); - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - } - - // Update our read-side keys. - let new_read_key = self - .key_schedule - .next_server_application_traffic_secret(); - common - .record_layer - .set_message_decrypter( - self.suite - .derive_decrypter(&new_read_key), - ); - - Ok(()) - } -} - -impl State for ExpectTraffic { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::NewSessionTicketTLS13(ref new_ticket), - .. - }, - .. - } => self.handle_new_ticket_tls13(cx, new_ticket)?, - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::KeyUpdate(ref key_update), - .. - }, - .. - } => self.handle_key_update(cx.common, key_update)?, - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::NewSessionTicket, HandshakeType::KeyUpdate], - )); - } - } - - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } - - fn perhaps_write_key_update(&mut self, common: &mut CommonState) { - if self.want_write_key_update { - self.want_write_key_update = false; - common.send_msg_encrypt(Message::build_key_update_notify().into()); - - let write_key = self - .key_schedule - .next_client_application_traffic_secret(); - common - .record_layer - .set_message_encrypter(self.suite.derive_encrypter(&write_key)); - } - } - - #[cfg(feature = "secret_extraction")] - fn extract_secrets(&self) -> Result { - self.key_schedule - .extract_secrets(self.suite.common.aead_algorithm, Side::Client) - } -} - -#[cfg(feature = "quic")] -struct ExpectQuicTraffic(ExpectTraffic); - -#[cfg(feature = "quic")] -impl State for ExpectQuicTraffic { - fn handle(mut self: Box, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError { - let nst = require_handshake_msg!( - m, - HandshakeType::NewSessionTicket, - HandshakePayload::NewSessionTicketTLS13 - )?; - self.0 - .handle_new_ticket_tls13(cx, nst)?; - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.0 - .export_keying_material(output, label, context) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/conn.rs b/third_party/rustls-fork-shadow-tls/src/conn.rs deleted file mode 100644 index f7d93a8..0000000 --- a/third_party/rustls-fork-shadow-tls/src/conn.rs +++ /dev/null @@ -1,1466 +0,0 @@ -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::key; -#[cfg(feature = "logging")] -use crate::log::{debug, error, trace, warn}; -use crate::msgs::alert::AlertMessagePayload; -use crate::msgs::base::Payload; -use crate::msgs::deframer::MessageDeframer; -use crate::msgs::enums::HandshakeType; -use crate::msgs::enums::{AlertDescription, AlertLevel, ContentType}; -use crate::msgs::fragmenter::MessageFragmenter; -use crate::msgs::handshake::Random; -use crate::msgs::hsjoiner::{HandshakeJoiner, JoinerError}; -use crate::msgs::message::{ - BorrowedPlainMessage, Message, MessagePayload, OpaqueMessage, PlainMessage, -}; -#[cfg(feature = "quic")] -use crate::quic; -use crate::record_layer; -use crate::suites::SupportedCipherSuite; -#[cfg(feature = "secret_extraction")] -use crate::suites::{ExtractedSecrets, PartiallyExtractedSecrets}; -#[cfg(feature = "tls12")] -use crate::tls12::ConnectionSecrets; -use crate::vecbuf::ChunkVecBuffer; -#[cfg(feature = "quic")] -use std::collections::VecDeque; - -use std::convert::TryFrom; -use std::fmt::Debug; -use std::io; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// A client or server connection. -#[derive(Debug)] -pub enum Connection { - /// A client connection - Client(crate::client::ClientConnection), - /// A server connection - Server(crate::server::ServerConnection), -} - -impl Connection { - /// Read TLS content from `rd`. - /// - /// See [`ConnectionCommon::read_tls()`] for more information. - pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { - match self { - Self::Client(conn) => conn.read_tls(rd), - Self::Server(conn) => conn.read_tls(rd), - } - } - - /// Returns an object that allows reading plaintext. - pub fn reader(&mut self) -> Reader { - match self { - Self::Client(conn) => conn.reader(), - Self::Server(conn) => conn.reader(), - } - } - - /// Returns an object that allows writing plaintext. - pub fn writer(&mut self) -> Writer { - match self { - Self::Client(conn) => Writer::new(&mut **conn), - Self::Server(conn) => Writer::new(&mut **conn), - } - } - - /// Processes any new packets read by a previous call to [`Connection::read_tls`]. - /// - /// See [`ConnectionCommon::process_new_packets()`] for more information. - pub fn process_new_packets(&mut self) -> Result { - match self { - Self::Client(conn) => conn.process_new_packets(), - Self::Server(conn) => conn.process_new_packets(), - } - } - - /// Derives key material from the agreed connection secrets. - /// - /// See [`ConnectionCommon::export_keying_material()`] for more information. - pub fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - match self { - Self::Client(conn) => conn.export_keying_material(output, label, context), - Self::Server(conn) => conn.export_keying_material(output, label, context), - } - } - - /// Extract secrets, to set up kTLS for example - #[cfg(feature = "secret_extraction")] - pub fn extract_secrets(self) -> Result { - match self { - Self::Client(conn) => conn.extract_secrets(), - Self::Server(conn) => conn.extract_secrets(), - } - } - - /// This function uses `io` to complete any outstanding IO for this connection. - /// - /// See [`ConnectionCommon::complete_io()`] for more information. - pub fn complete_io(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> - where - Self: Sized, - T: io::Read + io::Write, - { - match self { - Self::Client(conn) => conn.complete_io(io), - Self::Server(conn) => conn.complete_io(io), - } - } -} - -#[cfg(feature = "quic")] -impl crate::quic::QuicExt for Connection { - fn quic_transport_parameters(&self) -> Option<&[u8]> { - match self { - Self::Client(conn) => conn.quic_transport_parameters(), - Self::Server(conn) => conn.quic_transport_parameters(), - } - } - - fn zero_rtt_keys(&self) -> Option { - match self { - Self::Client(conn) => conn.zero_rtt_keys(), - Self::Server(conn) => conn.zero_rtt_keys(), - } - } - - fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - match self { - Self::Client(conn) => conn.read_quic_hs(plaintext), - Self::Server(conn) => conn.read_quic_hs(plaintext), - } - } - - fn write_hs(&mut self, buf: &mut Vec) -> Option { - match self { - Self::Client(conn) => quic::write_hs(conn, buf), - Self::Server(conn) => quic::write_hs(conn, buf), - } - } - - fn alert(&self) -> Option { - match self { - Self::Client(conn) => conn.alert(), - Self::Server(conn) => conn.alert(), - } - } -} - -impl Deref for Connection { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - match self { - Self::Client(conn) => &conn.common_state, - Self::Server(conn) => &conn.common_state, - } - } -} - -impl DerefMut for Connection { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - Self::Client(conn) => &mut conn.common_state, - Self::Server(conn) => &mut conn.common_state, - } - } -} - -/// Values of this structure are returned from [`Connection::process_new_packets`] -/// and tell the caller the current I/O state of the TLS connection. -#[derive(Debug, Eq, PartialEq)] -pub struct IoState { - tls_bytes_to_write: usize, - plaintext_bytes_to_read: usize, - peer_has_closed: bool, -} - -impl IoState { - /// How many bytes could be written by [`CommonState::write_tls`] if called - /// right now. A non-zero value implies [`CommonState::wants_write`]. - pub fn tls_bytes_to_write(&self) -> usize { - self.tls_bytes_to_write - } - - /// How many plaintext bytes could be obtained via [`std::io::Read`] - /// without further I/O. - pub fn plaintext_bytes_to_read(&self) -> usize { - self.plaintext_bytes_to_read - } - - /// True if the peer has sent us a close_notify alert. This is - /// the TLS mechanism to securely half-close a TLS connection, - /// and signifies that the peer will not send any further data - /// on this connection. - /// - /// This is also signalled via returning `Ok(0)` from - /// [`std::io::Read`], after all the received bytes have been - /// retrieved. - pub fn peer_has_closed(&self) -> bool { - self.peer_has_closed - } -} - -/// A structure that implements [`std::io::Read`] for reading plaintext. -pub struct Reader<'a> { - received_plaintext: &'a mut ChunkVecBuffer, - peer_cleanly_closed: bool, - has_seen_eof: bool, -} - -impl<'a> io::Read for Reader<'a> { - /// Obtain plaintext data received from the peer over this TLS connection. - /// - /// If the peer closes the TLS session cleanly, this returns `Ok(0)` once all - /// the pending data has been read. No further data can be received on that - /// connection, so the underlying TCP connection should be half-closed too. - /// - /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a - /// `close_notify` alert) this function returns `Err(ErrorKind::UnexpectedEof.into())` - /// once any pending data has been read. - /// - /// Note that support for `close_notify` varies in peer TLS libraries: many do not - /// support it and uncleanly close the TCP connection (this might be - /// vulnerable to truncation attacks depending on the application protocol). - /// This means applications using rustls must both handle EOF - /// from this function, *and* unexpected EOF of the underlying TCP connection. - /// - /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. - /// - /// You may learn the number of bytes available at any time by inspecting - /// the return of [`Connection::process_new_packets`]. - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = self.received_plaintext.read(buf)?; - - if len == 0 && !buf.is_empty() { - // No bytes available: - match (self.peer_cleanly_closed, self.has_seen_eof) { - // cleanly closed; don't care about TCP EOF: express this as Ok(0) - (true, _) => {} - // unclean closure - (false, true) => return Err(io::ErrorKind::UnexpectedEof.into()), - // connection still going, but need more data: signal `WouldBlock` so that - // the caller knows this - (false, false) => return Err(io::ErrorKind::WouldBlock.into()), - } - } - - Ok(len) - } - - /// Obtain plaintext data received from the peer over this TLS connection. - /// - /// If the peer closes the TLS session, this returns `Ok(())` without filling - /// any more of the buffer once all the pending data has been read. No further - /// data can be received on that connection, so the underlying TCP connection - /// should be half-closed too. - /// - /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a - /// `close_notify` alert) this function returns `Err(ErrorKind::UnexpectedEof.into())` - /// once any pending data has been read. - /// - /// Note that support for `close_notify` varies in peer TLS libraries: many do not - /// support it and uncleanly close the TCP connection (this might be - /// vulnerable to truncation attacks depending on the application protocol). - /// This means applications using rustls must both handle EOF - /// from this function, *and* unexpected EOF of the underlying TCP connection. - /// - /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. - /// - /// You may learn the number of bytes available at any time by inspecting - /// the return of [`Connection::process_new_packets`]. - #[cfg(read_buf)] - fn read_buf(&mut self, mut cursor: io::BorrowedCursor<'_>) -> io::Result<()> { - let before = cursor.written(); - self.received_plaintext - .read_buf(cursor.reborrow())?; - let len = cursor.written() - before; - - if len == 0 && cursor.capacity() > 0 { - // No bytes available: - match (self.peer_cleanly_closed, self.has_seen_eof) { - // cleanly closed; don't care about TCP EOF: express this as Ok(0) - (true, _) => {} - // unclean closure - (false, true) => return Err(io::ErrorKind::UnexpectedEof.into()), - // connection still going, but need more data: signal `WouldBlock` so that - // the caller knows this - (false, false) => return Err(io::ErrorKind::WouldBlock.into()), - } - } - - Ok(()) - } -} - -/// Internal trait implemented by the [`ServerConnection`]/[`ClientConnection`] -/// allowing them to be the subject of a [`Writer`]. -pub trait PlaintextSink { - fn write(&mut self, buf: &[u8]) -> io::Result; - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result; - fn flush(&mut self) -> io::Result<()>; -} - -impl PlaintextSink for ConnectionCommon { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(self.send_some_plaintext(buf)) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - let mut sz = 0; - for buf in bufs { - sz += self.send_some_plaintext(buf); - } - Ok(sz) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -/// A structure that implements [`std::io::Write`] for writing plaintext. -pub struct Writer<'a> { - sink: &'a mut dyn PlaintextSink, -} - -impl<'a> Writer<'a> { - /// Create a new Writer. - /// - /// This is not an external interface. Get one of these objects - /// from [`Connection::writer`]. - #[doc(hidden)] - pub fn new(sink: &'a mut dyn PlaintextSink) -> Writer<'a> { - Writer { sink } - } -} - -impl<'a> io::Write for Writer<'a> { - /// Send the plaintext `buf` to the peer, encrypting - /// and authenticating it. Once this function succeeds - /// you should call [`CommonState::write_tls`] which will output the - /// corresponding TLS records. - /// - /// This function buffers plaintext sent before the - /// TLS handshake completes, and sends it as soon - /// as it can. See [`CommonState::set_buffer_limit`] to control - /// the size of this buffer. - fn write(&mut self, buf: &[u8]) -> io::Result { - self.sink.write(buf) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.sink.write_vectored(bufs) - } - - fn flush(&mut self) -> io::Result<()> { - self.sink.flush() - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub(crate) enum Protocol { - Tcp, - #[cfg(feature = "quic")] - Quic, -} - -#[derive(Debug)] -pub(crate) struct ConnectionRandoms { - pub(crate) client: [u8; 32], - pub(crate) server: [u8; 32], -} - -/// How many ChangeCipherSpec messages we accept and drop in TLS1.3 handshakes. -/// The spec says 1, but implementations (namely the boringssl test suite) get -/// this wrong. BoringSSL itself accepts up to 32. -static TLS13_MAX_DROPPED_CCS: u8 = 2u8; - -impl ConnectionRandoms { - pub(crate) fn new(client: Random, server: Random) -> Self { - Self { - client: client.0, - server: server.0, - } - } -} - -// --- Common (to client and server) connection functions --- - -fn is_valid_ccs(msg: &OpaqueMessage) -> bool { - // nb. this is prior to the record layer, so is unencrypted. see - // third paragraph of section 5 in RFC8446. - msg.typ == ContentType::ChangeCipherSpec && msg.payload.0 == [0x01] -} - -enum Limit { - Yes, - No, -} - -/// Interface shared by client and server connections. -pub struct ConnectionCommon { - state: Result>, Error>, - pub(crate) data: Data, - pub(crate) common_state: CommonState, - message_deframer: MessageDeframer, - handshake_joiner: HandshakeJoiner, -} - -impl ConnectionCommon { - pub(crate) fn new(state: Box>, data: Data, common_state: CommonState) -> Self { - Self { - state: Ok(state), - data, - common_state, - message_deframer: MessageDeframer::new(), - handshake_joiner: HandshakeJoiner::new(), - } - } - - /// Returns an object that allows reading plaintext. - pub fn reader(&mut self) -> Reader { - Reader { - received_plaintext: &mut self.common_state.received_plaintext, - /// Are we done? i.e., have we processed all received messages, and received a - /// close_notify to indicate that no new messages will arrive? - peer_cleanly_closed: self - .common_state - .has_received_close_notify - && !self.message_deframer.has_pending(), - has_seen_eof: self.common_state.has_seen_eof, - } - } - - /// Returns an object that allows writing plaintext. - pub fn writer(&mut self) -> Writer { - Writer::new(self) - } - - /// This function uses `io` to complete any outstanding IO for - /// this connection. - /// - /// This is a convenience function which solely uses other parts - /// of the public API. - /// - /// What this means depends on the connection state: - /// - /// - If the connection [`is_handshaking`], then IO is performed until - /// the handshake is complete. - /// - Otherwise, if [`wants_write`] is true, [`write_tls`] is invoked - /// until it is all written. - /// - Otherwise, if [`wants_read`] is true, [`read_tls`] is invoked - /// once. - /// - /// The return value is the number of bytes read from and written - /// to `io`, respectively. - /// - /// This function will block if `io` blocks. - /// - /// Errors from TLS record handling (i.e., from [`process_new_packets`]) - /// are wrapped in an `io::ErrorKind::InvalidData`-kind error. - /// - /// [`is_handshaking`]: CommonState::is_handshaking - /// [`wants_read`]: CommonState::wants_read - /// [`wants_write`]: CommonState::wants_write - /// [`write_tls`]: CommonState::write_tls - /// [`read_tls`]: ConnectionCommon::read_tls - /// [`process_new_packets`]: ConnectionCommon::process_new_packets - pub fn complete_io(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> - where - Self: Sized, - T: io::Read + io::Write, - { - let until_handshaked = self.is_handshaking(); - let mut eof = false; - let mut wrlen = 0; - let mut rdlen = 0; - - loop { - while self.wants_write() { - wrlen += self.write_tls(io)?; - } - - if !until_handshaked && wrlen > 0 { - return Ok((rdlen, wrlen)); - } - - while !eof && self.wants_read() { - let read_size = match self.read_tls(io) { - Ok(0) => { - eof = true; - Some(0) - } - Ok(n) => { - rdlen += n; - Some(n) - } - Err(ref err) if err.kind() == io::ErrorKind::Interrupted => None, // nothing to do - Err(err) => return Err(err), - }; - if read_size.is_some() { - break; - } - } - - match self.process_new_packets() { - Ok(_) => {} - Err(e) => { - // In case we have an alert to send describing this error, - // try a last-gasp write -- but don't predate the primary - // error. - let _ignored = self.write_tls(io); - - return Err(io::Error::new(io::ErrorKind::InvalidData, e)); - } - }; - - match (eof, until_handshaked, self.is_handshaking()) { - (_, true, false) => return Ok((rdlen, wrlen)), - (_, false, _) => return Ok((rdlen, wrlen)), - (true, true, true) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)), - (..) => {} - } - } - } - - /// Extract the first handshake message. - /// - /// This is a shortcut to the `process_new_packets()` -> `process_msg()` -> - /// `process_handshake_messages()` path, specialized for the first handshake message. - pub(crate) fn first_handshake_message(&mut self) -> Result, Error> { - let msg = match self.message_deframer.pop()? { - Some(msg) => msg, - None => return Ok(None), - }; - - let msg = msg.into_plain_message(); - self.handshake_joiner - .push(msg) - .and_then(|aligned| { - self.common_state.aligned_handshake = aligned; - self.handshake_joiner.pop() - }) - .map_err(|_| { - self.common_state - .send_fatal_alert(AlertDescription::DecodeError); - Error::CorruptMessagePayload(ContentType::Handshake) - }) - } - - pub(crate) fn replace_state(&mut self, new: Box>) { - self.state = Ok(new); - } - - fn process_msg( - &mut self, - msg: OpaqueMessage, - state: Box>, - ) -> Result>, Error> { - // Drop CCS messages during handshake in TLS1.3 - if msg.typ == ContentType::ChangeCipherSpec - && !self - .common_state - .may_receive_application_data - && self.common_state.is_tls13() - { - if !is_valid_ccs(&msg) - || self.common_state.received_middlebox_ccs > TLS13_MAX_DROPPED_CCS - { - // "An implementation which receives any other change_cipher_spec value or - // which receives a protected change_cipher_spec record MUST abort the - // handshake with an "unexpected_message" alert." - self.common_state - .send_fatal_alert(AlertDescription::UnexpectedMessage); - return Err(Error::PeerMisbehavedError( - "illegal middlebox CCS received".into(), - )); - } else { - self.common_state.received_middlebox_ccs += 1; - trace!("Dropping CCS"); - return Ok(state); - } - } - - // Decrypt if demanded by current state. - let msg = match self - .common_state - .record_layer - .is_decrypting() - { - true => match self.common_state.decrypt_incoming(msg) { - Ok(None) => { - // message dropped - return Ok(state); - } - Err(e) => { - return Err(e); - } - Ok(Some(msg)) => msg, - }, - false => msg.into_plain_message(), - }; - - // For handshake messages, we need to join them before parsing and processing. - let msg = match self.handshake_joiner.push(msg) { - // Handshake message, we handle these in another method. - Ok(aligned) => { - self.common_state.aligned_handshake = aligned; - - // First decryptable handshake message concludes trial decryption - self.common_state - .record_layer - .finish_trial_decryption(); - - return self.process_new_handshake_messages(state); - } - // Not a handshake message, continue to handle it here. - Err(JoinerError::Unwanted(msg)) => msg, - // Decoding the handshake message failed, yield an error. - Err(JoinerError::Decode) => { - self.common_state - .send_fatal_alert(AlertDescription::DecodeError); - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - }; - - // Now we can fully parse the message payload. - let msg = Message::try_from(msg)?; - - // For alerts, we have separate logic. - if let MessagePayload::Alert(alert) = &msg.payload { - self.common_state.process_alert(alert)?; - return Ok(state); - } - - self.common_state - .process_main_protocol(msg, state, &mut self.data) - } - - /// Processes any new packets read by a previous call to - /// [`Connection::read_tls`]. - /// - /// Errors from this function relate to TLS protocol errors, and - /// are fatal to the connection. Future calls after an error will do - /// no new work and will return the same error. After an error is - /// received from [`process_new_packets`], you should not call [`read_tls`] - /// any more (it will fill up buffers to no purpose). However, you - /// may call the other methods on the connection, including `write`, - /// `send_close_notify`, and `write_tls`. Most likely you will want to - /// call `write_tls` to send any alerts queued by the error and then - /// close the underlying connection. - /// - /// Success from this function comes with some sundry state data - /// about the connection. - /// - /// [`read_tls`]: Connection::read_tls - /// [`process_new_packets`]: Connection::process_new_packets - pub fn process_new_packets(&mut self) -> Result { - let mut state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) { - Ok(state) => state, - Err(e) => { - self.state = Err(e.clone()); - return Err(e); - } - }; - - while let Some(msg) = self.message_deframer.pop()? { - match self.process_msg(msg, state) { - Ok(new) => state = new, - Err(e) => { - self.state = Err(e.clone()); - return Err(e); - } - } - } - - self.state = Ok(state); - Ok(self.common_state.current_io_state()) - } - - fn process_new_handshake_messages( - &mut self, - mut state: Box>, - ) -> Result>, Error> { - loop { - match self.handshake_joiner.pop() { - Ok(Some(msg)) => { - state = self - .common_state - .process_main_protocol(msg, state, &mut self.data)?; - } - Ok(None) => return Ok(state), - Err(_) => { - #[cfg(feature = "quic")] - if self.common_state.is_quic() { - self.common_state.quic.alert = Some(AlertDescription::DecodeError); - } - - if !self.common_state.is_quic() { - self.common_state - .send_fatal_alert(AlertDescription::DecodeError); - } - - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - } - } - } - - pub(crate) fn send_some_plaintext(&mut self, buf: &[u8]) -> usize { - if let Ok(st) = &mut self.state { - st.perhaps_write_key_update(&mut self.common_state); - } - self.common_state - .send_some_plaintext(buf) - } - - /// Read TLS content from `rd` into the internal buffer. - /// - /// Due to the internal buffering, `rd` can supply TLS messages in arbitrary-sized chunks (like - /// a socket or pipe might). - /// - /// You should call [`process_new_packets()`] each time a call to this function succeeds in order - /// to empty the incoming TLS data buffer. - /// - /// This function returns `Ok(0)` when the underlying `rd` does so. This typically happens when - /// a socket is cleanly closed, or a file is at EOF. Errors may result from the IO done through - /// `rd`; additionally, errors of `ErrorKind::Other` are emitted to signal backpressure: - /// - /// * In order to empty the incoming TLS data buffer, you should call [`process_new_packets()`] - /// each time a call to this function succeeds. - /// * In order to empty the incoming plaintext data buffer, you should empty it through - /// the [`reader()`] after the call to [`process_new_packets()`]. - /// - /// [`process_new_packets()`]: ConnectionCommon::process_new_packets - /// [`reader()`]: ConnectionCommon::reader - pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { - if self.received_plaintext.is_full() { - return Err(io::Error::new( - io::ErrorKind::Other, - "received plaintext buffer full", - )); - } - - let res = self.message_deframer.read(rd); - if let Ok(0) = res { - self.common_state.has_seen_eof = true; - } - res - } - - /// Derives key material from the agreed connection secrets. - /// - /// This function fills in `output` with `output.len()` bytes of key - /// material derived from the master session secret using `label` - /// and `context` for diversification. - /// - /// See RFC5705 for more details on what this does and is for. - /// - /// For TLS1.3 connections, this function does not use the - /// "early" exporter at any point. - /// - /// This function fails if called prior to the handshake completing; - /// check with [`CommonState::is_handshaking`] first. - pub fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - match self.state.as_ref() { - Ok(st) => st.export_keying_material(output, label, context), - Err(e) => Err(e.clone()), - } - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - #[cfg(feature = "secret_extraction")] - pub fn extract_secrets(self) -> Result { - if !self.enable_secret_extraction { - return Err(Error::General("Secret extraction is disabled".into())); - } - - let st = self.state?; - - let record_layer = self.common_state.record_layer; - let PartiallyExtractedSecrets { tx, rx } = st.extract_secrets()?; - Ok(ExtractedSecrets { - tx: (record_layer.write_seq(), tx), - rx: (record_layer.read_seq(), rx), - }) - } -} - -#[cfg(feature = "quic")] -impl ConnectionCommon { - pub(crate) fn read_quic_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - let state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) { - Ok(state) => state, - Err(e) => { - self.state = Err(e.clone()); - return Err(e); - } - }; - - let msg = PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: Payload::new(plaintext.to_vec()), - }; - - if self.handshake_joiner.push(msg).is_err() { - self.common_state.quic.alert = Some(AlertDescription::DecodeError); - return Err(Error::CorruptMessage); - } - - self.process_new_handshake_messages(state) - .map(|state| self.state = Ok(state)) - } -} - -impl Deref for ConnectionCommon { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - &self.common_state - } -} - -impl DerefMut for ConnectionCommon { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.common_state - } -} - -/// Connection state common to both client and server connections. -pub struct CommonState { - pub(crate) negotiated_version: Option, - pub(crate) side: Side, - pub(crate) record_layer: record_layer::RecordLayer, - pub(crate) suite: Option, - pub(crate) alpn_protocol: Option>, - aligned_handshake: bool, - pub(crate) may_send_application_data: bool, - pub(crate) may_receive_application_data: bool, - pub(crate) early_traffic: bool, - sent_fatal_alert: bool, - /// If the peer has signaled end of stream. - has_received_close_notify: bool, - has_seen_eof: bool, - received_middlebox_ccs: u8, - pub(crate) peer_certificates: Option>, - message_fragmenter: MessageFragmenter, - received_plaintext: ChunkVecBuffer, - sendable_plaintext: ChunkVecBuffer, - pub(crate) sendable_tls: ChunkVecBuffer, - #[allow(dead_code)] // only read for QUIC - /// Protocol whose key schedule should be used. Unused for TLS < 1.3. - pub(crate) protocol: Protocol, - #[cfg(feature = "quic")] - pub(crate) quic: Quic, - #[cfg(feature = "secret_extraction")] - pub(crate) enable_secret_extraction: bool, -} - -impl CommonState { - pub(crate) fn new(side: Side) -> Self { - Self { - negotiated_version: None, - side, - record_layer: record_layer::RecordLayer::new(), - suite: None, - alpn_protocol: None, - aligned_handshake: true, - may_send_application_data: false, - may_receive_application_data: false, - early_traffic: false, - sent_fatal_alert: false, - has_received_close_notify: false, - has_seen_eof: false, - received_middlebox_ccs: 0, - peer_certificates: None, - message_fragmenter: MessageFragmenter::default(), - received_plaintext: ChunkVecBuffer::new(Some(DEFAULT_RECEIVED_PLAINTEXT_LIMIT)), - sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), - sendable_tls: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), - - protocol: Protocol::Tcp, - #[cfg(feature = "quic")] - quic: Quic::new(), - #[cfg(feature = "secret_extraction")] - enable_secret_extraction: false, - } - } - - /// Returns true if the caller should call [`CommonState::write_tls`] as soon - /// as possible. - pub fn wants_write(&self) -> bool { - !self.sendable_tls.is_empty() - } - - /// Returns true if the connection is currently performing the TLS handshake. - /// - /// During this time plaintext written to the connection is buffered in memory. After - /// [`Connection::process_new_packets`] has been called, this might start to return `false` - /// while the final handshake packets still need to be extracted from the connection's buffers. - pub fn is_handshaking(&self) -> bool { - !(self.may_send_application_data && self.may_receive_application_data) - } - - /// Retrieves the certificate chain used by the peer to authenticate. - /// - /// The order of the certificate chain is as it appears in the TLS - /// protocol: the first certificate relates to the peer, the - /// second certifies the first, the third certifies the second, and - /// so on. - /// - /// This is made available for both full and resumed handshakes. - /// - /// For clients, this is the certificate chain of the server. - /// - /// For servers, this is the certificate chain of the client, - /// if client authentication was completed. - /// - /// The return value is None until this value is available. - pub fn peer_certificates(&self) -> Option<&[key::Certificate]> { - self.peer_certificates.as_deref() - } - - /// Retrieves the protocol agreed with the peer via ALPN. - /// - /// A return value of `None` after handshake completion - /// means no protocol was agreed (because no protocols - /// were offered or accepted by the peer). - pub fn alpn_protocol(&self) -> Option<&[u8]> { - self.get_alpn_protocol() - } - - /// Retrieves the ciphersuite agreed with the peer. - /// - /// This returns None until the ciphersuite is agreed. - pub fn negotiated_cipher_suite(&self) -> Option { - self.suite - } - - /// Retrieves the protocol version agreed with the peer. - /// - /// This returns `None` until the version is agreed. - pub fn protocol_version(&self) -> Option { - self.negotiated_version - } - - pub(crate) fn is_tls13(&self) -> bool { - matches!(self.negotiated_version, Some(ProtocolVersion::TLSv1_3)) - } - - fn process_main_protocol( - &mut self, - msg: Message, - mut state: Box>, - data: &mut Data, - ) -> Result>, Error> { - // For TLS1.2, outside of the handshake, send rejection alerts for - // renegotiation requests. These can occur any time. - if self.may_receive_application_data && !self.is_tls13() { - let reject_ty = match self.side { - Side::Client => HandshakeType::HelloRequest, - Side::Server => HandshakeType::ClientHello, - }; - if msg.is_handshake_type(reject_ty) { - self.send_warning_alert(AlertDescription::NoRenegotiation); - return Ok(state); - } - } - - let mut cx = Context { common: self, data }; - match state.handle(&mut cx, msg) { - Ok(next) => { - state = next; - Ok(state) - } - Err(e @ Error::InappropriateMessage { .. }) - | Err(e @ Error::InappropriateHandshakeMessage { .. }) => { - self.send_fatal_alert(AlertDescription::UnexpectedMessage); - Err(e) - } - Err(e) => Err(e), - } - } - - /// Send plaintext application data, fragmenting and - /// encrypting it as it goes out. - /// - /// If internal buffers are too small, this function will not accept - /// all the data. - pub(crate) fn send_some_plaintext(&mut self, data: &[u8]) -> usize { - self.send_plain(data, Limit::Yes) - } - - pub(crate) fn send_early_plaintext(&mut self, data: &[u8]) -> usize { - debug_assert!(self.early_traffic); - debug_assert!(self.record_layer.is_encrypting()); - - if data.is_empty() { - // Don't send empty fragments. - return 0; - } - - self.send_appdata_encrypt(data, Limit::Yes) - } - - // Changing the keys must not span any fragmented handshake - // messages. Otherwise the defragmented messages will have - // been protected with two different record layer protections, - // which is illegal. Not mentioned in RFC. - pub(crate) fn check_aligned_handshake(&mut self) -> Result<(), Error> { - if !self.aligned_handshake { - self.send_fatal_alert(AlertDescription::UnexpectedMessage); - Err(Error::PeerMisbehavedError( - "key epoch or handshake flight with pending fragment".to_string(), - )) - } else { - Ok(()) - } - } - - pub(crate) fn illegal_param(&mut self, why: &str) -> Error { - self.send_fatal_alert(AlertDescription::IllegalParameter); - Error::PeerMisbehavedError(why.to_string()) - } - - pub(crate) fn decrypt_incoming( - &mut self, - encr: OpaqueMessage, - ) -> Result, Error> { - if self - .record_layer - .wants_close_before_decrypt() - { - self.send_close_notify(); - } - - let encrypted_len = encr.payload.0.len(); - let plain = self.record_layer.decrypt_incoming(encr); - - match plain { - Err(Error::PeerSentOversizedRecord) => { - self.send_fatal_alert(AlertDescription::RecordOverflow); - Err(Error::PeerSentOversizedRecord) - } - Err(Error::DecryptError) - if self - .record_layer - .doing_trial_decryption(encrypted_len) => - { - trace!("Dropping undecryptable message after aborted early_data"); - Ok(None) - } - Err(Error::DecryptError) => { - self.send_fatal_alert(AlertDescription::BadRecordMac); - Err(Error::DecryptError) - } - Err(e) => Err(e), - Ok(plain) => Ok(Some(plain)), - } - } - - /// Fragment `m`, encrypt the fragments, and then queue - /// the encrypted fragments for sending. - pub(crate) fn send_msg_encrypt(&mut self, m: PlainMessage) { - let iter = self - .message_fragmenter - .fragment_message(&m); - for m in iter { - self.send_single_fragment(m); - } - } - - /// Like send_msg_encrypt, but operate on an appdata directly. - fn send_appdata_encrypt(&mut self, payload: &[u8], limit: Limit) -> usize { - // Here, the limit on sendable_tls applies to encrypted data, - // but we're respecting it for plaintext data -- so we'll - // be out by whatever the cipher+record overhead is. That's a - // constant and predictable amount, so it's not a terrible issue. - let len = match limit { - Limit::Yes => self - .sendable_tls - .apply_limit(payload.len()), - Limit::No => payload.len(), - }; - - let iter = self.message_fragmenter.fragment_slice( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - &payload[..len], - ); - for m in iter { - self.send_single_fragment(m); - } - - len - } - - fn send_single_fragment(&mut self, m: BorrowedPlainMessage) { - // Close connection once we start to run out of - // sequence space. - if self - .record_layer - .wants_close_before_encrypt() - { - self.send_close_notify(); - } - - // Refuse to wrap counter at all costs. This - // is basically untestable unfortunately. - if self.record_layer.encrypt_exhausted() { - return; - } - - let em = self.record_layer.encrypt_outgoing(m); - self.queue_tls_message(em); - } - - /// Writes TLS messages to `wr`. - /// - /// On success, this function returns `Ok(n)` where `n` is a number of bytes written to `wr` - /// (after encoding and encryption). - /// - /// After this function returns, the connection buffer may not yet be fully flushed. The - /// [`CommonState::wants_write`] function can be used to check if the output buffer is empty. - pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result { - self.sendable_tls.write_to(wr) - } - - /// Encrypt and send some plaintext `data`. `limit` controls - /// whether the per-connection buffer limits apply. - /// - /// Returns the number of bytes written from `data`: this might - /// be less than `data.len()` if buffer limits were exceeded. - fn send_plain(&mut self, data: &[u8], limit: Limit) -> usize { - if !self.may_send_application_data { - // If we haven't completed handshaking, buffer - // plaintext to send once we do. - let len = match limit { - Limit::Yes => self - .sendable_plaintext - .append_limited_copy(data), - Limit::No => self - .sendable_plaintext - .append(data.to_vec()), - }; - return len; - } - - debug_assert!(self.record_layer.is_encrypting()); - - if data.is_empty() { - // Don't send empty fragments. - return 0; - } - - self.send_appdata_encrypt(data, limit) - } - - pub(crate) fn start_outgoing_traffic(&mut self) { - self.may_send_application_data = true; - self.flush_plaintext(); - } - - pub(crate) fn start_traffic(&mut self) { - self.may_receive_application_data = true; - self.start_outgoing_traffic(); - } - - /// Sets a limit on the internal buffers used to buffer - /// unsent plaintext (prior to completing the TLS handshake) - /// and unsent TLS records. This limit acts only on application - /// data written through [`Connection::writer`]. - /// - /// By default the limit is 64KB. The limit can be set - /// at any time, even if the current buffer use is higher. - /// - /// [`None`] means no limit applies, and will mean that written - /// data is buffered without bound -- it is up to the application - /// to appropriately schedule its plaintext and TLS writes to bound - /// memory usage. - /// - /// For illustration: `Some(1)` means a limit of one byte applies: - /// [`Connection::writer`] will accept only one byte, encrypt it and - /// add a TLS header. Once this is sent via [`CommonState::write_tls`], - /// another byte may be sent. - /// - /// # Internal write-direction buffering - /// rustls has two buffers whose size are bounded by this setting: - /// - /// ## Buffering of unsent plaintext data prior to handshake completion - /// - /// Calls to [`Connection::writer`] before or during the handshake - /// are buffered (up to the limit specified here). Once the - /// handshake completes this data is encrypted and the resulting - /// TLS records are added to the outgoing buffer. - /// - /// ## Buffering of outgoing TLS records - /// - /// This buffer is used to store TLS records that rustls needs to - /// send to the peer. It is used in these two circumstances: - /// - /// - by [`Connection::process_new_packets`] when a handshake or alert - /// TLS record needs to be sent. - /// - by [`Connection::writer`] post-handshake: the plaintext is - /// encrypted and the resulting TLS record is buffered. - /// - /// This buffer is emptied by [`CommonState::write_tls`]. - pub fn set_buffer_limit(&mut self, limit: Option) { - self.sendable_plaintext.set_limit(limit); - self.sendable_tls.set_limit(limit); - } - - /// Send any buffered plaintext. Plaintext is buffered if - /// written during handshake. - fn flush_plaintext(&mut self) { - if !self.may_send_application_data { - return; - } - - while let Some(buf) = self.sendable_plaintext.pop() { - self.send_plain(&buf, Limit::No); - } - } - - // Put m into sendable_tls for writing. - fn queue_tls_message(&mut self, m: OpaqueMessage) { - self.sendable_tls.append(m.encode()); - } - - /// Send a raw TLS message, fragmenting it if needed. - pub(crate) fn send_msg(&mut self, m: Message, must_encrypt: bool) { - #[cfg(feature = "quic")] - { - if let Protocol::Quic = self.protocol { - if let MessagePayload::Alert(alert) = m.payload { - self.quic.alert = Some(alert.description); - } else { - debug_assert!( - matches!(m.payload, MessagePayload::Handshake { .. }), - "QUIC uses TLS for the cryptographic handshake only" - ); - let mut bytes = Vec::new(); - m.payload.encode(&mut bytes); - self.quic - .hs_queue - .push_back((must_encrypt, bytes)); - } - return; - } - } - if !must_encrypt { - let msg = &m.into(); - let iter = self - .message_fragmenter - .fragment_message(msg); - for m in iter { - self.queue_tls_message(m.to_unencrypted_opaque()); - } - } else { - self.send_msg_encrypt(m.into()); - } - } - - pub(crate) fn take_received_plaintext(&mut self, bytes: Payload) { - self.received_plaintext.append(bytes.0); - } - - #[cfg(feature = "tls12")] - pub(crate) fn start_encryption_tls12(&mut self, secrets: &ConnectionSecrets, side: Side) { - let (dec, enc) = secrets.make_cipher_pair(side); - self.record_layer - .prepare_message_encrypter(enc); - self.record_layer - .prepare_message_decrypter(dec); - } - - #[cfg(feature = "quic")] - pub(crate) fn missing_extension(&mut self, why: &str) -> Error { - self.send_fatal_alert(AlertDescription::MissingExtension); - Error::PeerMisbehavedError(why.to_string()) - } - - fn send_warning_alert(&mut self, desc: AlertDescription) { - warn!("Sending warning alert {:?}", desc); - self.send_warning_alert_no_log(desc); - } - - fn process_alert(&mut self, alert: &AlertMessagePayload) -> Result<(), Error> { - // Reject unknown AlertLevels. - if let AlertLevel::Unknown(_) = alert.level { - self.send_fatal_alert(AlertDescription::IllegalParameter); - } - - // If we get a CloseNotify, make a note to declare EOF to our - // caller. - if alert.description == AlertDescription::CloseNotify { - self.has_received_close_notify = true; - return Ok(()); - } - - // Warnings are nonfatal for TLS1.2, but outlawed in TLS1.3 - // (except, for no good reason, user_cancelled). - if alert.level == AlertLevel::Warning { - if self.is_tls13() && alert.description != AlertDescription::UserCanceled { - self.send_fatal_alert(AlertDescription::DecodeError); - } else { - warn!("TLS alert warning received: {:#?}", alert); - return Ok(()); - } - } - - error!("TLS alert received: {:#?}", alert); - Err(Error::AlertReceived(alert.description)) - } - - pub(crate) fn send_fatal_alert(&mut self, desc: AlertDescription) { - warn!("Sending fatal alert {:?}", desc); - debug_assert!(!self.sent_fatal_alert); - let m = Message::build_alert(AlertLevel::Fatal, desc); - self.send_msg(m, self.record_layer.is_encrypting()); - self.sent_fatal_alert = true; - } - - /// Queues a close_notify warning alert to be sent in the next - /// [`CommonState::write_tls`] call. This informs the peer that the - /// connection is being closed. - pub fn send_close_notify(&mut self) { - debug!("Sending warning alert {:?}", AlertDescription::CloseNotify); - self.send_warning_alert_no_log(AlertDescription::CloseNotify); - } - - fn send_warning_alert_no_log(&mut self, desc: AlertDescription) { - let m = Message::build_alert(AlertLevel::Warning, desc); - self.send_msg(m, self.record_layer.is_encrypting()); - } - - pub(crate) fn set_max_fragment_size(&mut self, new: Option) -> Result<(), Error> { - self.message_fragmenter - .set_max_fragment_size(new) - } - - pub(crate) fn get_alpn_protocol(&self) -> Option<&[u8]> { - self.alpn_protocol - .as_ref() - .map(AsRef::as_ref) - } - - /// Returns true if the caller should call [`Connection::read_tls`] as soon - /// as possible. - /// - /// If there is pending plaintext data to read with [`Connection::reader`], - /// this returns false. If your application respects this mechanism, - /// only one full TLS message will be buffered by rustls. - pub fn wants_read(&self) -> bool { - // We want to read more data all the time, except when we have unprocessed plaintext. - // This provides back-pressure to the TCP buffers. We also don't want to read more after - // the peer has sent us a close notification. - // - // In the handshake case we don't have readable plaintext before the handshake has - // completed, but also don't want to read if we still have sendable tls. - self.received_plaintext.is_empty() - && !self.has_received_close_notify - && (self.may_send_application_data || self.sendable_tls.is_empty()) - } - - fn current_io_state(&self) -> IoState { - IoState { - tls_bytes_to_write: self.sendable_tls.len(), - plaintext_bytes_to_read: self.received_plaintext.len(), - peer_has_closed: self.has_received_close_notify, - } - } - - pub(crate) fn is_quic(&self) -> bool { - #[cfg(feature = "quic")] - { - self.protocol == Protocol::Quic - } - #[cfg(not(feature = "quic"))] - false - } -} - -pub(crate) trait State: Send + Sync { - fn handle( - self: Box, - cx: &mut Context<'_, Data>, - message: Message, - ) -> Result>, Error>; - - fn export_keying_material( - &self, - _output: &mut [u8], - _label: &[u8], - _context: Option<&[u8]>, - ) -> Result<(), Error> { - Err(Error::HandshakeNotComplete) - } - - #[cfg(feature = "secret_extraction")] - fn extract_secrets(&self) -> Result { - Err(Error::HandshakeNotComplete) - } - - fn perhaps_write_key_update(&mut self, _cx: &mut CommonState) {} -} - -pub(crate) struct Context<'a, Data> { - pub(crate) common: &'a mut CommonState, - pub(crate) data: &'a mut Data, -} - -#[cfg(feature = "quic")] -pub(crate) struct Quic { - /// QUIC transport parameters received from the peer during the handshake - pub(crate) params: Option>, - pub(crate) alert: Option, - pub(crate) hs_queue: VecDeque<(bool, Vec)>, - pub(crate) early_secret: Option, - pub(crate) hs_secrets: Option, - pub(crate) traffic_secrets: Option, - /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation - pub(crate) returned_traffic_keys: bool, -} - -#[cfg(feature = "quic")] -impl Quic { - fn new() -> Self { - Self { - params: None, - alert: None, - hs_queue: VecDeque::new(), - early_secret: None, - hs_secrets: None, - traffic_secrets: None, - returned_traffic_keys: false, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub(crate) enum Side { - Client, - Server, -} - -/// Data specific to the peer's side (client or server). -pub trait SideData {} - -const DEFAULT_RECEIVED_PLAINTEXT_LIMIT: usize = 16 * 1024; -const DEFAULT_BUFFER_LIMIT: usize = 64 * 1024; diff --git a/third_party/rustls-fork-shadow-tls/src/enums.rs b/third_party/rustls-fork-shadow-tls/src/enums.rs deleted file mode 100644 index 20c39ee..0000000 --- a/third_party/rustls-fork-shadow-tls/src/enums.rs +++ /dev/null @@ -1,431 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(missing_docs)] -use crate::msgs::codec::{Codec, Reader}; - -enum_builder! { - /// The `ProtocolVersion` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: ProtocolVersion; - EnumVal{ - SSLv2 => 0x0200, - SSLv3 => 0x0300, - TLSv1_0 => 0x0301, - TLSv1_1 => 0x0302, - TLSv1_2 => 0x0303, - TLSv1_3 => 0x0304, - DTLSv1_0 => 0xFEFF, - DTLSv1_2 => 0xFEFD, - DTLSv1_3 => 0xFEFC - } -} - -enum_builder! { - /// The `CipherSuite` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: CipherSuite; - EnumVal{ - TLS_NULL_WITH_NULL_NULL => 0x0000, - TLS_RSA_WITH_NULL_MD5 => 0x0001, - TLS_RSA_WITH_NULL_SHA => 0x0002, - TLS_RSA_EXPORT_WITH_RC4_40_MD5 => 0x0003, - TLS_RSA_WITH_RC4_128_MD5 => 0x0004, - TLS_RSA_WITH_RC4_128_SHA => 0x0005, - TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 => 0x0006, - TLS_RSA_WITH_IDEA_CBC_SHA => 0x0007, - TLS_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0008, - TLS_RSA_WITH_DES_CBC_SHA => 0x0009, - TLS_RSA_WITH_3DES_EDE_CBC_SHA => 0x000a, - TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x000b, - TLS_DH_DSS_WITH_DES_CBC_SHA => 0x000c, - TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA => 0x000d, - TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x000e, - TLS_DH_RSA_WITH_DES_CBC_SHA => 0x000f, - TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA => 0x0010, - TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x0011, - TLS_DHE_DSS_WITH_DES_CBC_SHA => 0x0012, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA => 0x0013, - TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0014, - TLS_DHE_RSA_WITH_DES_CBC_SHA => 0x0015, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA => 0x0016, - TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 => 0x0017, - TLS_DH_anon_WITH_RC4_128_MD5 => 0x0018, - TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA => 0x0019, - TLS_DH_anon_WITH_DES_CBC_SHA => 0x001a, - TLS_DH_anon_WITH_3DES_EDE_CBC_SHA => 0x001b, - SSL_FORTEZZA_KEA_WITH_NULL_SHA => 0x001c, - SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA => 0x001d, - TLS_KRB5_WITH_DES_CBC_SHA_or_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA => 0x001e, - TLS_KRB5_WITH_3DES_EDE_CBC_SHA => 0x001f, - TLS_KRB5_WITH_RC4_128_SHA => 0x0020, - TLS_KRB5_WITH_IDEA_CBC_SHA => 0x0021, - TLS_KRB5_WITH_DES_CBC_MD5 => 0x0022, - TLS_KRB5_WITH_3DES_EDE_CBC_MD5 => 0x0023, - TLS_KRB5_WITH_RC4_128_MD5 => 0x0024, - TLS_KRB5_WITH_IDEA_CBC_MD5 => 0x0025, - TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA => 0x0026, - TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA => 0x0027, - TLS_KRB5_EXPORT_WITH_RC4_40_SHA => 0x0028, - TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 => 0x0029, - TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 => 0x002a, - TLS_KRB5_EXPORT_WITH_RC4_40_MD5 => 0x002b, - TLS_PSK_WITH_NULL_SHA => 0x002c, - TLS_DHE_PSK_WITH_NULL_SHA => 0x002d, - TLS_RSA_PSK_WITH_NULL_SHA => 0x002e, - TLS_RSA_WITH_AES_128_CBC_SHA => 0x002f, - TLS_DH_DSS_WITH_AES_128_CBC_SHA => 0x0030, - TLS_DH_RSA_WITH_AES_128_CBC_SHA => 0x0031, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA => 0x0032, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA => 0x0033, - TLS_DH_anon_WITH_AES_128_CBC_SHA => 0x0034, - TLS_RSA_WITH_AES_256_CBC_SHA => 0x0035, - TLS_DH_DSS_WITH_AES_256_CBC_SHA => 0x0036, - TLS_DH_RSA_WITH_AES_256_CBC_SHA => 0x0037, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA => 0x0038, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA => 0x0039, - TLS_DH_anon_WITH_AES_256_CBC_SHA => 0x003a, - TLS_RSA_WITH_NULL_SHA256 => 0x003b, - TLS_RSA_WITH_AES_128_CBC_SHA256 => 0x003c, - TLS_RSA_WITH_AES_256_CBC_SHA256 => 0x003d, - TLS_DH_DSS_WITH_AES_128_CBC_SHA256 => 0x003e, - TLS_DH_RSA_WITH_AES_128_CBC_SHA256 => 0x003f, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 => 0x0040, - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0041, - TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0042, - TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0043, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0044, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0045, - TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA => 0x0046, - TLS_ECDH_ECDSA_WITH_NULL_SHA_draft => 0x0047, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA_draft => 0x0048, - TLS_ECDH_ECDSA_WITH_DES_CBC_SHA_draft => 0x0049, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x004a, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA_draft => 0x004b, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA_draft => 0x004c, - TLS_ECDH_ECNRA_WITH_DES_CBC_SHA_draft => 0x004d, - TLS_ECDH_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x004e, - TLS_ECMQV_ECDSA_NULL_SHA_draft => 0x004f, - TLS_ECMQV_ECDSA_WITH_RC4_128_SHA_draft => 0x0050, - TLS_ECMQV_ECDSA_WITH_DES_CBC_SHA_draft => 0x0051, - TLS_ECMQV_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x0052, - TLS_ECMQV_ECNRA_NULL_SHA_draft => 0x0053, - TLS_ECMQV_ECNRA_WITH_RC4_128_SHA_draft => 0x0054, - TLS_ECMQV_ECNRA_WITH_DES_CBC_SHA_draft => 0x0055, - TLS_ECMQV_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x0056, - TLS_ECDH_anon_NULL_WITH_SHA_draft => 0x0057, - TLS_ECDH_anon_WITH_RC4_128_SHA_draft => 0x0058, - TLS_ECDH_anon_WITH_DES_CBC_SHA_draft => 0x0059, - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA_draft => 0x005a, - TLS_ECDH_anon_EXPORT_WITH_DES40_CBC_SHA_draft => 0x005b, - TLS_ECDH_anon_EXPORT_WITH_RC4_40_SHA_draft => 0x005c, - TLS_RSA_EXPORT1024_WITH_RC4_56_MD5 => 0x0060, - TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 => 0x0061, - TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA => 0x0062, - TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA => 0x0063, - TLS_RSA_EXPORT1024_WITH_RC4_56_SHA => 0x0064, - TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA => 0x0065, - TLS_DHE_DSS_WITH_RC4_128_SHA => 0x0066, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 => 0x0067, - TLS_DH_DSS_WITH_AES_256_CBC_SHA256 => 0x0068, - TLS_DH_RSA_WITH_AES_256_CBC_SHA256 => 0x0069, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 => 0x006a, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 => 0x006b, - TLS_DH_anon_WITH_AES_128_CBC_SHA256 => 0x006c, - TLS_DH_anon_WITH_AES_256_CBC_SHA256 => 0x006d, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD => 0x0072, - TLS_DHE_DSS_WITH_AES_128_CBC_RMD => 0x0073, - TLS_DHE_DSS_WITH_AES_256_CBC_RMD => 0x0074, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD => 0x0077, - TLS_DHE_RSA_WITH_AES_128_CBC_RMD => 0x0078, - TLS_DHE_RSA_WITH_AES_256_CBC_RMD => 0x0079, - TLS_RSA_WITH_3DES_EDE_CBC_RMD => 0x007c, - TLS_RSA_WITH_AES_128_CBC_RMD => 0x007d, - TLS_RSA_WITH_AES_256_CBC_RMD => 0x007e, - TLS_GOSTR341094_WITH_28147_CNT_IMIT => 0x0080, - TLS_GOSTR341001_WITH_28147_CNT_IMIT => 0x0081, - TLS_GOSTR341094_WITH_NULL_GOSTR3411 => 0x0082, - TLS_GOSTR341001_WITH_NULL_GOSTR3411 => 0x0083, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0084, - TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0085, - TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0086, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0087, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0088, - TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA => 0x0089, - TLS_PSK_WITH_RC4_128_SHA => 0x008a, - TLS_PSK_WITH_3DES_EDE_CBC_SHA => 0x008b, - TLS_PSK_WITH_AES_128_CBC_SHA => 0x008c, - TLS_PSK_WITH_AES_256_CBC_SHA => 0x008d, - TLS_DHE_PSK_WITH_RC4_128_SHA => 0x008e, - TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA => 0x008f, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA => 0x0090, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA => 0x0091, - TLS_RSA_PSK_WITH_RC4_128_SHA => 0x0092, - TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA => 0x0093, - TLS_RSA_PSK_WITH_AES_128_CBC_SHA => 0x0094, - TLS_RSA_PSK_WITH_AES_256_CBC_SHA => 0x0095, - TLS_RSA_WITH_SEED_CBC_SHA => 0x0096, - TLS_DH_DSS_WITH_SEED_CBC_SHA => 0x0097, - TLS_DH_RSA_WITH_SEED_CBC_SHA => 0x0098, - TLS_DHE_DSS_WITH_SEED_CBC_SHA => 0x0099, - TLS_DHE_RSA_WITH_SEED_CBC_SHA => 0x009a, - TLS_DH_anon_WITH_SEED_CBC_SHA => 0x009b, - TLS_RSA_WITH_AES_128_GCM_SHA256 => 0x009c, - TLS_RSA_WITH_AES_256_GCM_SHA384 => 0x009d, - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 => 0x009e, - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 => 0x009f, - TLS_DH_RSA_WITH_AES_128_GCM_SHA256 => 0x00a0, - TLS_DH_RSA_WITH_AES_256_GCM_SHA384 => 0x00a1, - TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 => 0x00a2, - TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 => 0x00a3, - TLS_DH_DSS_WITH_AES_128_GCM_SHA256 => 0x00a4, - TLS_DH_DSS_WITH_AES_256_GCM_SHA384 => 0x00a5, - TLS_DH_anon_WITH_AES_128_GCM_SHA256 => 0x00a6, - TLS_DH_anon_WITH_AES_256_GCM_SHA384 => 0x00a7, - TLS_PSK_WITH_AES_128_GCM_SHA256 => 0x00a8, - TLS_PSK_WITH_AES_256_GCM_SHA384 => 0x00a9, - TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 => 0x00aa, - TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 => 0x00ab, - TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 => 0x00ac, - TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 => 0x00ad, - TLS_PSK_WITH_AES_128_CBC_SHA256 => 0x00ae, - TLS_PSK_WITH_AES_256_CBC_SHA384 => 0x00af, - TLS_PSK_WITH_NULL_SHA256 => 0x00b0, - TLS_PSK_WITH_NULL_SHA384 => 0x00b1, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 => 0x00b2, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 => 0x00b3, - TLS_DHE_PSK_WITH_NULL_SHA256 => 0x00b4, - TLS_DHE_PSK_WITH_NULL_SHA384 => 0x00b5, - TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 => 0x00b6, - TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 => 0x00b7, - TLS_RSA_PSK_WITH_NULL_SHA256 => 0x00b8, - TLS_RSA_PSK_WITH_NULL_SHA384 => 0x00b9, - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00ba, - TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bb, - TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bc, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bd, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00be, - TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bf, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c0, - TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c1, - TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c2, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c3, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c4, - TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c5, - TLS_EMPTY_RENEGOTIATION_INFO_SCSV => 0x00ff, - TLS13_AES_128_GCM_SHA256 => 0x1301, - TLS13_AES_256_GCM_SHA384 => 0x1302, - TLS13_CHACHA20_POLY1305_SHA256 => 0x1303, - TLS13_AES_128_CCM_SHA256 => 0x1304, - TLS13_AES_128_CCM_8_SHA256 => 0x1305, - TLS_ECDH_ECDSA_WITH_NULL_SHA => 0xc001, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA => 0xc002, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc003, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA => 0xc004, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA => 0xc005, - TLS_ECDHE_ECDSA_WITH_NULL_SHA => 0xc006, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA => 0xc007, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc008, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA => 0xc009, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA => 0xc00a, - TLS_ECDH_RSA_WITH_NULL_SHA => 0xc00b, - TLS_ECDH_RSA_WITH_RC4_128_SHA => 0xc00c, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA => 0xc00d, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA => 0xc00e, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA => 0xc00f, - TLS_ECDHE_RSA_WITH_NULL_SHA => 0xc010, - TLS_ECDHE_RSA_WITH_RC4_128_SHA => 0xc011, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA => 0xc012, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA => 0xc013, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA => 0xc014, - TLS_ECDH_anon_WITH_NULL_SHA => 0xc015, - TLS_ECDH_anon_WITH_RC4_128_SHA => 0xc016, - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA => 0xc017, - TLS_ECDH_anon_WITH_AES_128_CBC_SHA => 0xc018, - TLS_ECDH_anon_WITH_AES_256_CBC_SHA => 0xc019, - TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA => 0xc01a, - TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA => 0xc01b, - TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA => 0xc01c, - TLS_SRP_SHA_WITH_AES_128_CBC_SHA => 0xc01d, - TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA => 0xc01e, - TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA => 0xc01f, - TLS_SRP_SHA_WITH_AES_256_CBC_SHA => 0xc020, - TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA => 0xc021, - TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA => 0xc022, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc023, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc024, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc025, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc026, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 => 0xc027, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 => 0xc028, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 => 0xc029, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 => 0xc02a, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02b, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02c, - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02d, - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02e, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => 0xc02f, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => 0xc030, - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 => 0xc031, - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 => 0xc032, - TLS_ECDHE_PSK_WITH_RC4_128_SHA => 0xc033, - TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA => 0xc034, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA => 0xc035, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA => 0xc036, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 => 0xc037, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 => 0xc038, - TLS_ECDHE_PSK_WITH_NULL_SHA => 0xc039, - TLS_ECDHE_PSK_WITH_NULL_SHA256 => 0xc03a, - TLS_ECDHE_PSK_WITH_NULL_SHA384 => 0xc03b, - TLS_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc03c, - TLS_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc03d, - TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc03e, - TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc03f, - TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc040, - TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc041, - TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc042, - TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc043, - TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc044, - TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc045, - TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 => 0xc046, - TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 => 0xc047, - TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc048, - TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc049, - TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc04a, - TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc04b, - TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04c, - TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04d, - TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04e, - TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04f, - TLS_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc050, - TLS_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc051, - TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc052, - TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc053, - TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc054, - TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc055, - TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc056, - TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc057, - TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc058, - TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc059, - TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 => 0xc05a, - TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 => 0xc05b, - TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05c, - TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05d, - TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05e, - TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05f, - TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc060, - TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc061, - TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc062, - TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc063, - TLS_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc064, - TLS_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc065, - TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc066, - TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc067, - TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc068, - TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc069, - TLS_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06a, - TLS_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06b, - TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06c, - TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06d, - TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06e, - TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06f, - TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc070, - TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc071, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc072, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc073, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc074, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc075, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc076, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc077, - TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc078, - TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc079, - TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07a, - TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07b, - TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07c, - TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07d, - TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07e, - TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07f, - TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc080, - TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc081, - TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc082, - TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc083, - TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 => 0xc084, - TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 => 0xc085, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc086, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc087, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc088, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc089, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08a, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08b, - TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08c, - TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08d, - TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08e, - TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08f, - TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc090, - TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc091, - TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc092, - TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc093, - TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc094, - TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc095, - TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc096, - TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc097, - TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc098, - TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc099, - TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc09a, - TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc09b, - TLS_RSA_WITH_AES_128_CCM => 0xc09c, - TLS_RSA_WITH_AES_256_CCM => 0xc09d, - TLS_DHE_RSA_WITH_AES_128_CCM => 0xc09e, - TLS_DHE_RSA_WITH_AES_256_CCM => 0xc09f, - TLS_RSA_WITH_AES_128_CCM_8 => 0xc0a0, - TLS_RSA_WITH_AES_256_CCM_8 => 0xc0a1, - TLS_DHE_RSA_WITH_AES_128_CCM_8 => 0xc0a2, - TLS_DHE_RSA_WITH_AES_256_CCM_8 => 0xc0a3, - TLS_PSK_WITH_AES_128_CCM => 0xc0a4, - TLS_PSK_WITH_AES_256_CCM => 0xc0a5, - TLS_DHE_PSK_WITH_AES_128_CCM => 0xc0a6, - TLS_DHE_PSK_WITH_AES_256_CCM => 0xc0a7, - TLS_PSK_WITH_AES_128_CCM_8 => 0xc0a8, - TLS_PSK_WITH_AES_256_CCM_8 => 0xc0a9, - TLS_PSK_DHE_WITH_AES_128_CCM_8 => 0xc0aa, - TLS_PSK_DHE_WITH_AES_256_CCM_8 => 0xc0ab, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM => 0xc0ac, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM => 0xc0ad, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 => 0xc0ae, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 => 0xc0af, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca8, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca9, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xccaa, - TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccab, - TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccac, - TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccad, - TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccae, - SSL_RSA_FIPS_WITH_DES_CBC_SHA => 0xfefe, - SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA => 0xfeff - } -} - -enum_builder! { - /// The `SignatureScheme` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: SignatureScheme; - EnumVal{ - RSA_PKCS1_SHA1 => 0x0201, - ECDSA_SHA1_Legacy => 0x0203, - RSA_PKCS1_SHA256 => 0x0401, - ECDSA_NISTP256_SHA256 => 0x0403, - RSA_PKCS1_SHA384 => 0x0501, - ECDSA_NISTP384_SHA384 => 0x0503, - RSA_PKCS1_SHA512 => 0x0601, - ECDSA_NISTP521_SHA512 => 0x0603, - RSA_PSS_SHA256 => 0x0804, - RSA_PSS_SHA384 => 0x0805, - RSA_PSS_SHA512 => 0x0806, - ED25519 => 0x0807, - ED448 => 0x0808 - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/error.rs b/third_party/rustls-fork-shadow-tls/src/error.rs deleted file mode 100644 index 32d4903..0000000 --- a/third_party/rustls-fork-shadow-tls/src/error.rs +++ /dev/null @@ -1,245 +0,0 @@ -use crate::msgs::enums::{AlertDescription, ContentType, HandshakeType}; -use crate::rand; - -use std::error::Error as StdError; -use std::fmt; -use std::time::SystemTimeError; - -/// rustls reports protocol errors using this type. -#[derive(Debug, PartialEq, Clone)] -pub enum Error { - /// We received a TLS message that isn't valid right now. - /// `expect_types` lists the message types we can expect right now. - /// `got_type` is the type we found. This error is typically - /// caused by a buggy TLS stack (the peer or this one), a broken - /// network, or an attack. - InappropriateMessage { - /// Which types we expected - expect_types: Vec, - /// What type we received - got_type: ContentType, - }, - - /// We received a TLS handshake message that isn't valid right now. - /// `expect_types` lists the handshake message types we can expect - /// right now. `got_type` is the type we found. - InappropriateHandshakeMessage { - /// Which handshake type we expected - expect_types: Vec, - /// What handshake type we received - got_type: HandshakeType, - }, - - /// The peer sent us a syntactically incorrect TLS message. - CorruptMessage, - - /// The peer sent us a TLS message with invalid contents. - CorruptMessagePayload(ContentType), - - /// The peer didn't give us any certificates. - NoCertificatesPresented, - - /// The certificate verifier doesn't support the given type of name. - UnsupportedNameType, - - /// We couldn't decrypt a message. This is invariably fatal. - DecryptError, - - /// We couldn't encrypt a message because it was larger than the allowed message size. - /// This should never happen if the application is using valid record sizes. - EncryptError, - - /// The peer doesn't support a protocol version/feature we require. - /// The parameter gives a hint as to what version/feature it is. - PeerIncompatibleError(String), - - /// The peer deviated from the standard TLS protocol. - /// The parameter gives a hint where. - PeerMisbehavedError(String), - - /// We received a fatal alert. This means the peer is unhappy. - AlertReceived(AlertDescription), - - /// We received an invalidly encoded certificate from the peer. - InvalidCertificateEncoding, - - /// We received a certificate with invalid signature type. - InvalidCertificateSignatureType, - - /// We received a certificate with invalid signature. - InvalidCertificateSignature, - - /// We received a certificate which includes invalid data. - InvalidCertificateData(String), - - /// The presented SCT(s) were invalid. - InvalidSct(sct::Error), - - /// A catch-all error for unlikely errors. - General(String), - - /// We failed to figure out what time it currently is. - FailedToGetCurrentTime, - - /// We failed to acquire random bytes from the system. - FailedToGetRandomBytes, - - /// This function doesn't work until the TLS handshake - /// is complete. - HandshakeNotComplete, - - /// The peer sent an oversized record/fragment. - PeerSentOversizedRecord, - - /// An incoming connection did not support any known application protocol. - NoApplicationProtocol, - - /// The `max_fragment_size` value supplied in configuration was too small, - /// or too large. - BadMaxFragmentSize, -} - -fn join(items: &[T]) -> String { - items - .iter() - .map(|x| format!("{:?}", x)) - .collect::>() - .join(" or ") -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Self::InappropriateMessage { - ref expect_types, - ref got_type, - } => write!( - f, - "received unexpected message: got {:?} when expecting {}", - got_type, - join::(expect_types) - ), - Self::InappropriateHandshakeMessage { - ref expect_types, - ref got_type, - } => write!( - f, - "received unexpected handshake message: got {:?} when expecting {}", - got_type, - join::(expect_types) - ), - Self::CorruptMessagePayload(ref typ) => { - write!(f, "received corrupt message of type {:?}", typ) - } - Self::PeerIncompatibleError(ref why) => write!(f, "peer is incompatible: {}", why), - Self::PeerMisbehavedError(ref why) => write!(f, "peer misbehaved: {}", why), - Self::AlertReceived(ref alert) => write!(f, "received fatal alert: {:?}", alert), - Self::InvalidCertificateEncoding => { - write!(f, "invalid peer certificate encoding") - } - Self::InvalidCertificateSignatureType => { - write!(f, "invalid peer certificate signature type") - } - Self::InvalidCertificateSignature => { - write!(f, "invalid peer certificate signature") - } - Self::InvalidCertificateData(ref reason) => { - write!(f, "invalid peer certificate contents: {}", reason) - } - Self::CorruptMessage => write!(f, "received corrupt message"), - Self::NoCertificatesPresented => write!(f, "peer sent no certificates"), - Self::UnsupportedNameType => write!(f, "presented server name type wasn't supported"), - Self::DecryptError => write!(f, "cannot decrypt peer's message"), - Self::EncryptError => write!(f, "cannot encrypt message"), - Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"), - Self::HandshakeNotComplete => write!(f, "handshake not complete"), - Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"), - Self::InvalidSct(ref err) => write!(f, "invalid certificate timestamp: {:?}", err), - Self::FailedToGetCurrentTime => write!(f, "failed to get current time"), - Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"), - Self::BadMaxFragmentSize => { - write!(f, "the supplied max_fragment_size was too small or large") - } - Self::General(ref err) => write!(f, "unexpected error: {}", err), - } - } -} - -impl From for Error { - #[inline] - fn from(_: SystemTimeError) -> Self { - Self::FailedToGetCurrentTime - } -} - -impl StdError for Error {} - -impl From for Error { - fn from(_: rand::GetRandomFailed) -> Self { - Self::FailedToGetRandomBytes - } -} - -#[cfg(test)] -mod tests { - use super::Error; - - #[test] - fn smoke() { - use crate::msgs::enums::{AlertDescription, ContentType, HandshakeType}; - use sct; - - let all = vec![ - Error::InappropriateMessage { - expect_types: vec![ContentType::Alert], - got_type: ContentType::Handshake, - }, - Error::InappropriateHandshakeMessage { - expect_types: vec![HandshakeType::ClientHello, HandshakeType::Finished], - got_type: HandshakeType::ServerHello, - }, - Error::CorruptMessage, - Error::CorruptMessagePayload(ContentType::Alert), - Error::NoCertificatesPresented, - Error::DecryptError, - Error::PeerIncompatibleError("no tls1.2".to_string()), - Error::PeerMisbehavedError("inconsistent something".to_string()), - Error::AlertReceived(AlertDescription::ExportRestriction), - Error::InvalidCertificateEncoding, - Error::InvalidCertificateSignatureType, - Error::InvalidCertificateSignature, - Error::InvalidCertificateData("Data".into()), - Error::InvalidSct(sct::Error::MalformedSct), - Error::General("undocumented error".to_string()), - Error::FailedToGetCurrentTime, - Error::FailedToGetRandomBytes, - Error::HandshakeNotComplete, - Error::PeerSentOversizedRecord, - Error::NoApplicationProtocol, - Error::BadMaxFragmentSize, - ]; - - for err in all { - println!("{:?}:", err); - println!(" fmt '{}'", err); - } - } - - #[test] - fn rand_error_mapping() { - use super::rand; - let err: Error = rand::GetRandomFailed.into(); - assert_eq!(err, Error::FailedToGetRandomBytes); - } - - #[test] - fn time_error_mapping() { - use std::time::SystemTime; - - let time_error = SystemTime::UNIX_EPOCH - .duration_since(SystemTime::now()) - .unwrap_err(); - let err: Error = time_error.into(); - assert_eq!(err, Error::FailedToGetCurrentTime); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/hash_hs.rs b/third_party/rustls-fork-shadow-tls/src/hash_hs.rs deleted file mode 100644 index 3dd66b1..0000000 --- a/third_party/rustls-fork-shadow-tls/src/hash_hs.rs +++ /dev/null @@ -1,240 +0,0 @@ -use crate::msgs::codec::Codec; -use crate::msgs::handshake::HandshakeMessagePayload; -use crate::msgs::message::{Message, MessagePayload}; -use ring::digest; -use std::mem; - -/// Early stage buffering of handshake payloads. -/// -/// Before we know the hash algorithm to use to verify the handshake, we just buffer the messages. -/// During the handshake, we may restart the transcript due to a HelloRetryRequest, reverting -/// from the `HandshakeHash` to a `HandshakeHashBuffer` again. -pub(crate) struct HandshakeHashBuffer { - buffer: Vec, - client_auth_enabled: bool, -} - -impl HandshakeHashBuffer { - pub(crate) fn new() -> Self { - Self { - buffer: Vec::new(), - client_auth_enabled: false, - } - } - - /// We might be doing client auth, so need to keep a full - /// log of the handshake. - pub(crate) fn set_client_auth_enabled(&mut self) { - self.client_auth_enabled = true; - } - - /// Hash/buffer a handshake message. - pub(crate) fn add_message(&mut self, m: &Message) { - if let MessagePayload::Handshake { encoded, .. } = &m.payload { - self.buffer - .extend_from_slice(&encoded.0); - } - } - - /// Hash or buffer a byte slice. - #[cfg(test)] - fn update_raw(&mut self, buf: &[u8]) { - self.buffer.extend_from_slice(buf); - } - - /// Get the hash value if we were to hash `extra` too. - pub(crate) fn get_hash_given( - &self, - hash: &'static digest::Algorithm, - extra: &[u8], - ) -> digest::Digest { - let mut ctx = digest::Context::new(hash); - ctx.update(&self.buffer); - ctx.update(extra); - ctx.finish() - } - - /// We now know what hash function the verify_data will use. - pub(crate) fn start_hash(self, alg: &'static digest::Algorithm) -> HandshakeHash { - let mut ctx = digest::Context::new(alg); - ctx.update(&self.buffer); - HandshakeHash { - ctx, - client_auth: match self.client_auth_enabled { - true => Some(self.buffer), - false => None, - }, - } - } -} - -/// This deals with keeping a running hash of the handshake -/// payloads. This is computed by buffering initially. Once -/// we know what hash function we need to use we switch to -/// incremental hashing. -/// -/// For client auth, we also need to buffer all the messages. -/// This is disabled in cases where client auth is not possible. -pub(crate) struct HandshakeHash { - /// None before we know what hash function we're using - ctx: digest::Context, - - /// buffer for client-auth. - client_auth: Option>, -} - -impl HandshakeHash { - /// We decided not to do client auth after all, so discard - /// the transcript. - pub(crate) fn abandon_client_auth(&mut self) { - self.client_auth = None; - } - - /// Hash/buffer a handshake message. - pub(crate) fn add_message(&mut self, m: &Message) -> &mut Self { - if let MessagePayload::Handshake { encoded, .. } = &m.payload { - self.update_raw(&encoded.0); - } - self - } - - /// Hash or buffer a byte slice. - fn update_raw(&mut self, buf: &[u8]) -> &mut Self { - self.ctx.update(buf); - - if let Some(buffer) = &mut self.client_auth { - buffer.extend_from_slice(buf); - } - - self - } - - /// Get the hash value if we were to hash `extra` too, - /// using hash function `hash`. - pub(crate) fn get_hash_given(&self, extra: &[u8]) -> digest::Digest { - let mut ctx = self.ctx.clone(); - ctx.update(extra); - ctx.finish() - } - - pub(crate) fn into_hrr_buffer(self) -> HandshakeHashBuffer { - let old_hash = self.ctx.finish(); - let old_handshake_hash_msg = - HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); - - HandshakeHashBuffer { - client_auth_enabled: self.client_auth.is_some(), - buffer: old_handshake_hash_msg.get_encoding(), - } - } - - /// Take the current hash value, and encapsulate it in a - /// 'handshake_hash' handshake message. Start this hash - /// again, with that message at the front. - pub(crate) fn rollup_for_hrr(&mut self) { - let ctx = &mut self.ctx; - - let old_ctx = mem::replace(ctx, digest::Context::new(ctx.algorithm())); - let old_hash = old_ctx.finish(); - let old_handshake_hash_msg = - HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); - - self.update_raw(&old_handshake_hash_msg.get_encoding()); - } - - /// Get the current hash value. - pub(crate) fn get_current_hash(&self) -> digest::Digest { - self.ctx.clone().finish() - } - - /// Takes this object's buffer containing all handshake messages - /// so far. This method only works once; it resets the buffer - /// to empty. - #[cfg(feature = "tls12")] - pub(crate) fn take_handshake_buf(&mut self) -> Option> { - self.client_auth.take() - } - - /// The digest algorithm - pub(crate) fn algorithm(&self) -> &'static digest::Algorithm { - self.ctx.algorithm() - } -} - -#[cfg(test)] -mod test { - use super::HandshakeHashBuffer; - use ring::digest; - - #[test] - fn hashes_correctly() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.update_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&digest::SHA256); - assert!(hh.client_auth.is_none()); - hh.update_raw(b"world"); - let h = hh.get_current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - } - - #[cfg(feature = "tls12")] - #[test] - fn buffers_correctly() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.set_client_auth_enabled(); - hhb.update_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&digest::SHA256); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(5) - ); - hh.update_raw(b"world"); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(10) - ); - let h = hh.get_current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - let buf = hh.take_handshake_buf(); - assert_eq!(Some(b"helloworld".to_vec()), buf); - } - - #[test] - fn abandon() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.set_client_auth_enabled(); - hhb.update_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&digest::SHA256); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(5) - ); - hh.abandon_client_auth(); - assert_eq!(hh.client_auth, None); - hh.update_raw(b"world"); - assert_eq!(hh.client_auth, None); - let h = hh.get_current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/key.rs b/third_party/rustls-fork-shadow-tls/src/key.rs deleted file mode 100644 index dbd4cc5..0000000 --- a/third_party/rustls-fork-shadow-tls/src/key.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::fmt; - -/// This type contains a private key by value. -/// -/// The private key must be DER-encoded ASN.1 in either -/// PKCS#8 or PKCS#1 format. -/// -/// The `rustls-pemfile` crate can be used to extract -/// private keys from a PEM file in these formats. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct PrivateKey(pub Vec); - -/// This type contains a single certificate by value. -/// -/// The certificate must be DER-encoded X.509. -/// -/// The `rustls-pemfile` crate can be used to parse a PEM file. -/// -/// ## Note -/// -/// If you are receiving certificates from an untrusted client or server, the contents -/// must be validated manually. -#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Certificate(pub Vec); - -impl AsRef<[u8]> for Certificate { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl fmt::Debug for Certificate { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use super::bs_debug::BsDebug; - f.debug_tuple("Certificate") - .field(&BsDebug(&self.0)) - .finish() - } -} - -#[cfg(test)] -mod test { - use super::Certificate; - - #[test] - fn certificate_debug() { - assert_eq!( - "Certificate(b\"ab\")", - format!("{:?}", Certificate(b"ab".to_vec())) - ); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/key_log.rs b/third_party/rustls-fork-shadow-tls/src/key_log.rs deleted file mode 100644 index 1b6b3fe..0000000 --- a/third_party/rustls-fork-shadow-tls/src/key_log.rs +++ /dev/null @@ -1,55 +0,0 @@ -/// This trait represents the ability to do something useful -/// with key material, such as logging it to a file for debugging. -/// -/// Naturally, secrets passed over the interface are *extremely* -/// sensitive and can break the security of past, present and -/// future sessions. -/// -/// You'll likely want some interior mutability in your -/// implementation to make this useful. -/// -/// See [`KeyLogFile`](crate::KeyLogFile) that implements the standard -/// `SSLKEYLOGFILE` environment variable behaviour. -pub trait KeyLog: Send + Sync { - /// Log the given `secret`. `client_random` is provided for - /// session identification. `label` describes precisely what - /// `secret` means: - /// - /// - `CLIENT_RANDOM`: `secret` is the master secret for a TLSv1.2 session. - /// - `CLIENT_EARLY_TRAFFIC_SECRET`: `secret` encrypts early data - /// transmitted by a client - /// - `SERVER_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts - /// handshake messages from the server during a TLSv1.3 handshake. - /// - `CLIENT_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts - /// handshake messages from the client during a TLSv1.3 handshake. - /// - `SERVER_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data - /// from the server in a TLSv1.3 session. - /// - `CLIENT_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data - /// from the client in a TLSv1.3 session. - /// - `EXPORTER_SECRET`: `secret` is the post-handshake exporter secret - /// in a TLSv1.3 session. - /// - /// These strings are selected to match the NSS key log format: - /// - fn log(&self, label: &str, client_random: &[u8], secret: &[u8]); - - /// Indicates whether the secret with label `label` will be logged. - /// - /// If `will_log` returns true then `log` will be called with the secret. - /// Otherwise, `log` will not be called for the secret. This is a - /// performance optimization. - fn will_log(&self, _label: &str) -> bool { - true - } -} - -/// KeyLog that does exactly nothing. -pub struct NoKeyLog; - -impl KeyLog for NoKeyLog { - fn log(&self, _: &str, _: &[u8], _: &[u8]) {} - #[inline] - fn will_log(&self, _label: &str) -> bool { - false - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/key_log_file.rs b/third_party/rustls-fork-shadow-tls/src/key_log_file.rs deleted file mode 100644 index 7907113..0000000 --- a/third_party/rustls-fork-shadow-tls/src/key_log_file.rs +++ /dev/null @@ -1,154 +0,0 @@ -#[cfg(feature = "logging")] -use crate::log::warn; -use crate::KeyLog; -use std::env; -use std::fs::{File, OpenOptions}; -use std::io; -use std::io::Write; -use std::path::Path; -use std::sync::Mutex; - -// Internal mutable state for KeyLogFile -struct KeyLogFileInner { - file: Option, - buf: Vec, -} - -impl KeyLogFileInner { - fn new(var: Result) -> Self { - let path = match var { - Ok(ref s) => Path::new(s), - Err(env::VarError::NotUnicode(ref s)) => Path::new(s), - Err(env::VarError::NotPresent) => { - return Self { - file: None, - buf: Vec::new(), - }; - } - }; - - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - let file = match OpenOptions::new() - .append(true) - .create(true) - .open(path) - { - Ok(f) => Some(f), - Err(e) => { - warn!("unable to create key log file {:?}: {}", path, e); - None - } - }; - - Self { - file, - buf: Vec::new(), - } - } - - fn try_write(&mut self, label: &str, client_random: &[u8], secret: &[u8]) -> io::Result<()> { - let mut file = match self.file { - None => { - return Ok(()); - } - Some(ref f) => f, - }; - - self.buf.truncate(0); - write!(self.buf, "{} ", label)?; - for b in client_random.iter() { - write!(self.buf, "{:02x}", b)?; - } - write!(self.buf, " ")?; - for b in secret.iter() { - write!(self.buf, "{:02x}", b)?; - } - writeln!(self.buf)?; - file.write_all(&self.buf) - } -} - -/// [`KeyLog`] implementation that opens a file whose name is -/// given by the `SSLKEYLOGFILE` environment variable, and writes -/// keys into it. -/// -/// If `SSLKEYLOGFILE` is not set, this does nothing. -/// -/// If such a file cannot be opened, or cannot be written then -/// this does nothing but logs errors at warning-level. -pub struct KeyLogFile(Mutex); - -impl KeyLogFile { - /// Makes a new `KeyLogFile`. The environment variable is - /// inspected and the named file is opened during this call. - pub fn new() -> Self { - let var = env::var("SSLKEYLOGFILE"); - Self(Mutex::new(KeyLogFileInner::new(var))) - } -} - -impl KeyLog for KeyLogFile { - fn log(&self, label: &str, client_random: &[u8], secret: &[u8]) { - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - match self - .0 - .lock() - .unwrap() - .try_write(label, client_random, secret) - { - Ok(()) => {} - Err(e) => { - warn!("error writing to key log file: {}", e); - } - } - } -} - -#[cfg(all(test, target_os = "linux"))] -mod test { - use super::*; - - fn init() { - let _ = env_logger::builder() - .is_test(true) - .try_init(); - } - - #[test] - fn test_env_var_is_not_unicode() { - init(); - let mut inner = KeyLogFileInner::new(Err(env::VarError::NotUnicode( - "/tmp/keylogfileinnertest".into(), - ))); - assert!(inner - .try_write("label", b"random", b"secret") - .is_ok()); - } - - #[test] - fn test_env_var_is_not_set() { - init(); - let mut inner = KeyLogFileInner::new(Err(env::VarError::NotPresent)); - assert!(inner - .try_write("label", b"random", b"secret") - .is_ok()); - } - - #[test] - fn test_env_var_cannot_be_opened() { - init(); - let mut inner = KeyLogFileInner::new(Ok("/dev/does-not-exist".into())); - assert!(inner - .try_write("label", b"random", b"secret") - .is_ok()); - } - - #[test] - fn test_env_var_cannot_be_written() { - init(); - let mut inner = KeyLogFileInner::new(Ok("/dev/full".into())); - assert!(inner - .try_write("label", b"random", b"secret") - .is_err()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/kx.rs b/third_party/rustls-fork-shadow-tls/src/kx.rs deleted file mode 100644 index 4736570..0000000 --- a/third_party/rustls-fork-shadow-tls/src/kx.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::fmt; - -use crate::error::Error; -use crate::msgs::enums::NamedGroup; - -/// An in-progress key exchange. This has the algorithm, -/// our private key, and our public key. -pub(crate) struct KeyExchange { - skxg: &'static SupportedKxGroup, - privkey: ring::agreement::EphemeralPrivateKey, - pub(crate) pubkey: ring::agreement::PublicKey, -} - -impl KeyExchange { - /// Choose a SupportedKxGroup by name, from a list of supported groups. - pub(crate) fn choose( - name: NamedGroup, - supported: &[&'static SupportedKxGroup], - ) -> Option<&'static SupportedKxGroup> { - supported - .iter() - .find(|skxg| skxg.name == name) - .cloned() - } - - /// Start a key exchange, using the given SupportedKxGroup. - /// - /// This generates an ephemeral key pair and stores it in the returned KeyExchange object. - pub(crate) fn start(skxg: &'static SupportedKxGroup) -> Option { - let rng = ring::rand::SystemRandom::new(); - let ours = - ring::agreement::EphemeralPrivateKey::generate(skxg.agreement_algorithm, &rng).ok()?; - - let pubkey = ours.compute_public_key().ok()?; - - Some(Self { - skxg, - privkey: ours, - pubkey, - }) - } - - /// Return the group being used. - pub(crate) fn group(&self) -> NamedGroup { - self.skxg.name - } - - /// Completes the key exchange, given the peer's public key. - /// - /// The shared secret is passed into the closure passed down in `f`, and the result of calling - /// `f` is returned to the caller. - pub(crate) fn complete( - self, - peer: &[u8], - f: impl FnOnce(&[u8]) -> Result, - ) -> Result { - let peer_key = ring::agreement::UnparsedPublicKey::new(self.skxg.agreement_algorithm, peer); - ring::agreement::agree_ephemeral(self.privkey, &peer_key, (), f) - .map_err(|()| Error::PeerMisbehavedError("key agreement failed".to_string())) - } -} - -/// A key-exchange group supported by rustls. -/// -/// All possible instances of this class are provided by the library in -/// the `ALL_KX_GROUPS` array. -pub struct SupportedKxGroup { - /// The IANA "TLS Supported Groups" name of the group - pub name: NamedGroup, - - /// The corresponding ring agreement::Algorithm - agreement_algorithm: &'static ring::agreement::Algorithm, -} - -impl fmt::Debug for SupportedKxGroup { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.name.fmt(f) - } -} - -/// Ephemeral ECDH on curve25519 (see RFC7748) -pub static X25519: SupportedKxGroup = SupportedKxGroup { - name: NamedGroup::X25519, - agreement_algorithm: &ring::agreement::X25519, -}; - -/// Ephemeral ECDH on secp256r1 (aka NIST-P256) -pub static SECP256R1: SupportedKxGroup = SupportedKxGroup { - name: NamedGroup::secp256r1, - agreement_algorithm: &ring::agreement::ECDH_P256, -}; - -/// Ephemeral ECDH on secp384r1 (aka NIST-P384) -pub static SECP384R1: SupportedKxGroup = SupportedKxGroup { - name: NamedGroup::secp384r1, - agreement_algorithm: &ring::agreement::ECDH_P384, -}; - -/// A list of all the key exchange groups supported by rustls. -pub static ALL_KX_GROUPS: [&SupportedKxGroup; 3] = [&X25519, &SECP256R1, &SECP384R1]; diff --git a/third_party/rustls-fork-shadow-tls/src/lib.rs b/third_party/rustls-fork-shadow-tls/src/lib.rs deleted file mode 100644 index 27db2b2..0000000 --- a/third_party/rustls-fork-shadow-tls/src/lib.rs +++ /dev/null @@ -1,534 +0,0 @@ -//! # Rustls - a modern TLS library -//! Rustls is a TLS library that aims to provide a good level of cryptographic security, -//! requires no configuration to achieve that security, and provides no unsafe features or -//! obsolete cryptography. -//! -//! ## Current features -//! -//! * TLS1.2 and TLS1.3. -//! * ECDSA, Ed25519 or RSA server authentication by clients. -//! * ECDSA, Ed25519 or RSA server authentication by servers. -//! * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. -//! * AES128-GCM and AES256-GCM bulk encryption, with safe nonces. -//! * ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). -//! * ALPN support. -//! * SNI support. -//! * Tunable fragment size to make TLS messages match size of underlying transport. -//! * Optional use of vectored IO to minimise system calls. -//! * TLS1.2 session resumption. -//! * TLS1.2 resumption via tickets ([RFC5077](https://tools.ietf.org/html/rfc5077)). -//! * TLS1.3 resumption via tickets or session storage. -//! * TLS1.3 0-RTT data for clients. -//! * TLS1.3 0-RTT data for servers. -//! * Client authentication by clients. -//! * Client authentication by servers. -//! * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)). -//! * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)). -//! * OCSP stapling by servers. -//! * SCT stapling by servers. -//! * SCT verification by clients. -//! -//! ## Possible future features -//! -//! * PSK support. -//! * OCSP verification by clients. -//! * Certificate pinning. -//! -//! ## Non-features -//! -//! For reasons [explained in the manual](manual), -//! rustls does not and will not support: -//! -//! * SSL1, SSL2, SSL3, TLS1 or TLS1.1. -//! * RC4. -//! * DES or triple DES. -//! * EXPORT ciphersuites. -//! * MAC-then-encrypt ciphersuites. -//! * Ciphersuites without forward secrecy. -//! * Renegotiation. -//! * Kerberos. -//! * Compression. -//! * Discrete-log Diffie-Hellman. -//! * Automatic protocol version downgrade. -//! -//! There are plenty of other libraries that provide these features should you -//! need them. -//! -//! ### Platform support -//! -//! Rustls uses [`ring`](https://crates.io/crates/ring) for implementing the -//! cryptography in TLS. As a result, rustls only runs on platforms -//! [supported by `ring`](https://github.com/briansmith/ring#online-automated-testing). -//! At the time of writing this means x86, x86-64, armv7, and aarch64. -//! -//! ## Design Overview -//! ### Rustls does not take care of network IO -//! It doesn't make or accept TCP connections, or do DNS, or read or write files. -//! -//! There's example client and server code which uses mio to do all needed network -//! IO. -//! -//! ### Rustls provides encrypted pipes -//! These are the [`ServerConnection`] and [`ClientConnection`] types. You supply raw TLS traffic -//! on the left (via the [`read_tls()`] and [`write_tls()`] methods) and then read/write the -//! plaintext on the right: -//! -//! [`read_tls()`]: Connection::read_tls -//! [`write_tls()`]: Connection::read_tls -//! -//! ```text -//! TLS Plaintext -//! === ========= -//! read_tls() +-----------------------+ reader() as io::Read -//! | | -//! +---------> ClientConnection +---------> -//! | or | -//! <---------+ ServerConnection <---------+ -//! | | -//! write_tls() +-----------------------+ writer() as io::Write -//! ``` -//! -//! ### Rustls takes care of server certificate verification -//! You do not need to provide anything other than a set of root certificates to trust. -//! Certificate verification cannot be turned off or disabled in the main API. -//! -//! ## Getting started -//! This is the minimum you need to do to make a TLS client connection. -//! -//! First we load some root certificates. These are used to authenticate the server. -//! The recommended way is to depend on the `webpki_roots` crate which contains -//! the Mozilla set of root certificates. -//! -//! ```rust,no_run -//! let mut root_store = rustls::RootCertStore::empty(); -//! root_store.add_server_trust_anchors( -//! webpki_roots::TLS_SERVER_ROOTS -//! .0 -//! .iter() -//! .map(|ta| { -//! rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( -//! ta.subject, -//! ta.spki, -//! ta.name_constraints, -//! ) -//! }) -//! ); -//! ``` -//! -//! Next, we make a `ClientConfig`. You're likely to make one of these per process, -//! and use it for all connections made by that process. -//! -//! ```rust,no_run -//! # let root_store: rustls::RootCertStore = panic!(); -//! let config = rustls::ClientConfig::builder() -//! .with_safe_defaults() -//! .with_root_certificates(root_store) -//! .with_no_client_auth(); -//! ``` -//! -//! Now we can make a connection. You need to provide the server's hostname so we -//! know what to expect to find in the server's certificate. -//! -//! ```rust -//! # use rustls; -//! # use webpki; -//! # use std::sync::Arc; -//! # use std::convert::TryInto; -//! # let mut root_store = rustls::RootCertStore::empty(); -//! # root_store.add_server_trust_anchors( -//! # webpki_roots::TLS_SERVER_ROOTS -//! # .0 -//! # .iter() -//! # .map(|ta| { -//! # rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( -//! # ta.subject, -//! # ta.spki, -//! # ta.name_constraints, -//! # ) -//! # }) -//! # ); -//! # let config = rustls::ClientConfig::builder() -//! # .with_safe_defaults() -//! # .with_root_certificates(root_store) -//! # .with_no_client_auth(); -//! let rc_config = Arc::new(config); -//! let example_com = "example.com".try_into().unwrap(); -//! let mut client = rustls::ClientConnection::new(rc_config, example_com); -//! ``` -//! -//! Now you should do appropriate IO for the `client` object. If `client.wants_read()` yields -//! true, you should call `client.read_tls()` when the underlying connection has data. -//! Likewise, if `client.wants_write()` yields true, you should call `client.write_tls()` -//! when the underlying connection is able to send data. You should continue doing this -//! as long as the connection is valid. -//! -//! The return types of `read_tls()` and `write_tls()` only tell you if the IO worked. No -//! parsing or processing of the TLS messages is done. After each `read_tls()` you should -//! therefore call `client.process_new_packets()` which parses and processes the messages. -//! Any error returned from `process_new_packets` is fatal to the connection, and will tell you -//! why. For example, if the server's certificate is expired `process_new_packets` will -//! return `Err(WebPkiError(CertExpired, ValidateServerCert))`. From this point on, -//! `process_new_packets` will not do any new work and will return that error continually. -//! -//! You can extract newly received data by calling `client.reader()` (which implements the -//! `io::Read` trait). You can send data to the peer by calling `client.writer()` (which -//! implements `io::Write` trait). Note that `client.writer().write()` buffers data you -//! send if the TLS connection is not yet established: this is useful for writing (say) a -//! HTTP request, but this is buffered so avoid large amounts of data. -//! -//! The following code uses a fictional socket IO API for illustration, and does not handle -//! errors. -//! -//! ```rust,no_run -//! # let mut client = rustls::ClientConnection::new(panic!(), panic!()).unwrap(); -//! # struct Socket { } -//! # impl Socket { -//! # fn ready_for_write(&self) -> bool { false } -//! # fn ready_for_read(&self) -> bool { false } -//! # fn wait_for_something_to_happen(&self) { } -//! # } -//! # -//! # use std::io::{Read, Write, Result}; -//! # impl Read for Socket { -//! # fn read(&mut self, buf: &mut [u8]) -> Result { panic!() } -//! # } -//! # impl Write for Socket { -//! # fn write(&mut self, buf: &[u8]) -> Result { panic!() } -//! # fn flush(&mut self) -> Result<()> { panic!() } -//! # } -//! # -//! # fn connect(_address: &str, _port: u16) -> Socket { -//! # panic!(); -//! # } -//! use std::io; -//! use rustls::Connection; -//! -//! client.writer().write(b"GET / HTTP/1.0\r\n\r\n").unwrap(); -//! let mut socket = connect("example.com", 443); -//! loop { -//! if client.wants_read() && socket.ready_for_read() { -//! client.read_tls(&mut socket).unwrap(); -//! client.process_new_packets().unwrap(); -//! -//! let mut plaintext = Vec::new(); -//! client.reader().read_to_end(&mut plaintext).unwrap(); -//! io::stdout().write(&plaintext).unwrap(); -//! } -//! -//! if client.wants_write() && socket.ready_for_write() { -//! client.write_tls(&mut socket).unwrap(); -//! } -//! -//! socket.wait_for_something_to_happen(); -//! } -//! ``` -//! -//! # Examples -//! [`tlsserver`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsserver-mio.rs) -//! and [`tlsclient`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsclient-mio.rs) -//! are full worked examples. These both use mio. -//! -//! # Crate features -//! Here's a list of what features are exposed by the rustls crate and what -//! they mean. -//! -//! - `logging`: this makes the rustls crate depend on the `log` crate. -//! rustls outputs interesting protocol-level messages at `trace!` and `debug!` -//! level, and protocol-level errors at `warn!` and `error!` level. The log -//! messages do not contain secret key data, and so are safe to archive without -//! affecting session security. This feature is in the default set. -//! -//! - `dangerous_configuration`: this feature enables a `dangerous()` method on -//! `ClientConfig` and `ServerConfig` that allows setting inadvisable options, -//! such as replacing the certificate verification process. Applications -//! requesting this feature should be reviewed carefully. -//! -//! - `quic`: this feature exposes additional constructors and functions -//! for using rustls as a TLS library for QUIC. See the `quic` module for -//! details of these. You will only need this if you're writing a QUIC -//! implementation. -//! -//! - `tls12`: enables support for TLS version 1.2. This feature is in the default -//! set. Note that, due to the additive nature of Cargo features and because it -//! is enabled by default, other crates in your dependency graph could re-enable -//! it for your application. If you want to disable TLS 1.2 for security reasons, -//! consider explicitly enabling TLS 1.3 only in the config builder API. -//! -//! - `read_buf`: When building with Rust Nightly, adds support for the unstable -//! `std::io::ReadBuf` and related APIs. This reduces costs from initializing -//! buffers. Will do nothing on non-Nightly releases. - -// Require docs for public APIs, deny unsafe code, etc. -#![forbid(unsafe_code, unused_must_use)] -#![cfg_attr(not(read_buf), forbid(unstable_features))] -#![deny( - clippy::clone_on_ref_ptr, - clippy::use_self, - trivial_casts, - trivial_numeric_casts, - missing_docs, - unreachable_pub, - unused_import_braces, - unused_extern_crates -)] -// Relax these clippy lints: -// - ptr_arg: this triggers on references to type aliases that are Vec -// underneath. -// - too_many_arguments: some things just need a lot of state, wrapping it -// doesn't necessarily make it easier to follow what's going on -// - new_ret_no_self: we sometimes return `Arc`, which seems fine -// - single_component_path_imports: our top-level `use log` import causes -// a false positive, https://github.com/rust-lang/rust-clippy/issues/5210 -// - new_without_default: for internal constructors, the indirection is not -// helpful -#![allow( - clippy::too_many_arguments, - clippy::new_ret_no_self, - clippy::ptr_arg, - clippy::single_component_path_imports, - clippy::new_without_default -)] -// Enable documentation for all features on docs.rs -#![cfg_attr(docsrs, feature(doc_cfg))] -// XXX: Because of https://github.com/rust-lang/rust/issues/54726, we cannot -// write `#![rustversion::attr(nightly, feature(read_buf))]` here. Instead, -// build.rs set `read_buf` for (only) Rust Nightly to get the same effect. -// -// All the other conditional logic in the crate could use -// `#[rustversion::nightly]` instead of `#[cfg(read_buf)]`; `#[cfg(read_buf)]` -// is used to avoid needing `rustversion` to be compiled twice during -// cross-compiling. -#![cfg_attr(read_buf, feature(read_buf))] - -// log for logging (optional). -#[cfg(feature = "logging")] -use log; - -#[cfg(not(feature = "logging"))] -#[macro_use] -mod log { - macro_rules! trace ( ($($tt:tt)*) => {{}} ); - macro_rules! debug ( ($($tt:tt)*) => {{}} ); - macro_rules! warn ( ($($tt:tt)*) => {{}} ); - macro_rules! error ( ($($tt:tt)*) => {{}} ); -} - -#[macro_use] -mod msgs; -mod anchors; -mod cipher; -mod conn; -mod error; -mod hash_hs; -mod limited_cache; -mod rand; -mod record_layer; -mod stream; -#[cfg(feature = "tls12")] -mod tls12; -mod tls13; -mod vecbuf; -mod verify; -#[cfg(test)] -mod verifybench; -mod x509; -#[macro_use] -mod check; -mod bs_debug; -mod builder; -mod enums; -mod key; -mod key_log; -mod key_log_file; -mod kx; -mod suites; -mod ticketer; -mod versions; - -/// Internal classes which may be useful outside the library. -/// The contents of this section DO NOT form part of the stable interface. -pub mod internal { - /// Low-level TLS message parsing and encoding functions. - pub mod msgs { - pub use crate::msgs::*; - } - /// Low-level TLS message decryption functions. - pub mod cipher { - pub use crate::cipher::MessageDecrypter; - } -} - -// The public interface is: -pub use crate::anchors::{OwnedTrustAnchor, RootCertStore}; -pub use crate::builder::{ - ConfigBuilder, ConfigSide, WantsCipherSuites, WantsKxGroups, WantsVerifier, WantsVersions, -}; -pub use crate::conn::{ - CommonState, Connection, ConnectionCommon, IoState, Reader, SideData, Writer, -}; -pub use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -pub use crate::error::Error; -pub use crate::key::{Certificate, PrivateKey}; -pub use crate::key_log::{KeyLog, NoKeyLog}; -pub use crate::key_log_file::KeyLogFile; -pub use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS}; -pub use crate::msgs::enums::{ - AlertDescription, ContentType, HandshakeType, NamedGroup, SignatureAlgorithm, -}; -pub use crate::msgs::handshake::{DigitallySignedStruct, DistinguishedNames}; -pub use crate::stream::{Stream, StreamOwned}; -pub use crate::suites::{ - BulkAlgorithm, SupportedCipherSuite, ALL_CIPHER_SUITES, DEFAULT_CIPHER_SUITES, -}; -#[cfg(feature = "secret_extraction")] -pub use crate::suites::{ConnectionTrafficSecrets, ExtractedSecrets}; -pub use crate::ticketer::Ticketer; -#[cfg(feature = "tls12")] -pub use crate::tls12::Tls12CipherSuite; -pub use crate::tls13::Tls13CipherSuite; -pub use crate::versions::{SupportedProtocolVersion, ALL_VERSIONS, DEFAULT_VERSIONS}; - -/// Items for use in a client. -pub mod client { - pub(super) mod builder; - mod client_conn; - mod common; - pub(super) mod handy; - mod hs; - #[cfg(feature = "tls12")] - mod tls12; - mod tls13; - - pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert}; - #[cfg(feature = "quic")] - pub use client_conn::ClientQuicExt; - pub use client_conn::InvalidDnsNameError; - pub use client_conn::ResolvesClientCert; - pub use client_conn::ServerName; - pub use client_conn::StoresClientSessions; - pub use client_conn::{ - ClientConfig, ClientConnection, ClientConnectionData, ClientSessionIdGenerator, - ClientSessionIdGenerators, ClientTls12SessionIdGenerator, WriteEarlyData, - }; - pub use handy::{ClientSessionMemoryCache, NoClientSessionStorage}; - - #[cfg(feature = "dangerous_configuration")] - pub use crate::verify::{ - CertificateTransparencyPolicy, HandshakeSignatureValid, ServerCertVerified, - ServerCertVerifier, WebPkiVerifier, - }; - #[cfg(feature = "dangerous_configuration")] - pub use client_conn::danger::DangerousClientConfig; -} - -pub use client::{ - ClientConfig, ClientConnection, ClientSessionIdGenerator, ClientSessionIdGenerators, - ClientTls12SessionIdGenerator, ServerName, -}; - -/// Items for use in a server. -pub mod server { - pub(crate) mod builder; - mod common; - pub(crate) mod handy; - mod hs; - mod server_conn; - #[cfg(feature = "tls12")] - mod tls12; - mod tls13; - - pub use crate::verify::{ - AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth, - }; - pub use builder::WantsServerCert; - pub use handy::ResolvesServerCertUsingSni; - pub use handy::{NoServerSessionStorage, ServerSessionMemoryCache}; - #[cfg(feature = "quic")] - pub use server_conn::ServerQuicExt; - pub use server_conn::StoresServerSessions; - pub use server_conn::{ - Accepted, Acceptor, ReadEarlyData, ServerConfig, ServerConnection, ServerConnectionData, - }; - pub use server_conn::{ClientHello, ProducesTickets, ResolvesServerCert}; - - #[cfg(feature = "dangerous_configuration")] - pub use crate::verify::{ClientCertVerified, ClientCertVerifier, DnsName}; -} - -pub use server::{ServerConfig, ServerConnection}; - -/// All defined ciphersuites appear in this module. -/// -/// [`ALL_CIPHER_SUITES`] is provided as an array of all of these values. -pub mod cipher_suite { - pub use crate::suites::CipherSuiteCommon; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; - #[cfg(feature = "tls12")] - pub use crate::tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; - pub use crate::tls13::TLS13_AES_128_GCM_SHA256; - pub use crate::tls13::TLS13_AES_256_GCM_SHA384; - pub use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256; -} - -/// All defined protocol versions appear in this module. -/// -/// ALL_VERSIONS is a provided as an array of all of these values. -pub mod version { - #[cfg(feature = "tls12")] - pub use crate::versions::TLS12; - pub use crate::versions::TLS13; -} - -/// All defined key exchange groups appear in this module. -/// -/// ALL_KX_GROUPS is provided as an array of all of these values. -pub mod kx_group { - pub use crate::kx::SECP256R1; - pub use crate::kx::SECP384R1; - pub use crate::kx::X25519; -} - -/// Message signing interfaces and implementations. -pub mod sign; - -#[cfg(feature = "quic")] -#[cfg_attr(docsrs, doc(cfg(feature = "quic")))] -/// APIs for implementing QUIC TLS -pub mod quic; - -/// This is the rustls manual. -pub mod manual; - -/** Type renames. */ -#[allow(clippy::upper_case_acronyms)] -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use ResolvesServerCertUsingSni")] -pub type ResolvesServerCertUsingSNI = server::ResolvesServerCertUsingSni; -#[allow(clippy::upper_case_acronyms)] -#[cfg(feature = "dangerous_configuration")] -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use client::WebPkiVerifier")] -pub type WebPKIVerifier = client::WebPkiVerifier; -#[allow(clippy::upper_case_acronyms)] -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use Error")] -pub type TLSError = Error; -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use ClientConnection")] -pub type ClientSession = ClientConnection; -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use ServerConnection")] -pub type ServerSession = ServerConnection; - -/* Apologies: would make a trait alias here, but those remain unstable. -pub trait Session = Connection; -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/limited_cache.rs b/third_party/rustls-fork-shadow-tls/src/limited_cache.rs deleted file mode 100644 index 6994d88..0000000 --- a/third_party/rustls-fork-shadow-tls/src/limited_cache.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::borrow::Borrow; -use std::collections::hash_map::Entry; -use std::collections::{HashMap, VecDeque}; -use std::hash::Hash; - -/// A HashMap-alike, which never gets larger than a specified -/// capacity, and evicts the oldest insertion to maintain this. -/// -/// The requested capacity may be rounded up by the underlying -/// collections. This implementation uses all the allocated -/// storage. -/// -/// This is inefficient: it stores keys twice. -pub(crate) struct LimitedCache { - map: HashMap, - - // first item is the oldest key - oldest: VecDeque, -} - -impl LimitedCache -where - K: Eq + Hash + Clone + std::fmt::Debug, -{ - /// Create a new LimitedCache with the given rough capacity. - pub(crate) fn new(capacity_order_of_magnitude: usize) -> Self { - Self { - map: HashMap::with_capacity(capacity_order_of_magnitude), - oldest: VecDeque::with_capacity(capacity_order_of_magnitude), - } - } - - pub(crate) fn insert(&mut self, k: K, v: V) { - let inserted_new_item = match self.map.entry(k) { - Entry::Occupied(mut old) => { - // nb. does not freshen entry in `oldest` - old.insert(v); - false - } - - entry @ Entry::Vacant(_) => { - self.oldest - .push_back(entry.key().clone()); - entry.or_insert(v); - true - } - }; - - // ensure next insert() does not require a realloc - if inserted_new_item && self.oldest.capacity() == self.oldest.len() { - if let Some(oldest_key) = self.oldest.pop_front() { - self.map.remove(&oldest_key); - } - } - } - - pub(crate) fn get(&self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq, - { - self.map.get(k) - } - - pub(crate) fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - Q: Hash + Eq, - { - if let Some(value) = self.map.remove(k) { - // O(N) search, followed by O(N) removal - if let Some(index) = self - .oldest - .iter() - .position(|item| item.borrow() == k) - { - self.oldest.remove(index); - } - Some(value) - } else { - None - } - } -} - -#[cfg(test)] -mod test { - type Test = super::LimitedCache; - - #[test] - fn test_updates_existing_item() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("abc".into(), 2); - assert_eq!(t.get("abc"), Some(&2)); - } - - #[test] - fn test_evicts_oldest_item() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - t.insert("ghi".into(), 3); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), Some(&2)); - assert_eq!(t.get("ghi"), Some(&3)); - } - - #[test] - fn test_evicts_second_oldest_item_if_first_removed() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("abc"), Some(1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), Some(&3)); - assert_eq!(t.get("jkl"), Some(&4)); - } - - #[test] - fn test_evicts_after_second_oldest_item_removed() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("def"), Some(2)); - assert_eq!(t.get("abc"), Some(&1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), Some(&3)); - assert_eq!(t.get("jkl"), Some(&4)); - } - - #[test] - fn test_removes_all_items() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("def"), Some(2)); - assert_eq!(t.remove("abc"), Some(1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - t.insert("mno".into(), 5); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), None); - assert_eq!(t.get("jkl"), Some(&4)); - assert_eq!(t.get("mno"), Some(&5)); - } - - #[test] - fn test_inserts_many_items() { - let mut t = Test::new(3); - - for _ in 0..10000 { - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - t.insert("ghi".into(), 3); - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/manual/defaults.rs b/third_party/rustls-fork-shadow-tls/src/manual/defaults.rs deleted file mode 100644 index aa15863..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/defaults.rs +++ /dev/null @@ -1,29 +0,0 @@ -/*! - -## Rationale for defaults - -### Why is AES-256 preferred over AES-128? - -This is a trade-off between: - -1. classical security level: searching a 2^128 key space is as implausible as 2^256. -2. post-quantum security level: the difference is more meaningful, and AES-256 seems like the conservative choice. -3. performance: AES-256 is around 40% slower than AES-128, though hardware acceleration typically narrows this gap. - -The choice is frankly quite marginal. - -### Why is AES-GCM preferred over chacha20-poly1305? - -Hardware support for accelerating AES-GCM is widespread, and hardware-accelerated AES-GCM -is quicker than un-accelerated chacha20-poly1305. - -However, if you know your application will run on a platform without that, you should -_definitely_ change the default order to prefer chacha20-poly1305: both the performance and -the implementation security will be improved. We think this is an uncommon case. - -### Why is x25519 preferred for key exchange over nistp256? - -Both provide roughly the same classical security level, but x25519 has better performance and -it's _much_ more likely that both peers will have good quality implementations. - -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/manual/features.rs b/third_party/rustls-fork-shadow-tls/src/manual/features.rs deleted file mode 100644 index 639a231..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/features.rs +++ /dev/null @@ -1,50 +0,0 @@ -/*! - -## Current features - -* TLS1.2 and TLS1.3. -* ECDSA, Ed25519 or RSA server authentication by clients. -* ECDSA, Ed25519 or RSA server authentication by servers. -* Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. -* AES128-GCM and AES256-GCM bulk encryption, with safe nonces. -* ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)). -* ALPN support. -* SNI support. -* Tunable MTU to make TLS messages match size of underlying transport. -* Optional use of vectored IO to minimise system calls. -* TLS1.2 session resumption. -* TLS1.2 resumption via tickets (RFC5077). -* TLS1.3 resumption via tickets or session storage. -* TLS1.3 0-RTT data for clients. -* Client authentication by clients. -* Client authentication by servers. -* Extended master secret support (RFC7627). -* Exporters (RFC5705). -* OCSP stapling by servers. -* SCT stapling by servers. -* SCT verification by clients. - -## Possible future features - -* PSK support. -* OCSP verification by clients. -* Certificate pinning. - -## Non-features - -For reasons explained in the other sections of this manual, rustls does not -and will not support: - -* SSL1, SSL2, SSL3, TLS1 or TLS1.1. -* RC4. -* DES or triple DES. -* EXPORT ciphersuites. -* MAC-then-encrypt ciphersuites. -* Ciphersuites without forward secrecy. -* Renegotiation. -* Kerberos. -* Compression. -* Discrete-log Diffie-Hellman. -* Automatic protocol version downgrade. - -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/manual/howto.rs b/third_party/rustls-fork-shadow-tls/src/manual/howto.rs deleted file mode 100644 index aa68a1e..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/howto.rs +++ /dev/null @@ -1,36 +0,0 @@ -/*! # Customising private key usage - -By default rustls supports PKCS#8-format[^1] RSA or ECDSA keys, plus PKCS#1-format RSA keys. - -However, if your private key resides in a HSM, or in another process, or perhaps -another machine, rustls has some extension points to support this: - -The main trait you must implement is [`sign::SigningKey`][signing_key]. The primary method here -is [`choose_scheme`][choose_scheme] where you are given a set of [`SignatureScheme`s][sig_scheme] the client says -it supports: you must choose one (or return `None` -- this aborts the handshake). Having -done that, you return an implementation of the [`sign::Signer`][signer] trait. -The [`sign()`][sign_method] performs the signature and returns it. - -(Unfortunately this is currently designed for keys with low latency access, like in a -PKCS#11 provider, Microsoft CryptoAPI, etc. so is blocking rather than asynchronous. -It's a TODO to make these and other extension points async.) - -Once you have these two pieces, configuring a server to use them involves, briefly: - -- packaging your `sign::SigningKey` with the matching certificate chain into a [`sign::CertifiedKey`][certified_key] -- making a [`ResolvesServerCertUsingSni`][cert_using_sni] and feeding in your `sign::CertifiedKey` for all SNI hostnames you want to use it for, -- setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver] - -[signing_key]: ../../sign/trait.SigningKey.html -[choose_scheme]: ../../sign/trait.SigningKey.html#tymethod.choose_scheme -[sig_scheme]: ../../enum.SignatureScheme.html -[signer]: ../../sign/trait.Signer.html -[sign_method]: ../../sign/trait.Signer.html#tymethod.sign -[certified_key]: ../../sign/struct.CertifiedKey.html -[cert_using_sni]: ../../struct.ResolvesServerCertUsingSni.html -[cert_resolver]: ../../struct.ServerConfig.html#structfield.cert_resolver - -[^1]: For PKCS#8 it does not support password encryption -- there's not a meaningful threat - model addressed by this, and the encryption supported is typically extremely poor. - -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/manual/implvulns.rs b/third_party/rustls-fork-shadow-tls/src/manual/implvulns.rs deleted file mode 100644 index d08e110..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/implvulns.rs +++ /dev/null @@ -1,104 +0,0 @@ -/*! # A review of TLS Implementation Vulnerabilities - -An important part of engineering involves studying and learning from the mistakes of the past. -It would be tremendously unfortunate to spend effort re-discovering and re-fixing the same -vulnerabilities that were discovered in the past. - -## Memory safety - -Being written entirely in the safe-subset of Rust immediately offers us freedom from the entire -class of memory safety vulnerabilities. There are too many to exhaustively list, and there will -certainly be more in the future. - -Examples: - -- Heartbleed [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160) (OpenSSL) -- Memory corruption in ASN.1 decoder [CVE-2016-2108](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2108) (OpenSSL) -- Buffer overflow in read_server_hello [CVE-2014-3466](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3466) (GnuTLS) - -## `goto fail` - -This is the name of a vulnerability in Apple Secure Transport [CVE-2014-1266](https://nvd.nist.gov/vuln/detail/CVE-2014-1266). -This boiled down to the following code, which validates the server's signature on the key exchange: - -```c - if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) - goto fail; - if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) - goto fail; -> goto fail; - if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) - goto fail; -``` - -The marked line was duplicated, likely accidentally during a merge. This meant -the remaining part of the function (including the actual signature validation) -was unconditionally skipped. - -Ultimately the one countermeasure to this type of bug is basic testing: that a -valid signature returns success, and that an invalid one does not. rustls -has such testing, but this is really table stakes for security code. - -Further than this, though, we could consider that the *lack* of an error from -this function is a poor indicator that the signature was valid. rustls, instead, -has zero-size and non-copyable types that indicate a particular signature validation -has been performed. These types can be thought of as *capabilities* originated only -by designated signature verification functions -- such functions can then be a focus -of manual code review. Like capabilities, values of these types are otherwise unforgeable, -and are communicable only by Rust's move semantics. - -Values of these types are threaded through the protocol state machine, leading to terminal -states that look like: - -```ignore -struct ExpectTraffic { - (...) - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} -``` - -Since this state requires a value of these types, it will be a compile-time error to -reach that state without performing the requisite security-critical operations. - -This approach is not infallible, but it has zero runtime cost. - -## State machine attacks: EarlyCCS and SMACK/SKIP/FREAK - -EarlyCCS [CVE-2014-0224](https://nvd.nist.gov/vuln/detail/CVE-2014-0224) was a vulnerability in OpenSSL -found in 2014. The TLS `ChangeCipherSpec` message would be processed at inappropriate times, leading -to data being encrypted with the wrong keys (specifically, keys which were not secret). This resulted -from OpenSSL taking a *reactive* strategy to incoming messages ("when I get a message X, I should do Y") -which allows it to diverge from the proper state machine under attacker control. - -[SMACK](https://mitls.org/pages/attacks/SMACK) is a similar suite of vulnerabilities found in JSSE, -CyaSSL, OpenSSL, Mono and axTLS. "SKIP-TLS" demonstrated that some implementations allowed handshake -messages (and in one case, the entire handshake!) to be skipped leading to breaks in security. "FREAK" -found that some implementations incorrectly allowed export-only state transitions (i.e., transitions that -were only valid when an export ciphersuite was in use). - -rustls represents its protocol state machine carefully to avoid these defects. We model the handshake, -CCS and application data subprotocols in the same single state machine. Each state in this machine is -represented with a single struct, and transitions are modelled as functions that consume the current state -plus one TLS message[^1] and return a struct representing the next state. These functions fully validate -the message type before further operations. - -A sample sequence for a full TLSv1.2 handshake by a client looks like: - -- `hs::ExpectServerHello` (nb. ClientHello is logically sent before this state); transition to `tls12::ExpectCertificate` -- `tls12::ExpectCertificate`; transition to `tls12::ExpectServerKX` -- `tls12::ExpectServerKX`; transition to `tls12::ExpectServerDoneOrCertReq` -- `tls12::ExpectServerDoneOrCertReq`; delegates to `tls12::ExpectCertificateRequest` or `tls12::ExpectServerDone` depending on incoming message. - - `tls12::ExpectServerDone`; transition to `tls12::ExpectCCS` -- `tls12::ExpectCCS`; transition to `tls12::ExpectFinished` -- `tls12::ExpectFinished`; transition to `tls12::ExpectTraffic` -- `tls12::ExpectTraffic`; terminal state; transitions to `tls12::ExpectTraffic` - -In the future we plan to formally prove that all possible transitions modelled in this system of types -are correct with respect to the standard(s). At the moment we rely merely on exhaustive testing. - -[^1]: a logical TLS message: post-decryption, post-fragmentation. - - -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/manual/mod.rs b/third_party/rustls-fork-shadow-tls/src/manual/mod.rs deleted file mode 100644 index 778d24b..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -/*! - -This documentation primarily aims to explain design decisions taken in rustls. - -It does this from a few aspects: how rustls attempts to avoid construction errors -that occurred in other TLS libraries, how rustls attempts to avoid past TLS -protocol vulnerabilities, and assorted advice for achieving common tasks with rustls. -*/ -#![allow(non_snake_case)] - -/// This section discusses vulnerabilities in other TLS implementations, theorising their -/// root cause and how we aim to avoid them in rustls. -#[path = "implvulns.rs"] -pub mod _01_impl_vulnerabilities; - -/// This section discusses vulnerabilities and design errors in the TLS protocol. -#[path = "tlsvulns.rs"] -pub mod _02_tls_vulnerabilities; - -/// This section collects together goal-oriented documentation. -#[path = "howto.rs"] -pub mod _03_howto; - -/// This section documents rustls itself: what protocol features are and are not implemented. -#[path = "features.rs"] -pub mod _04_features; - -/// This section provides rationale for the defaults in rustls. -#[path = "defaults.rs"] -pub mod _05_defaults; diff --git a/third_party/rustls-fork-shadow-tls/src/manual/tlsvulns.rs b/third_party/rustls-fork-shadow-tls/src/manual/tlsvulns.rs deleted file mode 100644 index 77d5510..0000000 --- a/third_party/rustls-fork-shadow-tls/src/manual/tlsvulns.rs +++ /dev/null @@ -1,173 +0,0 @@ -/*! # A review of protocol vulnerabilities - -## CBC MAC-then-encrypt ciphersuites - -Back in 2000 [Bellare and Namprempre](https://eprint.iacr.org/2000/025) discussed how to make authenticated -encryption by composing separate encryption and authentication primitives. That paper included this table: - -| Composition Method | Privacy || Integrity || -|--------------------|---------||-----------|| -|| IND-CPA | IND-CCA | NM-CPA | INT-PTXT | INT-CTXT | -| Encrypt-and-MAC | insecure | insecure | insecure | secure | insecure | -| MAC-then-encrypt | secure | insecure | insecure | secure | insecure | -| Encrypt-then-MAC | secure | secure | secure | secure | secure | - -One may assume from this fairly clear result that encrypt-and-MAC and MAC-then-encrypt compositions would be quickly abandoned -in favour of the remaining proven-secure option. But that didn't happen, not in TLSv1.1 (2006) nor in TLSv1.2 (2008). Worse, -both RFCs included incorrect advice on countermeasures for implementers, suggesting that the flaw was "not believed to be large -enough to be exploitable". - -[Lucky 13](http://www.isg.rhul.ac.uk/tls/Lucky13.html) (2013) exploited this flaw and affected all implementations, including -those written [after discovery](https://aws.amazon.com/blogs/security/s2n-and-lucky-13/). OpenSSL even had a -[memory safety vulnerability in the fix for Lucky 13](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2107), which -gives a flavour of the kind of complexity required to remove the side channel. - -rustls does not implement CBC MAC-then-encrypt ciphersuites for these reasons. TLSv1.3 removed support for these -ciphersuites in 2018. - -There are some further rejected options worth mentioning: [RFC7366](https://tools.ietf.org/html/rfc7366) defines -Encrypt-then-MAC for TLS, but unfortunately cannot be negotiated without also supporting MAC-then-encrypt -(clients cannot express "I offer CBC, but only EtM and not MtE"). - -## RSA PKCS#1 encryption - -"RSA key exchange" in TLS involves the client choosing a large random value and encrypting it using the server's -public key. This has two overall problems: - -1. It provides no _forward secrecy_: later compromise of the server's private key breaks confidentiality of - *all* past sessions using that key. This is a crucial property in the presence of software that is often - [poor at keeping a secret](http://heartbleed.com/). -2. The padding used in practice in TLS ("PKCS#1", or fully "RSAES-PKCS1-v1_5") has been known to be broken since - [1998](http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf). - -In a similar pattern to the MAC-then-encrypt problem discussed above, TLSv1.0 (1999), TLSv1.1 (2006) and TLSv1.2 (2008) -continued to specify use of PKCS#1 encryption, again with incrementally more complex and incorrect advice on countermeasures. - -[ROBOT](https://robotattack.org/) (2018) showed that implementations were still vulnerable to these attacks twenty years later. - -rustls does not support RSA key exchange. TLSv1.3 also removed support. - -## BEAST - -[BEAST](https://vnhacker.blogspot.com/2011/09/beast.html) ([CVE-2011-3389](https://nvd.nist.gov/vuln/detail/CVE-2011-3389)) -was demonstrated in 2011 by Thai Duong and Juliano Rizzo, -and was another vulnerability in CBC-based ciphersuites in SSLv3.0 and TLSv1.0. CBC mode is vulnerable to adaptive -chosen-plaintext attacks if the IV is predictable. In the case of these protocol versions, the IV was the previous -block of ciphertext (as if the entire TLS session was one CBC ciphertext, albeit revealed incrementally). This was -obviously predictable, since it was published on the wire. - -OpenSSL contained a countermeasure for this problem from 2002 onwards: it encrypts an empty message before each real -one, so that the IV used in the real message is unpredictable. This was turned off by default due to bugs in IE6. - -TLSv1.1 fix this vulnerability, but not any of the other deficiencies of CBC mode (see above). - -rustls does not support these ciphersuites. - -## CRIME - -In 2002 [John Kelsey](https://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf) discussed the length side channel -as applied to compression of combined secret and attacker-chosen strings. - -Compression continued to be an option in TLSv1.1 (2006) and in TLSv1.2 (2008). Support in libraries was widespread. - -[CRIME](http://netifera.com/research/crime/CRIME_ekoparty2012.pdf) ([CVE-2012-4929](https://nvd.nist.gov/vuln/detail/CVE-2012-4929)) -was demonstrated in 2012, again by Thai Duong and Juliano Rizzo. It attacked several protocols offering transparent -compression of application data, allowing quick adaptive chosen-plaintext attacks against secret values like cookies. - -rustls does not implement compression. TLSv1.3 also removed support. - -## Logjam / FREAK - -Way back when SSL was first being born, circa 1995, the US government considered cryptography a munition requiring -export control. SSL contained specific ciphersuites with dramatically small key sizes that were not subject -to export control. These controls were dropped in 2000. - -Since the "export-grade" ciphersuites no longer fulfilled any purpose, and because they were actively harmful to users, -one may have expected software support to disappear quickly. This did not happen. - -In 2015 [the FREAK attack](https://mitls.org/pages/attacks/SMACK#freak) ([CVE-2015-0204](https://nvd.nist.gov/vuln/detail/CVE-2015-0204)) -and [the Logjam attack](https://weakdh.org/) ([CVE-2015-4000](https://nvd.nist.gov/vuln/detail/CVE-2015-4000)) both -demonstrated total breaks of security in the presence of servers that accepted export ciphersuites. FREAK factored -512-bit RSA keys, while Logjam optimised solving discrete logs in the 512-bit group used by many different servers. - -Naturally, rustls does not implement any of these ciphersuites. - -## SWEET32 - -Block ciphers are vulnerable to birthday attacks, where the probability of repeating a block increases dramatically -once a particular key has been used for many blocks. For block ciphers with 64-bit blocks, this becomes probable -once a given key encrypts the order of 32GB of data. - -[Sweet32](https://sweet32.info/) ([CVE-2016-2183](https://nvd.nist.gov/vuln/detail/CVE-2016-2183)) attacked this fact -in the context of TLS support for 3DES, breaking confidentiality by analysing a large amount of attacker-induced traffic -in one session. - -rustls does not support any 64-bit block ciphers. - -## DROWN - -[DROWN](https://drownattack.com/) ([CVE-2016-0800](https://nvd.nist.gov/vuln/detail/CVE-2016-0800)) is a cross-protocol -attack that breaks the security of TLSv1.2 and earlier (when used with RSA key exchange) by using SSLv2. It is required -that the server uses the same key for both protocol versions. - -rustls naturally does not support SSLv2, but most importantly does not support RSA key exchange for TLSv1.2. - -## Poodle - -[POODLE](https://www.openssl.org/~bodo/ssl-poodle.pdf) ([CVE-2014-3566](https://nvd.nist.gov/vuln/detail/CVE-2014-3566)) -is an attack against CBC mode ciphersuites in SSLv3. This was possible in most cases because some clients willingly -downgraded to SSLv3 after failed handshakes for later versions. - -rustls does not support CBC mode ciphersuites, or SSLv3. Note that rustls does not need to implement `TLS_FALLBACK_SCSV` -introduced as a countermeasure because it contains no ability to downgrade to earlier protocol versions. - -## GCM nonces - -[RFC5288](https://tools.ietf.org/html/rfc5288) introduced GCM-based ciphersuites for use in TLS. Unfortunately -the design was poor; it reused design for an unrelated security setting proposed in RFC5116. - -GCM is a typical nonce-based AEAD: it requires a unique (but not necessarily unpredictable) 96-bit nonce for each encryption -with a given key. The design specified by RFC5288 left two-thirds of the nonce construction up to implementations: - -- wasting 8 bytes per TLS ciphertext, -- meaning correct operation cannot be tested for (e.g., in protocol-level test vectors). - -There were no trade-offs here: TLS has a 64-bit sequence number that is not allowed to wrap and would make an ideal nonce. - -As a result, a [2016 study](https://eprint.iacr.org/2016/475.pdf) found: - -- implementations from IBM, A10 and Citrix used randomly-chosen nonces, which are unlikely to be unique over long connections, -- an implementation from Radware used the same nonce for the first two messages. - -rustls uses a counter from a random starting point for GCM nonces. TLSv1.3 and the Chacha20-Poly1305 TLSv1.2 ciphersuite -standardise this method. - -## Renegotiation - -In 2009 Marsh Ray and Steve Dispensa [discovered](https://kryptera.se/Renegotiating%20TLS.pdf) that the renegotiation -feature of all versions of TLS allows a MitM to splice a request of their choice onto the front of the client's real HTTP -request. A countermeasure was proposed and widely implemented to bind renegotiations to their previous negotiations; -unfortunately this was insufficient. - -rustls does not support renegotiation in TLSv1.2. TLSv1.3 also no longer supports renegotiation. - -## 3SHAKE - -[3SHAKE](https://www.mitls.org/pages/attacks/3SHAKE) (2014) described a complex attack that broke the "Secure Renegotiation" extension -introduced as a countermeasure to the previous protocol flaw. - -rustls does not support renegotiation for TLSv1.2 connections, or RSA key exchange, and both are required for this attack -to work. rustls implements the "Extended Master Secret" (RFC7627) extension for TLSv1.2 which was standardised as a countermeasure. - -TLSv1.3 no longer supports renegotiation and RSA key exchange. It also effectively incorporates the improvements made in RFC7627. - -## KCI - -[This vulnerability](https://kcitls.org/) makes use of TLS ciphersuites (those offering static DH) which were standardised -yet not widely used. However, they were implemented by libraries, and as a result enabled for various clients. It coupled -this with misconfigured certificates (on services including facebook.com) which allowed their misuse to MitM connections. - -rustls does not support static DH/EC-DH ciphersuites. We assert that it is misissuance to sign an EC certificate -with the keyUsage extension allowing both signatures and key exchange. That it isn't is probably a failure -of CAB Forum baseline requirements. -*/ diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/alert.rs b/third_party/rustls-fork-shadow-tls/src/msgs/alert.rs deleted file mode 100644 index 2e12e6e..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/alert.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{AlertDescription, AlertLevel}; - -#[derive(Debug)] -pub struct AlertMessagePayload { - pub level: AlertLevel, - pub description: AlertDescription, -} - -impl Codec for AlertMessagePayload { - fn encode(&self, bytes: &mut Vec) { - self.level.encode(bytes); - self.description.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let level = AlertLevel::read(r)?; - let description = AlertDescription::read(r)?; - - Some(Self { level, description }) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/base.rs b/third_party/rustls-fork-shadow-tls/src/msgs/base.rs deleted file mode 100644 index 8ae0f6d..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/base.rs +++ /dev/null @@ -1,170 +0,0 @@ -use std::fmt; - -use crate::key; -use crate::msgs::codec; -use crate::msgs::codec::{Codec, Reader}; - -/// An externally length'd payload -#[derive(Clone, Eq, PartialEq)] -pub struct Payload(pub Vec); - -impl Codec for Payload { - fn encode(&self, bytes: &mut Vec) { - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader) -> Option { - Some(Self::read(r)) - } -} - -impl Payload { - pub fn new(bytes: impl Into>) -> Self { - Self(bytes.into()) - } - - pub fn empty() -> Self { - Self::new(Vec::new()) - } - - pub fn read(r: &mut Reader) -> Self { - Self(r.rest().to_vec()) - } -} - -impl Codec for key::Certificate { - fn encode(&self, bytes: &mut Vec) { - codec::u24(self.0.len() as u32).encode(bytes); - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader) -> Option { - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Some(Self(body)) - } -} - -impl fmt::Debug for Payload { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -/// An arbitrary, unknown-content, u24-length-prefixed payload -#[derive(Clone, Eq, PartialEq)] -pub struct PayloadU24(pub Vec); - -impl PayloadU24 { - pub fn new(bytes: Vec) -> Self { - Self(bytes) - } -} - -impl Codec for PayloadU24 { - fn encode(&self, bytes: &mut Vec) { - codec::u24(self.0.len() as u32).encode(bytes); - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader) -> Option { - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Some(Self(body)) - } -} - -impl fmt::Debug for PayloadU24 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -/// An arbitrary, unknown-content, u16-length-prefixed payload -#[derive(Clone, Eq, PartialEq)] -pub struct PayloadU16(pub Vec); - -impl PayloadU16 { - pub fn new(bytes: Vec) -> Self { - Self(bytes) - } - - pub fn empty() -> Self { - Self::new(Vec::new()) - } - - pub fn encode_slice(slice: &[u8], bytes: &mut Vec) { - (slice.len() as u16).encode(bytes); - bytes.extend_from_slice(slice); - } -} - -impl Codec for PayloadU16 { - fn encode(&self, bytes: &mut Vec) { - Self::encode_slice(&self.0, bytes); - } - - fn read(r: &mut Reader) -> Option { - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Some(Self(body)) - } -} - -impl fmt::Debug for PayloadU16 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -/// An arbitrary, unknown-content, u8-length-prefixed payload -#[derive(Clone, Eq, PartialEq)] -pub struct PayloadU8(pub Vec); - -impl PayloadU8 { - pub fn new(bytes: Vec) -> Self { - Self(bytes) - } - - pub fn empty() -> Self { - Self(Vec::new()) - } - - pub fn into_inner(self) -> Vec { - self.0 - } -} - -impl Codec for PayloadU8 { - fn encode(&self, bytes: &mut Vec) { - (self.0.len() as u8).encode(bytes); - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader) -> Option { - let len = u8::read(r)? as usize; - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Some(Self(body)) - } -} - -impl fmt::Debug for PayloadU8 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -// Format an iterator of u8 into a hex string -pub(super) fn hex<'a>( - f: &mut fmt::Formatter<'_>, - payload: impl IntoIterator, -) -> fmt::Result { - for b in payload { - write!(f, "{:02x}", b)? - } - Ok(()) -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/ccs.rs b/third_party/rustls-fork-shadow-tls/src/msgs/ccs.rs deleted file mode 100644 index d9b0eb3..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/ccs.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::msgs::codec::{Codec, Reader}; - -#[derive(Debug)] -pub struct ChangeCipherSpecPayload; - -impl Codec for ChangeCipherSpecPayload { - fn encode(&self, bytes: &mut Vec) { - 1u8.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let typ = u8::read(r)?; - - if typ == 1 && !r.any_left() { - Some(Self {}) - } else { - None - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/codec.rs b/third_party/rustls-fork-shadow-tls/src/msgs/codec.rs deleted file mode 100644 index 9ad1b12..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/codec.rs +++ /dev/null @@ -1,290 +0,0 @@ -use std::convert::TryInto; -use std::fmt::Debug; - -/// Wrapper over a slice of bytes that allows reading chunks from -/// with the current position state held using a cursor. -/// -/// A new reader for a sub section of the the buffer can be created -/// using the `sub` function or a section of a certain length can -/// be obtained using the `take` function -pub struct Reader<'a> { - /// The underlying buffer storing the readers content - buffer: &'a [u8], - /// Stores the current reading position for the buffer - cursor: usize, -} - -impl<'a> Reader<'a> { - /// Creates a new Reader of the provided `bytes` slice with - /// the initial cursor position of zero. - pub fn init(bytes: &[u8]) -> Reader { - Reader { - buffer: bytes, - cursor: 0, - } - } - - /// Attempts to create a new Reader on a sub section of this - /// readers bytes by taking a slice of the provided `length` - /// will return None if there is not enough bytes - pub fn sub(&mut self, length: usize) -> Option { - self.take(length).map(Reader::init) - } - - /// Borrows a slice of all the remaining bytes - /// that appear after the cursor position. - /// - /// Moves the cursor to the end of the buffer length. - pub fn rest(&mut self) -> &[u8] { - let rest = &self.buffer[self.cursor..]; - self.cursor = self.buffer.len(); - rest - } - - /// Attempts to borrow a slice of bytes from the current - /// cursor position of `length` if there is not enough - /// bytes remaining after the cursor to take the length - /// then None is returned instead. - pub fn take(&mut self, length: usize) -> Option<&[u8]> { - if self.left() < length { - return None; - } - let current = self.cursor; - self.cursor += length; - Some(&self.buffer[current..current + length]) - } - - /// Used to check whether the reader has any content left - /// after the cursor (cursor has not reached end of buffer) - pub fn any_left(&self) -> bool { - self.cursor < self.buffer.len() - } - - /// Returns the cursor position which is also the number - /// of bytes that have been read from the buffer. - pub fn used(&self) -> usize { - self.cursor - } - - /// Returns the number of bytes that are still able to be - /// read (The number of remaining takes) - pub fn left(&self) -> usize { - self.buffer.len() - self.cursor - } -} - -/// Trait for implementing encoding and decoding functionality -/// on something. -pub trait Codec: Debug + Sized { - /// Function for encoding itself by appending itself to - /// the provided vec of bytes. - fn encode(&self, bytes: &mut Vec); - - /// Function for decoding itself from the provided reader - /// will return Some if the decoding was successful or - /// None if it was not. - fn read(_: &mut Reader) -> Option; - - /// Convenience function for encoding the implementation - /// into a vec and returning it - fn get_encoding(&self) -> Vec { - let mut bytes = Vec::new(); - self.encode(&mut bytes); - bytes - } - - /// Function for wrapping a call to the read function in - /// a Reader for the slice of bytes provided - fn read_bytes(bytes: &[u8]) -> Option { - let mut reader = Reader::init(bytes); - Self::read(&mut reader) - } -} - -fn decode_u8(bytes: &[u8]) -> Option { - let [value]: [u8; 1] = bytes.try_into().ok()?; - Some(value) -} - -impl Codec for u8 { - fn encode(&self, bytes: &mut Vec) { - bytes.push(*self); - } - - fn read(r: &mut Reader) -> Option { - r.take(1).and_then(decode_u8) - } -} - -pub fn put_u16(v: u16, out: &mut [u8]) { - let out: &mut [u8; 2] = (&mut out[..2]).try_into().unwrap(); - *out = u16::to_be_bytes(v); -} - -pub fn decode_u16(bytes: &[u8]) -> Option { - Some(u16::from_be_bytes(bytes.try_into().ok()?)) -} - -impl Codec for u16 { - fn encode(&self, bytes: &mut Vec) { - let mut b16 = [0u8; 2]; - put_u16(*self, &mut b16); - bytes.extend_from_slice(&b16); - } - - fn read(r: &mut Reader) -> Option { - r.take(2).and_then(decode_u16) - } -} - -// Make a distinct type for u24, even though it's a u32 underneath -#[allow(non_camel_case_types)] -#[derive(Debug, Copy, Clone)] -pub struct u24(pub u32); - -impl u24 { - pub fn decode(bytes: &[u8]) -> Option { - let [a, b, c]: [u8; 3] = bytes.try_into().ok()?; - Some(Self(u32::from_be_bytes([0, a, b, c]))) - } -} - -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -impl From for usize { - #[inline] - fn from(v: u24) -> Self { - v.0 as Self - } -} - -impl Codec for u24 { - fn encode(&self, bytes: &mut Vec) { - let be_bytes = u32::to_be_bytes(self.0); - bytes.extend_from_slice(&be_bytes[1..]) - } - - fn read(r: &mut Reader) -> Option { - r.take(3).and_then(Self::decode) - } -} - -pub fn decode_u32(bytes: &[u8]) -> Option { - Some(u32::from_be_bytes(bytes.try_into().ok()?)) -} - -impl Codec for u32 { - fn encode(&self, bytes: &mut Vec) { - bytes.extend(Self::to_be_bytes(*self)) - } - - fn read(r: &mut Reader) -> Option { - r.take(4).and_then(decode_u32) - } -} - -pub fn put_u64(v: u64, bytes: &mut [u8]) { - let bytes: &mut [u8; 8] = (&mut bytes[..8]).try_into().unwrap(); - *bytes = u64::to_be_bytes(v) -} - -pub fn decode_u64(bytes: &[u8]) -> Option { - Some(u64::from_be_bytes(bytes.try_into().ok()?)) -} - -impl Codec for u64 { - fn encode(&self, bytes: &mut Vec) { - let mut b64 = [0u8; 8]; - put_u64(*self, &mut b64); - bytes.extend_from_slice(&b64); - } - - fn read(r: &mut Reader) -> Option { - r.take(8).and_then(decode_u64) - } -} - -pub fn encode_vec_u8(bytes: &mut Vec, items: &[T]) { - let len_offset = bytes.len(); - bytes.push(0); - - for i in items { - i.encode(bytes); - } - - let len = bytes.len() - len_offset - 1; - debug_assert!(len <= 0xff); - bytes[len_offset] = len as u8; -} - -pub fn encode_vec_u16(bytes: &mut Vec, items: &[T]) { - let len_offset = bytes.len(); - bytes.extend([0, 0]); - - for i in items { - i.encode(bytes); - } - - let len = bytes.len() - len_offset - 2; - debug_assert!(len <= 0xffff); - let out: &mut [u8; 2] = (&mut bytes[len_offset..len_offset + 2]) - .try_into() - .unwrap(); - *out = u16::to_be_bytes(len as u16); -} - -pub fn encode_vec_u24(bytes: &mut Vec, items: &[T]) { - let len_offset = bytes.len(); - bytes.extend([0, 0, 0]); - - for i in items { - i.encode(bytes); - } - - let len = bytes.len() - len_offset - 3; - debug_assert!(len <= 0xff_ffff); - let len_bytes = u32::to_be_bytes(len as u32); - let out: &mut [u8; 3] = (&mut bytes[len_offset..len_offset + 3]) - .try_into() - .unwrap(); - out.copy_from_slice(&len_bytes[1..]); -} - -pub fn read_vec_u8(r: &mut Reader) -> Option> { - let mut ret: Vec = Vec::new(); - let len = usize::from(u8::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - ret.push(T::read(&mut sub)?); - } - - Some(ret) -} - -pub fn read_vec_u16(r: &mut Reader) -> Option> { - let mut ret: Vec = Vec::new(); - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - ret.push(T::read(&mut sub)?); - } - - Some(ret) -} - -pub fn read_vec_u24_limited(r: &mut Reader, max_bytes: usize) -> Option> { - let mut ret: Vec = Vec::new(); - let len = u24::read(r)?.0 as usize; - if len > max_bytes { - return None; - } - - let mut sub = r.sub(len)?; - - while sub.any_left() { - ret.push(T::read(&mut sub)?); - } - - Some(ret) -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/deframer.rs b/third_party/rustls-fork-shadow-tls/src/msgs/deframer.rs deleted file mode 100644 index 2ada2d8..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/deframer.rs +++ /dev/null @@ -1,425 +0,0 @@ -use std::collections::VecDeque; -use std::io; - -use crate::error::Error; -use crate::msgs::codec; -use crate::msgs::message::{MessageError, OpaqueMessage}; - -/// This deframer works to reconstruct TLS messages -/// from arbitrary-sized reads, buffering as necessary. -/// The input is `read()`, get the output from `pop()`. -pub struct MessageDeframer { - /// Completed frames for output. - frames: VecDeque, - - /// Set to true if the peer is not talking TLS, but some other - /// protocol. The caller should abort the connection, because - /// the deframer cannot recover. - desynced: bool, - - /// A fixed-size buffer containing the currently-accumulating - /// TLS message. - buf: Box<[u8; OpaqueMessage::MAX_WIRE_SIZE]>, - - /// What size prefix of `buf` is used. - used: usize, -} - -impl Default for MessageDeframer { - fn default() -> Self { - Self::new() - } -} - -impl MessageDeframer { - pub fn new() -> Self { - Self { - frames: VecDeque::new(), - desynced: false, - buf: Box::new([0u8; OpaqueMessage::MAX_WIRE_SIZE]), - used: 0, - } - } - - /// Return any complete messages that the deframer has been able to parse. - /// - /// Returns an `Error` if the deframer failed to parse some message contents, - /// `Ok(None)` if no full message is buffered, and `Ok(Some(_))` if a valid message was found. - pub fn pop(&mut self) -> Result, Error> { - if self.desynced { - return Err(Error::CorruptMessage); - } else if let Some(msg) = self.frames.pop_front() { - return Ok(Some(msg)); - } - - let mut taken = 0; - loop { - // Does our `buf` contain a full message? It does if it is big enough to - // contain a header, and that header has a length which falls within `buf`. - // If so, deframe it and place the message onto the frames output queue. - let mut rd = codec::Reader::init(&self.buf[taken..self.used]); - let m = match OpaqueMessage::read(&mut rd) { - Ok(m) => m, - Err(MessageError::TooShortForHeader | MessageError::TooShortForLength) => break, - Err(_) => { - self.desynced = true; - return Err(Error::CorruptMessage); - } - }; - - taken += rd.used(); - self.frames.push_back(m); - } - - #[allow(clippy::comparison_chain)] - if taken < self.used { - /* Before: - * +----------+----------+----------+ - * | taken | pending |xxxxxxxxxx| - * +----------+----------+----------+ - * 0 ^ taken ^ self.used - * - * After: - * +----------+----------+----------+ - * | pending |xxxxxxxxxxxxxxxxxxxxx| - * +----------+----------+----------+ - * 0 ^ self.used - */ - - self.buf - .copy_within(taken..self.used, 0); - self.used -= taken; - } else if taken == self.used { - self.used = 0; - } - - Ok(self.frames.pop_front()) - } - - /// Read some bytes from `rd`, and add them to our internal buffer. - #[allow(clippy::comparison_chain)] - pub fn read(&mut self, rd: &mut dyn io::Read) -> io::Result { - if self.used == OpaqueMessage::MAX_WIRE_SIZE { - return Err(io::Error::new(io::ErrorKind::Other, "message buffer full")); - } - - // Try to do the largest reads possible. Note that if - // we get a message with a length field out of range here, - // we do a zero length read. That looks like an EOF to - // the next layer up, which is fine. - debug_assert!(self.used <= OpaqueMessage::MAX_WIRE_SIZE); - let new_bytes = rd.read(&mut self.buf[self.used..])?; - self.used += new_bytes; - Ok(new_bytes) - } - - /// Returns true if we have messages for the caller - /// to process, either whole messages in our output - /// queue or partial messages in our buffer. - pub fn has_pending(&self) -> bool { - !self.frames.is_empty() || self.used > 0 - } -} - -#[cfg(test)] -mod tests { - use super::MessageDeframer; - use crate::msgs::message::{Message, OpaqueMessage}; - use crate::{msgs, Error}; - use std::convert::TryFrom; - use std::io; - - const FIRST_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.1.bin"); - const SECOND_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.2.bin"); - - const EMPTY_APPLICATIONDATA_MESSAGE: &[u8] = - include_bytes!("../testdata/deframer-empty-applicationdata.bin"); - - const INVALID_EMPTY_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-empty.bin"); - const INVALID_CONTENTTYPE_MESSAGE: &[u8] = - include_bytes!("../testdata/deframer-invalid-contenttype.bin"); - const INVALID_VERSION_MESSAGE: &[u8] = - include_bytes!("../testdata/deframer-invalid-version.bin"); - const INVALID_LENGTH_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-length.bin"); - - struct ByteRead<'a> { - buf: &'a [u8], - offs: usize, - } - - impl<'a> ByteRead<'a> { - fn new(bytes: &'a [u8]) -> Self { - ByteRead { - buf: bytes, - offs: 0, - } - } - } - - impl<'a> io::Read for ByteRead<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut len = 0; - - while len < buf.len() && len < self.buf.len() - self.offs { - buf[len] = self.buf[self.offs + len]; - len += 1; - } - - self.offs += len; - - Ok(len) - } - } - - fn input_bytes(d: &mut MessageDeframer, bytes: &[u8]) -> io::Result { - let mut rd = ByteRead::new(bytes); - d.read(&mut rd) - } - - fn input_bytes_concat( - d: &mut MessageDeframer, - bytes1: &[u8], - bytes2: &[u8], - ) -> io::Result { - let mut bytes = vec![0u8; bytes1.len() + bytes2.len()]; - bytes[..bytes1.len()].clone_from_slice(bytes1); - bytes[bytes1.len()..].clone_from_slice(bytes2); - let mut rd = ByteRead::new(&bytes); - d.read(&mut rd) - } - - struct ErrorRead { - error: Option, - } - - impl ErrorRead { - fn new(error: io::Error) -> Self { - Self { error: Some(error) } - } - } - - impl io::Read for ErrorRead { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - for (i, b) in buf.iter_mut().enumerate() { - *b = i as u8; - } - - let error = self.error.take().unwrap(); - Err(error) - } - } - - fn input_error(d: &mut MessageDeframer) { - let error = io::Error::from(io::ErrorKind::TimedOut); - let mut rd = ErrorRead::new(error); - d.read(&mut rd) - .expect_err("error not propagated"); - } - - fn input_whole_incremental(d: &mut MessageDeframer, bytes: &[u8]) { - let before = d.used; - - for i in 0..bytes.len() { - assert_len(1, input_bytes(d, &bytes[i..i + 1])); - assert!(d.has_pending()); - } - - assert_eq!(before + bytes.len(), d.used); - } - - fn assert_len(want: usize, got: io::Result) { - if let Ok(gotval) = got { - assert_eq!(gotval, want); - } else { - panic!("read failed, expected {:?} bytes", want); - } - } - - fn pop_first(d: &mut MessageDeframer) { - let m = d.pop().unwrap().unwrap(); - assert_eq!(m.typ, msgs::enums::ContentType::Handshake); - Message::try_from(m.into_plain_message()).unwrap(); - } - - fn pop_second(d: &mut MessageDeframer) { - let m = d.pop().unwrap().unwrap(); - assert_eq!(m.typ, msgs::enums::ContentType::Alert); - Message::try_from(m.into_plain_message()).unwrap(); - } - - #[test] - fn check_incremental() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - input_whole_incremental(&mut d, FIRST_MESSAGE); - assert!(d.has_pending()); - assert_eq!(0, d.frames.len()); - pop_first(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn check_incremental_2() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - input_whole_incremental(&mut d, FIRST_MESSAGE); - assert!(d.has_pending()); - input_whole_incremental(&mut d, SECOND_MESSAGE); - assert!(d.has_pending()); - assert_eq!(0, d.frames.len()); - pop_first(&mut d); - assert!(d.has_pending()); - assert_eq!(1, d.frames.len()); - pop_second(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn check_whole() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); - assert!(d.has_pending()); - assert_eq!(d.frames.len(), 0); - pop_first(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn check_whole_2() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); - assert_len(SECOND_MESSAGE.len(), input_bytes(&mut d, SECOND_MESSAGE)); - assert_eq!(d.frames.len(), 0); - pop_first(&mut d); - assert_eq!(d.frames.len(), 1); - pop_second(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn test_two_in_one_read() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - assert_len( - FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), - input_bytes_concat(&mut d, FIRST_MESSAGE, SECOND_MESSAGE), - ); - assert_eq!(d.frames.len(), 0); - pop_first(&mut d); - assert_eq!(d.frames.len(), 1); - pop_second(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn test_two_in_one_read_shortest_first() { - let mut d = MessageDeframer::new(); - assert!(!d.has_pending()); - assert_len( - FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), - input_bytes_concat(&mut d, SECOND_MESSAGE, FIRST_MESSAGE), - ); - assert_eq!(d.frames.len(), 0); - pop_second(&mut d); - assert_eq!(d.frames.len(), 1); - pop_first(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn test_incremental_with_nonfatal_read_error() { - let mut d = MessageDeframer::new(); - assert_len(3, input_bytes(&mut d, &FIRST_MESSAGE[..3])); - input_error(&mut d); - assert_len( - FIRST_MESSAGE.len() - 3, - input_bytes(&mut d, &FIRST_MESSAGE[3..]), - ); - assert_eq!(d.frames.len(), 0); - pop_first(&mut d); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn test_invalid_contenttype_errors() { - let mut d = MessageDeframer::new(); - assert_len( - INVALID_CONTENTTYPE_MESSAGE.len(), - input_bytes(&mut d, INVALID_CONTENTTYPE_MESSAGE), - ); - assert_eq!(d.pop().unwrap_err(), Error::CorruptMessage); - } - - #[test] - fn test_invalid_version_errors() { - let mut d = MessageDeframer::new(); - assert_len( - INVALID_VERSION_MESSAGE.len(), - input_bytes(&mut d, INVALID_VERSION_MESSAGE), - ); - assert_eq!(d.pop().unwrap_err(), Error::CorruptMessage); - } - - #[test] - fn test_invalid_length_errors() { - let mut d = MessageDeframer::new(); - assert_len( - INVALID_LENGTH_MESSAGE.len(), - input_bytes(&mut d, INVALID_LENGTH_MESSAGE), - ); - assert_eq!(d.pop().unwrap_err(), Error::CorruptMessage); - } - - #[test] - fn test_empty_applicationdata() { - let mut d = MessageDeframer::new(); - assert_len( - EMPTY_APPLICATIONDATA_MESSAGE.len(), - input_bytes(&mut d, EMPTY_APPLICATIONDATA_MESSAGE), - ); - let m = d.pop().unwrap().unwrap(); - assert_eq!(m.typ, msgs::enums::ContentType::ApplicationData); - assert_eq!(m.payload.0.len(), 0); - assert!(!d.has_pending()); - assert!(!d.desynced); - } - - #[test] - fn test_invalid_empty_errors() { - let mut d = MessageDeframer::new(); - assert_len( - INVALID_EMPTY_MESSAGE.len(), - input_bytes(&mut d, INVALID_EMPTY_MESSAGE), - ); - assert_eq!(d.pop().unwrap_err(), Error::CorruptMessage); - // CorruptMessage has been fused - assert_eq!(d.pop().unwrap_err(), Error::CorruptMessage); - } - - #[test] - fn test_limited_buffer() { - const PAYLOAD_LEN: usize = 16_384; - let mut message = Vec::with_capacity(8192); - message.push(0x17); // ApplicationData - message.extend(&[0x03, 0x04]); // ProtocolVersion - message.extend((PAYLOAD_LEN as u16).to_be_bytes()); // payload length - message.extend(&[0; PAYLOAD_LEN]); - - let mut d = MessageDeframer::new(); - assert_len(message.len(), input_bytes(&mut d, &message)); - assert_len( - OpaqueMessage::MAX_WIRE_SIZE - 16_389, - input_bytes(&mut d, &message), - ); - assert!(input_bytes(&mut d, &message).is_err()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/enums.rs b/third_party/rustls-fork-shadow-tls/src/msgs/enums.rs deleted file mode 100644 index 333db73..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/enums.rs +++ /dev/null @@ -1,375 +0,0 @@ -#![allow(clippy::upper_case_acronyms)] -#![allow(non_camel_case_types)] -/// This file is autogenerated. See https://github.com/ctz/tls-hacking/ -use crate::msgs::codec::{Codec, Reader}; - -enum_builder! { - /// The `HashAlgorithm` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: HashAlgorithm; - EnumVal{ - NONE => 0x00, - MD5 => 0x01, - SHA1 => 0x02, - SHA224 => 0x03, - SHA256 => 0x04, - SHA384 => 0x05, - SHA512 => 0x06 - } -} - -enum_builder! { - /// The `SignatureAlgorithm` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: SignatureAlgorithm; - EnumVal{ - Anonymous => 0x00, - RSA => 0x01, - DSA => 0x02, - ECDSA => 0x03, - ED25519 => 0x07, - ED448 => 0x08 - } -} - -enum_builder! { - /// The `ClientCertificateType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: ClientCertificateType; - EnumVal{ - RSASign => 0x01, - DSSSign => 0x02, - RSAFixedDH => 0x03, - DSSFixedDH => 0x04, - RSAEphemeralDH => 0x05, - DSSEphemeralDH => 0x06, - FortezzaDMS => 0x14, - ECDSASign => 0x40, - RSAFixedECDH => 0x41, - ECDSAFixedECDH => 0x42 - } -} - -enum_builder! { - /// The `Compression` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: Compression; - EnumVal{ - Null => 0x00, - Deflate => 0x01, - LSZ => 0x40 - } -} - -enum_builder! { - /// The `ContentType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: ContentType; - EnumVal{ - ChangeCipherSpec => 0x14, - Alert => 0x15, - Handshake => 0x16, - ApplicationData => 0x17, - Heartbeat => 0x18 - } -} - -enum_builder! { - /// The `HandshakeType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: HandshakeType; - EnumVal{ - HelloRequest => 0x00, - ClientHello => 0x01, - ServerHello => 0x02, - HelloVerifyRequest => 0x03, - NewSessionTicket => 0x04, - EndOfEarlyData => 0x05, - HelloRetryRequest => 0x06, - EncryptedExtensions => 0x08, - Certificate => 0x0b, - ServerKeyExchange => 0x0c, - CertificateRequest => 0x0d, - ServerHelloDone => 0x0e, - CertificateVerify => 0x0f, - ClientKeyExchange => 0x10, - Finished => 0x14, - CertificateURL => 0x15, - CertificateStatus => 0x16, - KeyUpdate => 0x18, - MessageHash => 0xfe - } -} - -enum_builder! { - /// The `AlertLevel` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: AlertLevel; - EnumVal{ - Warning => 0x01, - Fatal => 0x02 - } -} - -enum_builder! { - /// The `AlertDescription` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: AlertDescription; - EnumVal{ - CloseNotify => 0x00, - UnexpectedMessage => 0x0a, - BadRecordMac => 0x14, - DecryptionFailed => 0x15, - RecordOverflow => 0x16, - DecompressionFailure => 0x1e, - HandshakeFailure => 0x28, - NoCertificate => 0x29, - BadCertificate => 0x2a, - UnsupportedCertificate => 0x2b, - CertificateRevoked => 0x2c, - CertificateExpired => 0x2d, - CertificateUnknown => 0x2e, - IllegalParameter => 0x2f, - UnknownCA => 0x30, - AccessDenied => 0x31, - DecodeError => 0x32, - DecryptError => 0x33, - ExportRestriction => 0x3c, - ProtocolVersion => 0x46, - InsufficientSecurity => 0x47, - InternalError => 0x50, - InappropriateFallback => 0x56, - UserCanceled => 0x5a, - NoRenegotiation => 0x64, - MissingExtension => 0x6d, - UnsupportedExtension => 0x6e, - CertificateUnobtainable => 0x6f, - UnrecognisedName => 0x70, - BadCertificateStatusResponse => 0x71, - BadCertificateHashValue => 0x72, - UnknownPSKIdentity => 0x73, - CertificateRequired => 0x74, - NoApplicationProtocol => 0x78 - } -} - -enum_builder! { - /// The `HeartbeatMessageType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: HeartbeatMessageType; - EnumVal{ - Request => 0x01, - Response => 0x02 - } -} - -enum_builder! { - /// The `ExtensionType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: ExtensionType; - EnumVal{ - ServerName => 0x0000, - MaxFragmentLength => 0x0001, - ClientCertificateUrl => 0x0002, - TrustedCAKeys => 0x0003, - TruncatedHMAC => 0x0004, - StatusRequest => 0x0005, - UserMapping => 0x0006, - ClientAuthz => 0x0007, - ServerAuthz => 0x0008, - CertificateType => 0x0009, - EllipticCurves => 0x000a, - ECPointFormats => 0x000b, - SRP => 0x000c, - SignatureAlgorithms => 0x000d, - UseSRTP => 0x000e, - Heartbeat => 0x000f, - ALProtocolNegotiation => 0x0010, - SCT => 0x0012, - Padding => 0x0015, - ExtendedMasterSecret => 0x0017, - SessionTicket => 0x0023, - PreSharedKey => 0x0029, - EarlyData => 0x002a, - SupportedVersions => 0x002b, - Cookie => 0x002c, - PSKKeyExchangeModes => 0x002d, - TicketEarlyDataInfo => 0x002e, - CertificateAuthorities => 0x002f, - OIDFilters => 0x0030, - PostHandshakeAuth => 0x0031, - SignatureAlgorithmsCert => 0x0032, - KeyShare => 0x0033, - TransportParameters => 0x0039, - NextProtocolNegotiation => 0x3374, - ChannelId => 0x754f, - RenegotiationInfo => 0xff01, - TransportParametersDraft => 0xffa5 - } -} - -enum_builder! { - /// The `ServerNameType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: ServerNameType; - EnumVal{ - HostName => 0x00 - } -} - -enum_builder! { - /// The `NamedCurve` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: NamedCurve; - EnumVal{ - sect163k1 => 0x0001, - sect163r1 => 0x0002, - sect163r2 => 0x0003, - sect193r1 => 0x0004, - sect193r2 => 0x0005, - sect233k1 => 0x0006, - sect233r1 => 0x0007, - sect239k1 => 0x0008, - sect283k1 => 0x0009, - sect283r1 => 0x000a, - sect409k1 => 0x000b, - sect409r1 => 0x000c, - sect571k1 => 0x000d, - sect571r1 => 0x000e, - secp160k1 => 0x000f, - secp160r1 => 0x0010, - secp160r2 => 0x0011, - secp192k1 => 0x0012, - secp192r1 => 0x0013, - secp224k1 => 0x0014, - secp224r1 => 0x0015, - secp256k1 => 0x0016, - secp256r1 => 0x0017, - secp384r1 => 0x0018, - secp521r1 => 0x0019, - brainpoolp256r1 => 0x001a, - brainpoolp384r1 => 0x001b, - brainpoolp512r1 => 0x001c, - X25519 => 0x001d, - X448 => 0x001e, - arbitrary_explicit_prime_curves => 0xff01, - arbitrary_explicit_char2_curves => 0xff02 - } -} - -enum_builder! { - /// The `NamedGroup` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U16 - EnumName: NamedGroup; - EnumVal{ - secp256r1 => 0x0017, - secp384r1 => 0x0018, - secp521r1 => 0x0019, - X25519 => 0x001d, - X448 => 0x001e, - FFDHE2048 => 0x0100, - FFDHE3072 => 0x0101, - FFDHE4096 => 0x0102, - FFDHE6144 => 0x0103, - FFDHE8192 => 0x0104 - } -} - -enum_builder! { - /// The `ECPointFormat` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: ECPointFormat; - EnumVal{ - Uncompressed => 0x00, - ANSIX962CompressedPrime => 0x01, - ANSIX962CompressedChar2 => 0x02 - } -} - -enum_builder! { - /// The `HeartbeatMode` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: HeartbeatMode; - EnumVal{ - PeerAllowedToSend => 0x01, - PeerNotAllowedToSend => 0x02 - } -} - -enum_builder! { - /// The `ECCurveType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: ECCurveType; - EnumVal{ - ExplicitPrime => 0x01, - ExplicitChar2 => 0x02, - NamedCurve => 0x03 - } -} - -enum_builder! { - /// The `PSKKeyExchangeMode` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: PSKKeyExchangeMode; - EnumVal{ - PSK_KE => 0x00, - PSK_DHE_KE => 0x01 - } -} - -enum_builder! { - /// The `KeyUpdateRequest` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: KeyUpdateRequest; - EnumVal{ - UpdateNotRequested => 0x00, - UpdateRequested => 0x01 - } -} - -enum_builder! { - /// The `CertificateStatusType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - @U8 - EnumName: CertificateStatusType; - EnumVal{ - OCSP => 0x01 - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/enums_test.rs b/third_party/rustls-fork-shadow-tls/src/msgs/enums_test.rs deleted file mode 100644 index 220b5aa..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/enums_test.rs +++ /dev/null @@ -1,88 +0,0 @@ -/// These tests are intended to provide coverage and -/// check panic-safety of relatively unused values. -use super::codec::Codec; -use super::enums::*; - -fn get8(enum_value: &T) -> u8 { - let enc = enum_value.get_encoding(); - assert_eq!(enc.len(), 1); - enc[0] -} - -fn get16(enum_value: &T) -> u16 { - let enc = enum_value.get_encoding(); - assert_eq!(enc.len(), 2); - (enc[0] as u16 >> 8) | (enc[1] as u16) -} - -fn test_enum16(first: T, last: T) { - let first_v = get16(&first); - let last_v = get16(&last); - - for val in first_v..last_v + 1 { - let mut buf = Vec::new(); - val.encode(&mut buf); - assert_eq!(buf.len(), 2); - - let t = T::read_bytes(&buf).unwrap(); - assert_eq!(val, get16(&t)); - } -} - -fn test_enum8(first: T, last: T) { - let first_v = get8(&first); - let last_v = get8(&last); - - for val in first_v..last_v + 1 { - let mut buf = Vec::new(); - val.encode(&mut buf); - assert_eq!(buf.len(), 1); - - let t = T::read_bytes(&buf).unwrap(); - assert_eq!(val, get8(&t)); - } -} - -#[test] -fn test_enums() { - test_enum8::(HashAlgorithm::NONE, HashAlgorithm::SHA512); - test_enum8::(SignatureAlgorithm::Anonymous, SignatureAlgorithm::ECDSA); - test_enum8::( - ClientCertificateType::RSASign, - ClientCertificateType::ECDSAFixedECDH, - ); - test_enum8::(Compression::Null, Compression::LSZ); - test_enum8::(ContentType::ChangeCipherSpec, ContentType::Heartbeat); - test_enum8::(HandshakeType::HelloRequest, HandshakeType::MessageHash); - test_enum8::(AlertLevel::Warning, AlertLevel::Fatal); - test_enum8::( - AlertDescription::CloseNotify, - AlertDescription::NoApplicationProtocol, - ); - test_enum8::( - HeartbeatMessageType::Request, - HeartbeatMessageType::Response, - ); - test_enum16::(ExtensionType::ServerName, ExtensionType::RenegotiationInfo); - test_enum8::(ServerNameType::HostName, ServerNameType::HostName); - test_enum16::( - NamedCurve::sect163k1, - NamedCurve::arbitrary_explicit_char2_curves, - ); - test_enum16::(NamedGroup::secp256r1, NamedGroup::FFDHE8192); - test_enum8::( - ECPointFormat::Uncompressed, - ECPointFormat::ANSIX962CompressedChar2, - ); - test_enum8::( - HeartbeatMode::PeerAllowedToSend, - HeartbeatMode::PeerNotAllowedToSend, - ); - test_enum8::(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve); - test_enum8::(PSKKeyExchangeMode::PSK_KE, PSKKeyExchangeMode::PSK_DHE_KE); - test_enum8::( - KeyUpdateRequest::UpdateNotRequested, - KeyUpdateRequest::UpdateRequested, - ); - test_enum8::(CertificateStatusType::OCSP, CertificateStatusType::OCSP); -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/fragmenter.rs b/third_party/rustls-fork-shadow-tls/src/msgs/fragmenter.rs deleted file mode 100644 index b649bcf..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/fragmenter.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::enums::ProtocolVersion; -use crate::msgs::enums::ContentType; -use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; -use crate::Error; -pub const MAX_FRAGMENT_LEN: usize = 16384; -pub const PACKET_OVERHEAD: usize = 1 + 2 + 2; -pub const MAX_FRAGMENT_SIZE: usize = MAX_FRAGMENT_LEN + PACKET_OVERHEAD; - -pub struct MessageFragmenter { - max_frag: usize, -} - -impl Default for MessageFragmenter { - fn default() -> Self { - Self { - max_frag: MAX_FRAGMENT_LEN, - } - } -} - -impl MessageFragmenter { - /// Take the Message `msg` and re-fragment it into new - /// messages whose fragment is no more than max_frag. - /// Return an iterator across those messages. - /// Payloads are borrowed. - pub fn fragment_message<'a>( - &self, - msg: &'a PlainMessage, - ) -> impl Iterator> + 'a { - self.fragment_slice(msg.typ, msg.version, &msg.payload.0) - } - - /// Enqueue borrowed fragments of (version, typ, payload) which - /// are no longer than max_frag onto the `out` deque. - pub fn fragment_slice<'a>( - &self, - typ: ContentType, - version: ProtocolVersion, - payload: &'a [u8], - ) -> impl Iterator> + 'a { - payload - .chunks(self.max_frag) - .map(move |c| BorrowedPlainMessage { - typ, - version, - payload: c, - }) - } - - /// Set the maximum fragment size that will be produced. - /// - /// This includes overhead. A `max_fragment_size` of 10 will produce TLS fragments - /// up to 10 bytes long. - /// - /// A `max_fragment_size` of `None` sets the highest allowable fragment size. - /// - /// Returns BadMaxFragmentSize if the size is smaller than 32 or larger than 16389. - pub fn set_max_fragment_size(&mut self, max_fragment_size: Option) -> Result<(), Error> { - self.max_frag = match max_fragment_size { - Some(sz @ 32..=MAX_FRAGMENT_SIZE) => sz - PACKET_OVERHEAD, - None => MAX_FRAGMENT_LEN, - _ => return Err(Error::BadMaxFragmentSize), - }; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::{MessageFragmenter, PACKET_OVERHEAD}; - use crate::enums::ProtocolVersion; - use crate::msgs::base::Payload; - use crate::msgs::enums::ContentType; - use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; - - fn msg_eq( - m: &BorrowedPlainMessage, - total_len: usize, - typ: &ContentType, - version: &ProtocolVersion, - bytes: &[u8], - ) { - assert_eq!(&m.typ, typ); - assert_eq!(&m.version, version); - assert_eq!(m.payload, bytes); - - let buf = m.to_unencrypted_opaque().encode(); - - assert_eq!(total_len, buf.len()); - } - - #[test] - fn smoke() { - let typ = ContentType::Handshake; - let version = ProtocolVersion::TLSv1_2; - let data: Vec = (1..70u8).collect(); - let m = PlainMessage { - typ, - version, - payload: Payload::new(data), - }; - - let mut frag = MessageFragmenter::default(); - frag.set_max_fragment_size(Some(32)) - .unwrap(); - let q = frag - .fragment_message(&m) - .collect::>(); - assert_eq!(q.len(), 3); - msg_eq( - &q[0], - 32, - &typ, - &version, - &[ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, - ], - ); - msg_eq( - &q[1], - 32, - &typ, - &version, - &[ - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, - ], - ); - msg_eq( - &q[2], - 20, - &typ, - &version, - &[55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69], - ); - } - - #[test] - fn non_fragment() { - let m = PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x01\x02\x03\x04\x05\x06\x07\x08".to_vec()), - }; - - let mut frag = MessageFragmenter::default(); - frag.set_max_fragment_size(Some(32)) - .unwrap(); - let q = frag - .fragment_message(&m) - .collect::>(); - assert_eq!(q.len(), 1); - msg_eq( - &q[0], - PACKET_OVERHEAD + 8, - &ContentType::Handshake, - &ProtocolVersion::TLSv1_2, - b"\x01\x02\x03\x04\x05\x06\x07\x08", - ); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/handshake-test.1.bin b/third_party/rustls-fork-shadow-tls/src/msgs/handshake-test.1.bin deleted file mode 100644 index 5c04f3f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/msgs/handshake-test.1.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/handshake.rs b/third_party/rustls-fork-shadow-tls/src/msgs/handshake.rs deleted file mode 100644 index 74dd5c5..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/handshake.rs +++ /dev/null @@ -1,2380 +0,0 @@ -#![allow(non_camel_case_types)] -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::key; -use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; -use crate::msgs::codec; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{ - CertificateStatusType, ClientCertificateType, Compression, ECCurveType, ECPointFormat, - ExtensionType, HandshakeType, HashAlgorithm, KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, - ServerNameType, SignatureAlgorithm, -}; -use crate::rand; - -#[cfg(feature = "logging")] -use crate::log::warn; - -use std::collections; -use std::fmt; - -macro_rules! declare_u8_vec( - ($name:ident, $itemtype:ty) => { - pub type $name = Vec<$itemtype>; - - impl Codec for $name { - fn encode(&self, bytes: &mut Vec) { - codec::encode_vec_u8(bytes, self); - } - - fn read(r: &mut Reader) -> Option { - codec::read_vec_u8::<$itemtype>(r) - } - } - } -); - -macro_rules! declare_u16_vec( - ($name:ident, $itemtype:ty) => { - pub type $name = Vec<$itemtype>; - - impl Codec for $name { - fn encode(&self, bytes: &mut Vec) { - codec::encode_vec_u16(bytes, self); - } - - fn read(r: &mut Reader) -> Option { - codec::read_vec_u16::<$itemtype>(r) - } - } - } -); - -declare_u16_vec!(VecU16OfPayloadU8, PayloadU8); -declare_u16_vec!(VecU16OfPayloadU16, PayloadU16); - -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct Random(pub [u8; 32]); - -impl fmt::Debug for Random { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - super::base::hex(f, &self.0) - } -} - -static HELLO_RETRY_REQUEST_RANDOM: Random = Random([ - 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, - 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, -]); - -static ZERO_RANDOM: Random = Random([0u8; 32]); - -impl Codec for Random { - fn encode(&self, bytes: &mut Vec) { - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader) -> Option { - let bytes = r.take(32)?; - let mut opaque = [0; 32]; - opaque.clone_from_slice(bytes); - - Some(Self(opaque)) - } -} - -impl Random { - pub fn new() -> Result { - let mut data = [0u8; 32]; - rand::fill_random(&mut data)?; - Ok(Self(data)) - } - - pub fn write_slice(&self, bytes: &mut [u8]) { - let buf = self.get_encoding(); - bytes.copy_from_slice(&buf); - } -} - -impl From<[u8; 32]> for Random { - #[inline] - fn from(bytes: [u8; 32]) -> Self { - Self(bytes) - } -} - -#[derive(Copy, Clone)] -pub struct SessionID { - // hack: we need to access it - pub(crate) len: usize, - // hack: we need to access it - pub(crate) data: [u8; 32], -} - -impl fmt::Debug for SessionID { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - super::base::hex(f, &self.data[..self.len]) - } -} - -impl PartialEq for SessionID { - fn eq(&self, other: &Self) -> bool { - if self.len != other.len { - return false; - } - - let mut diff = 0u8; - for i in 0..self.len { - diff |= self.data[i] ^ other.data[i] - } - - diff == 0u8 - } -} - -impl Codec for SessionID { - fn encode(&self, bytes: &mut Vec) { - debug_assert!(self.len <= 32); - bytes.push(self.len as u8); - bytes.extend_from_slice(&self.data[..self.len]); - } - - fn read(r: &mut Reader) -> Option { - let len = u8::read(r)? as usize; - if len > 32 { - return None; - } - - let bytes = r.take(len)?; - let mut out = [0u8; 32]; - out[..len].clone_from_slice(&bytes[..len]); - - Some(Self { data: out, len }) - } -} - -impl SessionID { - pub fn random() -> Result { - let mut data = [0u8; 32]; - rand::fill_random(&mut data)?; - Ok(Self { data, len: 32 }) - } - - pub fn zero() -> Self { - Self { - data: [0u8; 32], - len: 32, - } - } - - pub fn empty() -> Self { - Self { - data: [0u8; 32], - len: 0, - } - } - - pub fn len(&self) -> usize { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } -} - -#[derive(Clone, Debug)] -pub struct UnknownExtension { - pub typ: ExtensionType, - pub payload: Payload, -} - -impl UnknownExtension { - fn encode(&self, bytes: &mut Vec) { - self.payload.encode(bytes); - } - - fn read(typ: ExtensionType, r: &mut Reader) -> Self { - let payload = Payload::read(r); - Self { typ, payload } - } -} - -declare_u8_vec!(ECPointFormatList, ECPointFormat); - -pub trait SupportedPointFormats { - fn supported() -> ECPointFormatList; -} - -impl SupportedPointFormats for ECPointFormatList { - fn supported() -> ECPointFormatList { - vec![ECPointFormat::Uncompressed] - } -} - -declare_u16_vec!(NamedGroups, NamedGroup); - -declare_u16_vec!(SupportedSignatureSchemes, SignatureScheme); - -pub trait DecomposedSignatureScheme { - fn sign(&self) -> SignatureAlgorithm; - fn make(alg: SignatureAlgorithm, hash: HashAlgorithm) -> SignatureScheme; -} - -impl DecomposedSignatureScheme for SignatureScheme { - fn sign(&self) -> SignatureAlgorithm { - match *self { - Self::RSA_PKCS1_SHA1 - | Self::RSA_PKCS1_SHA256 - | Self::RSA_PKCS1_SHA384 - | Self::RSA_PKCS1_SHA512 - | Self::RSA_PSS_SHA256 - | Self::RSA_PSS_SHA384 - | Self::RSA_PSS_SHA512 => SignatureAlgorithm::RSA, - Self::ECDSA_NISTP256_SHA256 - | Self::ECDSA_NISTP384_SHA384 - | Self::ECDSA_NISTP521_SHA512 => SignatureAlgorithm::ECDSA, - _ => SignatureAlgorithm::Unknown(0), - } - } - - fn make(alg: SignatureAlgorithm, hash: HashAlgorithm) -> SignatureScheme { - use crate::msgs::enums::HashAlgorithm::{SHA1, SHA256, SHA384, SHA512}; - use crate::msgs::enums::SignatureAlgorithm::{ECDSA, RSA}; - - match (alg, hash) { - (RSA, SHA1) => Self::RSA_PKCS1_SHA1, - (RSA, SHA256) => Self::RSA_PKCS1_SHA256, - (RSA, SHA384) => Self::RSA_PKCS1_SHA384, - (RSA, SHA512) => Self::RSA_PKCS1_SHA512, - (ECDSA, SHA256) => Self::ECDSA_NISTP256_SHA256, - (ECDSA, SHA384) => Self::ECDSA_NISTP384_SHA384, - (ECDSA, SHA512) => Self::ECDSA_NISTP521_SHA512, - (_, _) => unreachable!(), - } - } -} - -#[derive(Clone, Debug)] -pub enum ServerNamePayload { - // Stored twice, bytes so we can round-trip, and DnsName for use - HostName((PayloadU16, webpki::DnsName)), - Unknown(Payload), -} - -impl ServerNamePayload { - pub fn new_hostname(hostname: webpki::DnsName) -> Self { - let raw = { - let s: &str = hostname.as_ref().into(); - PayloadU16::new(s.as_bytes().into()) - }; - Self::HostName((raw, hostname)) - } - - fn read_hostname(r: &mut Reader) -> Option { - let raw = PayloadU16::read(r)?; - - let dns_name = { - match webpki::DnsNameRef::try_from_ascii(&raw.0) { - Ok(dns_name) => dns_name.into(), - Err(_) => { - warn!("Illegal SNI hostname received {:?}", raw.0); - return None; - } - } - }; - Some(Self::HostName((raw, dns_name))) - } - - fn encode(&self, bytes: &mut Vec) { - match *self { - Self::HostName((ref r, _)) => r.encode(bytes), - Self::Unknown(ref r) => r.encode(bytes), - } - } -} - -#[derive(Clone, Debug)] -pub struct ServerName { - pub typ: ServerNameType, - pub payload: ServerNamePayload, -} - -impl Codec for ServerName { - fn encode(&self, bytes: &mut Vec) { - self.typ.encode(bytes); - self.payload.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let typ = ServerNameType::read(r)?; - - let payload = match typ { - ServerNameType::HostName => ServerNamePayload::read_hostname(r)?, - _ => ServerNamePayload::Unknown(Payload::read(r)), - }; - - Some(Self { typ, payload }) - } -} - -declare_u16_vec!(ServerNameRequest, ServerName); - -pub trait ConvertServerNameList { - fn has_duplicate_names_for_type(&self) -> bool; - fn get_single_hostname(&self) -> Option; -} - -impl ConvertServerNameList for ServerNameRequest { - /// RFC6066: "The ServerNameList MUST NOT contain more than one name of the same name_type." - fn has_duplicate_names_for_type(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for name in self { - if !seen.insert(name.typ.get_u8()) { - return true; - } - } - - false - } - - fn get_single_hostname(&self) -> Option { - fn only_dns_hostnames(name: &ServerName) -> Option { - if let ServerNamePayload::HostName((_, ref dns)) = name.payload { - Some(dns.as_ref()) - } else { - None - } - } - - self.iter() - .filter_map(only_dns_hostnames) - .next() - } -} - -pub type ProtocolNameList = VecU16OfPayloadU8; - -pub trait ConvertProtocolNameList { - fn from_slices(names: &[&[u8]]) -> Self; - fn to_slices(&self) -> Vec<&[u8]>; - fn as_single_slice(&self) -> Option<&[u8]>; -} - -impl ConvertProtocolNameList for ProtocolNameList { - fn from_slices(names: &[&[u8]]) -> Self { - let mut ret = Self::new(); - - for name in names { - ret.push(PayloadU8::new(name.to_vec())); - } - - ret - } - - fn to_slices(&self) -> Vec<&[u8]> { - self.iter() - .map(|proto| -> &[u8] { &proto.0 }) - .collect::>() - } - - fn as_single_slice(&self) -> Option<&[u8]> { - if self.len() == 1 { - Some(&self[0].0) - } else { - None - } - } -} - -// --- TLS 1.3 Key shares --- -#[derive(Clone, Debug)] -pub struct KeyShareEntry { - pub group: NamedGroup, - pub payload: PayloadU16, -} - -impl KeyShareEntry { - pub fn new(group: NamedGroup, payload: &[u8]) -> Self { - Self { - group, - payload: PayloadU16::new(payload.to_vec()), - } - } -} - -impl Codec for KeyShareEntry { - fn encode(&self, bytes: &mut Vec) { - self.group.encode(bytes); - self.payload.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let group = NamedGroup::read(r)?; - let payload = PayloadU16::read(r)?; - - Some(Self { group, payload }) - } -} - -// --- TLS 1.3 PresharedKey offers --- -#[derive(Clone, Debug)] -pub struct PresharedKeyIdentity { - pub identity: PayloadU16, - pub obfuscated_ticket_age: u32, -} - -impl PresharedKeyIdentity { - pub fn new(id: Vec, age: u32) -> Self { - Self { - identity: PayloadU16::new(id), - obfuscated_ticket_age: age, - } - } -} - -impl Codec for PresharedKeyIdentity { - fn encode(&self, bytes: &mut Vec) { - self.identity.encode(bytes); - self.obfuscated_ticket_age.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - Some(Self { - identity: PayloadU16::read(r)?, - obfuscated_ticket_age: u32::read(r)?, - }) - } -} - -declare_u16_vec!(PresharedKeyIdentities, PresharedKeyIdentity); -pub type PresharedKeyBinder = PayloadU8; -pub type PresharedKeyBinders = VecU16OfPayloadU8; - -#[derive(Clone, Debug)] -pub struct PresharedKeyOffer { - pub identities: PresharedKeyIdentities, - pub binders: PresharedKeyBinders, -} - -impl PresharedKeyOffer { - /// Make a new one with one entry. - pub fn new(id: PresharedKeyIdentity, binder: Vec) -> Self { - Self { - identities: vec![id], - binders: vec![PresharedKeyBinder::new(binder)], - } - } -} - -impl Codec for PresharedKeyOffer { - fn encode(&self, bytes: &mut Vec) { - self.identities.encode(bytes); - self.binders.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - Some(Self { - identities: PresharedKeyIdentities::read(r)?, - binders: PresharedKeyBinders::read(r)?, - }) - } -} - -// --- RFC6066 certificate status request --- -type ResponderIDs = VecU16OfPayloadU16; - -#[derive(Clone, Debug)] -pub struct OCSPCertificateStatusRequest { - pub responder_ids: ResponderIDs, - pub extensions: PayloadU16, -} - -impl Codec for OCSPCertificateStatusRequest { - fn encode(&self, bytes: &mut Vec) { - CertificateStatusType::OCSP.encode(bytes); - self.responder_ids.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - Some(Self { - responder_ids: ResponderIDs::read(r)?, - extensions: PayloadU16::read(r)?, - }) - } -} - -#[derive(Clone, Debug)] -pub enum CertificateStatusRequest { - OCSP(OCSPCertificateStatusRequest), - Unknown((CertificateStatusType, Payload)), -} - -impl Codec for CertificateStatusRequest { - fn encode(&self, bytes: &mut Vec) { - match self { - Self::OCSP(ref r) => r.encode(bytes), - Self::Unknown((typ, payload)) => { - typ.encode(bytes); - payload.encode(bytes); - } - } - } - - fn read(r: &mut Reader) -> Option { - let typ = CertificateStatusType::read(r)?; - - match typ { - CertificateStatusType::OCSP => { - let ocsp_req = OCSPCertificateStatusRequest::read(r)?; - Some(Self::OCSP(ocsp_req)) - } - _ => { - let data = Payload::read(r); - Some(Self::Unknown((typ, data))) - } - } - } -} - -impl CertificateStatusRequest { - pub fn build_ocsp() -> Self { - let ocsp = OCSPCertificateStatusRequest { - responder_ids: ResponderIDs::new(), - extensions: PayloadU16::empty(), - }; - Self::OCSP(ocsp) - } -} - -// --- -// SCTs - -pub type SCTList = VecU16OfPayloadU16; - -// --- - -declare_u8_vec!(PSKKeyExchangeModes, PSKKeyExchangeMode); -declare_u16_vec!(KeyShareEntries, KeyShareEntry); -declare_u8_vec!(ProtocolVersions, ProtocolVersion); - -#[derive(Clone, Debug)] -pub enum ClientExtension { - ECPointFormats(ECPointFormatList), - NamedGroups(NamedGroups), - SignatureAlgorithms(SupportedSignatureSchemes), - ServerName(ServerNameRequest), - SessionTicket(ClientSessionTicket), - Protocols(ProtocolNameList), - SupportedVersions(ProtocolVersions), - KeyShare(KeyShareEntries), - PresharedKeyModes(PSKKeyExchangeModes), - PresharedKey(PresharedKeyOffer), - Cookie(PayloadU16), - ExtendedMasterSecretRequest, - CertificateStatusRequest(CertificateStatusRequest), - SignedCertificateTimestampRequest, - TransportParameters(Vec), - TransportParametersDraft(Vec), - EarlyData, - Unknown(UnknownExtension), -} - -impl ClientExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::ECPointFormats(_) => ExtensionType::ECPointFormats, - Self::NamedGroups(_) => ExtensionType::EllipticCurves, - Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, - Self::ServerName(_) => ExtensionType::ServerName, - Self::SessionTicket(_) => ExtensionType::SessionTicket, - Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, - Self::SupportedVersions(_) => ExtensionType::SupportedVersions, - Self::KeyShare(_) => ExtensionType::KeyShare, - Self::PresharedKeyModes(_) => ExtensionType::PSKKeyExchangeModes, - Self::PresharedKey(_) => ExtensionType::PreSharedKey, - Self::Cookie(_) => ExtensionType::Cookie, - Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret, - Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest, - Self::SignedCertificateTimestampRequest => ExtensionType::SCT, - Self::TransportParameters(_) => ExtensionType::TransportParameters, - Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, - Self::EarlyData => ExtensionType::EarlyData, - Self::Unknown(ref r) => r.typ, - } - } -} - -impl Codec for ClientExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::ECPointFormats(ref r) => r.encode(&mut sub), - Self::NamedGroups(ref r) => r.encode(&mut sub), - Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), - Self::ServerName(ref r) => r.encode(&mut sub), - Self::SessionTicket(ClientSessionTicket::Request) - | Self::ExtendedMasterSecretRequest - | Self::SignedCertificateTimestampRequest - | Self::EarlyData => {} - Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub), - Self::Protocols(ref r) => r.encode(&mut sub), - Self::SupportedVersions(ref r) => r.encode(&mut sub), - Self::KeyShare(ref r) => r.encode(&mut sub), - Self::PresharedKeyModes(ref r) => r.encode(&mut sub), - Self::PresharedKey(ref r) => r.encode(&mut sub), - Self::Cookie(ref r) => r.encode(&mut sub), - Self::CertificateStatusRequest(ref r) => r.encode(&mut sub), - Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { - sub.extend_from_slice(r) - } - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::ECPointFormats => { - Self::ECPointFormats(ECPointFormatList::read(&mut sub)?) - } - ExtensionType::EllipticCurves => Self::NamedGroups(NamedGroups::read(&mut sub)?), - ExtensionType::SignatureAlgorithms => { - let schemes = SupportedSignatureSchemes::read(&mut sub)?; - Self::SignatureAlgorithms(schemes) - } - ExtensionType::ServerName => Self::ServerName(ServerNameRequest::read(&mut sub)?), - ExtensionType::SessionTicket => { - if sub.any_left() { - let contents = Payload::read(&mut sub); - Self::SessionTicket(ClientSessionTicket::Offer(contents)) - } else { - Self::SessionTicket(ClientSessionTicket::Request) - } - } - ExtensionType::ALProtocolNegotiation => { - Self::Protocols(ProtocolNameList::read(&mut sub)?) - } - ExtensionType::SupportedVersions => { - Self::SupportedVersions(ProtocolVersions::read(&mut sub)?) - } - ExtensionType::KeyShare => Self::KeyShare(KeyShareEntries::read(&mut sub)?), - ExtensionType::PSKKeyExchangeModes => { - Self::PresharedKeyModes(PSKKeyExchangeModes::read(&mut sub)?) - } - ExtensionType::PreSharedKey => Self::PresharedKey(PresharedKeyOffer::read(&mut sub)?), - ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), - ExtensionType::ExtendedMasterSecret if !sub.any_left() => { - Self::ExtendedMasterSecretRequest - } - ExtensionType::StatusRequest => { - let csr = CertificateStatusRequest::read(&mut sub)?; - Self::CertificateStatusRequest(csr) - } - ExtensionType::SCT if !sub.any_left() => Self::SignedCertificateTimestampRequest, - ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), - ExtensionType::TransportParametersDraft => { - Self::TransportParametersDraft(sub.rest().to_vec()) - } - ExtensionType::EarlyData if !sub.any_left() => Self::EarlyData, - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -fn trim_hostname_trailing_dot_for_sni(dns_name: webpki::DnsNameRef) -> webpki::DnsName { - let dns_name_str: &str = dns_name.into(); - - // RFC6066: "The hostname is represented as a byte string using - // ASCII encoding without a trailing dot" - if dns_name_str.ends_with('.') { - let trimmed = &dns_name_str[0..dns_name_str.len() - 1]; - webpki::DnsNameRef::try_from_ascii_str(trimmed) - .unwrap() - .to_owned() - } else { - dns_name.to_owned() - } -} - -impl ClientExtension { - /// Make a basic SNI ServerNameRequest quoting `hostname`. - pub fn make_sni(dns_name: webpki::DnsNameRef) -> Self { - let name = ServerName { - typ: ServerNameType::HostName, - payload: ServerNamePayload::new_hostname(trim_hostname_trailing_dot_for_sni(dns_name)), - }; - - Self::ServerName(vec![name]) - } -} - -#[derive(Clone, Debug)] -pub enum ClientSessionTicket { - Request, - Offer(Payload), -} - -#[derive(Clone, Debug)] -pub enum ServerExtension { - ECPointFormats(ECPointFormatList), - ServerNameAck, - SessionTicketAck, - RenegotiationInfo(PayloadU8), - Protocols(ProtocolNameList), - KeyShare(KeyShareEntry), - PresharedKey(u16), - ExtendedMasterSecretAck, - CertificateStatusAck, - SignedCertificateTimestamp(SCTList), - SupportedVersions(ProtocolVersion), - TransportParameters(Vec), - TransportParametersDraft(Vec), - EarlyData, - Unknown(UnknownExtension), -} - -impl ServerExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::ECPointFormats(_) => ExtensionType::ECPointFormats, - Self::ServerNameAck => ExtensionType::ServerName, - Self::SessionTicketAck => ExtensionType::SessionTicket, - Self::RenegotiationInfo(_) => ExtensionType::RenegotiationInfo, - Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, - Self::KeyShare(_) => ExtensionType::KeyShare, - Self::PresharedKey(_) => ExtensionType::PreSharedKey, - Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret, - Self::CertificateStatusAck => ExtensionType::StatusRequest, - Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, - Self::SupportedVersions(_) => ExtensionType::SupportedVersions, - Self::TransportParameters(_) => ExtensionType::TransportParameters, - Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, - Self::EarlyData => ExtensionType::EarlyData, - Self::Unknown(ref r) => r.typ, - } - } -} - -impl Codec for ServerExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::ECPointFormats(ref r) => r.encode(&mut sub), - Self::ServerNameAck - | Self::SessionTicketAck - | Self::ExtendedMasterSecretAck - | Self::CertificateStatusAck - | Self::EarlyData => {} - Self::RenegotiationInfo(ref r) => r.encode(&mut sub), - Self::Protocols(ref r) => r.encode(&mut sub), - Self::KeyShare(ref r) => r.encode(&mut sub), - Self::PresharedKey(r) => r.encode(&mut sub), - Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), - Self::SupportedVersions(ref r) => r.encode(&mut sub), - Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { - sub.extend_from_slice(r) - } - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::ECPointFormats => { - Self::ECPointFormats(ECPointFormatList::read(&mut sub)?) - } - ExtensionType::ServerName => Self::ServerNameAck, - ExtensionType::SessionTicket => Self::SessionTicketAck, - ExtensionType::StatusRequest => Self::CertificateStatusAck, - ExtensionType::RenegotiationInfo => Self::RenegotiationInfo(PayloadU8::read(&mut sub)?), - ExtensionType::ALProtocolNegotiation => { - Self::Protocols(ProtocolNameList::read(&mut sub)?) - } - ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?), - ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?), - ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck, - ExtensionType::SCT => { - let scts = SCTList::read(&mut sub)?; - Self::SignedCertificateTimestamp(scts) - } - ExtensionType::SupportedVersions => { - Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) - } - ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), - ExtensionType::TransportParametersDraft => { - Self::TransportParametersDraft(sub.rest().to_vec()) - } - ExtensionType::EarlyData => Self::EarlyData, - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -impl ServerExtension { - pub fn make_alpn(proto: &[&[u8]]) -> Self { - Self::Protocols(ProtocolNameList::from_slices(proto)) - } - - pub fn make_empty_renegotiation_info() -> Self { - let empty = Vec::new(); - Self::RenegotiationInfo(PayloadU8::new(empty)) - } - - pub fn make_sct(sctl: Vec) -> Self { - let scts = SCTList::read_bytes(&sctl).expect("invalid SCT list"); - Self::SignedCertificateTimestamp(scts) - } -} - -#[derive(Debug)] -pub struct ClientHelloPayload { - pub client_version: ProtocolVersion, - pub random: Random, - pub session_id: SessionID, - pub cipher_suites: Vec, - pub compression_methods: Vec, - pub extensions: Vec, -} - -impl Codec for ClientHelloPayload { - fn encode(&self, bytes: &mut Vec) { - self.client_version.encode(bytes); - self.random.encode(bytes); - self.session_id.encode(bytes); - codec::encode_vec_u16(bytes, &self.cipher_suites); - codec::encode_vec_u8(bytes, &self.compression_methods); - - if !self.extensions.is_empty() { - codec::encode_vec_u16(bytes, &self.extensions); - } - } - - fn read(r: &mut Reader) -> Option { - let mut ret = Self { - client_version: ProtocolVersion::read(r)?, - random: Random::read(r)?, - session_id: SessionID::read(r)?, - cipher_suites: codec::read_vec_u16::(r)?, - compression_methods: codec::read_vec_u8::(r)?, - extensions: Vec::new(), - }; - - if r.any_left() { - ret.extensions = codec::read_vec_u16::(r)?; - } - - if r.any_left() || ret.extensions.is_empty() { - None - } else { - Some(ret) - } - } -} - -impl ClientHelloPayload { - /// Returns true if there is more than one extension of a given - /// type. - pub fn has_duplicate_extension(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for ext in &self.extensions { - let typ = ext.get_type().get_u16(); - - if seen.contains(&typ) { - return true; - } - seen.insert(typ); - } - - false - } - - pub fn find_extension(&self, ext: ExtensionType) -> Option<&ClientExtension> { - self.extensions - .iter() - .find(|x| x.get_type() == ext) - } - - pub fn get_sni_extension(&self) -> Option<&ServerNameRequest> { - let ext = self.find_extension(ExtensionType::ServerName)?; - match *ext { - ClientExtension::ServerName(ref req) => Some(req), - _ => None, - } - } - - pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> { - let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; - match *ext { - ClientExtension::SignatureAlgorithms(ref req) => Some(req), - _ => None, - } - } - - pub fn get_namedgroups_extension(&self) -> Option<&NamedGroups> { - let ext = self.find_extension(ExtensionType::EllipticCurves)?; - match *ext { - ClientExtension::NamedGroups(ref req) => Some(req), - _ => None, - } - } - - pub fn get_ecpoints_extension(&self) -> Option<&ECPointFormatList> { - let ext = self.find_extension(ExtensionType::ECPointFormats)?; - match *ext { - ClientExtension::ECPointFormats(ref req) => Some(req), - _ => None, - } - } - - pub fn get_alpn_extension(&self) -> Option<&ProtocolNameList> { - let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; - match *ext { - ClientExtension::Protocols(ref req) => Some(req), - _ => None, - } - } - - pub fn get_quic_params_extension(&self) -> Option> { - let ext = self - .find_extension(ExtensionType::TransportParameters) - .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; - match *ext { - ClientExtension::TransportParameters(ref bytes) - | ClientExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), - _ => None, - } - } - - pub fn get_ticket_extension(&self) -> Option<&ClientExtension> { - self.find_extension(ExtensionType::SessionTicket) - } - - pub fn get_versions_extension(&self) -> Option<&ProtocolVersions> { - let ext = self.find_extension(ExtensionType::SupportedVersions)?; - match *ext { - ClientExtension::SupportedVersions(ref vers) => Some(vers), - _ => None, - } - } - - pub fn get_keyshare_extension(&self) -> Option<&KeyShareEntries> { - let ext = self.find_extension(ExtensionType::KeyShare)?; - match *ext { - ClientExtension::KeyShare(ref shares) => Some(shares), - _ => None, - } - } - - pub fn has_keyshare_extension_with_duplicates(&self) -> bool { - if let Some(entries) = self.get_keyshare_extension() { - let mut seen = collections::HashSet::new(); - - for kse in entries { - let grp = kse.group.get_u16(); - - if !seen.insert(grp) { - return true; - } - } - } - - false - } - - pub fn get_psk(&self) -> Option<&PresharedKeyOffer> { - let ext = self.find_extension(ExtensionType::PreSharedKey)?; - match *ext { - ClientExtension::PresharedKey(ref psk) => Some(psk), - _ => None, - } - } - - pub fn check_psk_ext_is_last(&self) -> bool { - self.extensions - .last() - .map_or(false, |ext| ext.get_type() == ExtensionType::PreSharedKey) - } - - pub fn get_psk_modes(&self) -> Option<&PSKKeyExchangeModes> { - let ext = self.find_extension(ExtensionType::PSKKeyExchangeModes)?; - match *ext { - ClientExtension::PresharedKeyModes(ref psk_modes) => Some(psk_modes), - _ => None, - } - } - - pub fn psk_mode_offered(&self, mode: PSKKeyExchangeMode) -> bool { - self.get_psk_modes() - .map(|modes| modes.contains(&mode)) - .unwrap_or(false) - } - - pub fn set_psk_binder(&mut self, binder: impl Into>) { - let last_extension = self.extensions.last_mut(); - if let Some(ClientExtension::PresharedKey(ref mut offer)) = last_extension { - offer.binders[0] = PresharedKeyBinder::new(binder.into()); - } - } - - pub fn ems_support_offered(&self) -> bool { - self.find_extension(ExtensionType::ExtendedMasterSecret) - .is_some() - } - - pub fn early_data_extension_offered(&self) -> bool { - self.find_extension(ExtensionType::EarlyData) - .is_some() - } -} - -#[derive(Debug)] -pub enum HelloRetryExtension { - KeyShare(NamedGroup), - Cookie(PayloadU16), - SupportedVersions(ProtocolVersion), - Unknown(UnknownExtension), -} - -impl HelloRetryExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::KeyShare(_) => ExtensionType::KeyShare, - Self::Cookie(_) => ExtensionType::Cookie, - Self::SupportedVersions(_) => ExtensionType::SupportedVersions, - Self::Unknown(ref r) => r.typ, - } - } -} - -impl Codec for HelloRetryExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::KeyShare(ref r) => r.encode(&mut sub), - Self::Cookie(ref r) => r.encode(&mut sub), - Self::SupportedVersions(ref r) => r.encode(&mut sub), - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::KeyShare => Self::KeyShare(NamedGroup::read(&mut sub)?), - ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), - ExtensionType::SupportedVersions => { - Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) - } - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -#[derive(Debug)] -pub struct HelloRetryRequest { - pub legacy_version: ProtocolVersion, - pub session_id: SessionID, - pub cipher_suite: CipherSuite, - pub extensions: Vec, -} - -impl Codec for HelloRetryRequest { - fn encode(&self, bytes: &mut Vec) { - self.legacy_version.encode(bytes); - HELLO_RETRY_REQUEST_RANDOM.encode(bytes); - self.session_id.encode(bytes); - self.cipher_suite.encode(bytes); - Compression::Null.encode(bytes); - codec::encode_vec_u16(bytes, &self.extensions); - } - - fn read(r: &mut Reader) -> Option { - let session_id = SessionID::read(r)?; - let cipher_suite = CipherSuite::read(r)?; - let compression = Compression::read(r)?; - - if compression != Compression::Null { - return None; - } - - Some(Self { - legacy_version: ProtocolVersion::Unknown(0), - session_id, - cipher_suite, - extensions: codec::read_vec_u16::(r)?, - }) - } -} - -impl HelloRetryRequest { - /// Returns true if there is more than one extension of a given - /// type. - pub fn has_duplicate_extension(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for ext in &self.extensions { - let typ = ext.get_type().get_u16(); - - if seen.contains(&typ) { - return true; - } - seen.insert(typ); - } - - false - } - - pub fn has_unknown_extension(&self) -> bool { - self.extensions.iter().any(|ext| { - ext.get_type() != ExtensionType::KeyShare - && ext.get_type() != ExtensionType::SupportedVersions - && ext.get_type() != ExtensionType::Cookie - }) - } - - fn find_extension(&self, ext: ExtensionType) -> Option<&HelloRetryExtension> { - self.extensions - .iter() - .find(|x| x.get_type() == ext) - } - - pub fn get_requested_key_share_group(&self) -> Option { - let ext = self.find_extension(ExtensionType::KeyShare)?; - match *ext { - HelloRetryExtension::KeyShare(grp) => Some(grp), - _ => None, - } - } - - pub fn get_cookie(&self) -> Option<&PayloadU16> { - let ext = self.find_extension(ExtensionType::Cookie)?; - match *ext { - HelloRetryExtension::Cookie(ref ck) => Some(ck), - _ => None, - } - } - - pub fn get_supported_versions(&self) -> Option { - let ext = self.find_extension(ExtensionType::SupportedVersions)?; - match *ext { - HelloRetryExtension::SupportedVersions(ver) => Some(ver), - _ => None, - } - } -} - -#[derive(Debug)] -pub struct ServerHelloPayload { - pub legacy_version: ProtocolVersion, - pub random: Random, - pub session_id: SessionID, - pub cipher_suite: CipherSuite, - pub compression_method: Compression, - pub extensions: Vec, -} - -impl Codec for ServerHelloPayload { - fn encode(&self, bytes: &mut Vec) { - self.legacy_version.encode(bytes); - self.random.encode(bytes); - - self.session_id.encode(bytes); - self.cipher_suite.encode(bytes); - self.compression_method.encode(bytes); - - if !self.extensions.is_empty() { - codec::encode_vec_u16(bytes, &self.extensions); - } - } - - // minus version and random, which have already been read. - fn read(r: &mut Reader) -> Option { - let session_id = SessionID::read(r)?; - let suite = CipherSuite::read(r)?; - let compression = Compression::read(r)?; - - // RFC5246: - // "The presence of extensions can be detected by determining whether - // there are bytes following the compression_method field at the end of - // the ServerHello." - let extensions = if r.any_left() { - codec::read_vec_u16::(r)? - } else { - vec![] - }; - - let ret = Self { - legacy_version: ProtocolVersion::Unknown(0), - random: ZERO_RANDOM, - session_id, - cipher_suite: suite, - compression_method: compression, - extensions, - }; - - if r.any_left() { - None - } else { - Some(ret) - } - } -} - -impl HasServerExtensions for ServerHelloPayload { - fn get_extensions(&self) -> &[ServerExtension] { - &self.extensions - } -} - -impl ServerHelloPayload { - pub fn get_key_share(&self) -> Option<&KeyShareEntry> { - let ext = self.find_extension(ExtensionType::KeyShare)?; - match *ext { - ServerExtension::KeyShare(ref share) => Some(share), - _ => None, - } - } - - pub fn get_psk_index(&self) -> Option { - let ext = self.find_extension(ExtensionType::PreSharedKey)?; - match *ext { - ServerExtension::PresharedKey(ref index) => Some(*index), - _ => None, - } - } - - pub fn get_ecpoints_extension(&self) -> Option<&ECPointFormatList> { - let ext = self.find_extension(ExtensionType::ECPointFormats)?; - match *ext { - ServerExtension::ECPointFormats(ref fmts) => Some(fmts), - _ => None, - } - } - - pub fn ems_support_acked(&self) -> bool { - self.find_extension(ExtensionType::ExtendedMasterSecret) - .is_some() - } - - pub fn get_sct_list(&self) -> Option<&SCTList> { - let ext = self.find_extension(ExtensionType::SCT)?; - match *ext { - ServerExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl), - _ => None, - } - } - - pub fn get_supported_versions(&self) -> Option { - let ext = self.find_extension(ExtensionType::SupportedVersions)?; - match *ext { - ServerExtension::SupportedVersions(vers) => Some(vers), - _ => None, - } - } -} - -pub type CertificatePayload = Vec; - -impl Codec for CertificatePayload { - fn encode(&self, bytes: &mut Vec) { - codec::encode_vec_u24(bytes, self); - } - - fn read(r: &mut Reader) -> Option { - // 64KB of certificates is plenty, 16MB is obviously silly - codec::read_vec_u24_limited(r, 0x10000) - } -} - -// TLS1.3 changes the Certificate payload encoding. -// That's annoying. It means the parsing is not -// context-free any more. - -#[derive(Debug)] -pub enum CertificateExtension { - CertificateStatus(CertificateStatus), - SignedCertificateTimestamp(SCTList), - Unknown(UnknownExtension), -} - -impl CertificateExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::CertificateStatus(_) => ExtensionType::StatusRequest, - Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, - Self::Unknown(ref r) => r.typ, - } - } - - pub fn make_sct(sct_list: Vec) -> Self { - let sctl = SCTList::read_bytes(&sct_list).expect("invalid SCT list"); - Self::SignedCertificateTimestamp(sctl) - } - - pub fn get_cert_status(&self) -> Option<&Vec> { - match *self { - Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0), - _ => None, - } - } - - pub fn get_sct_list(&self) -> Option<&SCTList> { - match *self { - Self::SignedCertificateTimestamp(ref sctl) => Some(sctl), - _ => None, - } - } -} - -impl Codec for CertificateExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::CertificateStatus(ref r) => r.encode(&mut sub), - Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::StatusRequest => { - let st = CertificateStatus::read(&mut sub)?; - Self::CertificateStatus(st) - } - ExtensionType::SCT => { - let scts = SCTList::read(&mut sub)?; - Self::SignedCertificateTimestamp(scts) - } - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -declare_u16_vec!(CertificateExtensions, CertificateExtension); - -#[derive(Debug)] -pub struct CertificateEntry { - pub cert: key::Certificate, - pub exts: CertificateExtensions, -} - -impl Codec for CertificateEntry { - fn encode(&self, bytes: &mut Vec) { - self.cert.encode(bytes); - self.exts.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - Some(Self { - cert: key::Certificate::read(r)?, - exts: CertificateExtensions::read(r)?, - }) - } -} - -impl CertificateEntry { - pub fn new(cert: key::Certificate) -> Self { - Self { - cert, - exts: Vec::new(), - } - } - - pub fn has_duplicate_extension(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for ext in &self.exts { - let typ = ext.get_type().get_u16(); - - if seen.contains(&typ) { - return true; - } - seen.insert(typ); - } - - false - } - - pub fn has_unknown_extension(&self) -> bool { - self.exts.iter().any(|ext| { - ext.get_type() != ExtensionType::StatusRequest && ext.get_type() != ExtensionType::SCT - }) - } - - pub fn get_ocsp_response(&self) -> Option<&Vec> { - self.exts - .iter() - .find(|ext| ext.get_type() == ExtensionType::StatusRequest) - .and_then(CertificateExtension::get_cert_status) - } - - pub fn get_scts(&self) -> Option<&SCTList> { - self.exts - .iter() - .find(|ext| ext.get_type() == ExtensionType::SCT) - .and_then(CertificateExtension::get_sct_list) - } -} - -#[derive(Debug)] -pub struct CertificatePayloadTLS13 { - pub context: PayloadU8, - pub entries: Vec, -} - -impl Codec for CertificatePayloadTLS13 { - fn encode(&self, bytes: &mut Vec) { - self.context.encode(bytes); - codec::encode_vec_u24(bytes, &self.entries); - } - - fn read(r: &mut Reader) -> Option { - Some(Self { - context: PayloadU8::read(r)?, - entries: codec::read_vec_u24_limited::(r, 0x10000)?, - }) - } -} - -impl CertificatePayloadTLS13 { - pub fn new(entries: Vec) -> Self { - Self { - context: PayloadU8::empty(), - entries, - } - } - - pub fn any_entry_has_duplicate_extension(&self) -> bool { - for entry in &self.entries { - if entry.has_duplicate_extension() { - return true; - } - } - - false - } - - pub fn any_entry_has_unknown_extension(&self) -> bool { - for entry in &self.entries { - if entry.has_unknown_extension() { - return true; - } - } - - false - } - - pub fn any_entry_has_extension(&self) -> bool { - for entry in &self.entries { - if !entry.exts.is_empty() { - return true; - } - } - - false - } - - pub fn get_end_entity_ocsp(&self) -> Vec { - self.entries - .first() - .and_then(CertificateEntry::get_ocsp_response) - .cloned() - .unwrap_or_default() - } - - pub fn get_end_entity_scts(&self) -> Option { - self.entries - .first() - .and_then(CertificateEntry::get_scts) - .cloned() - } - - pub fn convert(&self) -> CertificatePayload { - let mut ret = Vec::new(); - for entry in &self.entries { - ret.push(entry.cert.clone()); - } - ret - } -} - -#[derive(Debug)] -pub enum KeyExchangeAlgorithm { - BulkOnly, - DH, - DHE, - RSA, - ECDH, - ECDHE, -} - -// We don't support arbitrary curves. It's a terrible -// idea and unnecessary attack surface. Please, -// get a grip. -#[derive(Debug)] -pub struct ECParameters { - pub curve_type: ECCurveType, - pub named_group: NamedGroup, -} - -impl Codec for ECParameters { - fn encode(&self, bytes: &mut Vec) { - self.curve_type.encode(bytes); - self.named_group.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let ct = ECCurveType::read(r)?; - - if ct != ECCurveType::NamedCurve { - return None; - } - - let grp = NamedGroup::read(r)?; - - Some(Self { - curve_type: ct, - named_group: grp, - }) - } -} - -#[derive(Debug, Clone)] -pub struct DigitallySignedStruct { - pub scheme: SignatureScheme, - #[deprecated(since = "0.20.7", note = "Use signature() accessor")] - pub sig: PayloadU16, -} - -impl DigitallySignedStruct { - #![allow(deprecated)] - pub fn new(scheme: SignatureScheme, sig: Vec) -> Self { - Self { - scheme, - sig: PayloadU16::new(sig), - } - } - - pub fn signature(&self) -> &[u8] { - &self.sig.0 - } -} - -impl Codec for DigitallySignedStruct { - #![allow(deprecated)] - fn encode(&self, bytes: &mut Vec) { - self.scheme.encode(bytes); - self.sig.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let scheme = SignatureScheme::read(r)?; - let sig = PayloadU16::read(r)?; - - Some(Self { scheme, sig }) - } -} - -#[derive(Debug)] -pub struct ClientECDHParams { - pub public: PayloadU8, -} - -impl Codec for ClientECDHParams { - fn encode(&self, bytes: &mut Vec) { - self.public.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let pb = PayloadU8::read(r)?; - Some(Self { public: pb }) - } -} - -#[derive(Debug)] -pub struct ServerECDHParams { - pub curve_params: ECParameters, - pub public: PayloadU8, -} - -impl ServerECDHParams { - pub fn new(named_group: NamedGroup, pubkey: &[u8]) -> Self { - Self { - curve_params: ECParameters { - curve_type: ECCurveType::NamedCurve, - named_group, - }, - public: PayloadU8::new(pubkey.to_vec()), - } - } -} - -impl Codec for ServerECDHParams { - fn encode(&self, bytes: &mut Vec) { - self.curve_params.encode(bytes); - self.public.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let cp = ECParameters::read(r)?; - let pb = PayloadU8::read(r)?; - - Some(Self { - curve_params: cp, - public: pb, - }) - } -} - -#[derive(Debug)] -pub struct ECDHEServerKeyExchange { - pub params: ServerECDHParams, - pub dss: DigitallySignedStruct, -} - -impl Codec for ECDHEServerKeyExchange { - fn encode(&self, bytes: &mut Vec) { - self.params.encode(bytes); - self.dss.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let params = ServerECDHParams::read(r)?; - let dss = DigitallySignedStruct::read(r)?; - - Some(Self { params, dss }) - } -} - -#[derive(Debug)] -pub enum ServerKeyExchangePayload { - ECDHE(ECDHEServerKeyExchange), - Unknown(Payload), -} - -impl Codec for ServerKeyExchangePayload { - fn encode(&self, bytes: &mut Vec) { - match *self { - Self::ECDHE(ref x) => x.encode(bytes), - Self::Unknown(ref x) => x.encode(bytes), - } - } - - fn read(r: &mut Reader) -> Option { - // read as Unknown, fully parse when we know the - // KeyExchangeAlgorithm - Some(Self::Unknown(Payload::read(r))) - } -} - -impl ServerKeyExchangePayload { - pub fn unwrap_given_kxa(&self, kxa: &KeyExchangeAlgorithm) -> Option { - if let Self::Unknown(ref unk) = *self { - let mut rd = Reader::init(&unk.0); - - let result = match *kxa { - KeyExchangeAlgorithm::ECDHE => ECDHEServerKeyExchange::read(&mut rd), - _ => None, - }; - - if !rd.any_left() { - return result; - }; - } - - None - } -} - -// -- EncryptedExtensions (TLS1.3 only) -- -declare_u16_vec!(EncryptedExtensions, ServerExtension); - -pub trait HasServerExtensions { - fn get_extensions(&self) -> &[ServerExtension]; - - /// Returns true if there is more than one extension of a given - /// type. - fn has_duplicate_extension(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for ext in self.get_extensions() { - let typ = ext.get_type().get_u16(); - - if seen.contains(&typ) { - return true; - } - seen.insert(typ); - } - - false - } - - fn find_extension(&self, ext: ExtensionType) -> Option<&ServerExtension> { - self.get_extensions() - .iter() - .find(|x| x.get_type() == ext) - } - - fn get_alpn_protocol(&self) -> Option<&[u8]> { - let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; - match *ext { - ServerExtension::Protocols(ref protos) => protos.as_single_slice(), - _ => None, - } - } - - fn get_quic_params_extension(&self) -> Option> { - let ext = self - .find_extension(ExtensionType::TransportParameters) - .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; - match *ext { - ServerExtension::TransportParameters(ref bytes) - | ServerExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), - _ => None, - } - } - - fn early_data_extension_offered(&self) -> bool { - self.find_extension(ExtensionType::EarlyData) - .is_some() - } -} - -impl HasServerExtensions for EncryptedExtensions { - fn get_extensions(&self) -> &[ServerExtension] { - self - } -} - -// -- CertificateRequest and sundries -- -declare_u8_vec!(ClientCertificateTypes, ClientCertificateType); -pub type DistinguishedName = PayloadU16; -/// DistinguishedNames is a `Vec>` wrapped in internal types. Each element contains the -/// DER or BER encoded [`Subject` field from RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) -/// for a single certificate. The Subject field is -/// [encoded as an RFC 5280 `Name`](https://datatracker.ietf.org/doc/html/rfc5280#page-116). -/// It can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/traits/trait.FromDer.html). -/// -/// ```ignore -/// for name in distinguished_names { -/// use x509_parser::traits::FromDer; -/// println!("{}", x509_parser::x509::X509Name::from_der(&name.0)?.1); -/// } -/// ``` -pub type DistinguishedNames = VecU16OfPayloadU16; - -#[derive(Debug)] -pub struct CertificateRequestPayload { - pub certtypes: ClientCertificateTypes, - pub sigschemes: SupportedSignatureSchemes, - pub canames: DistinguishedNames, -} - -impl Codec for CertificateRequestPayload { - fn encode(&self, bytes: &mut Vec) { - self.certtypes.encode(bytes); - self.sigschemes.encode(bytes); - self.canames.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let certtypes = ClientCertificateTypes::read(r)?; - let sigschemes = SupportedSignatureSchemes::read(r)?; - let canames = DistinguishedNames::read(r)?; - - if sigschemes.is_empty() { - warn!("meaningless CertificateRequest message"); - None - } else { - Some(Self { - certtypes, - sigschemes, - canames, - }) - } - } -} - -#[derive(Debug)] -pub enum CertReqExtension { - SignatureAlgorithms(SupportedSignatureSchemes), - AuthorityNames(DistinguishedNames), - Unknown(UnknownExtension), -} - -impl CertReqExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, - Self::AuthorityNames(_) => ExtensionType::CertificateAuthorities, - Self::Unknown(ref r) => r.typ, - } - } -} - -impl Codec for CertReqExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), - Self::AuthorityNames(ref r) => r.encode(&mut sub), - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::SignatureAlgorithms => { - let schemes = SupportedSignatureSchemes::read(&mut sub)?; - if schemes.is_empty() { - return None; - } - Self::SignatureAlgorithms(schemes) - } - ExtensionType::CertificateAuthorities => { - let cas = DistinguishedNames::read(&mut sub)?; - Self::AuthorityNames(cas) - } - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -declare_u16_vec!(CertReqExtensions, CertReqExtension); - -#[derive(Debug)] -pub struct CertificateRequestPayloadTLS13 { - pub context: PayloadU8, - pub extensions: CertReqExtensions, -} - -impl Codec for CertificateRequestPayloadTLS13 { - fn encode(&self, bytes: &mut Vec) { - self.context.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let context = PayloadU8::read(r)?; - let extensions = CertReqExtensions::read(r)?; - - Some(Self { - context, - extensions, - }) - } -} - -impl CertificateRequestPayloadTLS13 { - pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> { - self.extensions - .iter() - .find(|x| x.get_type() == ext) - } - - pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> { - let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; - match *ext { - CertReqExtension::SignatureAlgorithms(ref sa) => Some(sa), - _ => None, - } - } - - pub fn get_authorities_extension(&self) -> Option<&DistinguishedNames> { - let ext = self.find_extension(ExtensionType::CertificateAuthorities)?; - match *ext { - CertReqExtension::AuthorityNames(ref an) => Some(an), - _ => None, - } - } -} - -// -- NewSessionTicket -- -#[derive(Debug)] -pub struct NewSessionTicketPayload { - pub lifetime_hint: u32, - pub ticket: PayloadU16, -} - -impl NewSessionTicketPayload { - pub fn new(lifetime_hint: u32, ticket: Vec) -> Self { - Self { - lifetime_hint, - ticket: PayloadU16::new(ticket), - } - } -} - -impl Codec for NewSessionTicketPayload { - fn encode(&self, bytes: &mut Vec) { - self.lifetime_hint.encode(bytes); - self.ticket.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let lifetime = u32::read(r)?; - let ticket = PayloadU16::read(r)?; - - Some(Self { - lifetime_hint: lifetime, - ticket, - }) - } -} - -// -- NewSessionTicket electric boogaloo -- -#[derive(Debug)] -pub enum NewSessionTicketExtension { - EarlyData(u32), - Unknown(UnknownExtension), -} - -impl NewSessionTicketExtension { - pub fn get_type(&self) -> ExtensionType { - match *self { - Self::EarlyData(_) => ExtensionType::EarlyData, - Self::Unknown(ref r) => r.typ, - } - } -} - -impl Codec for NewSessionTicketExtension { - fn encode(&self, bytes: &mut Vec) { - self.get_type().encode(bytes); - - let mut sub: Vec = Vec::new(); - match *self { - Self::EarlyData(r) => r.encode(&mut sub), - Self::Unknown(ref r) => r.encode(&mut sub), - } - - (sub.len() as u16).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - let ext = match typ { - ExtensionType::EarlyData => Self::EarlyData(u32::read(&mut sub)?), - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(ext) - } - } -} - -declare_u16_vec!(NewSessionTicketExtensions, NewSessionTicketExtension); - -#[derive(Debug)] -pub struct NewSessionTicketPayloadTLS13 { - pub lifetime: u32, - pub age_add: u32, - pub nonce: PayloadU8, - pub ticket: PayloadU16, - pub exts: NewSessionTicketExtensions, -} - -impl NewSessionTicketPayloadTLS13 { - pub fn new(lifetime: u32, age_add: u32, nonce: Vec, ticket: Vec) -> Self { - Self { - lifetime, - age_add, - nonce: PayloadU8::new(nonce), - ticket: PayloadU16::new(ticket), - exts: vec![], - } - } - - pub fn has_duplicate_extension(&self) -> bool { - let mut seen = collections::HashSet::new(); - - for ext in &self.exts { - let typ = ext.get_type().get_u16(); - - if seen.contains(&typ) { - return true; - } - seen.insert(typ); - } - - false - } - - pub fn find_extension(&self, ext: ExtensionType) -> Option<&NewSessionTicketExtension> { - self.exts - .iter() - .find(|x| x.get_type() == ext) - } - - pub fn get_max_early_data_size(&self) -> Option { - let ext = self.find_extension(ExtensionType::EarlyData)?; - match *ext { - NewSessionTicketExtension::EarlyData(ref sz) => Some(*sz), - _ => None, - } - } -} - -impl Codec for NewSessionTicketPayloadTLS13 { - fn encode(&self, bytes: &mut Vec) { - self.lifetime.encode(bytes); - self.age_add.encode(bytes); - self.nonce.encode(bytes); - self.ticket.encode(bytes); - self.exts.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let lifetime = u32::read(r)?; - let age_add = u32::read(r)?; - let nonce = PayloadU8::read(r)?; - let ticket = PayloadU16::read(r)?; - let exts = NewSessionTicketExtensions::read(r)?; - - Some(Self { - lifetime, - age_add, - nonce, - ticket, - exts, - }) - } -} - -// -- RFC6066 certificate status types - -/// Only supports OCSP -#[derive(Debug)] -pub struct CertificateStatus { - pub ocsp_response: PayloadU24, -} - -impl Codec for CertificateStatus { - fn encode(&self, bytes: &mut Vec) { - CertificateStatusType::OCSP.encode(bytes); - self.ocsp_response.encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let typ = CertificateStatusType::read(r)?; - - match typ { - CertificateStatusType::OCSP => Some(Self { - ocsp_response: PayloadU24::read(r)?, - }), - _ => None, - } - } -} - -impl CertificateStatus { - pub fn new(ocsp: Vec) -> Self { - Self { - ocsp_response: PayloadU24::new(ocsp), - } - } - - pub fn into_inner(self) -> Vec { - self.ocsp_response.0 - } -} - -#[derive(Debug)] -pub enum HandshakePayload { - HelloRequest, - ClientHello(ClientHelloPayload), - ServerHello(ServerHelloPayload), - HelloRetryRequest(HelloRetryRequest), - Certificate(CertificatePayload), - CertificateTLS13(CertificatePayloadTLS13), - ServerKeyExchange(ServerKeyExchangePayload), - CertificateRequest(CertificateRequestPayload), - CertificateRequestTLS13(CertificateRequestPayloadTLS13), - CertificateVerify(DigitallySignedStruct), - ServerHelloDone, - EndOfEarlyData, - ClientKeyExchange(Payload), - NewSessionTicket(NewSessionTicketPayload), - NewSessionTicketTLS13(NewSessionTicketPayloadTLS13), - EncryptedExtensions(EncryptedExtensions), - KeyUpdate(KeyUpdateRequest), - Finished(Payload), - CertificateStatus(CertificateStatus), - MessageHash(Payload), - Unknown(Payload), -} - -impl HandshakePayload { - fn encode(&self, bytes: &mut Vec) { - use self::HandshakePayload::*; - match *self { - HelloRequest | ServerHelloDone | EndOfEarlyData => {} - ClientHello(ref x) => x.encode(bytes), - ServerHello(ref x) => x.encode(bytes), - HelloRetryRequest(ref x) => x.encode(bytes), - Certificate(ref x) => x.encode(bytes), - CertificateTLS13(ref x) => x.encode(bytes), - ServerKeyExchange(ref x) => x.encode(bytes), - ClientKeyExchange(ref x) => x.encode(bytes), - CertificateRequest(ref x) => x.encode(bytes), - CertificateRequestTLS13(ref x) => x.encode(bytes), - CertificateVerify(ref x) => x.encode(bytes), - NewSessionTicket(ref x) => x.encode(bytes), - NewSessionTicketTLS13(ref x) => x.encode(bytes), - EncryptedExtensions(ref x) => x.encode(bytes), - KeyUpdate(ref x) => x.encode(bytes), - Finished(ref x) => x.encode(bytes), - CertificateStatus(ref x) => x.encode(bytes), - MessageHash(ref x) => x.encode(bytes), - Unknown(ref x) => x.encode(bytes), - } - } -} - -#[derive(Debug)] -pub struct HandshakeMessagePayload { - pub typ: HandshakeType, - pub payload: HandshakePayload, -} - -impl Codec for HandshakeMessagePayload { - fn encode(&self, bytes: &mut Vec) { - // encode payload to learn length - let mut sub: Vec = Vec::new(); - self.payload.encode(&mut sub); - - // output type, length, and encoded payload - match self.typ { - HandshakeType::HelloRetryRequest => HandshakeType::ServerHello, - _ => self.typ, - } - .encode(bytes); - codec::u24(sub.len() as u32).encode(bytes); - bytes.append(&mut sub); - } - - fn read(r: &mut Reader) -> Option { - Self::read_version(r, ProtocolVersion::TLSv1_2) - } -} - -impl HandshakeMessagePayload { - pub fn read_version(r: &mut Reader, vers: ProtocolVersion) -> Option { - let mut typ = HandshakeType::read(r)?; - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - - let payload = match typ { - HandshakeType::HelloRequest if sub.left() == 0 => HandshakePayload::HelloRequest, - HandshakeType::ClientHello => { - HandshakePayload::ClientHello(ClientHelloPayload::read(&mut sub)?) - } - HandshakeType::ServerHello => { - let version = ProtocolVersion::read(&mut sub)?; - let random = Random::read(&mut sub)?; - - if random == HELLO_RETRY_REQUEST_RANDOM { - let mut hrr = HelloRetryRequest::read(&mut sub)?; - hrr.legacy_version = version; - typ = HandshakeType::HelloRetryRequest; - HandshakePayload::HelloRetryRequest(hrr) - } else { - let mut shp = ServerHelloPayload::read(&mut sub)?; - shp.legacy_version = version; - shp.random = random; - HandshakePayload::ServerHello(shp) - } - } - HandshakeType::Certificate if vers == ProtocolVersion::TLSv1_3 => { - let p = CertificatePayloadTLS13::read(&mut sub)?; - HandshakePayload::CertificateTLS13(p) - } - HandshakeType::Certificate => { - HandshakePayload::Certificate(CertificatePayload::read(&mut sub)?) - } - HandshakeType::ServerKeyExchange => { - let p = ServerKeyExchangePayload::read(&mut sub)?; - HandshakePayload::ServerKeyExchange(p) - } - HandshakeType::ServerHelloDone => { - if sub.any_left() { - return None; - } - HandshakePayload::ServerHelloDone - } - HandshakeType::ClientKeyExchange => { - HandshakePayload::ClientKeyExchange(Payload::read(&mut sub)) - } - HandshakeType::CertificateRequest if vers == ProtocolVersion::TLSv1_3 => { - let p = CertificateRequestPayloadTLS13::read(&mut sub)?; - HandshakePayload::CertificateRequestTLS13(p) - } - HandshakeType::CertificateRequest => { - let p = CertificateRequestPayload::read(&mut sub)?; - HandshakePayload::CertificateRequest(p) - } - HandshakeType::CertificateVerify => { - HandshakePayload::CertificateVerify(DigitallySignedStruct::read(&mut sub)?) - } - HandshakeType::NewSessionTicket if vers == ProtocolVersion::TLSv1_3 => { - let p = NewSessionTicketPayloadTLS13::read(&mut sub)?; - HandshakePayload::NewSessionTicketTLS13(p) - } - HandshakeType::NewSessionTicket => { - let p = NewSessionTicketPayload::read(&mut sub)?; - HandshakePayload::NewSessionTicket(p) - } - HandshakeType::EncryptedExtensions => { - HandshakePayload::EncryptedExtensions(EncryptedExtensions::read(&mut sub)?) - } - HandshakeType::KeyUpdate => { - HandshakePayload::KeyUpdate(KeyUpdateRequest::read(&mut sub)?) - } - HandshakeType::EndOfEarlyData => { - if sub.any_left() { - return None; - } - HandshakePayload::EndOfEarlyData - } - HandshakeType::Finished => HandshakePayload::Finished(Payload::read(&mut sub)), - HandshakeType::CertificateStatus => { - HandshakePayload::CertificateStatus(CertificateStatus::read(&mut sub)?) - } - HandshakeType::MessageHash => { - // does not appear on the wire - return None; - } - HandshakeType::HelloRetryRequest => { - // not legal on wire - return None; - } - _ => HandshakePayload::Unknown(Payload::read(&mut sub)), - }; - - if sub.any_left() { - None - } else { - Some(Self { typ, payload }) - } - } - - pub fn build_key_update_notify() -> Self { - Self { - typ: HandshakeType::KeyUpdate, - payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), - } - } - - pub fn get_encoding_for_binder_signing(&self) -> Vec { - let mut ret = self.get_encoding(); - - let binder_len = match self.payload { - HandshakePayload::ClientHello(ref ch) => match ch.extensions.last() { - Some(ClientExtension::PresharedKey(ref offer)) => { - let mut binders_encoding = Vec::new(); - offer - .binders - .encode(&mut binders_encoding); - binders_encoding.len() - } - _ => 0, - }, - _ => 0, - }; - - let ret_len = ret.len() - binder_len; - ret.truncate(ret_len); - ret - } - - pub fn build_handshake_hash(hash: &[u8]) -> Self { - Self { - typ: HandshakeType::MessageHash, - payload: HandshakePayload::MessageHash(Payload::new(hash.to_vec())), - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/handshake_test.rs b/third_party/rustls-fork-shadow-tls/src/msgs/handshake_test.rs deleted file mode 100644 index 3e19cc1..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/handshake_test.rs +++ /dev/null @@ -1,1247 +0,0 @@ -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::key::Certificate; -use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; -use crate::msgs::codec::{put_u16, Codec, Reader}; -use crate::msgs::enums::{ - ClientCertificateType, Compression, ECCurveType, ExtensionType, HandshakeType, HashAlgorithm, - KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, ServerNameType, SignatureAlgorithm, -}; -use crate::msgs::handshake::{ - CertReqExtension, CertificateEntry, CertificateExtension, CertificatePayloadTLS13, - CertificateRequestPayload, CertificateRequestPayloadTLS13, CertificateStatus, - CertificateStatusRequest, ClientExtension, ClientHelloPayload, ClientSessionTicket, - ConvertProtocolNameList, ConvertServerNameList, DecomposedSignatureScheme, - DigitallySignedStruct, ECDHEServerKeyExchange, ECParameters, ECPointFormatList, - EncryptedExtensions, HandshakeMessagePayload, HandshakePayload, HasServerExtensions, - HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension, - NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder, - PresharedKeyIdentity, PresharedKeyOffer, Random, ServerECDHParams, ServerExtension, - ServerHelloPayload, ServerKeyExchangePayload, SessionID, SupportedPointFormats, - UnknownExtension, -}; -use webpki::DnsNameRef; - -#[test] -fn rejects_short_random() { - let bytes = [0x01; 31]; - let mut rd = Reader::init(&bytes); - assert_eq!(Random::read(&mut rd), None); -} - -#[test] -fn reads_random() { - let bytes = [0x01; 32]; - let mut rd = Reader::init(&bytes); - let rnd = Random::read(&mut rd).unwrap(); - println!("{:?}", rnd); - - assert!(!rd.any_left()); -} - -#[test] -fn debug_random() { - assert_eq!( - "0101010101010101010101010101010101010101010101010101010101010101", - format!("{:?}", Random::from([1; 32])) - ); -} - -#[test] -fn rejects_truncated_sessionid() { - let bytes = [32; 32]; - let mut rd = Reader::init(&bytes); - assert_eq!(SessionID::read(&mut rd), None); -} - -#[test] -fn rejects_sessionid_with_bad_length() { - let bytes = [33; 33]; - let mut rd = Reader::init(&bytes); - assert_eq!(SessionID::read(&mut rd), None); -} - -#[test] -fn sessionid_with_different_lengths_are_unequal() { - let a = SessionID::read(&mut Reader::init(&[1u8, 1])).unwrap(); - let b = SessionID::read(&mut Reader::init(&[2u8, 1, 2])).unwrap(); - assert_ne!(a, b); -} - -#[test] -fn accepts_short_sessionid() { - let bytes = [1; 2]; - let mut rd = Reader::init(&bytes); - let sess = SessionID::read(&mut rd).unwrap(); - println!("{:?}", sess); - - assert!(!sess.is_empty()); - assert_eq!(sess.len(), 1); - assert!(!rd.any_left()); -} - -#[test] -fn accepts_empty_sessionid() { - let bytes = [0; 1]; - let mut rd = Reader::init(&bytes); - let sess = SessionID::read(&mut rd).unwrap(); - println!("{:?}", sess); - - assert!(sess.is_empty()); - assert_eq!(sess.len(), 0); - assert!(!rd.any_left()); -} - -#[test] -fn debug_sessionid() { - let bytes = [ - 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, - ]; - let mut rd = Reader::init(&bytes); - let sess = SessionID::read(&mut rd).unwrap(); - assert_eq!( - "0101010101010101010101010101010101010101010101010101010101010101", - format!("{:?}", sess) - ); -} - -#[test] -fn can_roundtrip_unknown_client_ext() { - let bytes = [0x12u8, 0x34u8, 0, 3, 1, 2, 3]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - - println!("{:?}", ext); - assert_eq!(ext.get_type(), ExtensionType::Unknown(0x1234)); - assert_eq!(bytes.to_vec(), ext.get_encoding()); -} - -#[test] -fn refuses_client_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; - let mut rd = Reader::init(&bytes); - assert!(ClientExtension::read(&mut rd).is_none()); -} - -#[test] -fn refuses_server_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; - let mut rd = Reader::init(&bytes); - assert!(ServerExtension::read(&mut rd).is_none()); -} - -#[test] -fn refuses_certificate_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x12, 0x00, 0x03, 0x00, 0x00, 0x01]; - let mut rd = Reader::init(&bytes); - assert!(CertificateExtension::read(&mut rd).is_none()); -} - -#[test] -fn refuses_certificate_req_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x0d, 0x00, 0x05, 0x00, 0x02, 0x01, 0x02, 0xff]; - let mut rd = Reader::init(&bytes); - assert!(CertReqExtension::read(&mut rd).is_none()); -} - -#[test] -fn refuses_helloreq_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x2b, 0x00, 0x03, 0x00, 0x00, 0x01]; - let mut rd = Reader::init(&bytes); - assert!(HelloRetryExtension::read(&mut rd).is_none()); -} - -#[test] -fn refuses_newsessionticket_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x2a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01]; - let mut rd = Reader::init(&bytes); - assert!(NewSessionTicketExtension::read(&mut rd).is_none()); -} - -#[test] -fn can_roundtrip_single_sni() { - let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x6c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ServerName); - assert_eq!(bytes.to_vec(), ext.get_encoding()); -} - -#[test] -fn can_round_trip_mixed_case_sni() { - let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x4c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ServerName); - assert_eq!(bytes.to_vec(), ext.get_encoding()); -} - -#[test] -fn can_roundtrip_other_sni_name_types() { - let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ServerName); - assert_eq!(bytes.to_vec(), ext.get_encoding()); -} - -#[test] -fn get_single_hostname_returns_none_for_other_sni_name_types() { - let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ServerName); - if let ClientExtension::ServerName(snr) = ext { - assert!(!snr.has_duplicate_names_for_type()); - assert!(snr.get_single_hostname().is_none()); - } else { - unreachable!(); - } -} - -#[test] -fn can_roundtrip_multiname_sni() { - let bytes = [0, 0, 0, 12, 0, 10, 0, 0, 2, 0x68, 0x69, 0, 0, 2, 0x6c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ServerName); - assert_eq!(bytes.to_vec(), ext.get_encoding()); - match ext { - ClientExtension::ServerName(req) => { - assert_eq!(2, req.len()); - - assert!(req.has_duplicate_names_for_type()); - - let dns_name_str: &str = req - .get_single_hostname() - .unwrap() - .into(); - assert_eq!(dns_name_str, "hi"); - - assert_eq!(req[0].typ, ServerNameType::HostName); - assert_eq!(req[1].typ, ServerNameType::HostName); - } - _ => unreachable!(), - } -} - -#[test] -fn rejects_truncated_sni() { - let bytes = [0, 0, 0, 1, 0]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 2, 0, 1]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 3, 0, 1, 0]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 4, 0, 2, 0, 0]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 0]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 1]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); - - let bytes = [0, 0, 0, 6, 0, 4, 0, 0, 2, 0x68]; - assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_none()); -} - -#[test] -fn can_roundtrip_psk_identity() { - let bytes = [0, 0, 0x11, 0x22, 0x33, 0x44]; - let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); - println!("{:?}", psk_id); - assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); - assert_eq!(psk_id.get_encoding(), bytes.to_vec()); - - let bytes = [0, 5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x11, 0x22, 0x33, 0x44]; - let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); - println!("{:?}", psk_id); - assert_eq!(psk_id.identity.0, vec![0x1, 0x2, 0x3, 0x4, 0x5]); - assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); - assert_eq!(psk_id.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_roundtrip_psk_offer() { - let bytes = [ - 0, 7, 0, 1, 0x99, 0x11, 0x22, 0x33, 0x44, 0, 4, 3, 0x01, 0x02, 0x3, - ]; - let psko = PresharedKeyOffer::read(&mut Reader::init(&bytes)).unwrap(); - println!("{:?}", psko); - - assert_eq!(psko.identities.len(), 1); - assert_eq!(psko.identities[0].identity.0, vec![0x99]); - assert_eq!(psko.identities[0].obfuscated_ticket_age, 0x11223344); - assert_eq!(psko.binders.len(), 1); - assert_eq!(psko.binders[0].0, vec![1, 2, 3]); - assert_eq!(psko.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_roundtrip_certstatusreq_for_ocsp() { - let ext = ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()); - println!("{:?}", ext); - - let bytes = [ - 0, 5, // CertificateStatusRequest - 0, 11, 1, // OCSP - 0, 5, 0, 3, 0, 1, 1, 0, 1, 2, - ]; - - let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); - println!("{:?}", csr); - assert_eq!(csr.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_roundtrip_certstatusreq_for_other() { - let bytes = [ - 0, 5, // CertificateStatusRequest - 0, 5, 2, // !OCSP - 1, 2, 3, 4, - ]; - - let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); - println!("{:?}", csr); - assert_eq!(csr.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_roundtrip_multi_proto() { - let bytes = [0, 16, 0, 8, 0, 6, 2, 0x68, 0x69, 2, 0x6c, 0x6f]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); - assert_eq!(ext.get_encoding(), bytes.to_vec()); - match ext { - ClientExtension::Protocols(prot) => { - assert_eq!(2, prot.len()); - assert_eq!(vec![b"hi", b"lo"], prot.to_slices()); - assert_eq!(prot.as_single_slice(), None); - } - _ => unreachable!(), - } -} - -#[test] -fn can_roundtrip_single_proto() { - let bytes = [0, 16, 0, 5, 0, 3, 2, 0x68, 0x69]; - let mut rd = Reader::init(&bytes); - let ext = ClientExtension::read(&mut rd).unwrap(); - println!("{:?}", ext); - - assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); - assert_eq!(bytes.to_vec(), ext.get_encoding()); - match ext { - ClientExtension::Protocols(prot) => { - assert_eq!(1, prot.len()); - assert_eq!(vec![b"hi"], prot.to_slices()); - assert_eq!(prot.as_single_slice(), Some(&b"hi"[..])); - } - _ => unreachable!(), - } -} - -#[test] -fn decomposed_signature_scheme_has_correct_mappings() { - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::RSA, HashAlgorithm::SHA1), - SignatureScheme::RSA_PKCS1_SHA1 - ); - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::RSA, HashAlgorithm::SHA256), - SignatureScheme::RSA_PKCS1_SHA256 - ); - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::RSA, HashAlgorithm::SHA384), - SignatureScheme::RSA_PKCS1_SHA384 - ); - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::RSA, HashAlgorithm::SHA512), - SignatureScheme::RSA_PKCS1_SHA512 - ); - - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::ECDSA, HashAlgorithm::SHA256), - SignatureScheme::ECDSA_NISTP256_SHA256 - ); - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::ECDSA, HashAlgorithm::SHA384), - SignatureScheme::ECDSA_NISTP384_SHA384 - ); - assert_eq!( - SignatureScheme::make(SignatureAlgorithm::ECDSA, HashAlgorithm::SHA512), - SignatureScheme::ECDSA_NISTP521_SHA512 - ); -} - -fn get_sample_clienthellopayload() -> ClientHelloPayload { - ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_2, - random: Random::from([0; 32]), - session_id: SessionID::empty(), - cipher_suites: vec![CipherSuite::TLS_NULL_WITH_NULL_NULL], - compression_methods: vec![Compression::Null], - extensions: vec![ - ClientExtension::ECPointFormats(ECPointFormatList::supported()), - ClientExtension::NamedGroups(vec![NamedGroup::X25519]), - ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), - ClientExtension::make_sni(DnsNameRef::try_from_ascii_str("hello").unwrap()), - ClientExtension::SessionTicket(ClientSessionTicket::Request), - ClientExtension::SessionTicket(ClientSessionTicket::Offer(Payload(vec![]))), - ClientExtension::Protocols(vec![PayloadU8(vec![0])]), - ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), - ClientExtension::KeyShare(vec![KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])]), - ClientExtension::PresharedKeyModes(vec![PSKKeyExchangeMode::PSK_DHE_KE]), - ClientExtension::PresharedKey(PresharedKeyOffer { - identities: vec![ - PresharedKeyIdentity::new(vec![3, 4, 5], 123456), - PresharedKeyIdentity::new(vec![6, 7, 8], 7891011), - ], - binders: vec![ - PresharedKeyBinder::new(vec![1, 2, 3]), - PresharedKeyBinder::new(vec![3, 4, 5]), - ], - }), - ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])), - ClientExtension::ExtendedMasterSecretRequest, - ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()), - ClientExtension::SignedCertificateTimestampRequest, - ClientExtension::TransportParameters(vec![1, 2, 3]), - ClientExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - }), - ], - } -} - -#[test] -fn can_print_all_clientextensions() { - println!("client hello {:?}", get_sample_clienthellopayload()); -} - -#[test] -fn can_clone_all_clientextensions() { - let _ = get_sample_serverhellopayload().extensions; -} - -#[test] -fn client_has_duplicate_extensions_works() { - let mut chp = get_sample_clienthellopayload(); - assert!(chp.has_duplicate_extension()); // due to SessionTicketRequest/SessionTicketOffer - - chp.extensions.drain(1..); - assert!(!chp.has_duplicate_extension()); - - chp.extensions = vec![]; - assert!(!chp.has_duplicate_extension()); -} - -#[test] -fn test_truncated_psk_offer() { - let ext = ClientExtension::PresharedKey(PresharedKeyOffer { - identities: vec![PresharedKeyIdentity::new(vec![3, 4, 5], 123456)], - binders: vec![PresharedKeyBinder::new(vec![1, 2, 3])], - }); - - let mut enc = ext.get_encoding(); - println!("testing {:?} enc {:?}", ext, enc); - for l in 0..enc.len() { - if l == 9 { - continue; - } - put_u16(l as u16, &mut enc[4..]); - let rc = ClientExtension::read_bytes(&enc); - assert!(rc.is_none()); - } -} - -#[test] -fn test_truncated_client_hello_is_detected() { - let ch = get_sample_clienthellopayload(); - let enc = ch.get_encoding(); - println!("testing {:?} enc {:?}", ch, enc); - - for l in 0..enc.len() { - println!("len {:?} enc {:?}", l, &enc[..l]); - if l == 41 { - continue; // where extensions are empty - } - assert!(ClientHelloPayload::read_bytes(&enc[..l]).is_none()); - } -} - -#[test] -fn test_truncated_client_extension_is_detected() { - let chp = get_sample_clienthellopayload(); - - for ext in &chp.extensions { - let mut enc = ext.get_encoding(); - println!("testing {:?} enc {:?}", ext, enc); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 0..enc.len() { - assert!(ClientExtension::read_bytes(&enc[..l]).is_none()); - } - - // these extension types don't have any internal encoding that rustls validates: - match ext.get_type() { - ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { - continue; - } - _ => {} - }; - - // "inner" truncation, where the extension-level length agrees with the input - // length, but isn't long enough for the type of extension - for l in 0..(enc.len() - 4) { - put_u16(l as u16, &mut enc[2..]); - println!(" encoding {:?} len {:?}", enc, l); - assert!(ClientExtension::read_bytes(&enc).is_none()); - } - } -} - -fn test_client_extension_getter(typ: ExtensionType, getter: fn(&ClientHelloPayload) -> bool) { - let mut chp = get_sample_clienthellopayload(); - let ext = chp.find_extension(typ).unwrap().clone(); - - chp.extensions = vec![]; - assert!(!getter(&chp)); - - chp.extensions = vec![ext]; - assert!(getter(&chp)); - - chp.extensions = vec![ClientExtension::Unknown(UnknownExtension { - typ, - payload: Payload(vec![]), - })]; - assert!(!getter(&chp)); -} - -#[test] -fn client_get_sni_extension() { - test_client_extension_getter(ExtensionType::ServerName, |chp| { - chp.get_sni_extension().is_some() - }); -} - -#[test] -fn client_get_sigalgs_extension() { - test_client_extension_getter(ExtensionType::SignatureAlgorithms, |chp| { - chp.get_sigalgs_extension().is_some() - }); -} - -#[test] -fn client_get_namedgroups_extension() { - test_client_extension_getter(ExtensionType::EllipticCurves, |chp| { - chp.get_namedgroups_extension() - .is_some() - }); -} - -#[test] -fn client_get_ecpoints_extension() { - test_client_extension_getter(ExtensionType::ECPointFormats, |chp| { - chp.get_ecpoints_extension().is_some() - }); -} - -#[test] -fn client_get_alpn_extension() { - test_client_extension_getter(ExtensionType::ALProtocolNegotiation, |chp| { - chp.get_alpn_extension().is_some() - }); -} - -#[test] -fn client_get_quic_params_extension() { - test_client_extension_getter(ExtensionType::TransportParameters, |chp| { - chp.get_quic_params_extension() - .is_some() - }); -} - -#[test] -fn client_get_versions_extension() { - test_client_extension_getter(ExtensionType::SupportedVersions, |chp| { - chp.get_versions_extension().is_some() - }); -} - -#[test] -fn client_get_keyshare_extension() { - test_client_extension_getter(ExtensionType::KeyShare, |chp| { - chp.get_keyshare_extension().is_some() - }); -} - -#[test] -fn client_get_psk() { - test_client_extension_getter(ExtensionType::PreSharedKey, |chp| chp.get_psk().is_some()); -} - -#[test] -fn client_get_psk_modes() { - test_client_extension_getter(ExtensionType::PSKKeyExchangeModes, |chp| { - chp.get_psk_modes().is_some() - }); -} - -#[test] -fn test_truncated_helloretry_extension_is_detected() { - let hrr = get_sample_helloretryrequest(); - - for ext in &hrr.extensions { - let mut enc = ext.get_encoding(); - println!("testing {:?} enc {:?}", ext, enc); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 0..enc.len() { - assert!(HelloRetryExtension::read_bytes(&enc[..l]).is_none()); - } - - // these extension types don't have any internal encoding that rustls validates: - if let ExtensionType::Unknown(_) = ext.get_type() { - continue; - } - - // "inner" truncation, where the extension-level length agrees with the input - // length, but isn't long enough for the type of extension - for l in 0..(enc.len() - 4) { - put_u16(l as u16, &mut enc[2..]); - println!(" encoding {:?} len {:?}", enc, l); - assert!(HelloRetryExtension::read_bytes(&enc).is_none()); - } - } -} - -fn test_helloretry_extension_getter(typ: ExtensionType, getter: fn(&HelloRetryRequest) -> bool) { - let mut hrr = get_sample_helloretryrequest(); - let mut exts = std::mem::take(&mut hrr.extensions); - exts.retain(|ext| ext.get_type() == typ); - - assert!(!getter(&hrr)); - - hrr.extensions = exts; - assert!(getter(&hrr)); - - hrr.extensions = vec![HelloRetryExtension::Unknown(UnknownExtension { - typ, - payload: Payload(vec![]), - })]; - assert!(!getter(&hrr)); -} - -#[test] -fn helloretry_get_requested_key_share_group() { - test_helloretry_extension_getter(ExtensionType::KeyShare, |hrr| { - hrr.get_requested_key_share_group() - .is_some() - }); -} - -#[test] -fn helloretry_get_cookie() { - test_helloretry_extension_getter(ExtensionType::Cookie, |hrr| hrr.get_cookie().is_some()); -} - -#[test] -fn helloretry_get_supported_versions() { - test_helloretry_extension_getter(ExtensionType::SupportedVersions, |hrr| { - hrr.get_supported_versions().is_some() - }); -} - -#[test] -fn test_truncated_server_extension_is_detected() { - let shp = get_sample_serverhellopayload(); - - for ext in &shp.extensions { - let mut enc = ext.get_encoding(); - println!("testing {:?} enc {:?}", ext, enc); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 0..enc.len() { - assert!(ServerExtension::read_bytes(&enc[..l]).is_none()); - } - - // these extension types don't have any internal encoding that rustls validates: - match ext.get_type() { - ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { - continue; - } - _ => {} - }; - - // "inner" truncation, where the extension-level length agrees with the input - // length, but isn't long enough for the type of extension - for l in 0..(enc.len() - 4) { - put_u16(l as u16, &mut enc[2..]); - println!(" encoding {:?} len {:?}", enc, l); - assert!(ServerExtension::read_bytes(&enc).is_none()); - } - } -} - -fn test_server_extension_getter(typ: ExtensionType, getter: fn(&ServerHelloPayload) -> bool) { - let mut shp = get_sample_serverhellopayload(); - let ext = shp.find_extension(typ).unwrap().clone(); - - shp.extensions = vec![]; - assert!(!getter(&shp)); - - shp.extensions = vec![ext]; - assert!(getter(&shp)); - - shp.extensions = vec![ServerExtension::Unknown(UnknownExtension { - typ, - payload: Payload(vec![]), - })]; - assert!(!getter(&shp)); -} - -#[test] -fn server_get_key_share() { - test_server_extension_getter(ExtensionType::KeyShare, |shp| shp.get_key_share().is_some()); -} - -#[test] -fn server_get_psk_index() { - test_server_extension_getter(ExtensionType::PreSharedKey, |shp| { - shp.get_psk_index().is_some() - }); -} - -#[test] -fn server_get_ecpoints_extension() { - test_server_extension_getter(ExtensionType::ECPointFormats, |shp| { - shp.get_ecpoints_extension().is_some() - }); -} - -#[test] -fn server_get_sct_list() { - test_server_extension_getter(ExtensionType::SCT, |shp| shp.get_sct_list().is_some()); -} - -#[test] -fn server_get_supported_versions() { - test_server_extension_getter(ExtensionType::SupportedVersions, |shp| { - shp.get_supported_versions().is_some() - }); -} - -fn test_cert_extension_getter(typ: ExtensionType, getter: fn(&CertificateEntry) -> bool) { - let mut ce = get_sample_certificatepayloadtls13() - .entries - .remove(0); - let mut exts = std::mem::take(&mut ce.exts); - exts.retain(|ext| ext.get_type() == typ); - - assert!(!getter(&ce)); - - ce.exts = exts; - assert!(getter(&ce)); - - ce.exts = vec![CertificateExtension::Unknown(UnknownExtension { - typ, - payload: Payload(vec![]), - })]; - assert!(!getter(&ce)); -} - -#[test] -fn certentry_get_ocsp_response() { - test_cert_extension_getter(ExtensionType::StatusRequest, |ce| { - ce.get_ocsp_response().is_some() - }); -} - -#[test] -fn certentry_get_scts() { - test_cert_extension_getter(ExtensionType::SCT, |ce| ce.get_scts().is_some()); -} - -fn get_sample_serverhellopayload() -> ServerHelloPayload { - ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from([0; 32]), - session_id: SessionID::empty(), - cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, - compression_method: Compression::Null, - extensions: vec![ - ServerExtension::ECPointFormats(ECPointFormatList::supported()), - ServerExtension::ServerNameAck, - ServerExtension::SessionTicketAck, - ServerExtension::RenegotiationInfo(PayloadU8(vec![0])), - ServerExtension::Protocols(vec![PayloadU8(vec![0])]), - ServerExtension::KeyShare(KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])), - ServerExtension::PresharedKey(3), - ServerExtension::ExtendedMasterSecretAck, - ServerExtension::CertificateStatusAck, - ServerExtension::SignedCertificateTimestamp(vec![PayloadU16(vec![0])]), - ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2), - ServerExtension::TransportParameters(vec![1, 2, 3]), - ServerExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - }), - ], - } -} - -#[test] -fn can_print_all_serverextensions() { - println!("server hello {:?}", get_sample_serverhellopayload()); -} - -#[test] -fn can_clone_all_serverextensions() { - let _ = get_sample_serverhellopayload().extensions; -} - -fn get_sample_helloretryrequest() -> HelloRetryRequest { - HelloRetryRequest { - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionID::empty(), - cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, - extensions: vec![ - HelloRetryExtension::KeyShare(NamedGroup::X25519), - HelloRetryExtension::Cookie(PayloadU16(vec![0])), - HelloRetryExtension::SupportedVersions(ProtocolVersion::TLSv1_2), - HelloRetryExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - }), - ], - } -} - -fn get_sample_certificatepayloadtls13() -> CertificatePayloadTLS13 { - CertificatePayloadTLS13 { - context: PayloadU8(vec![1, 2, 3]), - entries: vec![CertificateEntry { - cert: Certificate(vec![3, 4, 5]), - exts: vec![ - CertificateExtension::CertificateStatus(CertificateStatus { - ocsp_response: PayloadU24(vec![1, 2, 3]), - }), - CertificateExtension::SignedCertificateTimestamp(vec![PayloadU16(vec![0])]), - CertificateExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - }), - ], - }], - } -} - -fn get_sample_serverkeyexchangepayload_ecdhe() -> ServerKeyExchangePayload { - ServerKeyExchangePayload::ECDHE(ECDHEServerKeyExchange { - params: ServerECDHParams { - curve_params: ECParameters { - curve_type: ECCurveType::NamedCurve, - named_group: NamedGroup::X25519, - }, - public: PayloadU8(vec![1, 2, 3]), - }, - dss: DigitallySignedStruct::new(SignatureScheme::RSA_PSS_SHA256, vec![1, 2, 3]), - }) -} - -fn get_sample_serverkeyexchangepayload_unknown() -> ServerKeyExchangePayload { - ServerKeyExchangePayload::Unknown(Payload(vec![1, 2, 3])) -} - -fn get_sample_certificaterequestpayload() -> CertificateRequestPayload { - CertificateRequestPayload { - certtypes: vec![ClientCertificateType::RSASign], - sigschemes: vec![SignatureScheme::ECDSA_NISTP256_SHA256], - canames: vec![PayloadU16(vec![1, 2, 3])], - } -} - -fn get_sample_certificaterequestpayloadtls13() -> CertificateRequestPayloadTLS13 { - CertificateRequestPayloadTLS13 { - context: PayloadU8(vec![1, 2, 3]), - extensions: vec![ - CertReqExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), - CertReqExtension::AuthorityNames(vec![PayloadU16(vec![1, 2, 3])]), - CertReqExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - }), - ], - } -} - -fn get_sample_newsessionticketpayload() -> NewSessionTicketPayload { - NewSessionTicketPayload { - lifetime_hint: 1234, - ticket: PayloadU16(vec![1, 2, 3]), - } -} - -fn get_sample_newsessionticketpayloadtls13() -> NewSessionTicketPayloadTLS13 { - NewSessionTicketPayloadTLS13 { - lifetime: 123, - age_add: 1234, - nonce: PayloadU8(vec![1, 2, 3]), - ticket: PayloadU16(vec![4, 5, 6]), - exts: vec![NewSessionTicketExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(12345), - payload: Payload(vec![1, 2, 3]), - })], - } -} - -fn get_sample_encryptedextensions() -> EncryptedExtensions { - get_sample_serverhellopayload().extensions -} - -fn get_sample_certificatestatus() -> CertificateStatus { - CertificateStatus { - ocsp_response: PayloadU24(vec![1, 2, 3]), - } -} - -fn get_all_tls12_handshake_payloads() -> Vec { - vec![ - HandshakeMessagePayload { - typ: HandshakeType::HelloRequest, - payload: HandshakePayload::HelloRequest, - }, - HandshakeMessagePayload { - typ: HandshakeType::ClientHello, - payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerHello, - payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::HelloRetryRequest, - payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), - }, - HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::Certificate(vec![Certificate(vec![1, 2, 3])]), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerKeyExchange, - payload: HandshakePayload::ServerKeyExchange( - get_sample_serverkeyexchangepayload_ecdhe(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerKeyExchange, - payload: HandshakePayload::ServerKeyExchange( - get_sample_serverkeyexchangepayload_unknown(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::CertificateRequest, - payload: HandshakePayload::CertificateRequest(get_sample_certificaterequestpayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerHelloDone, - payload: HandshakePayload::ServerHelloDone, - }, - HandshakeMessagePayload { - typ: HandshakeType::ClientKeyExchange, - payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), - }, - HandshakeMessagePayload { - typ: HandshakeType::NewSessionTicket, - payload: HandshakePayload::NewSessionTicket(get_sample_newsessionticketpayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::EncryptedExtensions, - payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), - }, - HandshakeMessagePayload { - typ: HandshakeType::KeyUpdate, - payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), - }, - HandshakeMessagePayload { - typ: HandshakeType::KeyUpdate, - payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), - }, - HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), - }, - HandshakeMessagePayload { - typ: HandshakeType::CertificateStatus, - payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), - }, - HandshakeMessagePayload { - typ: HandshakeType::Unknown(99), - payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), - }, - ] -} - -#[test] -fn can_roundtrip_all_tls12_handshake_payloads() { - for ref hm in get_all_tls12_handshake_payloads().iter() { - println!("{:?}", hm.typ); - let bytes = hm.get_encoding(); - let mut rd = Reader::init(&bytes); - let other = HandshakeMessagePayload::read(&mut rd).unwrap(); - assert!(!rd.any_left()); - assert_eq!(hm.get_encoding(), other.get_encoding()); - - println!("{:?}", hm); - println!("{:?}", other); - } -} - -#[test] -fn can_detect_truncation_of_all_tls12_handshake_payloads() { - for hm in get_all_tls12_handshake_payloads().iter() { - let mut enc = hm.get_encoding(); - println!("test {:?} enc {:?}", hm, enc); - - // outer truncation - for l in 0..enc.len() { - assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_none()) - } - - // inner truncation - for l in 0..enc.len() - 4 { - put_u24(l as u32, &mut enc[1..]); - println!(" check len {:?} enc {:?}", l, enc); - - match (hm.typ, l) { - (HandshakeType::ClientHello, 41) - | (HandshakeType::ServerHello, 38) - | (HandshakeType::ServerKeyExchange, _) - | (HandshakeType::ClientKeyExchange, _) - | (HandshakeType::Finished, _) - | (HandshakeType::Unknown(_), _) => continue, - _ => {} - }; - - assert!(HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_2 - ) - .is_none()); - assert!(HandshakeMessagePayload::read_bytes(&enc).is_none()); - } - } -} - -fn get_all_tls13_handshake_payloads() -> Vec { - vec![ - HandshakeMessagePayload { - typ: HandshakeType::HelloRequest, - payload: HandshakePayload::HelloRequest, - }, - HandshakeMessagePayload { - typ: HandshakeType::ClientHello, - payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerHello, - payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), - }, - HandshakeMessagePayload { - typ: HandshakeType::HelloRetryRequest, - payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), - }, - HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::CertificateTLS13(get_sample_certificatepayloadtls13()), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerKeyExchange, - payload: HandshakePayload::ServerKeyExchange( - get_sample_serverkeyexchangepayload_ecdhe(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerKeyExchange, - payload: HandshakePayload::ServerKeyExchange( - get_sample_serverkeyexchangepayload_unknown(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::CertificateRequest, - payload: HandshakePayload::CertificateRequestTLS13( - get_sample_certificaterequestpayloadtls13(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::CertificateVerify, - payload: HandshakePayload::CertificateVerify(DigitallySignedStruct::new( - SignatureScheme::ECDSA_NISTP256_SHA256, - vec![1, 2, 3], - )), - }, - HandshakeMessagePayload { - typ: HandshakeType::ServerHelloDone, - payload: HandshakePayload::ServerHelloDone, - }, - HandshakeMessagePayload { - typ: HandshakeType::ClientKeyExchange, - payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), - }, - HandshakeMessagePayload { - typ: HandshakeType::NewSessionTicket, - payload: HandshakePayload::NewSessionTicketTLS13( - get_sample_newsessionticketpayloadtls13(), - ), - }, - HandshakeMessagePayload { - typ: HandshakeType::EncryptedExtensions, - payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), - }, - HandshakeMessagePayload { - typ: HandshakeType::KeyUpdate, - payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), - }, - HandshakeMessagePayload { - typ: HandshakeType::KeyUpdate, - payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), - }, - HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), - }, - HandshakeMessagePayload { - typ: HandshakeType::CertificateStatus, - payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), - }, - HandshakeMessagePayload { - typ: HandshakeType::Unknown(99), - payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), - }, - ] -} - -#[test] -fn can_roundtrip_all_tls13_handshake_payloads() { - for ref hm in get_all_tls13_handshake_payloads().iter() { - println!("{:?}", hm.typ); - let bytes = hm.get_encoding(); - let mut rd = Reader::init(&bytes); - - let other = - HandshakeMessagePayload::read_version(&mut rd, ProtocolVersion::TLSv1_3).unwrap(); - assert!(!rd.any_left()); - assert_eq!(hm.get_encoding(), other.get_encoding()); - - println!("{:?}", hm); - println!("{:?}", other); - } -} - -fn put_u24(u: u32, b: &mut [u8]) { - b[0] = (u >> 16) as u8; - b[1] = (u >> 8) as u8; - b[2] = u as u8; -} - -#[test] -fn can_detect_truncation_of_all_tls13_handshake_payloads() { - for hm in get_all_tls13_handshake_payloads().iter() { - let mut enc = hm.get_encoding(); - println!("test {:?} enc {:?}", hm, enc); - - // outer truncation - for l in 0..enc.len() { - assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_none()) - } - - // inner truncation - for l in 0..enc.len() - 4 { - put_u24(l as u32, &mut enc[1..]); - println!(" check len {:?} enc {:?}", l, enc); - - match (hm.typ, l) { - (HandshakeType::ClientHello, 41) - | (HandshakeType::ServerHello, 38) - | (HandshakeType::ServerKeyExchange, _) - | (HandshakeType::ClientKeyExchange, _) - | (HandshakeType::Finished, _) - | (HandshakeType::Unknown(_), _) => continue, - _ => {} - }; - - assert!(HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_3 - ) - .is_none()); - } - } -} - -#[test] -fn cannot_read_messagehash_from_network() { - let mh = HandshakeMessagePayload { - typ: HandshakeType::MessageHash, - payload: HandshakePayload::MessageHash(Payload::new(vec![1, 2, 3])), - }; - println!("mh {:?}", mh); - let enc = mh.get_encoding(); - assert!(HandshakeMessagePayload::read_bytes(&enc).is_none()); -} - -#[test] -fn cannot_decode_huge_certificate() { - let mut buf = [0u8; 65 * 1024]; - // exactly 64KB decodes fine - buf[0] = 0x0b; - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = 0x03; - buf[4] = 0x01; - buf[5] = 0x00; - buf[6] = 0x00; - buf[7] = 0x00; - buf[8] = 0xff; - buf[9] = 0xfd; - HandshakeMessagePayload::read_bytes(&buf).unwrap(); - - // however 64KB + 1 byte does not - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = 0x04; - buf[4] = 0x01; - buf[5] = 0x00; - buf[6] = 0x01; - assert!(HandshakeMessagePayload::read_bytes(&buf).is_none()); -} - -#[test] -fn can_decode_server_hello_from_api_devicecheck_apple_com() { - let data = include_bytes!("hello-api.devicecheck.apple.com.bin"); - let mut r = Reader::init(data); - let hm = HandshakeMessagePayload::read(&mut r).unwrap(); - println!("msg: {:?}", hm); -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/hello-api.devicecheck.apple.com.bin b/third_party/rustls-fork-shadow-tls/src/msgs/hello-api.devicecheck.apple.com.bin deleted file mode 100644 index fcbaaad..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/msgs/hello-api.devicecheck.apple.com.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/hsjoiner.rs b/third_party/rustls-fork-shadow-tls/src/msgs/hsjoiner.rs deleted file mode 100644 index 909f6a1..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/hsjoiner.rs +++ /dev/null @@ -1,281 +0,0 @@ -use std::collections::VecDeque; - -use crate::enums::ProtocolVersion; -use crate::msgs::base::Payload; -use crate::msgs::codec; -use crate::msgs::enums::ContentType; -use crate::msgs::handshake::HandshakeMessagePayload; -use crate::msgs::message::{Message, MessagePayload, PlainMessage}; - -const HEADER_SIZE: usize = 1 + 3; - -/// TLS allows for handshake messages of up to 16MB. We -/// restrict that to 64KB to limit potential for denial-of- -/// service. -const MAX_HANDSHAKE_SIZE: u32 = 0xffff; - -/// This works to reconstruct TLS handshake messages -/// from individual TLS messages. It's guaranteed that -/// TLS messages output from this layer contain precisely -/// one handshake payload. -pub struct HandshakeJoiner { - /// The message payload(s) we're currently accumulating. - buf: Vec, - - /// Sizes of messages currently in the buffer. - /// - /// The buffer can be larger than the sum of the sizes in this queue, because it might contain - /// the start of a message that hasn't fully been received yet as its suffix. - sizes: VecDeque, - - /// Version of the protocol we're currently parsing. - version: ProtocolVersion, -} - -impl HandshakeJoiner { - /// Make a new HandshakeJoiner. - pub fn new() -> Self { - Self { - buf: Vec::new(), - sizes: VecDeque::new(), - version: ProtocolVersion::TLSv1_2, - } - } - - /// Take the message, and join/split it as needed. - /// - /// Returns `Err(JoinerError::Unwanted(msg))` if `msg`'s type is not `ContentType::Handshake` or - /// `JoinerError::Decode` if a received payload has an advertised size larger than we accept. - /// - /// Otherwise, yields a `bool` to indicate whether the handshake is "aligned": if the buffer currently - /// only contains complete payloads (that is, no incomplete message in the suffix). - pub fn push(&mut self, msg: PlainMessage) -> Result { - if msg.typ != ContentType::Handshake { - return Err(JoinerError::Unwanted(msg)); - } - - // The vast majority of the time `self.buf` will be empty since most - // handshake messages arrive in a single fragment. Avoid allocating and - // copying in that common case. - if self.buf.is_empty() { - self.buf = msg.payload.0; - } else { - self.buf - .extend_from_slice(&msg.payload.0[..]); - } - - if msg.version == ProtocolVersion::TLSv1_3 { - self.version = msg.version; - } - - // Check the suffix of the buffer that hasn't been covered by `sizes` so far - // for complete messages. If we find any, update `self.sizes` and `complete`. - let mut complete = self.sizes.iter().copied().sum(); - while let Some(size) = payload_size(&self.buf[complete..])? { - self.sizes.push_back(size); - complete += size; - } - - // Use the value of `complete` to determine if the buffer currently contains any - // incomplete messages. If not, an incoming message is said to be "aligned". - Ok(complete == self.buf.len()) - } - - /// Parse the first received message out of the buffer. - /// - /// Returns `Ok(None)` if we don't have a complete message in the buffer, or `Err` if we - /// fail to parse the first message in the buffer. - pub fn pop(&mut self) -> Result, JoinerError> { - let len = match self.sizes.pop_front() { - Some(len) => len, - None => return Ok(None), - }; - - // Parse the first part of the buffer as a handshake buffer. - // If we get `None` back, we've failed to parse the message. - // If we succeed, drain the relevant bytes from the buffer. - - let buf = &self.buf[..len]; - let mut rd = codec::Reader::init(buf); - let parsed = match HandshakeMessagePayload::read_version(&mut rd, self.version) { - Some(p) => p, - None => return Err(JoinerError::Decode), - }; - - let message = Message { - version: self.version, - payload: MessagePayload::Handshake { - parsed, - encoded: Payload::new(buf), - }, - }; - - self.buf.drain(..len); - Ok(Some(message)) - } -} - -/// Does `buf` contain a full handshake payload? -/// -/// Returns `Ok(Some(_))` with the length of the payload (including header) if it does, -/// `Ok(None)` if the buffer is too small to contain a message with the length advertised in the -/// header, or `Err` if the advertised length is larger than what we want to accept -/// (`MAX_HANDSHAKE_SIZE`). -fn payload_size(buf: &[u8]) -> Result, JoinerError> { - if buf.len() < HEADER_SIZE { - return Ok(None); - } - - let (header, rest) = buf.split_at(HEADER_SIZE); - match codec::u24::decode(&header[1..]) { - Some(len) if len.0 > MAX_HANDSHAKE_SIZE => Err(JoinerError::Decode), - Some(len) if rest.get(..len.into()).is_some() => Ok(Some(HEADER_SIZE + usize::from(len))), - _ => Ok(None), - } -} - -#[derive(Debug)] -pub enum JoinerError { - Unwanted(PlainMessage), - Decode, -} - -#[cfg(test)] -mod tests { - use super::HandshakeJoiner; - use crate::enums::ProtocolVersion; - use crate::msgs::base::Payload; - use crate::msgs::codec::Codec; - use crate::msgs::enums::{ContentType, HandshakeType}; - use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; - use crate::msgs::message::{Message, MessagePayload, PlainMessage}; - - #[test] - fn want() { - let mut hj = HandshakeJoiner::new(); - let wanted = PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x00\x00\x00\x00".to_vec()), - }; - - let unwanted = PlainMessage { - typ: ContentType::Alert, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"ponytown".to_vec()), - }; - - hj.push(wanted).unwrap(); - hj.push(unwanted).unwrap_err(); - } - - fn pop_eq(expect: &PlainMessage, hj: &mut HandshakeJoiner) { - let got = hj.pop().unwrap().unwrap(); - assert_eq!(got.payload.content_type(), expect.typ); - assert_eq!(got.version, expect.version); - - let (mut left, mut right) = (Vec::new(), Vec::new()); - got.payload.encode(&mut left); - expect.payload.encode(&mut right); - - assert_eq!(left, right); - } - - #[test] - fn split() { - // Check we split two handshake messages within one PDU. - let mut hj = HandshakeJoiner::new(); - - // two HelloRequests - assert!(hj - .push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()), - }) - .unwrap()); - - let expect = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::HelloRequest, - payload: HandshakePayload::HelloRequest, - }), - } - .into(); - - pop_eq(&expect, &mut hj); - pop_eq(&expect, &mut hj); - } - - #[test] - fn broken() { - // Check obvious crap payloads are reported as errors, not panics. - let mut hj = HandshakeJoiner::new(); - - // short ClientHello - hj.push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x01\x00\x00\x02\xff\xff".to_vec()), - }) - .unwrap(); - - hj.pop().unwrap_err(); - } - - #[test] - fn join() { - // Check we join one handshake message split over two PDUs. - let mut hj = HandshakeJoiner::new(); - - // Introduce Finished of 16 bytes, providing 4. - hj.push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x14\x00\x00\x10\x00\x01\x02\x03\x04".to_vec()), - }) - .unwrap(); - - // 11 more bytes. - assert!(!hj - .push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e".to_vec()), - }) - .unwrap()); - - // Final 1 byte. - assert!(hj - .push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x0f".to_vec()), - }) - .unwrap()); - - let payload = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f".to_vec(); - let expect = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(Payload::new(payload)), - }), - } - .into(); - - pop_eq(&expect, &mut hj); - } - - #[test] - fn test_rejects_giant_certs() { - let mut hj = HandshakeJoiner::new(); - hj.push(PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x0b\x01\x00\x04\x01\x00\x01\x00\xff\xfe".to_vec()), - }) - .unwrap_err(); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/macros.rs b/third_party/rustls-fork-shadow-tls/src/msgs/macros.rs deleted file mode 100644 index da9ff6a..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/macros.rs +++ /dev/null @@ -1,88 +0,0 @@ -/// A macro which defines an enum type. -macro_rules! enum_builder { - ( - $(#[$comment:meta])* - @U8 - EnumName: $enum_name: ident; - EnumVal { $( $enum_var: ident => $enum_val: expr ),* } - ) => { - $(#[$comment])* - #[derive(Debug, PartialEq, Eq, Clone, Copy)] - pub enum $enum_name { - $( $enum_var),* - ,Unknown(u8) - } - impl $enum_name { - pub fn get_u8(&self) -> u8 { - let x = self.clone(); - match x { - $( $enum_name::$enum_var => $enum_val),* - ,$enum_name::Unknown(x) => x - } - } - } - impl Codec for $enum_name { - fn encode(&self, bytes: &mut Vec) { - self.get_u8().encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - u8::read(r).map($enum_name::from) - } - } - impl From for $enum_name { - fn from(x: u8) -> Self { - match x { - $($enum_val => $enum_name::$enum_var),* - , x => $enum_name::Unknown(x), - } - } - } - }; - ( - $(#[$comment:meta])* - @U16 - EnumName: $enum_name: ident; - EnumVal { $( $enum_var: ident => $enum_val: expr ),* } - ) => { - $(#[$comment])* - #[derive(Debug, PartialEq, Eq, Clone, Copy)] - pub enum $enum_name { - $( $enum_var),* - ,Unknown(u16) - } - impl $enum_name { - pub fn get_u16(&self) -> u16 { - let x = self.clone(); - match x { - $( $enum_name::$enum_var => $enum_val),* - ,$enum_name::Unknown(x) => x - } - } - - pub fn as_str(&self) -> Option<&'static str> { - match self { - $( $enum_name::$enum_var => Some(stringify!($enum_var))),* - ,$enum_name::Unknown(_) => None, - } - } - } - impl Codec for $enum_name { - fn encode(&self, bytes: &mut Vec) { - self.get_u16().encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - u16::read(r).map($enum_name::from) - } - } - impl From for $enum_name { - fn from(x: u16) -> Self { - match x { - $($enum_val => $enum_name::$enum_var),* - , x => $enum_name::Unknown(x), - } - } - } - }; -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/message.rs b/third_party/rustls-fork-shadow-tls/src/msgs/message.rs deleted file mode 100644 index a8b8308..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/message.rs +++ /dev/null @@ -1,292 +0,0 @@ -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::msgs::alert::AlertMessagePayload; -use crate::msgs::base::Payload; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{AlertDescription, AlertLevel, ContentType, HandshakeType}; -use crate::msgs::handshake::HandshakeMessagePayload; - -use std::convert::TryFrom; - -#[derive(Debug)] -pub enum MessagePayload { - Alert(AlertMessagePayload), - Handshake { - parsed: HandshakeMessagePayload, - encoded: Payload, - }, - ChangeCipherSpec(ChangeCipherSpecPayload), - ApplicationData(Payload), -} - -impl MessagePayload { - pub fn encode(&self, bytes: &mut Vec) { - match self { - Self::Alert(x) => x.encode(bytes), - Self::Handshake { encoded, .. } => bytes.extend(&encoded.0), - Self::ChangeCipherSpec(x) => x.encode(bytes), - Self::ApplicationData(x) => x.encode(bytes), - } - } - - pub fn handshake(parsed: HandshakeMessagePayload) -> Self { - Self::Handshake { - encoded: Payload::new(parsed.get_encoding()), - parsed, - } - } - - pub fn new(typ: ContentType, vers: ProtocolVersion, payload: Payload) -> Result { - let mut r = Reader::init(&payload.0); - let parsed = match typ { - ContentType::ApplicationData => return Ok(Self::ApplicationData(payload)), - ContentType::Alert => AlertMessagePayload::read(&mut r) - .filter(|_| !r.any_left()) - .map(MessagePayload::Alert), - ContentType::Handshake => HandshakeMessagePayload::read_version(&mut r, vers) - .filter(|_| !r.any_left()) - .map(|parsed| Self::Handshake { - parsed, - encoded: payload, - }), - ContentType::ChangeCipherSpec => ChangeCipherSpecPayload::read(&mut r) - .filter(|_| !r.any_left()) - .map(MessagePayload::ChangeCipherSpec), - _ => None, - }; - - parsed.ok_or(Error::CorruptMessagePayload(typ)) - } - - pub fn content_type(&self) -> ContentType { - match self { - Self::Alert(_) => ContentType::Alert, - Self::Handshake { .. } => ContentType::Handshake, - Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, - Self::ApplicationData(_) => ContentType::ApplicationData, - } - } -} - -/// A TLS frame, named TLSPlaintext in the standard. -/// -/// This type owns all memory for its interior parts. It is used to read/write from/to I/O -/// buffers as well as for fragmenting, joining and encryption/decryption. It can be converted -/// into a `Message` by decoding the payload. -#[derive(Clone, Debug)] -pub struct OpaqueMessage { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: Payload, -} - -impl OpaqueMessage { - /// `MessageError` allows callers to distinguish between valid prefixes (might - /// become valid if we read more data) and invalid data. - pub fn read(r: &mut Reader) -> Result { - let typ = ContentType::read(r).ok_or(MessageError::TooShortForHeader)?; - let version = ProtocolVersion::read(r).ok_or(MessageError::TooShortForHeader)?; - let len = u16::read(r).ok_or(MessageError::TooShortForHeader)?; - - // Reject undersize messages - // implemented per section 5.1 of RFC8446 (TLSv1.3) - // per section 6.2.1 of RFC5246 (TLSv1.2) - if typ != ContentType::ApplicationData && len == 0 { - return Err(MessageError::IllegalLength); - } - - // Reject oversize messages - if len >= Self::MAX_PAYLOAD { - return Err(MessageError::IllegalLength); - } - - // Don't accept any new content-types. - if let ContentType::Unknown(_) = typ { - return Err(MessageError::IllegalContentType); - } - - // Accept only versions 0x03XX for any XX. - match version { - ProtocolVersion::Unknown(ref v) if (v & 0xff00) != 0x0300 => { - return Err(MessageError::IllegalProtocolVersion); - } - _ => {} - }; - - let mut sub = r - .sub(len as usize) - .ok_or(MessageError::TooShortForLength)?; - let payload = Payload::read(&mut sub); - - Ok(Self { - typ, - version, - payload, - }) - } - - pub fn encode(self) -> Vec { - let mut buf = Vec::new(); - self.typ.encode(&mut buf); - self.version.encode(&mut buf); - (self.payload.0.len() as u16).encode(&mut buf); - self.payload.encode(&mut buf); - buf - } - - /// Force conversion into a plaintext message. - /// - /// This should only be used for messages that are known to be in plaintext. Otherwise, the - /// `OpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. - pub fn into_plain_message(self) -> PlainMessage { - PlainMessage { - version: self.version, - typ: self.typ, - payload: self.payload, - } - } - - /// This is the maximum on-the-wire size of a TLSCiphertext. - /// That's 2^14 payload bytes, a header, and a 2KB allowance - /// for ciphertext overheads. - const MAX_PAYLOAD: u16 = 16384 + 2048; - - /// Content type, version and size. - const HEADER_SIZE: u16 = 1 + 2 + 2; - - /// Maximum on-wire message size. - pub const MAX_WIRE_SIZE: usize = (Self::MAX_PAYLOAD + Self::HEADER_SIZE) as usize; -} - -impl From for PlainMessage { - fn from(msg: Message) -> Self { - let typ = msg.payload.content_type(); - let payload = match msg.payload { - MessagePayload::ApplicationData(payload) => payload, - _ => { - let mut buf = Vec::new(); - msg.payload.encode(&mut buf); - Payload(buf) - } - }; - - Self { - typ, - version: msg.version, - payload, - } - } -} - -/// A decrypted TLS frame -/// -/// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage -/// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting. -#[derive(Clone, Debug)] -pub struct PlainMessage { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: Payload, -} - -impl PlainMessage { - pub fn into_unencrypted_opaque(self) -> OpaqueMessage { - OpaqueMessage { - version: self.version, - typ: self.typ, - payload: self.payload, - } - } - - pub fn borrow(&self) -> BorrowedPlainMessage<'_> { - BorrowedPlainMessage { - version: self.version, - typ: self.typ, - payload: &self.payload.0, - } - } -} - -/// A message with decoded payload -#[derive(Debug)] -pub struct Message { - pub version: ProtocolVersion, - pub payload: MessagePayload, -} - -impl Message { - pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool { - // Bit of a layering violation, but OK. - if let MessagePayload::Handshake { parsed, .. } = &self.payload { - parsed.typ == hstyp - } else { - false - } - } - - pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self { - Self { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::Alert(AlertMessagePayload { - level, - description: desc, - }), - } - } - - pub fn build_key_update_notify() -> Self { - Self { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload::build_key_update_notify()), - } - } -} - -/// Parses a plaintext message into a well-typed [`Message`]. -/// -/// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an -/// [`OpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. -impl TryFrom for Message { - type Error = Error; - - fn try_from(plain: PlainMessage) -> Result { - Ok(Self { - version: plain.version, - payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, - }) - } -} - -/// A TLS frame, named TLSPlaintext in the standard. -/// -/// This type differs from `OpaqueMessage` because it borrows -/// its payload. You can make a `OpaqueMessage` from an -/// `BorrowMessage`, but this involves a copy. -/// -/// This type also cannot decode its internals and -/// cannot be read/encoded; only `OpaqueMessage` can do that. -pub struct BorrowedPlainMessage<'a> { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: &'a [u8], -} - -impl<'a> BorrowedPlainMessage<'a> { - pub fn to_unencrypted_opaque(&self) -> OpaqueMessage { - OpaqueMessage { - version: self.version, - typ: self.typ, - payload: Payload(self.payload.to_vec()), - } - } -} - -#[derive(Debug)] -pub enum MessageError { - TooShortForHeader, - TooShortForLength, - IllegalLength, - IllegalContentType, - IllegalProtocolVersion, -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/message_test.rs b/third_party/rustls-fork-shadow-tls/src/msgs/message_test.rs deleted file mode 100644 index a50df90..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/message_test.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::msgs::base::{PayloadU16, PayloadU24, PayloadU8}; - -use super::base::Payload; -use super::codec::Reader; -use super::enums::{AlertDescription, AlertLevel, HandshakeType}; -use super::message::{Message, OpaqueMessage, PlainMessage}; - -use std::convert::TryFrom; -use std::fs; -use std::io::Read; -use std::path::{Path, PathBuf}; - -#[test] -fn test_read_fuzz_corpus() { - fn corpus_dir() -> PathBuf { - let from_subcrate = Path::new("../fuzz/corpus/message"); - let from_root = Path::new("fuzz/corpus/message"); - - if from_root.is_dir() { - from_root.to_path_buf() - } else { - from_subcrate.to_path_buf() - } - } - - for file in fs::read_dir(corpus_dir()).unwrap() { - let mut f = fs::File::open(file.unwrap().path()).unwrap(); - let mut bytes = Vec::new(); - f.read_to_end(&mut bytes).unwrap(); - - let mut rd = Reader::init(&bytes); - let msg = OpaqueMessage::read(&mut rd) - .unwrap() - .into_plain_message(); - println!("{:?}", msg); - - let msg = match Message::try_from(msg) { - Ok(msg) => msg, - Err(_) => continue, - }; - - let enc = PlainMessage::from(msg) - .into_unencrypted_opaque() - .encode(); - assert_eq!(bytes.to_vec(), enc); - assert_eq!(bytes[..rd.used()].to_vec(), enc); - } -} - -#[test] -fn can_read_safari_client_hello() { - let _ = env_logger::Builder::new() - .filter(None, log::LevelFilter::Trace) - .try_init(); - - let bytes = b"\ - \x16\x03\x01\x00\xeb\x01\x00\x00\xe7\x03\x03\xb6\x1f\xe4\x3a\x55\ - \x90\x3e\xc0\x28\x9c\x12\xe0\x5c\x84\xea\x90\x1b\xfb\x11\xfc\xbd\ - \x25\x55\xda\x9f\x51\x93\x1b\x8d\x92\x66\xfd\x00\x00\x2e\xc0\x2c\ - \xc0\x2b\xc0\x24\xc0\x23\xc0\x0a\xc0\x09\xcc\xa9\xc0\x30\xc0\x2f\ - \xc0\x28\xc0\x27\xc0\x14\xc0\x13\xcc\xa8\x00\x9d\x00\x9c\x00\x3d\ - \x00\x3c\x00\x35\x00\x2f\xc0\x08\xc0\x12\x00\x0a\x01\x00\x00\x90\ - \xff\x01\x00\x01\x00\x00\x00\x00\x0e\x00\x0c\x00\x00\x09\x31\x32\ - \x37\x2e\x30\x2e\x30\x2e\x31\x00\x17\x00\x00\x00\x0d\x00\x18\x00\ - \x16\x04\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05\x05\ - \x01\x08\x06\x06\x01\x02\x01\x00\x05\x00\x05\x01\x00\x00\x00\x00\ - \x33\x74\x00\x00\x00\x12\x00\x00\x00\x10\x00\x30\x00\x2e\x02\x68\ - \x32\x05\x68\x32\x2d\x31\x36\x05\x68\x32\x2d\x31\x35\x05\x68\x32\ - \x2d\x31\x34\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x06\x73\x70\x64\ - \x79\x2f\x33\x08\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x0b\x00\x02\ - \x01\x00\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x18\x00\x19"; - let mut rd = Reader::init(bytes); - let m = OpaqueMessage::read(&mut rd).unwrap(); - println!("m = {:?}", m); - assert!(Message::try_from(m.into_plain_message()).is_err()); -} - -#[test] -fn alert_is_not_handshake() { - let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); - assert!(!m.is_handshake_type(HandshakeType::ClientHello)); -} - -#[test] -fn alert_is_not_opaque() { - let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); - assert!(Message::try_from(m).is_ok()); -} - -#[test] -fn construct_all_types() { - let samples = [ - &b"\x14\x03\x04\x00\x01\x01"[..], - &b"\x15\x03\x04\x00\x02\x01\x16"[..], - &b"\x16\x03\x04\x00\x05\x18\x00\x00\x01\x00"[..], - &b"\x17\x03\x04\x00\x04\x11\x22\x33\x44"[..], - &b"\x18\x03\x04\x00\x04\x11\x22\x33\x44"[..], - ]; - for &bytes in samples.iter() { - let m = OpaqueMessage::read(&mut Reader::init(bytes)).unwrap(); - println!("m = {:?}", m); - let m = Message::try_from(m.into_plain_message()); - println!("m' = {:?}", m); - } -} - -#[test] -fn debug_payload() { - assert_eq!("01020304", format!("{:?}", Payload(vec![1, 2, 3, 4]))); - assert_eq!("01020304", format!("{:?}", PayloadU8(vec![1, 2, 3, 4]))); - assert_eq!("01020304", format!("{:?}", PayloadU16(vec![1, 2, 3, 4]))); - assert_eq!("01020304", format!("{:?}", PayloadU24(vec![1, 2, 3, 4]))); -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/mod.rs b/third_party/rustls-fork-shadow-tls/src/msgs/mod.rs deleted file mode 100644 index 655ff13..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/mod.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![allow(clippy::upper_case_acronyms)] -#![allow(missing_docs)] - -#[macro_use] -mod macros; - -pub mod alert; -pub mod base; -pub mod ccs; -pub mod codec; -pub mod deframer; -pub mod enums; -pub mod fragmenter; -pub mod handshake; -pub mod hsjoiner; -pub mod message; -pub mod persist; - -#[cfg(test)] -mod handshake_test; - -#[cfg(test)] -mod persist_test; - -#[cfg(test)] -pub(crate) mod enums_test; - -#[cfg(test)] -mod message_test; - -#[cfg(test)] -mod test { - use std::convert::TryFrom; - - #[test] - fn smoketest() { - use super::codec::Reader; - use super::message::{Message, OpaqueMessage}; - let bytes = include_bytes!("handshake-test.1.bin"); - let mut r = Reader::init(bytes); - - while r.any_left() { - let m = OpaqueMessage::read(&mut r).unwrap(); - - let out = m.clone().encode(); - assert!(!out.is_empty()); - - Message::try_from(m.into_plain_message()).unwrap(); - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/persist.rs b/third_party/rustls-fork-shadow-tls/src/msgs/persist.rs deleted file mode 100644 index e9bcbda..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/persist.rs +++ /dev/null @@ -1,543 +0,0 @@ -use crate::client::ServerName; -use crate::enums::{CipherSuite, ProtocolVersion}; -use crate::key; -use crate::msgs::base::{PayloadU16, PayloadU8}; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::handshake::CertificatePayload; -use crate::msgs::handshake::SessionID; -use crate::suites::SupportedCipherSuite; -use crate::ticketer::TimeBase; -#[cfg(feature = "tls12")] -use crate::tls12::Tls12CipherSuite; -use crate::tls13::Tls13CipherSuite; - -use std::cmp; -#[cfg(feature = "tls12")] -use std::mem; - -// These are the keys and values we store in session storage. - -// --- Client types --- -/// Keys for session resumption and tickets. -/// Matching value is a `ClientSessionValue`. -#[derive(Debug)] -pub struct ClientSessionKey { - kind: &'static [u8], - name: Vec, -} - -impl Codec for ClientSessionKey { - fn encode(&self, bytes: &mut Vec) { - bytes.extend_from_slice(self.kind); - bytes.extend_from_slice(&self.name); - } - - // Don't need to read these. - fn read(_r: &mut Reader) -> Option { - None - } -} - -impl ClientSessionKey { - pub fn session_for_server_name(server_name: &ServerName) -> Self { - Self { - kind: b"session", - name: server_name.encode(), - } - } - - pub fn hint_for_server_name(server_name: &ServerName) -> Self { - Self { - kind: b"kx-hint", - name: server_name.encode(), - } - } -} - -#[derive(Debug)] -pub enum ClientSessionValue { - Tls13(Tls13ClientSessionValue), - #[cfg(feature = "tls12")] - Tls12(Tls12ClientSessionValue), -} - -impl ClientSessionValue { - pub fn read( - reader: &mut Reader<'_>, - suite: CipherSuite, - supported: &[SupportedCipherSuite], - ) -> Option { - match supported - .iter() - .find(|s| s.suite() == suite)? - { - SupportedCipherSuite::Tls13(inner) => { - Tls13ClientSessionValue::read(inner, reader).map(ClientSessionValue::Tls13) - } - #[cfg(feature = "tls12")] - SupportedCipherSuite::Tls12(inner) => { - Tls12ClientSessionValue::read(inner, reader).map(ClientSessionValue::Tls12) - } - } - } - - fn common(&self) -> &ClientSessionCommon { - match self { - Self::Tls13(inner) => &inner.common, - #[cfg(feature = "tls12")] - Self::Tls12(inner) => &inner.common, - } - } -} - -impl From for ClientSessionValue { - fn from(v: Tls13ClientSessionValue) -> Self { - Self::Tls13(v) - } -} - -#[cfg(feature = "tls12")] -impl From for ClientSessionValue { - fn from(v: Tls12ClientSessionValue) -> Self { - Self::Tls12(v) - } -} - -pub struct Retrieved { - pub value: T, - retrieved_at: TimeBase, -} - -impl Retrieved { - pub fn new(value: T, retrieved_at: TimeBase) -> Self { - Self { - value, - retrieved_at, - } - } -} - -impl Retrieved<&Tls13ClientSessionValue> { - pub fn obfuscated_ticket_age(&self) -> u32 { - let age_secs = self - .retrieved_at - .as_secs() - .saturating_sub(self.value.common.epoch); - let age_millis = age_secs as u32 * 1000; - age_millis.wrapping_add(self.value.age_add) - } -} - -impl Retrieved { - pub fn tls13(&self) -> Option> { - match &self.value { - ClientSessionValue::Tls13(value) => Some(Retrieved::new(value, self.retrieved_at)), - #[cfg(feature = "tls12")] - ClientSessionValue::Tls12(_) => None, - } - } - - pub fn has_expired(&self) -> bool { - let common = self.value.common(); - common.lifetime_secs != 0 - && common - .epoch - .saturating_add(u64::from(common.lifetime_secs)) - < self.retrieved_at.as_secs() - } -} - -impl std::ops::Deref for Retrieved { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -#[derive(Debug)] -pub struct Tls13ClientSessionValue { - suite: &'static Tls13CipherSuite, - age_add: u32, - max_early_data_size: u32, - pub common: ClientSessionCommon, -} - -impl Tls13ClientSessionValue { - pub fn new( - suite: &'static Tls13CipherSuite, - ticket: Vec, - secret: Vec, - server_cert_chain: Vec, - time_now: TimeBase, - lifetime_secs: u32, - age_add: u32, - max_early_data_size: u32, - ) -> Self { - Self { - suite, - age_add, - max_early_data_size, - common: ClientSessionCommon::new( - ticket, - secret, - time_now, - lifetime_secs, - server_cert_chain, - ), - } - } - - /// [`Codec::read()`] with an extra `suite` argument. - /// - /// We decode the `suite` argument separately because it allows us to - /// decide whether we're decoding an 1.2 or 1.3 session value. - pub fn read(suite: &'static Tls13CipherSuite, r: &mut Reader) -> Option { - Some(Self { - suite, - age_add: u32::read(r)?, - max_early_data_size: u32::read(r)?, - common: ClientSessionCommon::read(r)?, - }) - } - - /// Inherent implementation of the [`Codec::get_encoding()`] method. - /// - /// (See `read()` for why this is inherent here.) - pub fn get_encoding(&self) -> Vec { - let mut bytes = Vec::with_capacity(16); - self.suite - .common - .suite - .encode(&mut bytes); - self.age_add.encode(&mut bytes); - self.max_early_data_size - .encode(&mut bytes); - self.common.encode(&mut bytes); - bytes - } - - pub fn max_early_data_size(&self) -> u32 { - self.max_early_data_size - } - - pub fn suite(&self) -> &'static Tls13CipherSuite { - self.suite - } -} - -impl std::ops::Deref for Tls13ClientSessionValue { - type Target = ClientSessionCommon; - - fn deref(&self) -> &Self::Target { - &self.common - } -} - -#[cfg(feature = "tls12")] -#[derive(Debug)] -pub struct Tls12ClientSessionValue { - suite: &'static Tls12CipherSuite, - pub session_id: SessionID, - extended_ms: bool, - pub common: ClientSessionCommon, -} - -#[cfg(feature = "tls12")] -impl Tls12ClientSessionValue { - pub fn new( - suite: &'static Tls12CipherSuite, - session_id: SessionID, - ticket: Vec, - master_secret: Vec, - server_cert_chain: Vec, - time_now: TimeBase, - lifetime_secs: u32, - extended_ms: bool, - ) -> Self { - Self { - suite, - session_id, - extended_ms, - common: ClientSessionCommon::new( - ticket, - master_secret, - time_now, - lifetime_secs, - server_cert_chain, - ), - } - } - - /// [`Codec::read()`] with an extra `suite` argument. - /// - /// We decode the `suite` argument separately because it allows us to - /// decide whether we're decoding an 1.2 or 1.3 session value. - fn read(suite: &'static Tls12CipherSuite, r: &mut Reader) -> Option { - Some(Self { - suite, - session_id: SessionID::read(r)?, - extended_ms: u8::read(r)? == 1, - common: ClientSessionCommon::read(r)?, - }) - } - - /// Inherent implementation of the [`Codec::get_encoding()`] method. - /// - /// (See `read()` for why this is inherent here.) - pub fn get_encoding(&self) -> Vec { - let mut bytes = Vec::with_capacity(16); - self.suite - .common - .suite - .encode(&mut bytes); - self.session_id.encode(&mut bytes); - (u8::from(self.extended_ms)).encode(&mut bytes); - self.common.encode(&mut bytes); - bytes - } - - pub fn take_ticket(&mut self) -> Vec { - mem::take(&mut self.common.ticket.0) - } - - pub fn extended_ms(&self) -> bool { - self.extended_ms - } - - pub fn suite(&self) -> &'static Tls12CipherSuite { - self.suite - } -} - -#[cfg(feature = "tls12")] -impl std::ops::Deref for Tls12ClientSessionValue { - type Target = ClientSessionCommon; - - fn deref(&self) -> &Self::Target { - &self.common - } -} - -#[derive(Debug)] -pub struct ClientSessionCommon { - ticket: PayloadU16, - secret: PayloadU8, - epoch: u64, - lifetime_secs: u32, - server_cert_chain: CertificatePayload, -} - -impl ClientSessionCommon { - fn new( - ticket: Vec, - secret: Vec, - time_now: TimeBase, - lifetime_secs: u32, - server_cert_chain: Vec, - ) -> Self { - Self { - ticket: PayloadU16(ticket), - secret: PayloadU8(secret), - epoch: time_now.as_secs(), - lifetime_secs: cmp::min(lifetime_secs, MAX_TICKET_LIFETIME), - server_cert_chain, - } - } - - /// [`Codec::read()`] is inherent here to avoid leaking the [`Codec`] - /// implementation through [`Deref`] implementations on - /// [`Tls12ClientSessionValue`] and [`Tls13ClientSessionValue`]. - fn read(r: &mut Reader) -> Option { - Some(Self { - ticket: PayloadU16::read(r)?, - secret: PayloadU8::read(r)?, - epoch: u64::read(r)?, - lifetime_secs: u32::read(r)?, - server_cert_chain: CertificatePayload::read(r)?, - }) - } - - /// [`Codec::encode()`] is inherent here to avoid leaking the [`Codec`] - /// implementation through [`Deref`] implementations on - /// [`Tls12ClientSessionValue`] and [`Tls13ClientSessionValue`]. - fn encode(&self, bytes: &mut Vec) { - self.ticket.encode(bytes); - self.secret.encode(bytes); - self.epoch.encode(bytes); - self.lifetime_secs.encode(bytes); - self.server_cert_chain.encode(bytes); - } - - pub fn server_cert_chain(&self) -> &[key::Certificate] { - self.server_cert_chain.as_ref() - } - - pub fn secret(&self) -> &[u8] { - self.secret.0.as_ref() - } - - pub fn ticket(&self) -> &[u8] { - self.ticket.0.as_ref() - } - - /// Test only: wind back epoch by delta seconds. - pub fn rewind_epoch(&mut self, delta: u32) { - self.epoch -= delta as u64; - } -} - -static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60; - -/// This is the maximum allowed skew between server and client clocks, over -/// the maximum ticket lifetime period. This encompasses TCP retransmission -/// times in case packet loss occurs when the client sends the ClientHello -/// or receives the NewSessionTicket, _and_ actual clock skew over this period. -static MAX_FRESHNESS_SKEW_MS: u32 = 60 * 1000; - -// --- Server types --- -pub type ServerSessionKey = SessionID; - -#[derive(Debug)] -pub struct ServerSessionValue { - pub sni: Option, - pub version: ProtocolVersion, - pub cipher_suite: CipherSuite, - pub master_secret: PayloadU8, - pub extended_ms: bool, - pub client_cert_chain: Option, - pub alpn: Option, - pub application_data: PayloadU16, - pub creation_time_sec: u64, - pub age_obfuscation_offset: u32, - freshness: Option, -} - -impl Codec for ServerSessionValue { - fn encode(&self, bytes: &mut Vec) { - if let Some(ref sni) = self.sni { - 1u8.encode(bytes); - let sni_bytes: &str = sni.as_ref().into(); - PayloadU8::new(Vec::from(sni_bytes)).encode(bytes); - } else { - 0u8.encode(bytes); - } - self.version.encode(bytes); - self.cipher_suite.encode(bytes); - self.master_secret.encode(bytes); - (u8::from(self.extended_ms)).encode(bytes); - if let Some(ref chain) = self.client_cert_chain { - 1u8.encode(bytes); - chain.encode(bytes); - } else { - 0u8.encode(bytes); - } - if let Some(ref alpn) = self.alpn { - 1u8.encode(bytes); - alpn.encode(bytes); - } else { - 0u8.encode(bytes); - } - self.application_data.encode(bytes); - self.creation_time_sec.encode(bytes); - self.age_obfuscation_offset - .encode(bytes); - } - - fn read(r: &mut Reader) -> Option { - let has_sni = u8::read(r)?; - let sni = if has_sni == 1 { - let dns_name = PayloadU8::read(r)?; - let dns_name = webpki::DnsNameRef::try_from_ascii(&dns_name.0).ok()?; - Some(dns_name.into()) - } else { - None - }; - let v = ProtocolVersion::read(r)?; - let cs = CipherSuite::read(r)?; - let ms = PayloadU8::read(r)?; - let ems = u8::read(r)?; - let has_ccert = u8::read(r)? == 1; - let ccert = if has_ccert { - Some(CertificatePayload::read(r)?) - } else { - None - }; - let has_alpn = u8::read(r)? == 1; - let alpn = if has_alpn { - Some(PayloadU8::read(r)?) - } else { - None - }; - let application_data = PayloadU16::read(r)?; - let creation_time_sec = u64::read(r)?; - let age_obfuscation_offset = u32::read(r)?; - - Some(Self { - sni, - version: v, - cipher_suite: cs, - master_secret: ms, - extended_ms: ems == 1u8, - client_cert_chain: ccert, - alpn, - application_data, - creation_time_sec, - age_obfuscation_offset, - freshness: None, - }) - } -} - -impl ServerSessionValue { - pub fn new( - sni: Option<&webpki::DnsName>, - v: ProtocolVersion, - cs: CipherSuite, - ms: Vec, - client_cert_chain: Option, - alpn: Option>, - application_data: Vec, - creation_time: TimeBase, - age_obfuscation_offset: u32, - ) -> Self { - Self { - sni: sni.cloned(), - version: v, - cipher_suite: cs, - master_secret: PayloadU8::new(ms), - extended_ms: false, - client_cert_chain, - alpn: alpn.map(PayloadU8::new), - application_data: PayloadU16::new(application_data), - creation_time_sec: creation_time.as_secs(), - age_obfuscation_offset, - freshness: None, - } - } - - pub fn set_extended_ms_used(&mut self) { - self.extended_ms = true; - } - - pub fn set_freshness(mut self, obfuscated_client_age_ms: u32, time_now: TimeBase) -> Self { - let client_age_ms = obfuscated_client_age_ms.wrapping_sub(self.age_obfuscation_offset); - let server_age_ms = (time_now - .as_secs() - .saturating_sub(self.creation_time_sec) as u32) - .saturating_mul(1000); - - let age_difference = if client_age_ms < server_age_ms { - server_age_ms - client_age_ms - } else { - client_age_ms - server_age_ms - }; - - self.freshness = Some(age_difference <= MAX_FRESHNESS_SKEW_MS); - self - } - - pub fn is_fresh(&self) -> bool { - self.freshness.unwrap_or_default() - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/msgs/persist_test.rs b/third_party/rustls-fork-shadow-tls/src/msgs/persist_test.rs deleted file mode 100644 index c4a4165..0000000 --- a/third_party/rustls-fork-shadow-tls/src/msgs/persist_test.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::codec::{Codec, Reader}; -use super::persist::*; -use crate::enums::*; - -use crate::key::Certificate; -use crate::ticketer::TimeBase; -use crate::tls13::TLS13_AES_128_GCM_SHA256; - -use std::convert::TryInto; - -#[test] -fn clientsessionkey_is_debug() { - let name = "hello".try_into().unwrap(); - let csk = ClientSessionKey::session_for_server_name(&name); - println!("{:?}", csk); -} - -#[test] -fn clientsessionkey_cannot_be_read() { - let bytes = [0; 1]; - let mut rd = Reader::init(&bytes); - assert!(ClientSessionKey::read(&mut rd).is_none()); -} - -#[test] -fn clientsessionvalue_is_debug() { - let csv = ClientSessionValue::from(Tls13ClientSessionValue::new( - TLS13_AES_128_GCM_SHA256 - .tls13() - .unwrap(), - vec![], - vec![1, 2, 3], - vec![Certificate(b"abc".to_vec()), Certificate(b"def".to_vec())], - TimeBase::now().unwrap(), - 15, - 10, - 128, - )); - println!("{:?}", csv); -} - -#[test] -fn serversessionvalue_is_debug() { - let ssv = ServerSessionValue::new( - None, - ProtocolVersion::TLSv1_3, - CipherSuite::TLS13_AES_128_GCM_SHA256, - vec![1, 2, 3], - None, - None, - vec![4, 5, 6], - TimeBase::now().unwrap(), - 0x12345678, - ); - println!("{:?}", ssv); -} - -#[test] -fn serversessionvalue_no_sni() { - let bytes = [ - 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, - 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, - ]; - let mut rd = Reader::init(&bytes); - let ssv = ServerSessionValue::read(&mut rd).unwrap(); - assert_eq!(ssv.get_encoding(), bytes); -} - -#[test] -fn serversessionvalue_with_cert() { - let bytes = [ - 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, - 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, - ]; - let mut rd = Reader::init(&bytes); - let ssv = ServerSessionValue::read(&mut rd).unwrap(); - assert_eq!(ssv.get_encoding(), bytes); -} diff --git a/third_party/rustls-fork-shadow-tls/src/quic.rs b/third_party/rustls-fork-shadow-tls/src/quic.rs deleted file mode 100644 index 1621495..0000000 --- a/third_party/rustls-fork-shadow-tls/src/quic.rs +++ /dev/null @@ -1,620 +0,0 @@ -/// This module contains optional APIs for implementing QUIC TLS. -use crate::cipher::{Iv, IvLen}; -pub use crate::client::ClientQuicExt; -use crate::conn::CommonState; -use crate::error::Error; -use crate::msgs::enums::AlertDescription; -pub use crate::server::ServerQuicExt; -use crate::suites::BulkAlgorithm; -use crate::tls13::key_schedule::hkdf_expand; -use crate::tls13::{Tls13CipherSuite, TLS13_AES_128_GCM_SHA256_INTERNAL}; -use std::fmt::Debug; - -use ring::{aead, hkdf}; - -/// Secrets used to encrypt/decrypt traffic -#[derive(Clone, Debug)] -pub struct Secrets { - /// Secret used to encrypt packets transmitted by the client - client: hkdf::Prk, - /// Secret used to encrypt packets transmitted by the server - server: hkdf::Prk, - /// Cipher suite used with these secrets - suite: &'static Tls13CipherSuite, - is_client: bool, -} - -impl Secrets { - pub(crate) fn new( - client: hkdf::Prk, - server: hkdf::Prk, - suite: &'static Tls13CipherSuite, - is_client: bool, - ) -> Self { - Self { - client, - server, - suite, - is_client, - } - } - - /// Derive the next set of packet keys - pub fn next_packet_keys(&mut self) -> PacketKeySet { - let keys = PacketKeySet::new(self); - self.update(); - keys - } - - fn update(&mut self) { - let hkdf_alg = self.suite.hkdf_algorithm; - self.client = hkdf_expand(&self.client, hkdf_alg, b"quic ku", &[]); - self.server = hkdf_expand(&self.server, hkdf_alg, b"quic ku", &[]); - } - - fn local_remote(&self) -> (&hkdf::Prk, &hkdf::Prk) { - if self.is_client { - (&self.client, &self.server) - } else { - (&self.server, &self.client) - } - } -} - -/// Generic methods for QUIC sessions -pub trait QuicExt { - /// Return the TLS-encoded transport parameters for the session's peer. - /// - /// While the transport parameters are technically available prior to the - /// completion of the handshake, they cannot be fully trusted until the - /// handshake completes, and reliance on them should be minimized. - /// However, any tampering with the parameters will cause the handshake - /// to fail. - fn quic_transport_parameters(&self) -> Option<&[u8]>; - - /// Compute the keys for encrypting/decrypting 0-RTT packets, if available - fn zero_rtt_keys(&self) -> Option; - - /// Consume unencrypted TLS handshake data. - /// - /// Handshake data obtained from separate encryption levels should be supplied in separate calls. - fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error>; - - /// Emit unencrypted TLS handshake data. - /// - /// When this returns `Some(_)`, the new keys must be used for future handshake data. - fn write_hs(&mut self, buf: &mut Vec) -> Option; - - /// Emit the TLS description code of a fatal alert, if one has arisen. - /// - /// Check after `read_hs` returns `Err(_)`. - fn alert(&self) -> Option; -} - -/// Keys used to communicate in a single direction -pub struct DirectionalKeys { - /// Encrypts or decrypts a packet's headers - pub header: HeaderProtectionKey, - /// Encrypts or decrypts the payload of a packet - pub packet: PacketKey, -} - -impl DirectionalKeys { - pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self { - Self { - header: HeaderProtectionKey::new(suite, secret), - packet: PacketKey::new(suite, secret), - } - } -} - -/// A QUIC header protection key -pub struct HeaderProtectionKey(aead::quic::HeaderProtectionKey); - -impl HeaderProtectionKey { - fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self { - let alg = match suite.common.bulk { - BulkAlgorithm::Aes128Gcm => &aead::quic::AES_128, - BulkAlgorithm::Aes256Gcm => &aead::quic::AES_256, - BulkAlgorithm::Chacha20Poly1305 => &aead::quic::CHACHA20, - }; - - Self(hkdf_expand(secret, alg, b"quic hp", &[])) - } - - /// Adds QUIC Header Protection. - /// - /// `sample` must contain the sample of encrypted payload; see - /// [Header Protection Sample]. - /// - /// `first` must reference the first byte of the header, referred to as - /// `packet[0]` in [Header Protection Application]. - /// - /// `packet_number` must reference the Packet Number field; this is - /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. - /// - /// Returns an error without modifying anything if `sample` is not - /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), - /// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]). - /// - /// Otherwise, `first` and `packet_number` will have the header protection added. - /// - /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 - /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 - /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 - #[inline] - pub fn encrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error> { - self.xor_in_place(sample, first, packet_number, false) - } - - /// Removes QUIC Header Protection. - /// - /// `sample` must contain the sample of encrypted payload; see - /// [Header Protection Sample]. - /// - /// `first` must reference the first byte of the header, referred to as - /// `packet[0]` in [Header Protection Application]. - /// - /// `packet_number` must reference the Packet Number field; this is - /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. - /// - /// Returns an error without modifying anything if `sample` is not - /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), - /// or `packet_number` is longer than allowed (see - /// [Packet Number Encoding and Decoding]). - /// - /// Otherwise, `first` and `packet_number` will have the header protection removed. - /// - /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 - /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 - /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 - #[inline] - pub fn decrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error> { - self.xor_in_place(sample, first, packet_number, true) - } - - fn xor_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - masked: bool, - ) -> Result<(), Error> { - // This implements [Header Protection Application] almost verbatim. - - let mask = self - .0 - .new_mask(sample) - .map_err(|_| Error::General("sample of invalid length".into()))?; - - // The `unwrap()` will not panic because `new_mask` returns a - // non-empty result. - let (first_mask, pn_mask) = mask.split_first().unwrap(); - - // It is OK for the `mask` to be longer than `packet_number`, - // but a valid `packet_number` will never be longer than `mask`. - if packet_number.len() > pn_mask.len() { - return Err(Error::General("packet number too long".into())); - } - - // Infallible from this point on. Before this point, `first` and - // `packet_number` are unchanged. - - const LONG_HEADER_FORM: u8 = 0x80; - let bits = match *first & LONG_HEADER_FORM == LONG_HEADER_FORM { - true => 0x0f, // Long header: 4 bits masked - false => 0x1f, // Short header: 5 bits masked - }; - - let first_plain = match masked { - // When unmasking, use the packet length bits after unmasking - true => *first ^ (first_mask & bits), - // When masking, use the packet length bits before masking - false => *first, - }; - let pn_len = (first_plain & 0x03) as usize + 1; - - *first ^= first_mask & bits; - for (dst, m) in packet_number - .iter_mut() - .zip(pn_mask) - .take(pn_len) - { - *dst ^= m; - } - - Ok(()) - } - - /// Expected sample length for the key's algorithm - #[inline] - pub fn sample_len(&self) -> usize { - self.0.algorithm().sample_len() - } -} - -/// Keys to encrypt or decrypt the payload of a packet -pub struct PacketKey { - /// Encrypts or decrypts a packet's payload - key: aead::LessSafeKey, - /// Computes unique nonces for each packet - iv: Iv, - /// The cipher suite used for this packet key - suite: &'static Tls13CipherSuite, -} - -impl PacketKey { - fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self { - Self { - key: aead::LessSafeKey::new(hkdf_expand( - secret, - suite.common.aead_algorithm, - b"quic key", - &[], - )), - iv: hkdf_expand(secret, IvLen, b"quic iv", &[]), - suite, - } - } - - /// Encrypt a QUIC packet - /// - /// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as - /// the additional authenticated data; and the `payload`. The authentication tag is returned if - /// encryption succeeds. - /// - /// Fails iff the payload is longer than allowed by the cipher suite's AEAD algorithm. - pub fn encrypt_in_place( - &self, - packet_number: u64, - header: &[u8], - payload: &mut [u8], - ) -> Result { - let aad = aead::Aad::from(header); - let nonce = nonce_for(packet_number, &self.iv); - let tag = self - .key - .seal_in_place_separate_tag(nonce, aad, payload) - .map_err(|_| Error::EncryptError)?; - Ok(Tag(tag)) - } - - /// Decrypt a QUIC packet - /// - /// Takes the packet `header`, which is used as the additional authenticated data, and the - /// `payload`, which includes the authentication tag. - /// - /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the - /// length found in the return value. - pub fn decrypt_in_place<'a>( - &self, - packet_number: u64, - header: &[u8], - payload: &'a mut [u8], - ) -> Result<&'a [u8], Error> { - let payload_len = payload.len(); - let aad = aead::Aad::from(header); - let nonce = nonce_for(packet_number, &self.iv); - self.key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)?; - - let plain_len = payload_len - self.key.algorithm().tag_len(); - Ok(&payload[..plain_len]) - } - - /// Number of times the packet key can be used without sacrificing confidentiality - /// - /// See . - #[inline] - pub fn confidentiality_limit(&self) -> u64 { - self.suite.confidentiality_limit - } - - /// Number of times the packet key can be used without sacrificing integrity - /// - /// See . - #[inline] - pub fn integrity_limit(&self) -> u64 { - self.suite.integrity_limit - } - - /// Tag length for the underlying AEAD algorithm - #[inline] - pub fn tag_len(&self) -> usize { - self.key.algorithm().tag_len() - } -} - -/// AEAD tag, must be appended to encrypted cipher text -pub struct Tag(aead::Tag); - -impl AsRef<[u8]> for Tag { - #[inline] - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -/// Packet protection keys for bidirectional 1-RTT communication -pub struct PacketKeySet { - /// Encrypts outgoing packets - pub local: PacketKey, - /// Decrypts incoming packets - pub remote: PacketKey, -} - -impl PacketKeySet { - fn new(secrets: &Secrets) -> Self { - let (local, remote) = secrets.local_remote(); - Self { - local: PacketKey::new(secrets.suite, local), - remote: PacketKey::new(secrets.suite, remote), - } - } -} - -/// Complete set of keys used to communicate with the peer -pub struct Keys { - /// Encrypts outgoing packets - pub local: DirectionalKeys, - /// Decrypts incoming packets - pub remote: DirectionalKeys, -} - -impl Keys { - /// Construct keys for use with initial packets - pub fn initial(version: Version, client_dst_connection_id: &[u8], is_client: bool) -> Self { - const CLIENT_LABEL: &[u8] = b"client in"; - const SERVER_LABEL: &[u8] = b"server in"; - let salt = version.initial_salt(); - let hs_secret = hkdf::Salt::new(hkdf::HKDF_SHA256, salt).extract(client_dst_connection_id); - - let secrets = Secrets { - client: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, CLIENT_LABEL, &[]), - server: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, SERVER_LABEL, &[]), - suite: TLS13_AES_128_GCM_SHA256_INTERNAL, - is_client, - }; - Self::new(&secrets) - } - - fn new(secrets: &Secrets) -> Self { - let (local, remote) = secrets.local_remote(); - Self { - local: DirectionalKeys::new(secrets.suite, local), - remote: DirectionalKeys::new(secrets.suite, remote), - } - } -} - -pub(crate) fn write_hs(this: &mut CommonState, buf: &mut Vec) -> Option { - while let Some((_, msg)) = this.quic.hs_queue.pop_front() { - buf.extend_from_slice(&msg); - if let Some(&(true, _)) = this.quic.hs_queue.front() { - if this.quic.hs_secrets.is_some() { - // Allow the caller to switch keys before proceeding. - break; - } - } - } - - if let Some(secrets) = this.quic.hs_secrets.take() { - return Some(KeyChange::Handshake { - keys: Keys::new(&secrets), - }); - } - - if let Some(mut secrets) = this.quic.traffic_secrets.take() { - if !this.quic.returned_traffic_keys { - this.quic.returned_traffic_keys = true; - let keys = Keys::new(&secrets); - secrets.update(); - return Some(KeyChange::OneRtt { - keys, - next: secrets, - }); - } - } - - None -} - -/// Key material for use in QUIC packet spaces -/// -/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections): -/// -/// * Initial: these can be created from [`Keys::initial()`] -/// * 0-RTT keys: can be retrieved from [`QuicExt::zero_rtt_keys()`] -/// * Handshake: these are returned from [`QuicExt::write_hs()`] after `ClientHello` and -/// `ServerHello` messages have been exchanged -/// * 1-RTT keys: these are returned from [`QuicExt::write_hs()`] after the handshake is done -/// -/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive -/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that -/// only packet keys are updated by key updates; header protection keys remain the same. -#[allow(clippy::large_enum_variant)] -pub enum KeyChange { - /// Keys for the handshake space - Handshake { - /// Header and packet keys for the handshake space - keys: Keys, - }, - /// Keys for 1-RTT data - OneRtt { - /// Header and packet keys for 1-RTT data - keys: Keys, - /// Secrets to derive updated keys from - next: Secrets, - }, -} - -/// Compute the nonce to use for encrypting or decrypting `packet_number` -fn nonce_for(packet_number: u64, iv: &Iv) -> ring::aead::Nonce { - let mut out = [0; aead::NONCE_LEN]; - out[4..].copy_from_slice(&packet_number.to_be_bytes()); - for (out, inp) in out.iter_mut().zip(iv.0.iter()) { - *out ^= inp; - } - aead::Nonce::assume_unique_for_key(out) -} - -/// QUIC protocol version -/// -/// Governs version-specific behavior in the TLS layer -#[non_exhaustive] -#[derive(Clone, Copy, Debug)] -pub enum Version { - /// Draft versions 29, 30, 31 and 32 - V1Draft, - /// First stable RFC - V1, -} - -impl Version { - fn initial_salt(self) -> &'static [u8; 20] { - match self { - Self::V1Draft => &[ - // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2 - 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, - 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99, - ], - Self::V1 => &[ - // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets - 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, - 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a, - ], - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn short_packet_header_protection() { - // https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea - - const PN: u64 = 654360564; - const SECRET: &[u8] = &[ - 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad, - 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, - 0x0f, 0x21, 0x63, 0x2b, - ]; - - let secret = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, SECRET); - use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; - let hpk = HeaderProtectionKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret); - let packet = PacketKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret); - - const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, 0x01]; - - let mut buf = PLAIN.to_vec(); - let (header, payload) = buf.split_at_mut(4); - let tag = packet - .encrypt_in_place(PN, &*header, payload) - .unwrap(); - buf.extend(tag.as_ref()); - - let pn_offset = 1; - let (header, sample) = buf.split_at_mut(pn_offset + 4); - let (first, rest) = header.split_at_mut(1); - let sample = &sample[..hpk.sample_len()]; - hpk.encrypt_in_place(sample, &mut first[0], dbg!(rest)) - .unwrap(); - - const PROTECTED: &[u8] = &[ - 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57, - 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb, - ]; - - assert_eq!(&buf, PROTECTED); - - let (header, sample) = buf.split_at_mut(pn_offset + 4); - let (first, rest) = header.split_at_mut(1); - let sample = &sample[..hpk.sample_len()]; - hpk.decrypt_in_place(sample, &mut first[0], rest) - .unwrap(); - - let (header, payload_tag) = buf.split_at_mut(4); - let plain = packet - .decrypt_in_place(PN, &*header, payload_tag) - .unwrap(); - - assert_eq!(plain, &PLAIN[4..]); - } - - #[test] - fn key_update_test_vector() { - fn equal_prk(x: &hkdf::Prk, y: &hkdf::Prk) -> bool { - let mut x_data = [0; 16]; - let mut y_data = [0; 16]; - let x_okm = x - .expand(&[b"info"], &aead::quic::AES_128) - .unwrap(); - x_okm.fill(&mut x_data[..]).unwrap(); - let y_okm = y - .expand(&[b"info"], &aead::quic::AES_128) - .unwrap(); - y_okm.fill(&mut y_data[..]).unwrap(); - x_data == y_data - } - - let mut secrets = Secrets { - // Constant dummy values for reproducibility - client: hkdf::Prk::new_less_safe( - hkdf::HKDF_SHA256, - &[ - 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e, - 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0, - 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf, - ], - ), - server: hkdf::Prk::new_less_safe( - hkdf::HKDF_SHA256, - &[ - 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61, - 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82, - 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55, - ], - ), - suite: TLS13_AES_128_GCM_SHA256_INTERNAL, - is_client: true, - }; - secrets.update(); - - assert!(equal_prk( - &secrets.client, - &hkdf::Prk::new_less_safe( - hkdf::HKDF_SHA256, - &[ - 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf, - 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1, - 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce - ] - ) - )); - assert!(equal_prk( - &secrets.server, - &hkdf::Prk::new_less_safe( - hkdf::HKDF_SHA256, - &[ - 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca, - 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0, - 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a - ] - ) - )); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/rand.rs b/third_party/rustls-fork-shadow-tls/src/rand.rs deleted file mode 100644 index 14cde00..0000000 --- a/third_party/rustls-fork-shadow-tls/src/rand.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::msgs::codec; -/// The single place where we generate random material -/// for our own use. These functions never fail, -/// they panic on error. -use ring::rand::{SecureRandom, SystemRandom}; - -/// Fill the whole slice with random material. -pub(crate) fn fill_random(bytes: &mut [u8]) -> Result<(), GetRandomFailed> { - SystemRandom::new() - .fill(bytes) - .map_err(|_| GetRandomFailed) -} - -/// Make a Vec of the given size -/// containing random material. -pub(crate) fn random_vec(len: usize) -> Result, GetRandomFailed> { - let mut v = vec![0; len]; - fill_random(&mut v)?; - Ok(v) -} - -/// Return a uniformly random u32. -pub(crate) fn random_u32() -> Result { - let mut buf = [0u8; 4]; - fill_random(&mut buf)?; - codec::decode_u32(&buf).ok_or(GetRandomFailed) -} - -#[derive(Debug)] -pub struct GetRandomFailed; diff --git a/third_party/rustls-fork-shadow-tls/src/record_layer.rs b/third_party/rustls-fork-shadow-tls/src/record_layer.rs deleted file mode 100644 index e525772..0000000 --- a/third_party/rustls-fork-shadow-tls/src/record_layer.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::cipher::{MessageDecrypter, MessageEncrypter}; -use crate::error::Error; -use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; - -static SEQ_SOFT_LIMIT: u64 = 0xffff_ffff_ffff_0000u64; -static SEQ_HARD_LIMIT: u64 = 0xffff_ffff_ffff_fffeu64; - -#[derive(PartialEq)] -enum DirectionState { - /// No keying material. - Invalid, - - /// Keying material present, but not yet in use. - Prepared, - - /// Keying material in use. - Active, -} - -pub(crate) struct RecordLayer { - message_encrypter: Box, - message_decrypter: Box, - write_seq: u64, - read_seq: u64, - encrypt_state: DirectionState, - decrypt_state: DirectionState, - - // Message encrypted with other keys may be encountered, so failures - // should be swallowed by the caller. This struct tracks the amount - // of message size this is allowed for. - trial_decryption_len: Option, -} - -impl RecordLayer { - pub(crate) fn new() -> Self { - Self { - message_encrypter: ::invalid(), - message_decrypter: ::invalid(), - write_seq: 0, - read_seq: 0, - encrypt_state: DirectionState::Invalid, - decrypt_state: DirectionState::Invalid, - trial_decryption_len: None, - } - } - - pub(crate) fn is_encrypting(&self) -> bool { - self.encrypt_state == DirectionState::Active - } - - pub(crate) fn is_decrypting(&self) -> bool { - self.decrypt_state == DirectionState::Active - } - - #[cfg(feature = "secret_extraction")] - pub(crate) fn write_seq(&self) -> u64 { - self.write_seq - } - - #[cfg(feature = "secret_extraction")] - pub(crate) fn read_seq(&self) -> u64 { - self.read_seq - } - - pub(crate) fn doing_trial_decryption(&mut self, requested: usize) -> bool { - match self - .trial_decryption_len - .and_then(|value| value.checked_sub(requested)) - { - Some(remaining) => { - self.trial_decryption_len = Some(remaining); - true - } - _ => false, - } - } - - /// Prepare to use the given `MessageEncrypter` for future message encryption. - /// It is not used until you call `start_encrypting`. - pub(crate) fn prepare_message_encrypter(&mut self, cipher: Box) { - self.message_encrypter = cipher; - self.write_seq = 0; - self.encrypt_state = DirectionState::Prepared; - } - - /// Prepare to use the given `MessageDecrypter` for future message decryption. - /// It is not used until you call `start_decrypting`. - pub(crate) fn prepare_message_decrypter(&mut self, cipher: Box) { - self.message_decrypter = cipher; - self.read_seq = 0; - self.decrypt_state = DirectionState::Prepared; - } - - /// Start using the `MessageEncrypter` previously provided to the previous - /// call to `prepare_message_encrypter`. - pub(crate) fn start_encrypting(&mut self) { - debug_assert!(self.encrypt_state == DirectionState::Prepared); - self.encrypt_state = DirectionState::Active; - } - - /// Start using the `MessageDecrypter` previously provided to the previous - /// call to `prepare_message_decrypter`. - pub(crate) fn start_decrypting(&mut self) { - debug_assert!(self.decrypt_state == DirectionState::Prepared); - self.decrypt_state = DirectionState::Active; - } - - /// Set and start using the given `MessageEncrypter` for future outgoing - /// message encryption. - pub(crate) fn set_message_encrypter(&mut self, cipher: Box) { - self.prepare_message_encrypter(cipher); - self.start_encrypting(); - } - - /// Set and start using the given `MessageDecrypter` for future incoming - /// message decryption. - pub(crate) fn set_message_decrypter(&mut self, cipher: Box) { - self.prepare_message_decrypter(cipher); - self.start_decrypting(); - self.trial_decryption_len = None; - } - - /// Set and start using the given `MessageDecrypter` for future incoming - /// message decryption, and enable "trial decryption" mode for when TLS1.3 - /// 0-RTT is attempted but rejected by the server. - pub(crate) fn set_message_decrypter_with_trial_decryption( - &mut self, - cipher: Box, - max_length: usize, - ) { - self.prepare_message_decrypter(cipher); - self.start_decrypting(); - self.trial_decryption_len = Some(max_length); - } - - pub(crate) fn finish_trial_decryption(&mut self) { - self.trial_decryption_len = None; - } - - /// Return true if the peer appears to getting close to encrypting - /// too many messages with this key. - /// - /// Perhaps if we send an alert well before their counter wraps, a - /// buggy peer won't make a terrible mistake here? - /// - /// Note that there's no reason to refuse to decrypt: the security - /// failure has already happened. - pub(crate) fn wants_close_before_decrypt(&self) -> bool { - self.read_seq == SEQ_SOFT_LIMIT - } - - /// Return true if we are getting close to encrypting too many - /// messages with our encryption key. - pub(crate) fn wants_close_before_encrypt(&self) -> bool { - self.write_seq == SEQ_SOFT_LIMIT - } - - /// Return true if we outright refuse to do anything with the - /// encryption key. - pub(crate) fn encrypt_exhausted(&self) -> bool { - self.write_seq >= SEQ_HARD_LIMIT - } - - /// Decrypt a TLS message. - /// - /// `encr` is a decoded message allegedly received from the peer. - /// If it can be decrypted, its decryption is returned. Otherwise, - /// an error is returned. - pub(crate) fn decrypt_incoming(&mut self, encr: OpaqueMessage) -> Result { - debug_assert!(self.is_decrypting()); - let seq = self.read_seq; - let msg = self - .message_decrypter - .decrypt(encr, seq)?; - self.read_seq += 1; - Ok(msg) - } - - /// Encrypt a TLS message. - /// - /// `plain` is a TLS message we'd like to send. This function - /// panics if the requisite keying material hasn't been established yet. - pub(crate) fn encrypt_outgoing(&mut self, plain: BorrowedPlainMessage) -> OpaqueMessage { - debug_assert!(self.encrypt_state == DirectionState::Active); - assert!(!self.encrypt_exhausted()); - let seq = self.write_seq; - self.write_seq += 1; - self.message_encrypter - .encrypt(plain, seq) - .unwrap() - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/builder.rs b/third_party/rustls-fork-shadow-tls/src/server/builder.rs deleted file mode 100644 index d32ce44..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/builder.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::builder::{ConfigBuilder, WantsVerifier}; -use crate::error::Error; -use crate::key; -use crate::kx::SupportedKxGroup; -use crate::server::handy; -use crate::server::{ResolvesServerCert, ServerConfig}; -use crate::suites::SupportedCipherSuite; -use crate::verify; -use crate::versions; -use crate::NoKeyLog; - -use std::marker::PhantomData; -use std::sync::Arc; - -impl ConfigBuilder { - /// Choose how to verify client certificates. - pub fn with_client_cert_verifier( - self, - client_cert_verifier: Arc, - ) -> ConfigBuilder { - ConfigBuilder { - state: WantsServerCert { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - versions: self.state.versions, - verifier: client_cert_verifier, - }, - side: PhantomData::default(), - } - } - - /// Disable client authentication. - pub fn with_no_client_auth(self) -> ConfigBuilder { - self.with_client_cert_verifier(verify::NoClientAuth::new()) - } -} - -/// A config builder state where the caller must supply how to provide a server certificate to -/// the connecting peer. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsServerCert { - cipher_suites: Vec, - kx_groups: Vec<&'static SupportedKxGroup>, - versions: versions::EnabledVersions, - verifier: Arc, -} - -impl ConfigBuilder { - /// Sets a single certificate chain and matching private key. This - /// certificate and key is used for all subsequent connections, - /// irrespective of things like SNI hostname. - /// - /// Note that the end-entity certificate must have the - /// [Subject Alternative Name](https://tools.ietf.org/html/rfc6125#section-4.1) - /// extension to describe, e.g., the valid DNS name. The `commonName` field is - /// disregarded. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. - /// - /// This function fails if `key_der` is invalid. - pub fn with_single_cert( - self, - cert_chain: Vec, - key_der: key::PrivateKey, - ) -> Result { - let resolver = handy::AlwaysResolvesChain::new(cert_chain, &key_der)?; - Ok(self.with_cert_resolver(Arc::new(resolver))) - } - - /// Sets a single certificate chain, matching private key, OCSP - /// response and SCTs. This certificate and key is used for all - /// subsequent connections, irrespective of things like SNI hostname. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key. - /// `ocsp` is a DER-encoded OCSP response. Ignored if zero length. - /// `scts` is an `SignedCertificateTimestampList` encoding (see RFC6962) - /// and is ignored if empty. - /// - /// This function fails if `key_der` is invalid. - pub fn with_single_cert_with_ocsp_and_sct( - self, - cert_chain: Vec, - key_der: key::PrivateKey, - ocsp: Vec, - scts: Vec, - ) -> Result { - let resolver = - handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp, scts)?; - Ok(self.with_cert_resolver(Arc::new(resolver))) - } - - /// Sets a custom [`ResolvesServerCert`]. - pub fn with_cert_resolver(self, cert_resolver: Arc) -> ServerConfig { - ServerConfig { - cipher_suites: self.state.cipher_suites, - kx_groups: self.state.kx_groups, - verifier: self.state.verifier, - cert_resolver, - ignore_client_order: false, - max_fragment_size: None, - session_storage: handy::ServerSessionMemoryCache::new(256), - ticketer: Arc::new(handy::NeverProducesTickets {}), - alpn_protocols: Vec::new(), - versions: self.state.versions, - key_log: Arc::new(NoKeyLog {}), - #[cfg(feature = "secret_extraction")] - enable_secret_extraction: false, - max_early_data_size: 0, - send_half_rtt_data: false, - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/common.rs b/third_party/rustls-fork-shadow-tls/src/server/common.rs deleted file mode 100644 index 2e3420c..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/common.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{key, sign}; - -/// ActiveCertifiedKey wraps CertifiedKey and tracks OSCP and SCT state -/// in a single handshake. -pub(super) struct ActiveCertifiedKey<'a> { - key: &'a sign::CertifiedKey, - ocsp: Option<&'a [u8]>, - sct_list: Option<&'a [u8]>, -} - -impl<'a> ActiveCertifiedKey<'a> { - pub(super) fn from_certified_key(key: &sign::CertifiedKey) -> ActiveCertifiedKey { - ActiveCertifiedKey { - key, - ocsp: key.ocsp.as_deref(), - sct_list: key.sct_list.as_deref(), - } - } - - /// Get the certificate chain - #[inline] - pub(super) fn get_cert(&self) -> &[key::Certificate] { - &self.key.cert - } - - /// Get the signing key - #[inline] - pub(super) fn get_key(&self) -> &dyn sign::SigningKey { - &*self.key.key - } - - #[inline] - pub(super) fn get_ocsp(&self) -> Option<&[u8]> { - self.ocsp - } - - #[inline] - pub(super) fn get_sct_list(&self) -> Option<&[u8]> { - self.sct_list - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/handy.rs b/third_party/rustls-fork-shadow-tls/src/server/handy.rs deleted file mode 100644 index 296d20c..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/handy.rs +++ /dev/null @@ -1,278 +0,0 @@ -use crate::error::Error; -use crate::key; -use crate::limited_cache; -use crate::server; -use crate::server::ClientHello; -use crate::sign; - -use std::collections; -use std::sync::{Arc, Mutex}; - -/// Something which never stores sessions. -pub struct NoServerSessionStorage {} - -impl server::StoresServerSessions for NoServerSessionStorage { - fn put(&self, _id: Vec, _sec: Vec) -> bool { - false - } - fn get(&self, _id: &[u8]) -> Option> { - None - } - fn take(&self, _id: &[u8]) -> Option> { - None - } - fn can_cache(&self) -> bool { - false - } -} - -/// An implementer of `StoresServerSessions` that stores everything -/// in memory. If enforces a limit on the number of stored sessions -/// to bound memory usage. -pub struct ServerSessionMemoryCache { - cache: Mutex, Vec>>, -} - -impl ServerSessionMemoryCache { - /// Make a new ServerSessionMemoryCache. `size` is the maximum - /// number of stored sessions, and may be rounded-up for - /// efficiency. - pub fn new(size: usize) -> Arc { - Arc::new(Self { - cache: Mutex::new(limited_cache::LimitedCache::new(size)), - }) - } -} - -impl server::StoresServerSessions for ServerSessionMemoryCache { - fn put(&self, key: Vec, value: Vec) -> bool { - self.cache - .lock() - .unwrap() - .insert(key, value); - true - } - - fn get(&self, key: &[u8]) -> Option> { - self.cache - .lock() - .unwrap() - .get(key) - .cloned() - } - - fn take(&self, key: &[u8]) -> Option> { - self.cache.lock().unwrap().remove(key) - } - - fn can_cache(&self) -> bool { - true - } -} - -/// Something which never produces tickets. -pub(super) struct NeverProducesTickets {} - -impl server::ProducesTickets for NeverProducesTickets { - fn enabled(&self) -> bool { - false - } - fn lifetime(&self) -> u32 { - 0 - } - fn encrypt(&self, _bytes: &[u8]) -> Option> { - None - } - fn decrypt(&self, _bytes: &[u8]) -> Option> { - None - } -} - -/// Something which always resolves to the same cert chain. -pub(super) struct AlwaysResolvesChain(Arc); - -impl AlwaysResolvesChain { - /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private - /// key type and encoding. - pub(super) fn new( - chain: Vec, - priv_key: &key::PrivateKey, - ) -> Result { - let key = sign::any_supported_type(priv_key) - .map_err(|_| Error::General("invalid private key".into()))?; - Ok(Self(Arc::new(sign::CertifiedKey::new(chain, key)))) - } - - /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private - /// key type and encoding. - /// - /// If non-empty, the given OCSP response and SCTs are attached. - pub(super) fn new_with_extras( - chain: Vec, - priv_key: &key::PrivateKey, - ocsp: Vec, - scts: Vec, - ) -> Result { - let mut r = Self::new(chain, priv_key)?; - - { - let cert = Arc::make_mut(&mut r.0); - if !ocsp.is_empty() { - cert.ocsp = Some(ocsp); - } - if !scts.is_empty() { - cert.sct_list = Some(scts); - } - } - - Ok(r) - } -} - -impl server::ResolvesServerCert for AlwaysResolvesChain { - fn resolve(&self, _client_hello: ClientHello) -> Option> { - Some(Arc::clone(&self.0)) - } -} - -/// Something that resolves do different cert chains/keys based -/// on client-supplied server name (via SNI). -pub struct ResolvesServerCertUsingSni { - by_name: collections::HashMap>, -} - -impl ResolvesServerCertUsingSni { - /// Create a new and empty (i.e., knows no certificates) resolver. - pub fn new() -> Self { - Self { - by_name: collections::HashMap::new(), - } - } - - /// Add a new `sign::CertifiedKey` to be used for the given SNI `name`. - /// - /// This function fails if `name` is not a valid DNS name, or if - /// it's not valid for the supplied certificate, or if the certificate - /// chain is syntactically faulty. - pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> { - let checked_name = webpki::DnsNameRef::try_from_ascii_str(name) - .map_err(|_| Error::General("Bad DNS name".into()))? - .to_owned(); - - ck.cross_check_end_entity_cert(Some(checked_name.as_ref()))?; - let as_str: &str = checked_name.as_ref().into(); - self.by_name - .insert(as_str.to_string(), Arc::new(ck)); - Ok(()) - } -} - -impl server::ResolvesServerCert for ResolvesServerCertUsingSni { - fn resolve(&self, client_hello: ClientHello) -> Option> { - if let Some(name) = client_hello.server_name() { - self.by_name.get(name).map(Arc::clone) - } else { - // This kind of resolver requires SNI - None - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::server::ProducesTickets; - use crate::server::ResolvesServerCert; - use crate::server::StoresServerSessions; - - #[test] - fn test_noserversessionstorage_drops_put() { - let c = NoServerSessionStorage {}; - assert!(!c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_noserversessionstorage_denies_gets() { - let c = NoServerSessionStorage {}; - c.put(vec![0x01], vec![0x02]); - assert_eq!(c.get(&[]), None); - assert_eq!(c.get(&[0x01]), None); - assert_eq!(c.get(&[0x02]), None); - } - - #[test] - fn test_noserversessionstorage_denies_takes() { - let c = NoServerSessionStorage {}; - assert_eq!(c.take(&[]), None); - assert_eq!(c.take(&[0x01]), None); - assert_eq!(c.take(&[0x02]), None); - } - - #[test] - fn test_serversessionmemorycache_accepts_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_serversessionmemorycache_persists_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - } - - #[test] - fn test_serversessionmemorycache_overwrites_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x01], vec![0x04])); - assert_eq!(c.get(&[0x01]), Some(vec![0x04])); - } - - #[test] - fn test_serversessionmemorycache_drops_to_maintain_size_invariant() { - let c = ServerSessionMemoryCache::new(2); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x03], vec![0x04])); - assert!(c.put(vec![0x05], vec![0x06])); - assert!(c.put(vec![0x07], vec![0x08])); - assert!(c.put(vec![0x09], vec![0x0a])); - - let count = c.get(&[0x01]).iter().count() - + c.get(&[0x03]).iter().count() - + c.get(&[0x05]).iter().count() - + c.get(&[0x07]).iter().count() - + c.get(&[0x09]).iter().count(); - - assert!(count < 5); - } - - #[test] - fn test_neverproducestickets_does_nothing() { - let npt = NeverProducesTickets {}; - assert!(!npt.enabled()); - assert_eq!(0, npt.lifetime()); - assert_eq!(None, npt.encrypt(&[])); - assert_eq!(None, npt.decrypt(&[])); - } - - #[test] - fn test_resolvesservercertusingsni_requires_sni() { - let rscsni = ResolvesServerCertUsingSni::new(); - assert!(rscsni - .resolve(ClientHello::new(&None, &[], None, &[])) - .is_none()); - } - - #[test] - fn test_resolvesservercertusingsni_handles_unknown_name() { - let rscsni = ResolvesServerCertUsingSni::new(); - let name = webpki::DnsNameRef::try_from_ascii_str("hello.com") - .unwrap() - .to_owned(); - assert!(rscsni - .resolve(ClientHello::new(&Some(name), &[], None, &[])) - .is_none()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/hs.rs b/third_party/rustls-fork-shadow-tls/src/server/hs.rs deleted file mode 100644 index 6fc3bd8..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/hs.rs +++ /dev/null @@ -1,522 +0,0 @@ -use crate::conn::{CommonState, ConnectionRandoms, State}; -#[cfg(feature = "tls12")] -use crate::enums::CipherSuite; -use crate::enums::{ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::enums::HandshakeType; -use crate::msgs::enums::{AlertDescription, Compression, ExtensionType}; -#[cfg(feature = "tls12")] -use crate::msgs::handshake::SessionID; -use crate::msgs::handshake::{ClientHelloPayload, Random, ServerExtension}; -use crate::msgs::handshake::{ConvertProtocolNameList, ConvertServerNameList, HandshakePayload}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::server::{ClientHello, ServerConfig}; -use crate::suites; -use crate::SupportedCipherSuite; - -use super::server_conn::ServerConnectionData; -#[cfg(feature = "tls12")] -use super::tls12; -use crate::server::common::ActiveCertifiedKey; -use crate::server::tls13; - -use std::sync::Arc; - -pub(super) type NextState = Box>; -pub(super) type NextStateOrError = Result; -pub(super) type ServerContext<'a> = crate::conn::Context<'a, ServerConnectionData>; - -pub(super) fn incompatible(common: &mut CommonState, why: &str) -> Error { - common.send_fatal_alert(AlertDescription::HandshakeFailure); - Error::PeerIncompatibleError(why.to_string()) -} - -fn bad_version(common: &mut CommonState, why: &str) -> Error { - common.send_fatal_alert(AlertDescription::ProtocolVersion); - Error::PeerIncompatibleError(why.to_string()) -} - -pub(super) fn decode_error(common: &mut CommonState, why: &str) -> Error { - common.send_fatal_alert(AlertDescription::DecodeError); - Error::PeerMisbehavedError(why.to_string()) -} - -pub(super) fn can_resume( - suite: SupportedCipherSuite, - sni: &Option, - using_ems: bool, - resumedata: &persist::ServerSessionValue, -) -> bool { - // The RFCs underspecify what happens if we try to resume to - // an unoffered/varying suite. We merely don't resume in weird cases. - // - // RFC 6066 says "A server that implements this extension MUST NOT accept - // the request to resume the session if the server_name extension contains - // a different name. Instead, it proceeds with a full handshake to - // establish a new session." - resumedata.cipher_suite == suite.suite() - && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems)) - && &resumedata.sni == sni -} - -#[derive(Default)] -pub(super) struct ExtensionProcessing { - // extensions to reply with - pub(super) exts: Vec, - #[cfg(feature = "tls12")] - pub(super) send_ticket: bool, -} - -impl ExtensionProcessing { - pub(super) fn new() -> Self { - Default::default() - } - - pub(super) fn process_common( - &mut self, - config: &ServerConfig, - cx: &mut ServerContext<'_>, - ocsp_response: &mut Option<&[u8]>, - sct_list: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - extra_exts: Vec, - ) -> Result<(), Error> { - // ALPN - let our_protocols = &config.alpn_protocols; - let maybe_their_protocols = hello.get_alpn_extension(); - if let Some(their_protocols) = maybe_their_protocols { - let their_protocols = their_protocols.to_slices(); - - if their_protocols - .iter() - .any(|protocol| protocol.is_empty()) - { - return Err(Error::PeerMisbehavedError( - "client offered empty ALPN protocol".to_string(), - )); - } - - cx.common.alpn_protocol = our_protocols - .iter() - .find(|protocol| their_protocols.contains(&protocol.as_slice())) - .cloned(); - if let Some(ref selected_protocol) = cx.common.alpn_protocol { - debug!("Chosen ALPN protocol {:?}", selected_protocol); - self.exts - .push(ServerExtension::make_alpn(&[selected_protocol])); - } else if !our_protocols.is_empty() { - cx.common - .send_fatal_alert(AlertDescription::NoApplicationProtocol); - return Err(Error::NoApplicationProtocol); - } - } - - #[cfg(feature = "quic")] - { - if cx.common.is_quic() { - // QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001 - // says: "The server MUST treat the inability to select a compatible application - // protocol as a connection error of type 0x0178". We judge that ALPN was desired - // (rather than some out-of-band protocol negotiation mechanism) iff any ALPN - // protocols were configured locally or offered by the client. This helps prevent - // successful establishment of connections between peers that can't understand - // each other. - if cx.common.alpn_protocol.is_none() - && (!our_protocols.is_empty() || maybe_their_protocols.is_some()) - { - cx.common - .send_fatal_alert(AlertDescription::NoApplicationProtocol); - return Err(Error::NoApplicationProtocol); - } - - match hello.get_quic_params_extension() { - Some(params) => cx.common.quic.params = Some(params), - None => { - return Err(cx - .common - .missing_extension("QUIC transport parameters not found")); - } - } - } - } - - let for_resume = resumedata.is_some(); - // SNI - if !for_resume && hello.get_sni_extension().is_some() { - self.exts - .push(ServerExtension::ServerNameAck); - } - - // Send status_request response if we have one. This is not allowed - // if we're resuming, and is only triggered if we have an OCSP response - // to send. - if !for_resume - && hello - .find_extension(ExtensionType::StatusRequest) - .is_some() - { - if ocsp_response.is_some() && !cx.common.is_tls13() { - // Only TLS1.2 sends confirmation in ServerHello - self.exts - .push(ServerExtension::CertificateStatusAck); - } - } else { - // Throw away any OCSP response so we don't try to send it later. - ocsp_response.take(); - } - - if !for_resume - && hello - .find_extension(ExtensionType::SCT) - .is_some() - { - if !cx.common.is_tls13() { - // Take the SCT list, if any, so we don't send it later, - // and put it in the legacy extension. - if let Some(sct_list) = sct_list.take() { - self.exts - .push(ServerExtension::make_sct(sct_list.to_vec())); - } - } - } else { - // Throw away any SCT list so we don't send it later. - sct_list.take(); - } - - self.exts.extend(extra_exts); - - Ok(()) - } - - #[cfg(feature = "tls12")] - pub(super) fn process_tls12( - &mut self, - config: &ServerConfig, - hello: &ClientHelloPayload, - using_ems: bool, - ) { - // Renegotiation. - // (We don't do reneg at all, but would support the secure version if we did.) - let secure_reneg_offered = hello - .find_extension(ExtensionType::RenegotiationInfo) - .is_some() - || hello - .cipher_suites - .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - - if secure_reneg_offered { - self.exts - .push(ServerExtension::make_empty_renegotiation_info()); - } - - // Tickets: - // If we get any SessionTicket extension and have tickets enabled, - // we send an ack. - if hello - .find_extension(ExtensionType::SessionTicket) - .is_some() - && config.ticketer.enabled() - { - self.send_ticket = true; - self.exts - .push(ServerExtension::SessionTicketAck); - } - - // Confirm use of EMS if offered. - if using_ems { - self.exts - .push(ServerExtension::ExtendedMasterSecretAck); - } - } -} - -pub(super) struct ExpectClientHello { - pub(super) config: Arc, - pub(super) extra_exts: Vec, - pub(super) transcript: HandshakeHashOrBuffer, - #[cfg(feature = "tls12")] - pub(super) session_id: SessionID, - #[cfg(feature = "tls12")] - pub(super) using_ems: bool, - pub(super) done_retry: bool, - pub(super) send_ticket: bool, -} - -impl ExpectClientHello { - pub(super) fn new(config: Arc, extra_exts: Vec) -> Self { - let mut transcript_buffer = HandshakeHashBuffer::new(); - - if config.verifier.offer_client_auth() { - transcript_buffer.set_client_auth_enabled(); - } - - Self { - config, - extra_exts, - transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), - #[cfg(feature = "tls12")] - session_id: SessionID::empty(), - #[cfg(feature = "tls12")] - using_ems: false, - done_retry: false, - send_ticket: false, - } - } - - /// Continues handling of a `ClientHello` message once config and certificate are available. - pub(super) fn with_certified_key( - self, - mut sig_schemes: Vec, - client_hello: &ClientHelloPayload, - m: &Message, - cx: &mut ServerContext<'_>, - ) -> NextStateOrError { - let tls13_enabled = self - .config - .supports_version(ProtocolVersion::TLSv1_3); - let tls12_enabled = self - .config - .supports_version(ProtocolVersion::TLSv1_2); - - // Are we doing TLS1.3? - let maybe_versions_ext = client_hello.get_versions_extension(); - let version = if let Some(versions) = maybe_versions_ext { - if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { - ProtocolVersion::TLSv1_3 - } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { - return Err(bad_version(cx.common, "TLS1.2 not offered/enabled")); - } else if cx.common.is_quic() { - return Err(bad_version( - cx.common, - "Expecting QUIC connection, but client does not support TLSv1_3", - )); - } else { - ProtocolVersion::TLSv1_2 - } - } else if client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() { - return Err(bad_version(cx.common, "Client does not support TLSv1_2")); - } else if !tls12_enabled && tls13_enabled { - return Err(bad_version( - cx.common, - "Server requires TLS1.3, but client omitted versions ext", - )); - } else if cx.common.is_quic() { - return Err(bad_version( - cx.common, - "Expecting QUIC connection, but client does not support TLSv1_3", - )); - } else { - ProtocolVersion::TLSv1_2 - }; - - cx.common.negotiated_version = Some(version); - - // We communicate to the upper layer what kind of key they should choose - // via the sigschemes value. Clients tend to treat this extension - // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not). - // So: reduce the offered sigschemes to those compatible with the - // intersection of ciphersuites. - let client_suites = self - .config - .cipher_suites - .iter() - .copied() - .filter(|scs| { - client_hello - .cipher_suites - .contains(&scs.suite()) - }) - .collect::>(); - - sig_schemes - .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); - - // Choose a certificate. - let certkey = { - let client_hello = ClientHello::new( - &cx.data.sni, - &sig_schemes, - client_hello.get_alpn_extension(), - &client_hello.cipher_suites, - ); - - let certkey = self - .config - .cert_resolver - .resolve(client_hello); - - certkey.ok_or_else(|| { - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Error::General("no server certificate chain resolved".to_string()) - })? - }; - let certkey = ActiveCertifiedKey::from_certified_key(&certkey); - - // Reduce our supported ciphersuites by the certificate. - // (no-op for TLS1.3) - let suitable_suites = - suites::reduce_given_sigalg(&self.config.cipher_suites, certkey.get_key().algorithm()); - - // And version - let suitable_suites = suites::reduce_given_version(&suitable_suites, version); - - let suite = if self.config.ignore_client_order { - suites::choose_ciphersuite_preferring_server( - &client_hello.cipher_suites, - &suitable_suites, - ) - } else { - suites::choose_ciphersuite_preferring_client( - &client_hello.cipher_suites, - &suitable_suites, - ) - } - .ok_or_else(|| incompatible(cx.common, "no ciphersuites in common"))?; - - debug!("decided upon suite {:?}", suite); - cx.common.suite = Some(suite); - - // Start handshake hash. - let starting_hash = suite.hash_algorithm(); - let transcript = match self.transcript { - HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), - HandshakeHashOrBuffer::Hash(inner) if inner.algorithm() == starting_hash => inner, - _ => { - return Err(cx - .common - .illegal_param("hash differed on retry")); - } - }; - - // Save their Random. - let randoms = ConnectionRandoms::new(client_hello.random, Random::new()?); - match suite { - SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { - config: self.config, - transcript, - suite, - randoms, - done_retry: self.done_retry, - send_ticket: self.send_ticket, - extra_exts: self.extra_exts, - } - .handle_client_hello(cx, certkey, m, client_hello, sig_schemes), - #[cfg(feature = "tls12")] - SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling { - config: self.config, - transcript, - session_id: self.session_id, - suite, - using_ems: self.using_ems, - randoms, - send_ticket: self.send_ticket, - extra_exts: self.extra_exts, - } - .handle_client_hello( - cx, - certkey, - m, - client_hello, - sig_schemes, - tls13_enabled, - ), - } - } -} - -impl State for ExpectClientHello { - fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> NextStateOrError { - let (client_hello, sig_schemes) = - process_client_hello(&m, self.done_retry, cx.common, cx.data)?; - self.with_certified_key(sig_schemes, client_hello, &m, cx) - } -} - -/// Configuration-independent validation of a `ClientHello` message. -/// -/// This represents the first part of the `ClientHello` handling, where we do all validation that -/// doesn't depend on a `ServerConfig` being available and extract everything needed to build a -/// [`ClientHello`] value for a [`ResolvesServerConfig`]/`ResolvesServerCert`]. -/// -/// Note that this will modify `data.sni` even if config or certificate resolution fail. -pub(super) fn process_client_hello<'a>( - m: &'a Message, - done_retry: bool, - common: &mut CommonState, - data: &mut ServerConnectionData, -) -> Result<(&'a ClientHelloPayload, Vec), Error> { - let client_hello = - require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; - trace!("we got a clienthello {:?}", client_hello); - - if !client_hello - .compression_methods - .contains(&Compression::Null) - { - common.send_fatal_alert(AlertDescription::IllegalParameter); - return Err(Error::PeerIncompatibleError( - "client did not offer Null compression".to_string(), - )); - } - - if client_hello.has_duplicate_extension() { - return Err(decode_error(common, "client sent duplicate extensions")); - } - - // No handshake messages should follow this one in this flight. - common.check_aligned_handshake()?; - - // Extract and validate the SNI DNS name, if any, before giving it to - // the cert resolver. In particular, if it is invalid then we should - // send an Illegal Parameter alert instead of the Internal Error alert - // (or whatever) that we'd send if this were checked later or in a - // different way. - let sni: Option = match client_hello.get_sni_extension() { - Some(sni) => { - if sni.has_duplicate_names_for_type() { - return Err(decode_error( - common, - "ClientHello SNI contains duplicate name types", - )); - } - - if let Some(hostname) = sni.get_single_hostname() { - Some(hostname.into()) - } else { - return Err(common.illegal_param("ClientHello SNI did not contain a hostname")); - } - } - None => None, - }; - - // save only the first SNI - if let (Some(sni), false) = (&sni, done_retry) { - // Save the SNI into the session. - // The SNI hostname is immutable once set. - assert!(data.sni.is_none()); - data.sni = Some(sni.clone()) - } else if data.sni != sni { - return Err(Error::PeerIncompatibleError( - "SNI differed on retry".to_string(), - )); - } - - let sig_schemes = client_hello - .get_sigalgs_extension() - .ok_or_else(|| incompatible(common, "client didn't describe signature schemes"))? - .clone(); - - Ok((client_hello, sig_schemes)) -} - -#[allow(clippy::large_enum_variant)] -pub(crate) enum HandshakeHashOrBuffer { - Buffer(HandshakeHashBuffer), - Hash(HandshakeHash), -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/server_conn.rs b/third_party/rustls-fork-shadow-tls/src/server/server_conn.rs deleted file mode 100644 index cf8669b..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/server_conn.rs +++ /dev/null @@ -1,849 +0,0 @@ -use crate::builder::{ConfigBuilder, WantsCipherSuites}; -use crate::conn::{CommonState, ConnectionCommon, Side, State}; -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::kx::SupportedKxGroup; -#[cfg(feature = "logging")] -use crate::log::trace; -use crate::msgs::base::{Payload, PayloadU8}; -#[cfg(feature = "quic")] -use crate::msgs::enums::AlertDescription; -use crate::msgs::handshake::{ClientHelloPayload, ServerExtension}; -use crate::msgs::message::Message; -use crate::sign; -use crate::suites::SupportedCipherSuite; -use crate::vecbuf::ChunkVecBuffer; -use crate::verify; -#[cfg(feature = "secret_extraction")] -use crate::ExtractedSecrets; -use crate::KeyLog; -#[cfg(feature = "quic")] -use crate::{conn::Protocol, quic}; - -use super::hs; - -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::sync::Arc; -use std::{fmt, io}; - -/// A trait for the ability to store server session data. -/// -/// The keys and values are opaque. -/// -/// Both the keys and values should be treated as -/// **highly sensitive data**, containing enough key material -/// to break all security of the corresponding sessions. -/// -/// Implementations can be lossy (in other words, forgetting -/// key/value pairs) without any negative security consequences. -/// -/// However, note that `take` **must** reliably delete a returned -/// value. If it does not, there may be security consequences. -/// -/// `put` and `take` are mutating operations; this isn't expressed -/// in the type system to allow implementations freedom in -/// how to achieve interior mutability. `Mutex` is a common -/// choice. -pub trait StoresServerSessions: Send + Sync { - /// Store session secrets encoded in `value` against `key`, - /// overwrites any existing value against `key`. Returns `true` - /// if the value was stored. - fn put(&self, key: Vec, value: Vec) -> bool; - - /// Find a value with the given `key`. Return it, or None - /// if it doesn't exist. - fn get(&self, key: &[u8]) -> Option>; - - /// Find a value with the given `key`. Return it and delete it; - /// or None if it doesn't exist. - fn take(&self, key: &[u8]) -> Option>; - - /// Whether the store can cache another session. This is used to indicate to clients - /// whether their session can be resumed; the implementation is not required to remember - /// a session even if it returns `true` here. - fn can_cache(&self) -> bool; -} - -/// A trait for the ability to encrypt and decrypt tickets. -pub trait ProducesTickets: Send + Sync { - /// Returns true if this implementation will encrypt/decrypt - /// tickets. Should return false if this is a dummy - /// implementation: the server will not send the SessionTicket - /// extension and will not call the other functions. - fn enabled(&self) -> bool; - - /// Returns the lifetime in seconds of tickets produced now. - /// The lifetime is provided as a hint to clients that the - /// ticket will not be useful after the given time. - /// - /// This lifetime must be implemented by key rolling and - /// erasure, *not* by storing a lifetime in the ticket. - /// - /// The objective is to limit damage to forward secrecy caused - /// by tickets, not just limiting their lifetime. - fn lifetime(&self) -> u32; - - /// Encrypt and authenticate `plain`, returning the resulting - /// ticket. Return None if `plain` cannot be encrypted for - /// some reason: an empty ticket will be sent and the connection - /// will continue. - fn encrypt(&self, plain: &[u8]) -> Option>; - - /// Decrypt `cipher`, validating its authenticity protection - /// and recovering the plaintext. `cipher` is fully attacker - /// controlled, so this decryption must be side-channel free, - /// panic-proof, and otherwise bullet-proof. If the decryption - /// fails, return None. - fn decrypt(&self, cipher: &[u8]) -> Option>; -} - -/// How to choose a certificate chain and signing key for use -/// in server authentication. -pub trait ResolvesServerCert: Send + Sync { - /// Choose a certificate chain and matching key given simplified - /// ClientHello information. - /// - /// Return `None` to abort the handshake. - fn resolve(&self, client_hello: ClientHello) -> Option>; -} - -/// A struct representing the received Client Hello -pub struct ClientHello<'a> { - server_name: &'a Option, - signature_schemes: &'a [SignatureScheme], - alpn: Option<&'a Vec>, - cipher_suites: &'a [CipherSuite], -} - -impl<'a> ClientHello<'a> { - /// Creates a new ClientHello - pub(super) fn new( - server_name: &'a Option, - signature_schemes: &'a [SignatureScheme], - alpn: Option<&'a Vec>, - cipher_suites: &'a [CipherSuite], - ) -> Self { - trace!("sni {:?}", server_name); - trace!("sig schemes {:?}", signature_schemes); - trace!("alpn protocols {:?}", alpn); - trace!("cipher suites {:?}", cipher_suites); - - ClientHello { - server_name, - signature_schemes, - alpn, - cipher_suites, - } - } - - /// Get the server name indicator. - /// - /// Returns `None` if the client did not supply a SNI. - pub fn server_name(&self) -> Option<&str> { - self.server_name - .as_ref() - .map(>::as_ref) - } - - /// Get the compatible signature schemes. - /// - /// Returns standard-specified default if the client omitted this extension. - pub fn signature_schemes(&self) -> &[SignatureScheme] { - self.signature_schemes - } - - /// Get the ALPN protocol identifiers submitted by the client. - /// - /// Returns `None` if the client did not include an ALPN extension. - /// - /// Application Layer Protocol Negotiation (ALPN) is a TLS extension that lets a client - /// submit a set of identifiers that each a represent an application-layer protocol. - /// The server will then pick its preferred protocol from the set submitted by the client. - /// Each identifier is represented as a byte array, although common values are often ASCII-encoded. - /// See the official RFC-7301 specifications at - /// for more information on ALPN. - /// - /// For example, a HTTP client might specify "http/1.1" and/or "h2". Other well-known values - /// are listed in the at IANA registry at - /// . - /// - /// The server can specify supported ALPN protocols by setting [`ServerConfig::alpn_protocols`]. - /// During the handshake, the server will select the first protocol configured that the client supports. - pub fn alpn(&self) -> Option> { - self.alpn.map(|protocols| { - protocols - .iter() - .map(|proto| proto.0.as_slice()) - }) - } - - /// Get cipher suites. - pub fn cipher_suites(&self) -> &[CipherSuite] { - self.cipher_suites - } -} - -/// Common configuration for a set of server sessions. -/// -/// Making one of these can be expensive, and should be -/// once per process rather than once per connection. -/// -/// These must be created via the [`ServerConfig::builder()`] function. -/// -/// # Defaults -/// -/// * [`ServerConfig::max_fragment_size`]: the default is `None`: TLS packets are not fragmented to a specific size. -/// * [`ServerConfig::session_storage`]: the default stores 256 sessions in memory. -/// * [`ServerConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. -/// * [`ServerConfig::key_log`]: key material is not logged. -#[derive(Clone)] -pub struct ServerConfig { - /// List of ciphersuites, in preference order. - pub(super) cipher_suites: Vec, - - /// List of supported key exchange groups. - /// - /// The first is the highest priority: they will be - /// offered to the client in this order. - pub(super) kx_groups: Vec<&'static SupportedKxGroup>, - - /// Ignore the client's ciphersuite order. Instead, - /// choose the top ciphersuite in the server list - /// which is supported by the client. - pub ignore_client_order: bool, - - /// The maximum size of TLS message we'll emit. If None, we don't limit TLS - /// message lengths except to the 2**16 limit specified in the standard. - /// - /// rustls enforces an arbitrary minimum of 32 bytes for this field. - /// Out of range values are reported as errors from ServerConnection::new. - /// - /// Setting this value to the TCP MSS may improve latency for stream-y workloads. - pub max_fragment_size: Option, - - /// How to store client sessions. - pub session_storage: Arc, - - /// How to produce tickets. - pub ticketer: Arc, - - /// How to choose a server cert and key. - pub cert_resolver: Arc, - - /// Protocol names we support, most preferred first. - /// If empty we don't do ALPN at all. - pub alpn_protocols: Vec>, - - /// Supported protocol versions, in no particular order. - /// The default is all supported versions. - pub(super) versions: crate::versions::EnabledVersions, - - /// How to verify client certificates. - pub(super) verifier: Arc, - - /// How to output key material for debugging. The default - /// does nothing. - pub key_log: Arc, - - /// Allows traffic secrets to be extracted after the handshake, - /// e.g. for kTLS setup. - #[cfg(feature = "secret_extraction")] - pub enable_secret_extraction: bool, - - /// Amount of early data to accept for sessions created by - /// this config. Specify 0 to disable early data. The - /// default is 0. - /// - /// Read the early data via [`ServerConnection::early_data`]. - /// - /// The units for this are _both_ plaintext bytes, _and_ ciphertext - /// bytes, depending on whether the server accepts a client's early_data - /// or not. It is therefore recommended to include some slop in - /// this value to account for the unknown amount of ciphertext - /// expansion in the latter case. - pub max_early_data_size: u32, - - /// Whether the server should send "0.5RTT" data. This means the server - /// sends data after its first flight of handshake messages, without - /// waiting for the client to complete the handshake. - /// - /// This can improve TTFB latency for either server-speaks-first protocols, - /// or client-speaks-first protocols when paired with "0RTT" data. This - /// comes at the cost of a subtle weakening of the normal handshake - /// integrity guarantees that TLS provides. Note that the initial - /// `ClientHello` is indirectly authenticated because it is included - /// in the transcript used to derive the keys used to encrypt the data. - /// - /// This only applies to TLS1.3 connections. TLS1.2 connections cannot - /// do this optimisation and this setting is ignored for them. It is - /// also ignored for TLS1.3 connections that even attempt client - /// authentication. - /// - /// This defaults to false. This means the first application data - /// sent by the server comes after receiving and validating the client's - /// handshake up to the `Finished` message. This is the safest option. - pub send_half_rtt_data: bool, -} - -impl fmt::Debug for ServerConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ServerConfig") - .field("ignore_client_order", &self.ignore_client_order) - .field("max_fragment_size", &self.max_fragment_size) - .field("alpn_protocols", &self.alpn_protocols) - .field("max_early_data_size", &self.max_early_data_size) - .field("send_half_rtt_data", &self.send_half_rtt_data) - .finish_non_exhaustive() - } -} - -impl ServerConfig { - /// Create builder to build up the server configuration. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - pub fn builder() -> ConfigBuilder { - ConfigBuilder { - state: WantsCipherSuites(()), - side: PhantomData::default(), - } - } - - #[doc(hidden)] - /// We support a given TLS version if it's quoted in the configured - /// versions *and* at least one ciphersuite for this version is - /// also configured. - pub fn supports_version(&self, v: ProtocolVersion) -> bool { - self.versions.contains(v) - && self - .cipher_suites - .iter() - .any(|cs| cs.version().version == v) - } -} - -/// Allows reading of early data in resumed TLS1.3 connections. -/// -/// "Early data" is also known as "0-RTT data". -/// -/// This structure implements [`std::io::Read`]. -pub struct ReadEarlyData<'a> { - early_data: &'a mut EarlyDataState, -} - -impl<'a> ReadEarlyData<'a> { - fn new(early_data: &'a mut EarlyDataState) -> Self { - ReadEarlyData { early_data } - } -} - -impl<'a> std::io::Read for ReadEarlyData<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.early_data.read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: io::BorrowedCursor<'_>) -> io::Result<()> { - self.early_data.read_buf(cursor) - } -} - -/// This represents a single TLS server connection. -/// -/// Send TLS-protected data to the peer using the `io::Write` trait implementation. -/// Read data from the peer using the `io::Read` trait implementation. -pub struct ServerConnection { - inner: ConnectionCommon, -} - -impl ServerConnection { - /// Make a new ServerConnection. `config` controls how - /// we behave in the TLS protocol. - pub fn new(config: Arc) -> Result { - Self::from_config(config, vec![]) - } - - fn from_config( - config: Arc, - extra_exts: Vec, - ) -> Result { - let mut common = CommonState::new(Side::Server); - common.set_max_fragment_size(config.max_fragment_size)?; - #[cfg(feature = "secret_extraction")] - { - common.enable_secret_extraction = config.enable_secret_extraction; - } - Ok(Self { - inner: ConnectionCommon::new( - Box::new(hs::ExpectClientHello::new(config, extra_exts)), - ServerConnectionData::default(), - common, - ), - }) - } - - /// Retrieves the SNI hostname, if any, used to select the certificate and - /// private key. - /// - /// This returns `None` until some time after the client's SNI extension - /// value is processed during the handshake. It will never be `None` when - /// the connection is ready to send or process application data, unless the - /// client does not support SNI. - /// - /// This is useful for application protocols that need to enforce that the - /// SNI hostname matches an application layer protocol hostname. For - /// example, HTTP/1.1 servers commonly expect the `Host:` header field of - /// every request on a connection to match the hostname in the SNI extension - /// when the client provides the SNI extension. - /// - /// The SNI hostname is also used to match sessions during session - /// resumption. - pub fn sni_hostname(&self) -> Option<&str> { - self.inner.data.get_sni_str() - } - - /// Application-controlled portion of the resumption ticket supplied by the client, if any. - /// - /// Recovered from the prior session's `set_resumption_data`. Integrity is guaranteed by rustls. - /// - /// Returns `Some` iff a valid resumption ticket has been received from the client. - pub fn received_resumption_data(&self) -> Option<&[u8]> { - self.inner - .data - .received_resumption_data - .as_ref() - .map(|x| &x[..]) - } - - /// Set the resumption data to embed in future resumption tickets supplied to the client. - /// - /// Defaults to the empty byte string. Must be less than 2^15 bytes to allow room for other - /// data. Should be called while `is_handshaking` returns true to ensure all transmitted - /// resumption tickets are affected. - /// - /// Integrity will be assured by rustls, but the data will be visible to the client. If secrecy - /// from the client is desired, encrypt the data separately. - pub fn set_resumption_data(&mut self, data: &[u8]) { - assert!(data.len() < 2usize.pow(15)); - self.inner.data.resumption_data = data.into(); - } - - /// Explicitly discard early data, notifying the client - /// - /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. - /// - /// Must be called while `is_handshaking` is true. - pub fn reject_early_data(&mut self) { - assert!( - self.is_handshaking(), - "cannot retroactively reject early data" - ); - self.inner.data.early_data.reject(); - } - - /// Returns an `io::Read` implementer you can read bytes from that are - /// received from a client as TLS1.3 0RTT/"early" data, during the handshake. - /// - /// This returns `None` in many circumstances, such as : - /// - /// - Early data is disabled if [`ServerConfig::max_early_data_size`] is zero (the default). - /// - The session negotiated with the client is not TLS1.3. - /// - The client just doesn't support early data. - /// - The connection doesn't resume an existing session. - /// - The client hasn't sent a full ClientHello yet. - pub fn early_data(&mut self) -> Option { - if self - .inner - .data - .early_data - .was_accepted() - { - Some(ReadEarlyData::new(&mut self.inner.data.early_data)) - } else { - None - } - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - #[cfg(feature = "secret_extraction")] - pub fn extract_secrets(self) -> Result { - self.inner.extract_secrets() - } -} - -impl fmt::Debug for ServerConnection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ServerConnection") - .finish() - } -} - -impl Deref for ServerConnection { - type Target = ConnectionCommon; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for ServerConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl From for crate::Connection { - fn from(conn: ServerConnection) -> Self { - Self::Server(conn) - } -} - -/// Handle on a server-side connection before configuration is available. -/// -/// The `Acceptor` allows the caller to provide a [`ServerConfig`] based on the [`ClientHello`] of -/// the incoming connection. -pub struct Acceptor { - inner: Option>, -} - -impl Default for Acceptor { - fn default() -> Self { - Self { - inner: Some(ConnectionCommon::new( - Box::new(Accepting), - ServerConnectionData::default(), - CommonState::new(Side::Server), - )), - } - } -} - -impl Acceptor { - /// Create a new `Acceptor`. - #[deprecated( - since = "0.20.7", - note = "Use Acceptor::default instead for an infallible constructor" - )] - pub fn new() -> Result { - Ok(Self::default()) - } - - /// Returns true if the caller should call [`Connection::read_tls()`] as soon as possible. - /// - /// Since the purpose of an Acceptor is to read and then parse TLS bytes, this always returns true. - /// - /// [`Connection::read_tls()`]: crate::Connection::read_tls - #[deprecated(since = "0.20.7", note = "Always returns true")] - pub fn wants_read(&self) -> bool { - self.inner - .as_ref() - .map(|conn| conn.common_state.wants_read()) - .unwrap_or(false) - } - - /// Read TLS content from `rd`. - /// - /// Returns an error if this `Acceptor` has already yielded an [`Accepted`]. For more details, - /// refer to [`Connection::read_tls()`]. - /// - /// [`Connection::read_tls()`]: crate::Connection::read_tls - pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result { - match &mut self.inner { - Some(conn) => conn.read_tls(rd), - None => Err(io::Error::new( - io::ErrorKind::Other, - "acceptor cannot read after successful acceptance", - )), - } - } - - /// Check if a `ClientHello` message has been received. - /// - /// Returns `Ok(None)` if the complete `ClientHello` has not yet been received. - /// Do more I/O and then call this function again. - /// - /// Returns `Ok(Some(accepted))` if the connection has been accepted. Call - /// `accepted.into_connection()` to continue. Do not call this function again. - /// - /// Returns `Err(err)` if an error occurred. Do not call this function again. - pub fn accept(&mut self) -> Result, Error> { - let mut connection = match self.inner.take() { - Some(conn) => conn, - None => { - return Err(Error::General("Acceptor polled after completion".into())); - } - }; - - let message = match connection.first_handshake_message()? { - Some(msg) => msg, - None => { - self.inner = Some(connection); - return Ok(None); - } - }; - - let (_, sig_schemes) = hs::process_client_hello( - &message, - false, - &mut connection.common_state, - &mut connection.data, - )?; - - Ok(Some(Accepted { - connection, - message, - sig_schemes, - })) - } -} - -/// Represents a `ClientHello` message received through the [`Acceptor`]. -/// -/// Contains the state required to resume the connection through [`Accepted::into_connection()`]. -pub struct Accepted { - connection: ConnectionCommon, - message: Message, - sig_schemes: Vec, -} - -impl Accepted { - /// Get the [`ClientHello`] for this connection. - pub fn client_hello(&self) -> ClientHello<'_> { - let payload = Self::client_hello_payload(&self.message); - ClientHello::new( - &self.connection.data.sni, - &self.sig_schemes, - payload.get_alpn_extension(), - &payload.cipher_suites, - ) - } - - /// Convert the [`Accepted`] into a [`ServerConnection`]. - /// - /// Takes the state returned from [`Acceptor::accept()`] as well as the [`ServerConfig`] and - /// [`sign::CertifiedKey`] that should be used for the session. Returns an error if - /// configuration-dependent validation of the received `ClientHello` message fails. - pub fn into_connection(mut self, config: Arc) -> Result { - self.connection - .common_state - .set_max_fragment_size(config.max_fragment_size)?; - - #[cfg(feature = "secret_extraction")] - { - self.connection - .common_state - .enable_secret_extraction = config.enable_secret_extraction; - } - - let state = hs::ExpectClientHello::new(config, Vec::new()); - let mut cx = hs::ServerContext { - common: &mut self.connection.common_state, - data: &mut self.connection.data, - }; - - let new = state.with_certified_key( - self.sig_schemes, - Self::client_hello_payload(&self.message), - &self.message, - &mut cx, - )?; - - self.connection.replace_state(new); - Ok(ServerConnection { - inner: self.connection, - }) - } - - fn client_hello_payload(message: &Message) -> &ClientHelloPayload { - match &message.payload { - crate::msgs::message::MessagePayload::Handshake { parsed, .. } => match &parsed.payload - { - crate::msgs::handshake::HandshakePayload::ClientHello(ch) => ch, - _ => unreachable!(), - }, - _ => unreachable!(), - } - } -} - -struct Accepting; - -impl State for Accepting { - fn handle( - self: Box, - _cx: &mut hs::ServerContext<'_>, - _m: Message, - ) -> Result>, Error> { - Err(Error::General("unreachable state".into())) - } -} - -pub(super) enum EarlyDataState { - New, - Accepted(ChunkVecBuffer), - Rejected, -} - -impl Default for EarlyDataState { - fn default() -> Self { - Self::New - } -} - -impl EarlyDataState { - pub(super) fn reject(&mut self) { - *self = Self::Rejected; - } - - pub(super) fn accept(&mut self, max_size: usize) { - *self = Self::Accepted(ChunkVecBuffer::new(Some(max_size))); - } - - fn was_accepted(&self) -> bool { - matches!(self, Self::Accepted(_)) - } - - pub(super) fn was_rejected(&self) -> bool { - matches!(self, Self::Rejected) - } - - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self { - Self::Accepted(ref mut received) => received.read(buf), - _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), - } - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: io::BorrowedCursor<'_>) -> io::Result<()> { - match self { - Self::Accepted(ref mut received) => received.read_buf(cursor), - _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), - } - } - - pub(super) fn take_received_plaintext(&mut self, bytes: Payload) -> bool { - let available = bytes.0.len(); - match self { - Self::Accepted(ref mut received) if received.apply_limit(available) == available => { - received.append(bytes.0); - true - } - _ => false, - } - } -} - -// these branches not reachable externally, unless something else goes wrong. -#[test] -fn test_read_in_new_state() { - assert_eq!( - format!("{:?}", EarlyDataState::default().read(&mut [0u8; 5])), - "Err(Kind(BrokenPipe))" - ); -} - -#[cfg(read_buf)] -#[test] -fn test_read_buf_in_new_state() { - use std::io::BorrowedBuf; - - let mut buf = [0u8; 5]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - assert_eq!( - format!("{:?}", EarlyDataState::default().read_buf(buf.unfilled())), - "Err(Kind(BrokenPipe))" - ); -} - -/// State associated with a server connection. -#[derive(Default)] -pub struct ServerConnectionData { - pub(super) sni: Option, - pub(super) received_resumption_data: Option>, - pub(super) resumption_data: Vec, - pub(super) early_data: EarlyDataState, -} - -impl ServerConnectionData { - pub(super) fn get_sni_str(&self) -> Option<&str> { - self.sni.as_ref().map(AsRef::as_ref) - } -} - -impl crate::conn::SideData for ServerConnectionData {} - -#[cfg(feature = "quic")] -impl quic::QuicExt for ServerConnection { - fn quic_transport_parameters(&self) -> Option<&[u8]> { - self.inner - .common_state - .quic - .params - .as_ref() - .map(|v| v.as_ref()) - } - - fn zero_rtt_keys(&self) -> Option { - Some(quic::DirectionalKeys::new( - self.inner - .common_state - .suite - .and_then(|suite| suite.tls13())?, - self.inner - .common_state - .quic - .early_secret - .as_ref()?, - )) - } - - fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - self.inner.read_quic_hs(plaintext) - } - - fn write_hs(&mut self, buf: &mut Vec) -> Option { - quic::write_hs(&mut self.inner.common_state, buf) - } - - fn alert(&self) -> Option { - self.inner.common_state.quic.alert - } -} - -/// Methods specific to QUIC server sessions -#[cfg(feature = "quic")] -#[cfg_attr(docsrs, doc(cfg(feature = "quic")))] -pub trait ServerQuicExt { - /// Make a new QUIC ServerConnection. This differs from `ServerConnection::new()` - /// in that it takes an extra argument, `params`, which contains the - /// TLS-encoded transport parameters to send. - fn new_quic( - config: Arc, - quic_version: quic::Version, - params: Vec, - ) -> Result { - if !config.supports_version(ProtocolVersion::TLSv1_3) { - return Err(Error::General( - "TLS 1.3 support is required for QUIC".into(), - )); - } - - if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff { - return Err(Error::General( - "QUIC sessions must set a max early data of 0 or 2^32-1".into(), - )); - } - - let ext = match quic_version { - quic::Version::V1Draft => ServerExtension::TransportParametersDraft(params), - quic::Version::V1 => ServerExtension::TransportParameters(params), - }; - let mut new = ServerConnection::from_config(config, vec![ext])?; - new.inner.common_state.protocol = Protocol::Quic; - Ok(new) - } -} - -#[cfg(feature = "quic")] -impl ServerQuicExt for ServerConnection {} diff --git a/third_party/rustls-fork-shadow-tls/src/server/tls12.rs b/third_party/rustls-fork-shadow-tls/src/server/tls12.rs deleted file mode 100644 index 45b6c78..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/tls12.rs +++ /dev/null @@ -1,941 +0,0 @@ -use crate::check::inappropriate_message; -use crate::conn::{CommonState, ConnectionRandoms, Side, State}; -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::hash_hs::HandshakeHash; -use crate::key::Certificate; -#[cfg(feature = "logging")] -use crate::log::{debug, trace}; -use crate::msgs::base::Payload; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::Codec; -use crate::msgs::enums::{AlertDescription, ContentType, HandshakeType}; -use crate::msgs::handshake::{ClientECDHParams, HandshakeMessagePayload, HandshakePayload}; -use crate::msgs::handshake::{NewSessionTicketPayload, SessionID}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -#[cfg(feature = "secret_extraction")] -use crate::suites::PartiallyExtractedSecrets; -use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; -use crate::{kx, ticketer, verify}; - -use super::common::ActiveCertifiedKey; -use super::hs::{self, ServerContext}; -use super::server_conn::{ProducesTickets, ServerConfig, ServerConnectionData}; - -use ring::constant_time; - -use std::sync::Arc; - -pub(super) use client_hello::CompleteClientHelloHandling; - -mod client_hello { - use crate::enums::SignatureScheme; - use crate::msgs::enums::ECPointFormat; - use crate::msgs::enums::{ClientCertificateType, Compression}; - use crate::msgs::handshake::{CertificateRequestPayload, ClientSessionTicket, Random}; - use crate::msgs::handshake::{ - CertificateStatus, DigitallySignedStruct, ECDHEServerKeyExchange, - }; - use crate::msgs::handshake::{ClientExtension, SessionID}; - use crate::msgs::handshake::{ClientHelloPayload, ServerHelloPayload}; - use crate::msgs::handshake::{ECPointFormatList, ServerECDHParams, SupportedPointFormats}; - use crate::msgs::handshake::{ServerExtension, ServerKeyExchangePayload}; - use crate::sign; - - use super::*; - - pub(in crate::server) struct CompleteClientHelloHandling { - pub(in crate::server) config: Arc, - pub(in crate::server) transcript: HandshakeHash, - pub(in crate::server) session_id: SessionID, - pub(in crate::server) suite: &'static Tls12CipherSuite, - pub(in crate::server) using_ems: bool, - pub(in crate::server) randoms: ConnectionRandoms, - pub(in crate::server) send_ticket: bool, - pub(in crate::server) extra_exts: Vec, - } - - impl CompleteClientHelloHandling { - pub(in crate::server) fn handle_client_hello( - mut self, - cx: &mut ServerContext<'_>, - server_key: ActiveCertifiedKey, - chm: &Message, - client_hello: &ClientHelloPayload, - sigschemes_ext: Vec, - tls13_enabled: bool, - ) -> hs::NextStateOrError { - // -- TLS1.2 only from hereon in -- - self.transcript.add_message(chm); - - if client_hello.ems_support_offered() { - self.using_ems = true; - } - - let groups_ext = client_hello - .get_namedgroups_extension() - .ok_or_else(|| hs::incompatible(cx.common, "client didn't describe groups"))?; - let ecpoints_ext = client_hello - .get_ecpoints_extension() - .ok_or_else(|| hs::incompatible(cx.common, "client didn't describe ec points"))?; - - trace!("namedgroups {:?}", groups_ext); - trace!("ecpoints {:?}", ecpoints_ext); - - if !ecpoints_ext.contains(&ECPointFormat::Uncompressed) { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter); - return Err(Error::PeerIncompatibleError( - "client didn't support uncompressed ec points".to_string(), - )); - } - - // -- If TLS1.3 is enabled, signal the downgrade in the server random - if tls13_enabled { - self.randoms.server[24..].copy_from_slice(&tls12::DOWNGRADE_SENTINEL); - } - - // -- Check for resumption -- - // We can do this either by (in order of preference): - // 1. receiving a ticket that decrypts - // 2. receiving a sessionid that is in our cache - // - // If we receive a ticket, the sessionid won't be in our - // cache, so don't check. - // - // If either works, we end up with a ServerConnectionValue - // which is passed to start_resumption and concludes - // our handling of the ClientHello. - // - let mut ticket_received = false; - let resume_data = client_hello - .get_ticket_extension() - .and_then(|ticket_ext| match ticket_ext { - ClientExtension::SessionTicket(ClientSessionTicket::Offer(ticket)) => { - Some(ticket) - } - _ => None, - }) - .and_then(|ticket| { - ticket_received = true; - debug!("Ticket received"); - let data = self.config.ticketer.decrypt(&ticket.0); - if data.is_none() { - debug!("Ticket didn't decrypt"); - } - data - }) - .or_else(|| { - // Perhaps resume? If we received a ticket, the sessionid - // does not correspond to a real session. - if client_hello.session_id.is_empty() || ticket_received { - return None; - } - - self.config - .session_storage - .get(&client_hello.session_id.get_encoding()) - }) - .and_then(|x| persist::ServerSessionValue::read_bytes(&x)) - .filter(|resumedata| { - hs::can_resume(self.suite.into(), &cx.data.sni, self.using_ems, resumedata) - }); - - if let Some(data) = resume_data { - return self.start_resumption(cx, client_hello, &client_hello.session_id, data); - } - - // Now we have chosen a ciphersuite, we can make kx decisions. - let sigschemes = self - .suite - .resolve_sig_schemes(&sigschemes_ext); - - if sigschemes.is_empty() { - return Err(hs::incompatible(cx.common, "no overlapping sigschemes")); - } - - let group = self - .config - .kx_groups - .iter() - .find(|skxg| groups_ext.contains(&skxg.name)) - .cloned() - .ok_or_else(|| hs::incompatible(cx.common, "no supported group"))?; - - let ecpoint = ECPointFormatList::supported() - .iter() - .find(|format| ecpoints_ext.contains(format)) - .cloned() - .ok_or_else(|| hs::incompatible(cx.common, "no supported point format"))?; - - debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed); - - let (mut ocsp_response, mut sct_list) = - (server_key.get_ocsp(), server_key.get_sct_list()); - - // If we're not offered a ticket or a potential session ID, allocate a session ID. - if !self.config.session_storage.can_cache() { - self.session_id = SessionID::empty(); - } else if self.session_id.is_empty() && !ticket_received { - self.session_id = SessionID::random()?; - } - - self.send_ticket = emit_server_hello( - &self.config, - &mut self.transcript, - cx, - self.session_id, - self.suite, - self.using_ems, - &mut ocsp_response, - &mut sct_list, - client_hello, - None, - &self.randoms, - self.extra_exts, - )?; - emit_certificate(&mut self.transcript, cx.common, server_key.get_cert()); - if let Some(ocsp_response) = ocsp_response { - emit_cert_status(&mut self.transcript, cx.common, ocsp_response); - } - let server_kx = emit_server_kx( - &mut self.transcript, - cx.common, - sigschemes, - group, - server_key.get_key(), - &self.randoms, - )?; - let doing_client_auth = emit_certificate_req(&self.config, &mut self.transcript, cx)?; - emit_server_hello_done(&mut self.transcript, cx.common); - - if doing_client_auth { - Ok(Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx, - send_ticket: self.send_ticket, - })) - } else { - Ok(Box::new(ExpectClientKx { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx, - client_cert: None, - send_ticket: self.send_ticket, - })) - } - } - - fn start_resumption( - mut self, - cx: &mut ServerContext<'_>, - client_hello: &ClientHelloPayload, - id: &SessionID, - resumedata: persist::ServerSessionValue, - ) -> hs::NextStateOrError { - debug!("Resuming connection"); - - if resumedata.extended_ms && !self.using_ems { - return Err(cx - .common - .illegal_param("refusing to resume without ems")); - } - - self.session_id = *id; - self.send_ticket = emit_server_hello( - &self.config, - &mut self.transcript, - cx, - self.session_id, - self.suite, - self.using_ems, - &mut None, - &mut None, - client_hello, - Some(&resumedata), - &self.randoms, - self.extra_exts, - )?; - - let secrets = ConnectionSecrets::new_resume( - self.randoms, - self.suite, - &resumedata.master_secret.0, - ); - self.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Server); - cx.common.peer_certificates = resumedata.client_cert_chain; - - if self.send_ticket { - emit_ticket( - &secrets, - &mut self.transcript, - self.using_ems, - cx, - &*self.config.ticketer, - )?; - } - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&secrets, &mut self.transcript, cx.common); - - Ok(Box::new(ExpectCcs { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: true, - send_ticket: self.send_ticket, - })) - } - } - - fn emit_server_hello( - config: &ServerConfig, - transcript: &mut HandshakeHash, - cx: &mut ServerContext<'_>, - session_id: SessionID, - suite: &'static Tls12CipherSuite, - using_ems: bool, - ocsp_response: &mut Option<&[u8]>, - sct_list: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - randoms: &ConnectionRandoms, - extra_exts: Vec, - ) -> Result { - let mut ep = hs::ExtensionProcessing::new(); - ep.process_common( - config, - cx, - ocsp_response, - sct_list, - hello, - resumedata, - extra_exts, - )?; - ep.process_tls12(config, hello, using_ems); - - let sh = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ServerHello, - payload: HandshakePayload::ServerHello(ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from(randoms.server), - session_id, - cipher_suite: suite.common.suite, - compression_method: Compression::Null, - extensions: ep.exts, - }), - }), - }; - - trace!("sending server hello {:?}", sh); - transcript.add_message(&sh); - cx.common.send_msg(sh, false); - Ok(ep.send_ticket) - } - - fn emit_certificate( - transcript: &mut HandshakeHash, - common: &mut CommonState, - cert_chain: &[Certificate], - ) { - let c = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::Certificate(cert_chain.to_owned()), - }), - }; - - transcript.add_message(&c); - common.send_msg(c, false); - } - - fn emit_cert_status(transcript: &mut HandshakeHash, common: &mut CommonState, ocsp: &[u8]) { - let st = CertificateStatus::new(ocsp.to_owned()); - - let c = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateStatus, - payload: HandshakePayload::CertificateStatus(st), - }), - }; - - transcript.add_message(&c); - common.send_msg(c, false); - } - - fn emit_server_kx( - transcript: &mut HandshakeHash, - common: &mut CommonState, - sigschemes: Vec, - skxg: &'static kx::SupportedKxGroup, - signing_key: &dyn sign::SigningKey, - randoms: &ConnectionRandoms, - ) -> Result { - let kx = kx::KeyExchange::start(skxg).ok_or(Error::FailedToGetRandomBytes)?; - let secdh = ServerECDHParams::new(skxg.name, kx.pubkey.as_ref()); - - let mut msg = Vec::new(); - msg.extend(randoms.client); - msg.extend(randoms.server); - secdh.encode(&mut msg); - - let signer = signing_key - .choose_scheme(&sigschemes) - .ok_or_else(|| Error::General("incompatible signing key".to_string()))?; - let sigscheme = signer.scheme(); - let sig = signer.sign(&msg)?; - - let skx = ServerKeyExchangePayload::ECDHE(ECDHEServerKeyExchange { - params: secdh, - dss: DigitallySignedStruct::new(sigscheme, sig), - }); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ServerKeyExchange, - payload: HandshakePayload::ServerKeyExchange(skx), - }), - }; - - transcript.add_message(&m); - common.send_msg(m, false); - Ok(kx) - } - - fn emit_certificate_req( - config: &ServerConfig, - transcript: &mut HandshakeHash, - cx: &mut ServerContext<'_>, - ) -> Result { - let client_auth = &config.verifier; - - if !client_auth.offer_client_auth() { - return Ok(false); - } - - let verify_schemes = client_auth.supported_verify_schemes(); - - let names = client_auth - .client_auth_root_subjects() - .ok_or_else(|| { - debug!("could not determine root subjects based on SNI"); - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Error::General("client rejected by client_auth_root_subjects".into()) - })?; - - let cr = CertificateRequestPayload { - certtypes: vec![ - ClientCertificateType::RSASign, - ClientCertificateType::ECDSASign, - ], - sigschemes: verify_schemes, - canames: names, - }; - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateRequest, - payload: HandshakePayload::CertificateRequest(cr), - }), - }; - - trace!("Sending CertificateRequest {:?}", m); - transcript.add_message(&m); - cx.common.send_msg(m, false); - Ok(true) - } - - fn emit_server_hello_done(transcript: &mut HandshakeHash, common: &mut CommonState) { - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ServerHelloDone, - payload: HandshakePayload::ServerHelloDone, - }), - }; - - transcript.add_message(&m); - common.send_msg(m, false); - } -} - -// --- Process client's Certificate for client auth --- -struct ExpectCertificate { - config: Arc, - transcript: HandshakeHash, - randoms: ConnectionRandoms, - session_id: SessionID, - suite: &'static Tls12CipherSuite, - using_ems: bool, - server_kx: kx::KeyExchange, - send_ticket: bool, -} - -impl State for ExpectCertificate { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - self.transcript.add_message(&m); - let cert_chain = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::Certificate - )?; - - // If we can't determine if the auth is mandatory, abort - let mandatory = self - .config - .verifier - .client_auth_mandatory() - .ok_or_else(|| { - debug!("could not determine if client auth is mandatory based on SNI"); - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Error::General("client rejected by client_auth_mandatory".into()) - })?; - - trace!("certs {:?}", cert_chain); - - let client_cert = match cert_chain.split_first() { - None if mandatory => { - cx.common - .send_fatal_alert(AlertDescription::CertificateRequired); - return Err(Error::NoCertificatesPresented); - } - None => { - debug!("client auth requested but no certificate supplied"); - self.transcript.abandon_client_auth(); - None - } - Some((end_entity, intermediates)) => { - let now = std::time::SystemTime::now(); - self.config - .verifier - .verify_client_cert(end_entity, intermediates, now) - .map_err(|err| { - hs::incompatible(cx.common, "certificate invalid"); - err - })?; - - Some(cert_chain) - } - }; - - Ok(Box::new(ExpectClientKx { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx: self.server_kx, - client_cert, - send_ticket: self.send_ticket, - })) - } -} - -// --- Process client's KeyExchange --- -struct ExpectClientKx { - config: Arc, - transcript: HandshakeHash, - randoms: ConnectionRandoms, - session_id: SessionID, - suite: &'static Tls12CipherSuite, - using_ems: bool, - server_kx: kx::KeyExchange, - client_cert: Option>, - send_ticket: bool, -} - -impl State for ExpectClientKx { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let client_kx = require_handshake_msg!( - m, - HandshakeType::ClientKeyExchange, - HandshakePayload::ClientKeyExchange - )?; - self.transcript.add_message(&m); - let ems_seed = self - .using_ems - .then(|| self.transcript.get_current_hash()); - - // Complete key agreement, and set up encryption with the - // resulting premaster secret. - let peer_kx_params = - tls12::decode_ecdh_params::(cx.common, &client_kx.0)?; - let secrets = ConnectionSecrets::from_key_exchange( - self.server_kx, - &peer_kx_params.public.0, - ems_seed, - self.randoms, - self.suite, - )?; - - self.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Server); - - if let Some(client_cert) = self.client_cert { - Ok(Box::new(ExpectCertificateVerify { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - client_cert, - send_ticket: self.send_ticket, - })) - } else { - Ok(Box::new(ExpectCcs { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: false, - send_ticket: self.send_ticket, - })) - } - } -} - -// --- Process client's certificate proof --- -struct ExpectCertificateVerify { - config: Arc, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionID, - using_ems: bool, - client_cert: Vec, - send_ticket: bool, -} - -impl State for ExpectCertificateVerify { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let rc = { - let sig = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - - match self.transcript.take_handshake_buf() { - Some(msgs) => { - let certs = &self.client_cert; - self.config - .verifier - .verify_tls12_signature(&msgs, &certs[0], sig) - } - None => { - // This should be unreachable; the handshake buffer was initialized with - // client authentication if the verifier wants to offer it. - // `transcript.abandon_client_auth()` can extract it, but its only caller in - // this flow will also set `ExpectClientKx::client_cert` to `None`, making it - // impossible to reach this state. - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Err(Error::General("client authentication not set up".into())) - } - } - }; - - if let Err(e) = rc { - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - return Err(e); - } - - trace!("client CertificateVerify OK"); - cx.common.peer_certificates = Some(self.client_cert); - - self.transcript.add_message(&m); - Ok(Box::new(ExpectCcs { - config: self.config, - secrets: self.secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: false, - send_ticket: self.send_ticket, - })) - } -} - -// --- Process client's ChangeCipherSpec --- -struct ExpectCcs { - config: Arc, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionID, - using_ems: bool, - resuming: bool, - send_ticket: bool, -} - -impl State for ExpectCcs { - fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ChangeCipherSpec(..) => {} - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ChangeCipherSpec], - )) - } - } - - // CCS should not be received interleaved with fragmented handshake-level - // message. - cx.common.check_aligned_handshake()?; - - cx.common - .record_layer - .start_decrypting(); - Ok(Box::new(ExpectFinished { - config: self.config, - secrets: self.secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: self.resuming, - send_ticket: self.send_ticket, - })) - } -} - -// --- Process client's Finished --- -fn get_server_connection_value_tls12( - secrets: &ConnectionSecrets, - using_ems: bool, - cx: &ServerContext<'_>, - time_now: ticketer::TimeBase, -) -> persist::ServerSessionValue { - let version = ProtocolVersion::TLSv1_2; - let secret = secrets.get_master_secret(); - - let mut v = persist::ServerSessionValue::new( - cx.data.sni.as_ref(), - version, - secrets.suite().common.suite, - secret, - cx.common.peer_certificates.clone(), - cx.common.alpn_protocol.clone(), - cx.data.resumption_data.clone(), - time_now, - 0, - ); - - if using_ems { - v.set_extended_ms_used(); - } - - v -} - -fn emit_ticket( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - using_ems: bool, - cx: &mut ServerContext<'_>, - ticketer: &dyn ProducesTickets, -) -> Result<(), Error> { - let time_now = ticketer::TimeBase::now()?; - let plain = get_server_connection_value_tls12(secrets, using_ems, cx, time_now).get_encoding(); - - // If we can't produce a ticket for some reason, we can't - // report an error. Send an empty one. - let ticket = ticketer - .encrypt(&plain) - .unwrap_or_default(); - let ticket_lifetime = ticketer.lifetime(); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::NewSessionTicket, - payload: HandshakePayload::NewSessionTicket(NewSessionTicketPayload::new( - ticket_lifetime, - ticket, - )), - }), - }; - - transcript.add_message(&m); - cx.common.send_msg(m, false); - Ok(()) -} - -fn emit_ccs(common: &mut CommonState) { - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - - common.send_msg(m, false); -} - -fn emit_finished( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - common: &mut CommonState, -) { - let vh = transcript.get_current_hash(); - let verify_data = secrets.server_verify_data(&vh); - let verify_data_payload = Payload::new(verify_data); - - let f = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(verify_data_payload), - }), - }; - - transcript.add_message(&f); - common.send_msg(f, true); -} - -struct ExpectFinished { - config: Arc, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionID, - using_ems: bool, - resuming: bool, - send_ticket: bool, -} - -impl State for ExpectFinished { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - cx.common.check_aligned_handshake()?; - - let vh = self.transcript.get_current_hash(); - let expect_verify_data = self.secrets.client_verify_data(&vh); - - let _fin_verified = - constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) - .map_err(|_| { - cx.common - .send_fatal_alert(AlertDescription::DecryptError); - Error::DecryptError - }) - .map(|_| verify::FinishedMessageVerified::assertion())?; - - // Save connection, perhaps - if !self.resuming && !self.session_id.is_empty() { - let time_now = ticketer::TimeBase::now()?; - let value = - get_server_connection_value_tls12(&self.secrets, self.using_ems, cx, time_now); - - let worked = self - .config - .session_storage - .put(self.session_id.get_encoding(), value.get_encoding()); - if worked { - debug!("Session saved"); - } else { - debug!("Session not saved"); - } - } - - // Send our CCS and Finished. - self.transcript.add_message(&m); - if !self.resuming { - if self.send_ticket { - emit_ticket( - &self.secrets, - &mut self.transcript, - self.using_ems, - cx, - &*self.config.ticketer, - )?; - } - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&self.secrets, &mut self.transcript, cx.common); - } - - cx.common.start_traffic(); - Ok(Box::new(ExpectTraffic { - secrets: self.secrets, - _fin_verified, - })) - } -} - -// --- Process traffic --- -struct ExpectTraffic { - secrets: ConnectionSecrets, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic {} - -impl State for ExpectTraffic { - fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ApplicationData], - )); - } - } - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.secrets - .export_keying_material(output, label, context); - Ok(()) - } - - #[cfg(feature = "secret_extraction")] - fn extract_secrets(&self) -> Result { - self.secrets - .extract_secrets(Side::Server) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/server/tls13.rs b/third_party/rustls-fork-shadow-tls/src/server/tls13.rs deleted file mode 100644 index c7ec516..0000000 --- a/third_party/rustls-fork-shadow-tls/src/server/tls13.rs +++ /dev/null @@ -1,1386 +0,0 @@ -use crate::check::inappropriate_handshake_message; -use crate::conn::{CommonState, ConnectionRandoms, State}; -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::hash_hs::HandshakeHash; -use crate::key::Certificate; -#[cfg(feature = "logging")] -use crate::log::{debug, trace, warn}; -use crate::msgs::codec::Codec; -use crate::msgs::enums::{AlertDescription, KeyUpdateRequest}; -use crate::msgs::enums::{ContentType, HandshakeType}; -use crate::msgs::handshake::HandshakeMessagePayload; -use crate::msgs::handshake::HandshakePayload; -use crate::msgs::handshake::{NewSessionTicketExtension, NewSessionTicketPayloadTLS13}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::rand; -use crate::server::ServerConfig; -use crate::ticketer; -use crate::tls13::key_schedule::{KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending}; -use crate::tls13::Tls13CipherSuite; -use crate::verify; -#[cfg(feature = "quic")] -use crate::{check::inappropriate_message, conn::Protocol}; -#[cfg(feature = "secret_extraction")] -use crate::{conn::Side, suites::PartiallyExtractedSecrets}; - -use super::hs::{self, HandshakeHashOrBuffer, ServerContext}; -use super::server_conn::ServerConnectionData; - -use std::sync::Arc; - -use ring::constant_time; - -pub(super) use client_hello::CompleteClientHelloHandling; - -mod client_hello { - use crate::enums::SignatureScheme; - use crate::kx; - use crate::msgs::base::{Payload, PayloadU8}; - use crate::msgs::ccs::ChangeCipherSpecPayload; - use crate::msgs::enums::NamedGroup; - use crate::msgs::enums::{Compression, PSKKeyExchangeMode}; - use crate::msgs::handshake::CertReqExtension; - use crate::msgs::handshake::CertificateEntry; - use crate::msgs::handshake::CertificateExtension; - use crate::msgs::handshake::CertificatePayloadTLS13; - use crate::msgs::handshake::CertificateRequestPayloadTLS13; - use crate::msgs::handshake::CertificateStatus; - use crate::msgs::handshake::ClientHelloPayload; - use crate::msgs::handshake::DigitallySignedStruct; - use crate::msgs::handshake::HelloRetryExtension; - use crate::msgs::handshake::HelloRetryRequest; - use crate::msgs::handshake::KeyShareEntry; - use crate::msgs::handshake::Random; - use crate::msgs::handshake::ServerExtension; - use crate::msgs::handshake::ServerHelloPayload; - use crate::msgs::handshake::SessionID; - #[cfg(feature = "quic")] - use crate::quic; - use crate::server::common::ActiveCertifiedKey; - use crate::sign; - use crate::tls13::key_schedule::{ - KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, - }; - - use super::*; - - #[derive(PartialEq)] - pub(super) enum EarlyDataDecision { - Disabled, - RequestedButRejected, - Accepted, - } - - pub(in crate::server) struct CompleteClientHelloHandling { - pub(in crate::server) config: Arc, - pub(in crate::server) transcript: HandshakeHash, - pub(in crate::server) suite: &'static Tls13CipherSuite, - pub(in crate::server) randoms: ConnectionRandoms, - pub(in crate::server) done_retry: bool, - pub(in crate::server) send_ticket: bool, - pub(in crate::server) extra_exts: Vec, - } - - fn max_early_data_size(configured: u32) -> usize { - if configured != 0 { - configured as usize - } else { - // The relevant max_early_data_size may in fact be unknowable: if - // we (the server) have turned off early_data but the client has - // a stale ticket from when we allowed early_data: we'll naturally - // reject early_data but need an upper bound on the amount of data - // to drop. - // - // Use a single maximum-sized message. - 16384 - } - } - - impl CompleteClientHelloHandling { - fn check_binder( - &self, - suite: &'static Tls13CipherSuite, - client_hello: &Message, - psk: &[u8], - binder: &[u8], - ) -> bool { - let binder_plaintext = match &client_hello.payload { - MessagePayload::Handshake { parsed, .. } => { - parsed.get_encoding_for_binder_signing() - } - _ => unreachable!(), - }; - - let handshake_hash = self - .transcript - .get_hash_given(&binder_plaintext); - - let key_schedule = KeyScheduleEarly::new(suite.hkdf_algorithm, psk); - let real_binder = - key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); - - constant_time::verify_slices_are_equal(real_binder.as_ref(), binder).is_ok() - } - - fn attempt_tls13_ticket_decryption( - &mut self, - ticket: &[u8], - ) -> Option { - if self.config.ticketer.enabled() { - self.config - .ticketer - .decrypt(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) - } else { - self.config - .session_storage - .take(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) - } - } - - pub(in crate::server) fn handle_client_hello( - mut self, - cx: &mut ServerContext<'_>, - server_key: ActiveCertifiedKey, - chm: &Message, - client_hello: &ClientHelloPayload, - mut sigschemes_ext: Vec, - ) -> hs::NextStateOrError { - if client_hello.compression_methods.len() != 1 { - return Err(cx - .common - .illegal_param("client offered wrong compressions")); - } - - let groups_ext = client_hello - .get_namedgroups_extension() - .ok_or_else(|| hs::incompatible(cx.common, "client didn't describe groups"))?; - - let tls13_schemes = sign::supported_sign_tls13(); - sigschemes_ext.retain(|scheme| tls13_schemes.contains(scheme)); - - let shares_ext = client_hello - .get_keyshare_extension() - .ok_or_else(|| hs::incompatible(cx.common, "client didn't send keyshares"))?; - - if client_hello.has_keyshare_extension_with_duplicates() { - return Err(cx - .common - .illegal_param("client sent duplicate keyshares")); - } - - let early_data_requested = client_hello.early_data_extension_offered(); - - // EarlyData extension is illegal in second ClientHello - if self.done_retry && early_data_requested { - return Err(cx - .common - .illegal_param("client sent EarlyData in second ClientHello")); - } - - // choose a share that we support - let chosen_share = self - .config - .kx_groups - .iter() - .find_map(|group| { - shares_ext - .iter() - .find(|share| share.group == group.name) - }); - - let chosen_share = match chosen_share { - Some(s) => s, - None => { - // We don't have a suitable key share. Choose a suitable group and - // send a HelloRetryRequest. - let retry_group_maybe = self - .config - .kx_groups - .iter() - .find(|group| groups_ext.contains(&group.name)) - .cloned(); - - self.transcript.add_message(chm); - - if let Some(group) = retry_group_maybe { - if self.done_retry { - return Err(cx - .common - .illegal_param("did not follow retry request")); - } - - emit_hello_retry_request( - &mut self.transcript, - self.suite, - cx.common, - group.name, - ); - emit_fake_ccs(cx.common); - - let skip_early_data = max_early_data_size(self.config.max_early_data_size); - - let next = Box::new(hs::ExpectClientHello { - config: self.config, - transcript: HandshakeHashOrBuffer::Hash(self.transcript), - #[cfg(feature = "tls12")] - session_id: SessionID::empty(), - #[cfg(feature = "tls12")] - using_ems: false, - done_retry: true, - send_ticket: self.send_ticket, - extra_exts: self.extra_exts, - }); - - return if early_data_requested { - Ok(Box::new(ExpectAndSkipRejectedEarlyData { - skip_data_left: skip_early_data, - next, - })) - } else { - Ok(next) - }; - } - - return Err(hs::incompatible( - cx.common, - "no kx group overlap with client", - )); - } - }; - - let mut chosen_psk_index = None; - let mut resumedata = None; - let time_now = ticketer::TimeBase::now()?; - - if let Some(psk_offer) = client_hello.get_psk() { - if !client_hello.check_psk_ext_is_last() { - return Err(cx - .common - .illegal_param("psk extension in wrong position")); - } - - if psk_offer.binders.is_empty() { - return Err(hs::decode_error(cx.common, "psk extension missing binder")); - } - - if psk_offer.binders.len() != psk_offer.identities.len() { - return Err(cx - .common - .illegal_param("psk extension mismatched ids/binders")); - } - - for (i, psk_id) in psk_offer.identities.iter().enumerate() { - let resume = match self - .attempt_tls13_ticket_decryption(&psk_id.identity.0) - .map(|resumedata| { - resumedata.set_freshness(psk_id.obfuscated_ticket_age, time_now) - }) - .filter(|resumedata| { - hs::can_resume(self.suite.into(), &cx.data.sni, false, resumedata) - }) { - Some(resume) => resume, - None => continue, - }; - - if !self.check_binder( - self.suite, - chm, - &resume.master_secret.0, - &psk_offer.binders[i].0, - ) { - cx.common - .send_fatal_alert(AlertDescription::DecryptError); - return Err(Error::PeerMisbehavedError( - "client sent wrong binder".to_string(), - )); - } - - chosen_psk_index = Some(i); - resumedata = Some(resume); - break; - } - } - - if !client_hello.psk_mode_offered(PSKKeyExchangeMode::PSK_DHE_KE) { - debug!("Client unwilling to resume, DHE_KE not offered"); - self.send_ticket = false; - chosen_psk_index = None; - resumedata = None; - } else { - self.send_ticket = true; - } - - if let Some(ref resume) = resumedata { - cx.data.received_resumption_data = Some(resume.application_data.0.clone()); - cx.common.peer_certificates = resume.client_cert_chain.clone(); - } - - let full_handshake = resumedata.is_none(); - self.transcript.add_message(chm); - let key_schedule = emit_server_hello( - &mut self.transcript, - &self.randoms, - self.suite, - cx, - &client_hello.session_id, - chosen_share, - chosen_psk_index, - resumedata - .as_ref() - .map(|x| &x.master_secret.0[..]), - &self.config, - )?; - if !self.done_retry { - emit_fake_ccs(cx.common); - } - - let (mut ocsp_response, mut sct_list) = - (server_key.get_ocsp(), server_key.get_sct_list()); - let doing_early_data = emit_encrypted_extensions( - &mut self.transcript, - self.suite, - cx, - &mut ocsp_response, - &mut sct_list, - client_hello, - resumedata.as_ref(), - self.extra_exts, - &self.config, - )?; - - let doing_client_auth = if full_handshake { - let client_auth = - emit_certificate_req_tls13(&mut self.transcript, cx, &self.config)?; - emit_certificate_tls13( - &mut self.transcript, - cx.common, - server_key.get_cert(), - ocsp_response, - sct_list, - ); - emit_certificate_verify_tls13( - &mut self.transcript, - cx.common, - server_key.get_key(), - &sigschemes_ext, - )?; - client_auth - } else { - false - }; - - // If we're not doing early data, then the next messages we receive - // are encrypted with the handshake keys. - match doing_early_data { - EarlyDataDecision::Disabled => { - cx.common - .record_layer - .set_message_decrypter( - self.suite - .derive_decrypter(key_schedule.client_key()), - ); - cx.data.early_data.reject(); - } - EarlyDataDecision::RequestedButRejected => { - debug!("Client requested early_data, but not accepted: switching to handshake keys with trial decryption"); - cx.common - .record_layer - .set_message_decrypter_with_trial_decryption( - self.suite - .derive_decrypter(key_schedule.client_key()), - max_early_data_size(self.config.max_early_data_size), - ); - cx.data.early_data.reject(); - } - EarlyDataDecision::Accepted => { - cx.data - .early_data - .accept(self.config.max_early_data_size as usize); - } - } - - cx.common.check_aligned_handshake()?; - let key_schedule_traffic = emit_finished_tls13( - &mut self.transcript, - self.suite, - &self.randoms, - cx, - key_schedule, - &self.config, - ); - - if !doing_client_auth && self.config.send_half_rtt_data { - // Application data can be sent immediately after Finished, in one - // flight. However, if client auth is enabled, we don't want to send - // application data to an unauthenticated peer. - cx.common.start_outgoing_traffic(); - } - - if doing_client_auth { - Ok(Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_ticket: self.send_ticket, - })) - } else if doing_early_data == EarlyDataDecision::Accepted && !cx.common.is_quic() { - // Not used for QUIC: RFC 9001 §8.3: Clients MUST NOT send the EndOfEarlyData - // message. A server MUST treat receipt of a CRYPTO frame in a 0-RTT packet as a - // connection error of type PROTOCOL_VIOLATION. - Ok(Box::new(ExpectEarlyData { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_ticket: self.send_ticket, - })) - } else { - Ok(Box::new(ExpectFinished { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_ticket: self.send_ticket, - })) - } - } - } - - fn emit_server_hello( - transcript: &mut HandshakeHash, - randoms: &ConnectionRandoms, - suite: &'static Tls13CipherSuite, - cx: &mut ServerContext<'_>, - session_id: &SessionID, - share: &KeyShareEntry, - chosen_psk_idx: Option, - resuming_psk: Option<&[u8]>, - config: &ServerConfig, - ) -> Result { - let mut extensions = Vec::new(); - - // Prepare key exchange - let kx = kx::KeyExchange::choose(share.group, &config.kx_groups) - .and_then(kx::KeyExchange::start) - .ok_or(Error::FailedToGetRandomBytes)?; - - let kse = KeyShareEntry::new(share.group, kx.pubkey.as_ref()); - extensions.push(ServerExtension::KeyShare(kse)); - extensions.push(ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); - - if let Some(psk_idx) = chosen_psk_idx { - extensions.push(ServerExtension::PresharedKey(psk_idx as u16)); - } - - let sh = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ServerHello, - payload: HandshakePayload::ServerHello(ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from(randoms.server), - session_id: *session_id, - cipher_suite: suite.common.suite, - compression_method: Compression::Null, - extensions, - }), - }), - }; - - cx.common.check_aligned_handshake()?; - - let client_hello_hash = transcript.get_hash_given(&[]); - - trace!("sending server hello {:?}", sh); - transcript.add_message(&sh); - cx.common.send_msg(sh, false); - - // Start key schedule - let (key_schedule_pre_handshake, early_data_client_key) = if let Some(psk) = resuming_psk { - let early_key_schedule = KeyScheduleEarly::new(suite.hkdf_algorithm, psk); - let client_early_traffic_secret = early_key_schedule.client_early_traffic_secret( - &client_hello_hash, - &*config.key_log, - &randoms.client, - ); - - ( - KeySchedulePreHandshake::from(early_key_schedule), - Some(client_early_traffic_secret), - ) - } else { - (KeySchedulePreHandshake::new(suite.hkdf_algorithm), None) - }; - - // Do key exchange - let key_schedule = kx.complete(&share.payload.0, |secret| { - Ok(key_schedule_pre_handshake.into_handshake(secret)) - })?; - - let handshake_hash = transcript.get_current_hash(); - let (key_schedule, _client_key, server_key) = key_schedule.derive_handshake_secrets( - handshake_hash, - &*config.key_log, - &randoms.client, - ); - - // Set up to encrypt with handshake secrets, but decrypt with early_data keys. - // If not doing early_data after all, this is corrected later to the handshake - // keys (now stored in key_schedule). - cx.common - .record_layer - .set_message_encrypter(suite.derive_encrypter(&server_key)); - - if let Some(key) = &early_data_client_key { - cx.common - .record_layer - .set_message_decrypter(suite.derive_decrypter(key)); - } - - #[cfg(feature = "quic")] - if cx.common.is_quic() { - // If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing - // before the application can see. - cx.common.quic.early_secret = early_data_client_key; - cx.common.quic.hs_secrets = - Some(quic::Secrets::new(_client_key, server_key, suite, false)); - } - - Ok(key_schedule) - } - - fn emit_fake_ccs(common: &mut CommonState) { - if common.is_quic() { - return; - } - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - common.send_msg(m, false); - } - - fn emit_hello_retry_request( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - common: &mut CommonState, - group: NamedGroup, - ) { - let mut req = HelloRetryRequest { - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionID::empty(), - cipher_suite: suite.common.suite, - extensions: Vec::new(), - }; - - req.extensions - .push(HelloRetryExtension::KeyShare(group)); - req.extensions - .push(HelloRetryExtension::SupportedVersions( - ProtocolVersion::TLSv1_3, - )); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::HelloRetryRequest, - payload: HandshakePayload::HelloRetryRequest(req), - }), - }; - - trace!("Requesting retry {:?}", m); - transcript.rollup_for_hrr(); - transcript.add_message(&m); - common.send_msg(m, false); - } - - fn decide_if_early_data_allowed( - cx: &mut ServerContext<'_>, - client_hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - suite: &'static Tls13CipherSuite, - config: &ServerConfig, - ) -> EarlyDataDecision { - let early_data_requested = client_hello.early_data_extension_offered(); - let rejected_or_disabled = match early_data_requested { - true => EarlyDataDecision::RequestedButRejected, - false => EarlyDataDecision::Disabled, - }; - - let resume = match resumedata { - Some(resume) => resume, - None => { - // never any early data if not resuming. - return rejected_or_disabled; - } - }; - - /* Non-zero max_early_data_size controls whether early_data is allowed at all. - * We also require stateful resumption. */ - let early_data_configured = config.max_early_data_size > 0 && !config.ticketer.enabled(); - - /* "For PSKs provisioned via NewSessionTicket, a server MUST validate - * that the ticket age for the selected PSK identity (computed by - * subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age - * modulo 2^32) is within a small tolerance of the time since the ticket - * was issued (see Section 8)." -- this is implemented in ServerSessionValue::set_freshness() - * and related. - * - * "In order to accept early data, the server [...] MUST verify that the - * following values are the same as those associated with the - * selected PSK: - * - * - The TLS version number - * - The selected cipher suite - * - The selected ALPN [RFC7301] protocol, if any" - * - * (RFC8446, 4.2.10) */ - let early_data_possible = early_data_requested - && resume.is_fresh() - && Some(resume.version) == cx.common.negotiated_version - && resume.cipher_suite == suite.common.suite - && resume.alpn.as_ref().map(|x| &x.0) == cx.common.alpn_protocol.as_ref(); - - if early_data_configured && early_data_possible && !cx.data.early_data.was_rejected() { - EarlyDataDecision::Accepted - } else { - #[cfg(feature = "quic")] - if cx.common.is_quic() { - // Clobber value set in tls13::emit_server_hello - cx.common.quic.early_secret = None; - } - - rejected_or_disabled - } - } - - fn emit_encrypted_extensions( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - cx: &mut ServerContext<'_>, - ocsp_response: &mut Option<&[u8]>, - sct_list: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - extra_exts: Vec, - config: &ServerConfig, - ) -> Result { - let mut ep = hs::ExtensionProcessing::new(); - ep.process_common( - config, - cx, - ocsp_response, - sct_list, - hello, - resumedata, - extra_exts, - )?; - - let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config); - if early_data == EarlyDataDecision::Accepted { - ep.exts.push(ServerExtension::EarlyData); - } - - let ee = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::EncryptedExtensions, - payload: HandshakePayload::EncryptedExtensions(ep.exts), - }), - }; - - trace!("sending encrypted extensions {:?}", ee); - transcript.add_message(&ee); - cx.common.send_msg(ee, true); - Ok(early_data) - } - - fn emit_certificate_req_tls13( - transcript: &mut HandshakeHash, - cx: &mut ServerContext<'_>, - config: &ServerConfig, - ) -> Result { - if !config.verifier.offer_client_auth() { - return Ok(false); - } - - let mut cr = CertificateRequestPayloadTLS13 { - context: PayloadU8::empty(), - extensions: Vec::new(), - }; - - let schemes = config - .verifier - .supported_verify_schemes(); - cr.extensions - .push(CertReqExtension::SignatureAlgorithms(schemes.to_vec())); - - let names = config - .verifier - .client_auth_root_subjects() - .ok_or_else(|| { - debug!("could not determine root subjects based on SNI"); - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Error::General("client rejected by client_auth_root_subjects".into()) - })?; - - if !names.is_empty() { - cr.extensions - .push(CertReqExtension::AuthorityNames(names)); - } - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateRequest, - payload: HandshakePayload::CertificateRequestTLS13(cr), - }), - }; - - trace!("Sending CertificateRequest {:?}", m); - transcript.add_message(&m); - cx.common.send_msg(m, true); - Ok(true) - } - - fn emit_certificate_tls13( - transcript: &mut HandshakeHash, - common: &mut CommonState, - cert_chain: &[Certificate], - ocsp_response: Option<&[u8]>, - sct_list: Option<&[u8]>, - ) { - let mut cert_entries = vec![]; - for cert in cert_chain { - let entry = CertificateEntry { - cert: cert.to_owned(), - exts: Vec::new(), - }; - - cert_entries.push(entry); - } - - if let Some(end_entity_cert) = cert_entries.first_mut() { - // Apply OCSP response to first certificate (we don't support OCSP - // except for leaf certs). - if let Some(ocsp) = ocsp_response { - let cst = CertificateStatus::new(ocsp.to_owned()); - end_entity_cert - .exts - .push(CertificateExtension::CertificateStatus(cst)); - } - - // Likewise, SCT - if let Some(sct_list) = sct_list { - end_entity_cert - .exts - .push(CertificateExtension::make_sct(sct_list.to_owned())); - } - } - - let cert_body = CertificatePayloadTLS13::new(cert_entries); - let c = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::CertificateTLS13(cert_body), - }), - }; - - trace!("sending certificate {:?}", c); - transcript.add_message(&c); - common.send_msg(c, true); - } - - fn emit_certificate_verify_tls13( - transcript: &mut HandshakeHash, - common: &mut CommonState, - signing_key: &dyn sign::SigningKey, - schemes: &[SignatureScheme], - ) -> Result<(), Error> { - let message = verify::construct_tls13_server_verify_message(&transcript.get_current_hash()); - - let signer = signing_key - .choose_scheme(schemes) - .ok_or_else(|| hs::incompatible(common, "no overlapping sigschemes"))?; - - let scheme = signer.scheme(); - let sig = signer.sign(&message)?; - - let cv = DigitallySignedStruct::new(scheme, sig); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateVerify, - payload: HandshakePayload::CertificateVerify(cv), - }), - }; - - trace!("sending certificate-verify {:?}", m); - transcript.add_message(&m); - common.send_msg(m, true); - Ok(()) - } - - fn emit_finished_tls13( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - randoms: &ConnectionRandoms, - cx: &mut ServerContext<'_>, - key_schedule: KeyScheduleHandshake, - config: &ServerConfig, - ) -> KeyScheduleTrafficWithClientFinishedPending { - let handshake_hash = transcript.get_current_hash(); - let verify_data = key_schedule.sign_server_finish(&handshake_hash); - let verify_data_payload = Payload::new(verify_data.as_ref()); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(verify_data_payload), - }), - }; - - trace!("sending finished {:?}", m); - transcript.add_message(&m); - let hash_at_server_fin = transcript.get_current_hash(); - cx.common.send_msg(m, true); - - // Now move to application data keys. Read key change is deferred until - // the Finish message is received & validated. - let (key_schedule_traffic, _client_key, server_key) = key_schedule - .into_traffic_with_client_finished_pending( - hash_at_server_fin, - &*config.key_log, - &randoms.client, - ); - cx.common - .record_layer - .set_message_encrypter(suite.derive_encrypter(&server_key)); - - #[cfg(feature = "quic")] - { - cx.common.quic.traffic_secrets = - Some(quic::Secrets::new(_client_key, server_key, suite, false)); - } - - key_schedule_traffic - } -} - -struct ExpectAndSkipRejectedEarlyData { - skip_data_left: usize, - next: Box, -} - -impl State for ExpectAndSkipRejectedEarlyData { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - /* "The server then ignores early data by skipping all records with an external - * content type of "application_data" (indicating that they are encrypted), - * up to the configured max_early_data_size." - * (RFC8446, 14.2.10) */ - if let MessagePayload::ApplicationData(ref skip_data) = m.payload { - if skip_data.0.len() <= self.skip_data_left { - self.skip_data_left -= skip_data.0.len(); - return Ok(self); - } - } - - self.next.handle(cx, m) - } -} - -struct ExpectCertificate { - config: Arc, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_ticket: bool, -} - -impl State for ExpectCertificate { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let certp = require_handshake_msg!( - m, - HandshakeType::Certificate, - HandshakePayload::CertificateTLS13 - )?; - self.transcript.add_message(&m); - - // We don't send any CertificateRequest extensions, so any extensions - // here are illegal. - if certp.any_entry_has_extension() { - return Err(Error::PeerMisbehavedError( - "client sent unsolicited cert extension".to_string(), - )); - } - - let client_cert = certp.convert(); - - let mandatory = self - .config - .verifier - .client_auth_mandatory() - .ok_or_else(|| { - debug!("could not determine if client auth is mandatory based on SNI"); - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - Error::General("client rejected by client_auth_mandatory".into()) - })?; - - let (end_entity, intermediates) = match client_cert.split_first() { - None => { - if !mandatory { - debug!("client auth requested but no certificate supplied"); - self.transcript.abandon_client_auth(); - return Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_ticket: self.send_ticket, - })); - } - - cx.common - .send_fatal_alert(AlertDescription::CertificateRequired); - return Err(Error::NoCertificatesPresented); - } - Some(chain) => chain, - }; - - let now = std::time::SystemTime::now(); - self.config - .verifier - .verify_client_cert(end_entity, intermediates, now) - .map_err(|err| { - hs::incompatible(cx.common, "certificate invalid"); - err - })?; - - Ok(Box::new(ExpectCertificateVerify { - config: self.config, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_cert, - send_ticket: self.send_ticket, - })) - } -} - -struct ExpectCertificateVerify { - config: Arc, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - client_cert: Vec, - send_ticket: bool, -} - -impl State for ExpectCertificateVerify { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let rc = { - let sig = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - let handshake_hash = self.transcript.get_current_hash(); - self.transcript.abandon_client_auth(); - let certs = &self.client_cert; - let msg = verify::construct_tls13_client_verify_message(&handshake_hash); - - self.config - .verifier - .verify_tls13_signature(&msg, &certs[0], sig) - }; - - if let Err(e) = rc { - cx.common - .send_fatal_alert(AlertDescription::AccessDenied); - return Err(e); - } - - trace!("client CertificateVerify OK"); - cx.common.peer_certificates = Some(self.client_cert); - - self.transcript.add_message(&m); - Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_ticket: self.send_ticket, - })) - } -} - -// --- Process (any number of) early ApplicationData messages, -// followed by a terminating handshake EndOfEarlyData message --- - -struct ExpectEarlyData { - config: Arc, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_ticket: bool, -} - -impl State for ExpectEarlyData { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ApplicationData(payload) => { - match cx - .data - .early_data - .take_received_plaintext(payload) - { - true => Ok(self), - false => { - cx.common - .send_fatal_alert(AlertDescription::UnexpectedMessage); - Err(Error::PeerMisbehavedError( - "too much early_data received".into(), - )) - } - } - } - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - typ: HandshakeType::EndOfEarlyData, - payload: HandshakePayload::EndOfEarlyData, - }, - .. - } => { - cx.common - .record_layer - .set_message_decrypter( - self.suite - .derive_decrypter(self.key_schedule.client_key()), - ); - - self.transcript.add_message(&m); - Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_ticket: self.send_ticket, - })) - } - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::EndOfEarlyData], - )), - } - } -} - -// --- Process client's Finished --- -fn get_server_session_value( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: &KeyScheduleTraffic, - cx: &ServerContext<'_>, - nonce: &[u8], - time_now: ticketer::TimeBase, - age_obfuscation_offset: u32, -) -> persist::ServerSessionValue { - let version = ProtocolVersion::TLSv1_3; - - let handshake_hash = transcript.get_current_hash(); - let secret = - key_schedule.resumption_master_secret_and_derive_ticket_psk(&handshake_hash, nonce); - - persist::ServerSessionValue::new( - cx.data.sni.as_ref(), - version, - suite.common.suite, - secret, - cx.common.peer_certificates.clone(), - cx.common.alpn_protocol.clone(), - cx.data.resumption_data.clone(), - time_now, - age_obfuscation_offset, - ) -} - -struct ExpectFinished { - config: Arc, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_ticket: bool, -} - -impl ExpectFinished { - fn emit_ticket( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - cx: &mut ServerContext<'_>, - key_schedule: &KeyScheduleTraffic, - config: &ServerConfig, - ) -> Result<(), Error> { - let nonce = rand::random_vec(32)?; - let now = ticketer::TimeBase::now()?; - let age_add = rand::random_u32()?; - let plain = - get_server_session_value(transcript, suite, key_schedule, cx, &nonce, now, age_add) - .get_encoding(); - - let stateless = config.ticketer.enabled(); - let (ticket, lifetime) = if stateless { - let ticket = match config.ticketer.encrypt(&plain) { - Some(t) => t, - None => return Ok(()), - }; - (ticket, config.ticketer.lifetime()) - } else { - let id = rand::random_vec(32)?; - let stored = config - .session_storage - .put(id.clone(), plain); - if !stored { - trace!("resumption not available; not issuing ticket"); - return Ok(()); - } - let stateful_lifetime = 24 * 60 * 60; // this is a bit of a punt - (id, stateful_lifetime) - }; - - let mut payload = NewSessionTicketPayloadTLS13::new(lifetime, age_add, nonce, ticket); - - if config.max_early_data_size > 0 { - if !stateless { - payload - .exts - .push(NewSessionTicketExtension::EarlyData( - config.max_early_data_size, - )); - } else { - // We implement RFC8446 section 8.1: by enforcing that 0-RTT is - // only possible if using stateful resumption - warn!("early_data with stateless resumption is not allowed"); - } - } - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::NewSessionTicket, - payload: HandshakePayload::NewSessionTicketTLS13(payload), - }), - }; - - trace!("sending new ticket {:?} (stateless: {})", m, stateless); - transcript.add_message(&m); - cx.common.send_msg(m, true); - Ok(()) - } -} - -impl State for ExpectFinished { - fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - let handshake_hash = self.transcript.get_current_hash(); - let (key_schedule_traffic, expect_verify_data, client_key) = self - .key_schedule - .sign_client_finish(&handshake_hash); - - let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0) - .map_err(|_| { - cx.common - .send_fatal_alert(AlertDescription::DecryptError); - warn!("Finished wrong"); - Error::DecryptError - }) - .map(|_| verify::FinishedMessageVerified::assertion())?; - - // nb. future derivations include Client Finished, but not the - // main application data keying. - self.transcript.add_message(&m); - - cx.common.check_aligned_handshake()?; - - // Install keying to read future messages. - cx.common - .record_layer - .set_message_decrypter(self.suite.derive_decrypter(&client_key)); - - if self.send_ticket { - Self::emit_ticket( - &mut self.transcript, - self.suite, - cx, - &key_schedule_traffic, - &self.config, - )?; - } - - // Application data may now flow, even if we have client auth enabled. - cx.common.start_traffic(); - - #[cfg(feature = "quic")] - { - if cx.common.protocol == Protocol::Quic { - return Ok(Box::new(ExpectQuicTraffic { - key_schedule: key_schedule_traffic, - _fin_verified: fin, - })); - } - } - - Ok(Box::new(ExpectTraffic { - suite: self.suite, - key_schedule: key_schedule_traffic, - want_write_key_update: false, - _fin_verified: fin, - })) - } -} - -// --- Process traffic --- -struct ExpectTraffic { - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTraffic, - want_write_key_update: bool, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic { - fn handle_key_update( - &mut self, - common: &mut CommonState, - kur: &KeyUpdateRequest, - ) -> Result<(), Error> { - #[cfg(feature = "quic")] - { - if let Protocol::Quic = common.protocol { - common.send_fatal_alert(AlertDescription::UnexpectedMessage); - let msg = "KeyUpdate received in QUIC connection".to_string(); - warn!("{}", msg); - return Err(Error::PeerMisbehavedError(msg)); - } - } - - common.check_aligned_handshake()?; - - match kur { - KeyUpdateRequest::UpdateNotRequested => {} - KeyUpdateRequest::UpdateRequested => { - self.want_write_key_update = true; - } - _ => { - common.send_fatal_alert(AlertDescription::IllegalParameter); - return Err(Error::CorruptMessagePayload(ContentType::Handshake)); - } - } - - // Update our read-side keys. - let new_read_key = self - .key_schedule - .next_client_application_traffic_secret(); - common - .record_layer - .set_message_decrypter( - self.suite - .derive_decrypter(&new_read_key), - ); - - Ok(()) - } -} - -impl State for ExpectTraffic { - fn handle(mut self: Box, cx: &mut ServerContext, m: Message) -> hs::NextStateOrError { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - MessagePayload::Handshake { - parsed: - HandshakeMessagePayload { - payload: HandshakePayload::KeyUpdate(key_update), - .. - }, - .. - } => self.handle_key_update(cx.common, &key_update)?, - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::KeyUpdate], - )); - } - } - - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } - - fn perhaps_write_key_update(&mut self, common: &mut CommonState) { - if self.want_write_key_update { - self.want_write_key_update = false; - common.send_msg_encrypt(Message::build_key_update_notify().into()); - - let write_key = self - .key_schedule - .next_server_application_traffic_secret(); - common - .record_layer - .set_message_encrypter(self.suite.derive_encrypter(&write_key)); - } - } - - #[cfg(feature = "secret_extraction")] - fn extract_secrets(&self) -> Result { - self.key_schedule - .extract_secrets(self.suite.common.aead_algorithm, Side::Server) - } -} - -#[cfg(feature = "quic")] -struct ExpectQuicTraffic { - key_schedule: KeyScheduleTraffic, - _fin_verified: verify::FinishedMessageVerified, -} - -#[cfg(feature = "quic")] -impl State for ExpectQuicTraffic { - fn handle(self: Box, _cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { - // reject all messages - Err(inappropriate_message(&m.payload, &[])) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/sign.rs b/third_party/rustls-fork-shadow-tls/src/sign.rs deleted file mode 100644 index 9c916f6..0000000 --- a/third_party/rustls-fork-shadow-tls/src/sign.rs +++ /dev/null @@ -1,523 +0,0 @@ -use crate::enums::SignatureScheme; -use crate::error::Error; -use crate::key; -use crate::msgs::enums::SignatureAlgorithm; -use crate::x509::{wrap_in_asn1_len, wrap_in_sequence}; - -use ring::io::der; -use ring::signature::{self, EcdsaKeyPair, Ed25519KeyPair, RsaKeyPair}; - -use std::convert::TryFrom; -use std::error::Error as StdError; -use std::fmt; -use std::sync::Arc; - -/// An abstract signing key. -pub trait SigningKey: Send + Sync { - /// Choose a `SignatureScheme` from those offered. - /// - /// Expresses the choice by returning something that implements `Signer`, - /// using the chosen scheme. - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option>; - - /// What kind of key we have. - fn algorithm(&self) -> SignatureAlgorithm; -} - -/// A thing that can sign a message. -pub trait Signer: Send + Sync { - /// Signs `message` using the selected scheme. - fn sign(&self, message: &[u8]) -> Result, Error>; - - /// Reveals which scheme will be used when you call `sign()`. - fn scheme(&self) -> SignatureScheme; -} - -/// A packaged-together certificate chain, matching `SigningKey` and -/// optional stapled OCSP response and/or SCT list. -#[derive(Clone)] -pub struct CertifiedKey { - /// The certificate chain. - pub cert: Vec, - - /// The certified key. - pub key: Arc, - - /// An optional OCSP response from the certificate issuer, - /// attesting to its continued validity. - pub ocsp: Option>, - - /// An optional collection of SCTs from CT logs, proving the - /// certificate is included on those logs. This must be - /// a `SignedCertificateTimestampList` encoding; see RFC6962. - pub sct_list: Option>, -} - -impl CertifiedKey { - /// Make a new CertifiedKey, with the given chain and key. - /// - /// The cert chain must not be empty. The first certificate in the chain - /// must be the end-entity certificate. - pub fn new(cert: Vec, key: Arc) -> Self { - Self { - cert, - key, - ocsp: None, - sct_list: None, - } - } - - /// The end-entity certificate. - pub fn end_entity_cert(&self) -> Result<&key::Certificate, SignError> { - self.cert.get(0).ok_or(SignError(())) - } - - /// Check the certificate chain for validity: - /// - it should be non-empty list - /// - the first certificate should be parsable as a x509v3, - /// - the first certificate should quote the given server name - /// (if provided) - /// - /// These checks are not security-sensitive. They are the - /// *server* attempting to detect accidental misconfiguration. - pub(crate) fn cross_check_end_entity_cert( - &self, - name: Option, - ) -> Result<(), Error> { - // Always reject an empty certificate chain. - let end_entity_cert = self - .end_entity_cert() - .map_err(|SignError(())| { - Error::General("No end-entity certificate in certificate chain".to_string()) - })?; - - // Reject syntactically-invalid end-entity certificates. - let end_entity_cert = - webpki::EndEntityCert::try_from(end_entity_cert.as_ref()).map_err(|_| { - Error::General( - "End-entity certificate in certificate \ - chain is syntactically invalid" - .to_string(), - ) - })?; - - if let Some(name) = name { - // If SNI was offered then the certificate must be valid for - // that hostname. Note that this doesn't fully validate that the - // certificate is valid; it only validates that the name is one - // that the certificate is valid for, if the certificate is - // valid. - if end_entity_cert - .verify_is_valid_for_dns_name(name) - .is_err() - { - return Err(Error::General( - "The server certificate is not \ - valid for the given name" - .to_string(), - )); - } - } - - Ok(()) - } -} - -/// Parse `der` as any supported key encoding/type, returning -/// the first which works. -pub fn any_supported_type(der: &key::PrivateKey) -> Result, SignError> { - if let Ok(rsa) = RsaSigningKey::new(der) { - Ok(Arc::new(rsa)) - } else if let Ok(ecdsa) = any_ecdsa_type(der) { - Ok(ecdsa) - } else { - any_eddsa_type(der) - } -} - -/// Parse `der` as any ECDSA key type, returning the first which works. -/// -/// Both SEC1 (PEM section starting with 'BEGIN EC PRIVATE KEY') and PKCS8 -/// (PEM section starting with 'BEGIN PRIVATE KEY') encodings are supported. -pub fn any_ecdsa_type(der: &key::PrivateKey) -> Result, SignError> { - if let Ok(ecdsa_p256) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP256_SHA256, - &signature::ECDSA_P256_SHA256_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p256)); - } - - if let Ok(ecdsa_p384) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP384_SHA384, - &signature::ECDSA_P384_SHA384_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p384)); - } - - Err(SignError(())) -} - -/// Parse `der` as any EdDSA key type, returning the first which works. -pub fn any_eddsa_type(der: &key::PrivateKey) -> Result, SignError> { - if let Ok(ed25519) = Ed25519SigningKey::new(der, SignatureScheme::ED25519) { - return Ok(Arc::new(ed25519)); - } - - // TODO: Add support for Ed448 - - Err(SignError(())) -} - -/// A `SigningKey` for RSA-PKCS1 or RSA-PSS. -/// -/// This is used by the test suite, so it must be `pub`, but it isn't part of -/// the public, stable, API. -#[doc(hidden)] -pub struct RsaSigningKey { - key: Arc, -} - -static ALL_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -impl RsaSigningKey { - /// Make a new `RsaSigningKey` from a DER encoding, in either - /// PKCS#1 or PKCS#8 format. - pub fn new(der: &key::PrivateKey) -> Result { - RsaKeyPair::from_der(&der.0) - .or_else(|_| RsaKeyPair::from_pkcs8(&der.0)) - .map(|s| Self { key: Arc::new(s) }) - .map_err(|_| SignError(())) - } -} - -impl SigningKey for RsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { - ALL_RSA_SCHEMES - .iter() - .find(|scheme| offered.contains(scheme)) - .map(|scheme| RsaSigner::new(Arc::clone(&self.key), *scheme)) - } - - fn algorithm(&self) -> SignatureAlgorithm { - SignatureAlgorithm::RSA - } -} - -#[allow(clippy::upper_case_acronyms)] -#[doc(hidden)] -#[deprecated(since = "0.20.0", note = "Use RsaSigningKey")] -pub type RSASigningKey = RsaSigningKey; - -struct RsaSigner { - key: Arc, - scheme: SignatureScheme, - encoding: &'static dyn signature::RsaEncoding, -} - -impl RsaSigner { - fn new(key: Arc, scheme: SignatureScheme) -> Box { - let encoding: &dyn signature::RsaEncoding = match scheme { - SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256, - SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256, - SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512, - _ => unreachable!(), - }; - - Box::new(Self { - key, - scheme, - encoding, - }) - } -} - -impl Signer for RsaSigner { - fn sign(&self, message: &[u8]) -> Result, Error> { - let mut sig = vec![0; self.key.public_modulus_len()]; - - let rng = ring::rand::SystemRandom::new(); - self.key - .sign(self.encoding, &rng, message, &mut sig) - .map(|_| sig) - .map_err(|_| Error::General("signing failed".to_string())) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for ECDSA keys. -struct EcdsaSigningKey { - key: Arc, - scheme: SignatureScheme, -} - -impl EcdsaSigningKey { - /// Make a new `ECDSASigningKey` from a DER encoding in PKCS#8 or SEC1 - /// format, expecting a key usable with precisely the given signature - /// scheme. - fn new( - der: &key::PrivateKey, - scheme: SignatureScheme, - sigalg: &'static signature::EcdsaSigningAlgorithm, - ) -> Result { - EcdsaKeyPair::from_pkcs8(sigalg, &der.0) - .map_err(|_| ()) - .or_else(|_| Self::convert_sec1_to_pkcs8(scheme, sigalg, &der.0)) - .map(|kp| Self { - key: Arc::new(kp), - scheme, - }) - } - - /// Convert a SEC1 encoding to PKCS8, and ask ring to parse it. This - /// can be removed once https://github.com/briansmith/ring/pull/1456 - /// (or equivalent) is landed. - fn convert_sec1_to_pkcs8( - scheme: SignatureScheme, - sigalg: &'static signature::EcdsaSigningAlgorithm, - maybe_sec1_der: &[u8], - ) -> Result { - let pkcs8_prefix = match scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => &PKCS8_PREFIX_ECDSA_NISTP256, - SignatureScheme::ECDSA_NISTP384_SHA384 => &PKCS8_PREFIX_ECDSA_NISTP384, - _ => unreachable!(), // all callers are in this file - }; - - // wrap sec1 encoding in an OCTET STRING - let mut sec1_wrap = Vec::with_capacity(maybe_sec1_der.len() + 8); - sec1_wrap.extend_from_slice(maybe_sec1_der); - wrap_in_asn1_len(&mut sec1_wrap); - sec1_wrap.insert(0, der::Tag::OctetString as u8); - - let mut pkcs8 = Vec::with_capacity(pkcs8_prefix.len() + sec1_wrap.len() + 4); - pkcs8.extend_from_slice(pkcs8_prefix); - pkcs8.extend_from_slice(&sec1_wrap); - wrap_in_sequence(&mut pkcs8); - - EcdsaKeyPair::from_pkcs8(sigalg, &pkcs8).map_err(|_| ()) - } -} - -// This is (line-by-line): -// - INTEGER Version = 0 -// - SEQUENCE (privateKeyAlgorithm) -// - id-ecPublicKey OID -// - prime256v1 OID -const PKCS8_PREFIX_ECDSA_NISTP256: &[u8] = b"\x02\x01\x00\ - \x30\x13\ - \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ - \x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"; - -// This is (line-by-line): -// - INTEGER Version = 0 -// - SEQUENCE (privateKeyAlgorithm) -// - id-ecPublicKey OID -// - secp384r1 OID -const PKCS8_PREFIX_ECDSA_NISTP384: &[u8] = b"\x02\x01\x00\ - \x30\x10\ - \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ - \x06\x05\x2b\x81\x04\x00\x22"; - -impl SigningKey for EcdsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { - if offered.contains(&self.scheme) { - Some(Box::new(EcdsaSigner { - key: Arc::clone(&self.key), - scheme: self.scheme, - })) - } else { - None - } - } - - fn algorithm(&self) -> SignatureAlgorithm { - use crate::msgs::handshake::DecomposedSignatureScheme; - self.scheme.sign() - } -} - -struct EcdsaSigner { - key: Arc, - scheme: SignatureScheme, -} - -impl Signer for EcdsaSigner { - fn sign(&self, message: &[u8]) -> Result, Error> { - let rng = ring::rand::SystemRandom::new(); - self.key - .sign(&rng, message) - .map_err(|_| Error::General("signing failed".into())) - .map(|sig| sig.as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for Ed25519 keys. -struct Ed25519SigningKey { - key: Arc, - scheme: SignatureScheme, -} - -impl Ed25519SigningKey { - /// Make a new `Ed25519SigningKey` from a DER encoding in PKCS#8 format, - /// expecting a key usable with precisely the given signature scheme. - fn new(der: &key::PrivateKey, scheme: SignatureScheme) -> Result { - Ed25519KeyPair::from_pkcs8_maybe_unchecked(&der.0) - .map(|kp| Self { - key: Arc::new(kp), - scheme, - }) - .map_err(|_| SignError(())) - } -} - -impl SigningKey for Ed25519SigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { - if offered.contains(&self.scheme) { - Some(Box::new(Ed25519Signer { - key: Arc::clone(&self.key), - scheme: self.scheme, - })) - } else { - None - } - } - - fn algorithm(&self) -> SignatureAlgorithm { - use crate::msgs::handshake::DecomposedSignatureScheme; - self.scheme.sign() - } -} - -struct Ed25519Signer { - key: Arc, - scheme: SignatureScheme, -} - -impl Signer for Ed25519Signer { - fn sign(&self, message: &[u8]) -> Result, Error> { - Ok(self.key.sign(message).as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -/// The set of schemes we support for signatures and -/// that are allowed for TLS1.3. -pub fn supported_sign_tls13() -> &'static [SignatureScheme] { - &[ - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::ED25519, - ] -} - -/// Errors while signing -#[derive(Debug)] -pub struct SignError(()); - -impl fmt::Display for SignError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("sign error") - } -} - -impl StdError for SignError {} - -#[test] -fn can_load_ecdsa_nistp256_pkcs8() { - let key = key::PrivateKey(include_bytes!("testdata/nistp256key.pkcs8.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); -} - -#[test] -fn can_load_ecdsa_nistp256_sec1() { - let key = key::PrivateKey(include_bytes!("testdata/nistp256key.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); -} - -#[test] -fn can_load_ecdsa_nistp384_pkcs8() { - let key = key::PrivateKey(include_bytes!("testdata/nistp384key.pkcs8.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); -} - -#[test] -fn can_load_ecdsa_nistp384_sec1() { - let key = key::PrivateKey(include_bytes!("testdata/nistp384key.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); -} - -#[test] -fn can_load_eddsa_pkcs8() { - let key = key::PrivateKey(include_bytes!("testdata/eddsakey.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); -} - -#[test] -fn can_load_rsa2048_pkcs8() { - let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs8.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); - assert!(any_ecdsa_type(&key).is_err()); -} - -#[test] -fn can_load_rsa2048_pkcs1() { - let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs1.der").to_vec()); - assert!(any_supported_type(&key).is_ok()); - assert!(any_eddsa_type(&key).is_err()); - assert!(any_ecdsa_type(&key).is_err()); -} diff --git a/third_party/rustls-fork-shadow-tls/src/stream.rs b/third_party/rustls-fork-shadow-tls/src/stream.rs deleted file mode 100644 index 70f0fa4..0000000 --- a/third_party/rustls-fork-shadow-tls/src/stream.rs +++ /dev/null @@ -1,254 +0,0 @@ -use crate::conn::{ConnectionCommon, SideData}; - -use std::io::{IoSlice, Read, Result, Write}; -use std::ops::{Deref, DerefMut}; - -/// This type implements `io::Read` and `io::Write`, encapsulating -/// a Connection `C` and an underlying transport `T`, such as a socket. -/// -/// This allows you to use a rustls Connection like a normal stream. -#[derive(Debug)] -pub struct Stream<'a, C: 'a + ?Sized, T: 'a + Read + Write + ?Sized> { - /// Our TLS connection - pub conn: &'a mut C, - - /// The underlying transport, like a socket - pub sock: &'a mut T, -} - -impl<'a, C, T, S> Stream<'a, C, T> -where - C: 'a + DerefMut + Deref>, - T: 'a + Read + Write, - S: SideData, -{ - /// Make a new Stream using the Connection `conn` and socket-like object - /// `sock`. This does not fail and does no IO. - pub fn new(conn: &'a mut C, sock: &'a mut T) -> Self { - Self { conn, sock } - } - - /// If we're handshaking, complete all the IO for that. - /// If we have data to write, write it all. - fn complete_prior_io(&mut self) -> Result<()> { - if self.conn.is_handshaking() { - self.conn.complete_io(self.sock)?; - } - - if self.conn.wants_write() { - self.conn.complete_io(self.sock)?; - } - - Ok(()) - } -} - -impl<'a, C, T, S> Read for Stream<'a, C, T> -where - C: 'a + DerefMut + Deref>, - T: 'a + Read + Write, - S: SideData, -{ - fn read(&mut self, buf: &mut [u8]) -> Result { - self.complete_prior_io()?; - - // We call complete_io() in a loop since a single call may read only - // a partial packet from the underlying transport. A full packet is - // needed to get more plaintext, which we must do if EOF has not been - // hit. Otherwise, we will prematurely signal EOF by returning 0. We - // determine if EOF has actually been hit by checking if 0 bytes were - // read from the underlying transport. - while self.conn.wants_read() { - let at_eof = self.conn.complete_io(self.sock)?.0 == 0; - if at_eof { - if let Ok(io_state) = self.conn.process_new_packets() { - if at_eof && io_state.plaintext_bytes_to_read() == 0 { - return Ok(0); - } - } - break; - } - } - - self.conn.reader().read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: std::io::BorrowedCursor<'_>) -> Result<()> { - self.complete_prior_io()?; - - // We call complete_io() in a loop since a single call may read only - // a partial packet from the underlying transport. A full packet is - // needed to get more plaintext, which we must do if EOF has not been - // hit. Otherwise, we will prematurely signal EOF by returning without - // writing anything. We determine if EOF has actually been hit by - // checking if 0 bytes were read from the underlying transport. - while self.conn.wants_read() { - let at_eof = self.conn.complete_io(self.sock)?.0 == 0; - if at_eof { - if let Ok(io_state) = self.conn.process_new_packets() { - if at_eof && io_state.plaintext_bytes_to_read() == 0 { - return Ok(()); - } - } - break; - } - } - - self.conn.reader().read_buf(cursor) - } -} - -impl<'a, C, T, S> Write for Stream<'a, C, T> -where - C: 'a + DerefMut + Deref>, - T: 'a + Read + Write, - S: SideData, -{ - fn write(&mut self, buf: &[u8]) -> Result { - self.complete_prior_io()?; - - let len = self.conn.writer().write(buf)?; - - // Try to write the underlying transport here, but don't let - // any errors mask the fact we've consumed `len` bytes. - // Callers will learn of permanent errors on the next call. - let _ = self.conn.complete_io(self.sock); - - Ok(len) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.complete_prior_io()?; - - let len = self - .conn - .writer() - .write_vectored(bufs)?; - - // Try to write the underlying transport here, but don't let - // any errors mask the fact we've consumed `len` bytes. - // Callers will learn of permanent errors on the next call. - let _ = self.conn.complete_io(self.sock); - - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - self.complete_prior_io()?; - - self.conn.writer().flush()?; - if self.conn.wants_write() { - self.conn.complete_io(self.sock)?; - } - Ok(()) - } -} - -/// This type implements `io::Read` and `io::Write`, encapsulating -/// and owning a Connection `C` and an underlying blocking transport -/// `T`, such as a socket. -/// -/// This allows you to use a rustls Connection like a normal stream. -#[derive(Debug)] -pub struct StreamOwned { - /// Our connection - pub conn: C, - - /// The underlying transport, like a socket - pub sock: T, -} - -impl StreamOwned -where - C: DerefMut + Deref>, - T: Read + Write, - S: SideData, -{ - /// Make a new StreamOwned taking the Connection `conn` and socket-like - /// object `sock`. This does not fail and does no IO. - /// - /// This is the same as `Stream::new` except `conn` and `sock` are - /// moved into the StreamOwned. - pub fn new(conn: C, sock: T) -> Self { - Self { conn, sock } - } - - /// Get a reference to the underlying socket - pub fn get_ref(&self) -> &T { - &self.sock - } - - /// Get a mutable reference to the underlying socket - pub fn get_mut(&mut self) -> &mut T { - &mut self.sock - } -} - -impl<'a, C, T, S> StreamOwned -where - C: DerefMut + Deref>, - T: Read + Write, - S: SideData, -{ - fn as_stream(&'a mut self) -> Stream<'a, C, T> { - Stream { - conn: &mut self.conn, - sock: &mut self.sock, - } - } -} - -impl Read for StreamOwned -where - C: DerefMut + Deref>, - T: Read + Write, - S: SideData, -{ - fn read(&mut self, buf: &mut [u8]) -> Result { - self.as_stream().read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: std::io::BorrowedCursor<'_>) -> Result<()> { - self.as_stream().read_buf(cursor) - } -} - -impl Write for StreamOwned -where - C: DerefMut + Deref>, - T: Read + Write, - S: SideData, -{ - fn write(&mut self, buf: &[u8]) -> Result { - self.as_stream().write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.as_stream().flush() - } -} - -#[cfg(test)] -mod tests { - use super::{Stream, StreamOwned}; - use crate::client::ClientConnection; - use crate::server::ServerConnection; - use std::net::TcpStream; - - #[test] - fn stream_can_be_created_for_connection_and_tcpstream() { - type _Test<'a> = Stream<'a, ClientConnection, TcpStream>; - } - - #[test] - fn streamowned_can_be_created_for_client_and_tcpstream() { - type _Test = StreamOwned; - } - - #[test] - fn streamowned_can_be_created_for_server_and_tcpstream() { - type _Test = StreamOwned; - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/suites.rs b/third_party/rustls-fork-shadow-tls/src/suites.rs deleted file mode 100644 index 8d3590c..0000000 --- a/third_party/rustls-fork-shadow-tls/src/suites.rs +++ /dev/null @@ -1,340 +0,0 @@ -use std::fmt; - -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::msgs::enums::SignatureAlgorithm; -use crate::msgs::handshake::DecomposedSignatureScheme; -#[cfg(feature = "tls12")] -use crate::tls12::Tls12CipherSuite; -#[cfg(feature = "tls12")] -use crate::tls12::{ - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - // TLS1.2 suites - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -}; -use crate::tls13::Tls13CipherSuite; -use crate::tls13::{ - TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, -}; -#[cfg(feature = "tls12")] -use crate::versions::TLS12; -use crate::versions::{SupportedProtocolVersion, TLS13}; - -/// Bulk symmetric encryption scheme used by a cipher suite. -#[allow(non_camel_case_types)] -#[derive(Debug, Eq, PartialEq)] -pub enum BulkAlgorithm { - /// AES with 128-bit keys in Galois counter mode. - Aes128Gcm, - - /// AES with 256-bit keys in Galois counter mode. - Aes256Gcm, - - /// Chacha20 for confidentiality with poly1305 for authenticity. - Chacha20Poly1305, -} - -/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3) -#[derive(Debug)] -pub struct CipherSuiteCommon { - /// The TLS enumeration naming this cipher suite. - pub suite: CipherSuite, - - /// How to do bulk encryption. - pub bulk: BulkAlgorithm, - - pub(crate) aead_algorithm: &'static ring::aead::Algorithm, -} - -/// A cipher suite supported by rustls. -/// -/// All possible instances of this type are provided by the library in -/// the [`ALL_CIPHER_SUITES`] array. -#[derive(Clone, Copy, PartialEq)] -pub enum SupportedCipherSuite { - /// A TLS 1.2 cipher suite - #[cfg(feature = "tls12")] - Tls12(&'static Tls12CipherSuite), - /// A TLS 1.3 cipher suite - Tls13(&'static Tls13CipherSuite), -} - -impl fmt::Debug for SupportedCipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.suite().fmt(f) - } -} - -impl SupportedCipherSuite { - /// Which hash function to use with this suite. - pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(inner) => inner.hash_algorithm(), - Self::Tls13(inner) => inner.hash_algorithm(), - } - } - - /// The cipher suite's identifier - pub fn suite(&self) -> CipherSuite { - self.common().suite - } - - pub(crate) fn common(&self) -> &CipherSuiteCommon { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(inner) => &inner.common, - Self::Tls13(inner) => &inner.common, - } - } - - pub(crate) fn tls13(&self) -> Option<&'static Tls13CipherSuite> { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(_) => None, - Self::Tls13(inner) => Some(inner), - } - } - - /// Return supported protocol version for the cipher suite. - pub fn version(&self) -> &'static SupportedProtocolVersion { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(_) => &TLS12, - Self::Tls13(_) => &TLS13, - } - } - - /// Return true if this suite is usable for a key only offering `sig_alg` - /// signatures. This resolves to true for all TLS1.3 suites. - pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool { - match self { - Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3) - #[cfg(feature = "tls12")] - Self::Tls12(inner) => inner - .sign - .iter() - .any(|scheme| scheme.sign() == _sig_alg), - } - } -} - -/// A list of all the cipher suites supported by rustls. -pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ - // TLS1.3 suites - TLS13_AES_256_GCM_SHA384, - TLS13_AES_128_GCM_SHA256, - TLS13_CHACHA20_POLY1305_SHA256, - // TLS1.2 suites - #[cfg(feature = "tls12")] - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - #[cfg(feature = "tls12")] - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -]; - -/// The cipher suite configuration that an application should use by default. -/// -/// This will be [`ALL_CIPHER_SUITES`] sans any supported cipher suites that -/// shouldn't be enabled by most applications. -pub static DEFAULT_CIPHER_SUITES: &[SupportedCipherSuite] = ALL_CIPHER_SUITES; - -// These both O(N^2)! -pub(crate) fn choose_ciphersuite_preferring_client( - client_suites: &[CipherSuite], - server_suites: &[SupportedCipherSuite], -) -> Option { - for client_suite in client_suites { - if let Some(selected) = server_suites - .iter() - .find(|x| *client_suite == x.suite()) - { - return Some(*selected); - } - } - - None -} - -pub(crate) fn choose_ciphersuite_preferring_server( - client_suites: &[CipherSuite], - server_suites: &[SupportedCipherSuite], -) -> Option { - if let Some(selected) = server_suites - .iter() - .find(|x| client_suites.contains(&x.suite())) - { - return Some(*selected); - } - - None -} - -/// Return a list of the ciphersuites in `all` with the suites -/// incompatible with `SignatureAlgorithm` `sigalg` removed. -pub(crate) fn reduce_given_sigalg( - all: &[SupportedCipherSuite], - sigalg: SignatureAlgorithm, -) -> Vec { - all.iter() - .filter(|&&suite| suite.usable_for_signature_algorithm(sigalg)) - .copied() - .collect() -} - -/// Return a list of the ciphersuites in `all` with the suites -/// incompatible with the chosen `version` removed. -pub(crate) fn reduce_given_version( - all: &[SupportedCipherSuite], - version: ProtocolVersion, -) -> Vec { - all.iter() - .filter(|&&suite| suite.version().version == version) - .copied() - .collect() -} - -/// Return true if `sigscheme` is usable by any of the given suites. -pub(crate) fn compatible_sigscheme_for_suites( - sigscheme: SignatureScheme, - common_suites: &[SupportedCipherSuite], -) -> bool { - let sigalg = sigscheme.sign(); - common_suites - .iter() - .any(|&suite| suite.usable_for_signature_algorithm(sigalg)) -} - -/// Secrets for transmitting/receiving data over a TLS session. -/// -/// After performing a handshake with rustls, these secrets can be extracted -/// to configure kTLS for a socket, and have the kernel take over encryption -/// and/or decryption. -#[cfg(feature = "secret_extraction")] -pub struct ExtractedSecrets { - /// sequence number and secrets for the "tx" (transmit) direction - pub tx: (u64, ConnectionTrafficSecrets), - - /// sequence number and secrets for the "rx" (receive) direction - pub rx: (u64, ConnectionTrafficSecrets), -} - -/// [ExtractedSecrets] minus the sequence numbers -#[cfg(feature = "secret_extraction")] -pub(crate) struct PartiallyExtractedSecrets { - /// secrets for the "tx" (transmit) direction - pub(crate) tx: ConnectionTrafficSecrets, - - /// secrets for the "rx" (receive) direction - pub(crate) rx: ConnectionTrafficSecrets, -} - -/// Secrets used to encrypt/decrypt data in a TLS session. -/// -/// These can be used to configure kTLS for a socket in one direction. -/// The only other piece of information needed is the sequence number, -/// which is in [ExtractedSecrets]. -#[cfg(feature = "secret_extraction")] -#[non_exhaustive] -pub enum ConnectionTrafficSecrets { - /// Secrets for the AES_128_GCM AEAD algorithm - Aes128Gcm { - /// key (16 bytes) - key: [u8; 16], - /// salt (4 bytes) - salt: [u8; 4], - /// initialization vector (8 bytes, chopped from key block) - iv: [u8; 8], - }, - - /// Secrets for the AES_256_GCM AEAD algorithm - Aes256Gcm { - /// key (32 bytes) - key: [u8; 32], - /// salt (4 bytes) - salt: [u8; 4], - /// initialization vector (8 bytes, chopped from key block) - iv: [u8; 8], - }, - - /// Secrets for the CHACHA20_POLY1305 AEAD algorithm - Chacha20Poly1305 { - /// key (32 bytes) - key: [u8; 32], - /// initialization vector (12 bytes) - iv: [u8; 12], - }, -} - -#[cfg(test)] -mod test { - use super::*; - use crate::enums::CipherSuite; - - #[test] - fn test_client_pref() { - let client = vec![ - CipherSuite::TLS13_AES_128_GCM_SHA256, - CipherSuite::TLS13_AES_256_GCM_SHA384, - ]; - let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; - let chosen = choose_ciphersuite_preferring_client(&client, &server); - assert!(chosen.is_some()); - assert_eq!(chosen.unwrap(), TLS13_AES_128_GCM_SHA256); - } - - #[test] - fn test_server_pref() { - let client = vec![ - CipherSuite::TLS13_AES_128_GCM_SHA256, - CipherSuite::TLS13_AES_256_GCM_SHA384, - ]; - let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; - let chosen = choose_ciphersuite_preferring_server(&client, &server); - assert!(chosen.is_some()); - assert_eq!(chosen.unwrap(), TLS13_AES_256_GCM_SHA384); - } - - #[test] - fn test_pref_fails() { - assert!(choose_ciphersuite_preferring_client( - &[CipherSuite::TLS_NULL_WITH_NULL_NULL], - ALL_CIPHER_SUITES - ) - .is_none()); - assert!(choose_ciphersuite_preferring_server( - &[CipherSuite::TLS_NULL_WITH_NULL_NULL], - ALL_CIPHER_SUITES - ) - .is_none()); - } - - #[test] - fn test_scs_is_debug() { - println!("{:?}", ALL_CIPHER_SUITES); - } - - #[test] - fn test_can_resume_to() { - assert!(TLS13_AES_128_GCM_SHA256 - .tls13() - .unwrap() - .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) - .is_some()); - assert!(TLS13_AES_256_GCM_SHA384 - .tls13() - .unwrap() - .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) - .is_none()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.0.der deleted file mode 100644 index ac81cd8..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.1.der deleted file mode 100644 index 93f1fb0..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.2.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.2.der deleted file mode 100644 index 1dfb0e7..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.2.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.3.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.3.der deleted file mode 100644 index 75df0cc..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-arstechnica.3.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.0.der deleted file mode 100644 index 9f8267c..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.1.der deleted file mode 100644 index dd6a50f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-duckduckgo.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.0.der deleted file mode 100644 index 86d6fce..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.1.der deleted file mode 100644 index 78a66bb..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-github.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.0.der deleted file mode 100644 index e8c41b2..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.1.der deleted file mode 100644 index 6671504..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.2.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.2.der deleted file mode 100644 index fd888ec..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-google.2.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.0.der deleted file mode 100644 index bc42b61..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.1.der deleted file mode 100644 index dd6a50f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-hn.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.0.der deleted file mode 100644 index 3a26d36..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.1.der deleted file mode 100644 index dd6a50f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-reddit.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.0.der deleted file mode 100644 index 3af1cad..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.1.der deleted file mode 100644 index 93f1fb0..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.2.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.2.der deleted file mode 100644 index 1dfb0e7..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.2.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.3.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.3.der deleted file mode 100644 index 75df0cc..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-rustlang.3.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.0.der deleted file mode 100644 index 0b6271f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.1.der deleted file mode 100644 index 41c7421..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-servo.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.0.der deleted file mode 100644 index 68068a7..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.1.der deleted file mode 100644 index 2d66ea7..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.2.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.2.der deleted file mode 100644 index 79a33ba..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-stackoverflow.2.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.0.der deleted file mode 100644 index 36f4e06..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.1.der deleted file mode 100644 index 608f16c..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-twitter.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.0.der deleted file mode 100644 index 94d2cd9..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.1.der deleted file mode 100644 index 99ced21..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wapo.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.0.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.0.der deleted file mode 100644 index 5452038..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.0.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.1.der b/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.1.der deleted file mode 100644 index 7d8413a..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/cert-wikipedia.1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-empty-applicationdata.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-empty-applicationdata.bin deleted file mode 100644 index ff11f47..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-empty-applicationdata.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-contenttype.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-contenttype.bin deleted file mode 100644 index 813cc67..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-contenttype.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-empty.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-empty.bin deleted file mode 100644 index 4739075..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-empty.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-length.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-length.bin deleted file mode 100644 index 675415f..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-length.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-version.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-version.bin deleted file mode 100644 index 5c18e17..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-invalid-version.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.1.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.1.bin deleted file mode 100644 index 7040726..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.1.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.2.bin b/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.2.bin deleted file mode 100644 index ba7a178..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/deframer-test.2.bin and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/eddsakey.der b/third_party/rustls-fork-shadow-tls/src/testdata/eddsakey.der deleted file mode 100644 index 8eff00d..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/eddsakey.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.der b/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.der deleted file mode 100644 index 5755182..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.pkcs8.der b/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.pkcs8.der deleted file mode 100644 index 8e64b2c..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/nistp256key.pkcs8.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.der b/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.der deleted file mode 100644 index 80f0769..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.pkcs8.der b/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.pkcs8.der deleted file mode 100644 index f85de43..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/nistp384key.pkcs8.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.1.bin b/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.1.bin deleted file mode 100644 index a066b9c..0000000 --- a/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.1.bin +++ /dev/null @@ -1 +0,0 @@ -ãò)ºr{á{& U|ÔSª²ÃÔ•2›RÔæÛZk0‘é 5ÉɤkNºù¯ "÷}ï«ý7—ÀVK«O¼‘fnï›—üãOyg‰º¤€‚Ñ"îBŧ.ZQÿ÷‡4{f \ No newline at end of file diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.2.bin b/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.2.bin deleted file mode 100644 index 799eeca..0000000 --- a/third_party/rustls-fork-shadow-tls/src/testdata/prf-result.2.bin +++ /dev/null @@ -1 +0,0 @@ -aõˆÇ˜ÅÂÿnzœµíÍãùLfš*F8×Õ²ƒ-öx˜uÇ~m†‹Ç\Eâ´ ô¡q;'7hC%’÷ÜŽ¨ï">ê…„¿he= ü@VØð%Ä]ߦæþÇðT´ ÖòУ#>I¤>uÅcí¾"þ%N3¡°éö¹‚fu¾ÇЄVXÜœ9uE@@¹ôlz@á¸ø ¦ 9z(¿õÒïPfhBû¤v2½µOöc?†»È6æ@ÔØ˜ \ No newline at end of file diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs1.der b/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs1.der deleted file mode 100644 index d93402d..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs1.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs8.der b/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs8.der deleted file mode 100644 index 8e5c2e8..0000000 Binary files a/third_party/rustls-fork-shadow-tls/src/testdata/rsa2048key.pkcs8.der and /dev/null differ diff --git a/third_party/rustls-fork-shadow-tls/src/ticketer.rs b/third_party/rustls-fork-shadow-tls/src/ticketer.rs deleted file mode 100644 index 9660d71..0000000 --- a/third_party/rustls-fork-shadow-tls/src/ticketer.rs +++ /dev/null @@ -1,338 +0,0 @@ -use crate::rand; -use crate::server::ProducesTickets; -use crate::Error; - -use ring::aead; -use std::mem; -use std::sync::{Arc, Mutex, MutexGuard}; -use std::time; - -/// The timebase for expiring and rolling tickets and ticketing -/// keys. This is UNIX wall time in seconds. -/// -/// This is guaranteed to be on or after the UNIX epoch. -#[derive(Clone, Copy, Debug)] -pub struct TimeBase(time::Duration); - -impl TimeBase { - #[inline] - pub fn now() -> Result { - Ok(Self( - time::SystemTime::now().duration_since(time::UNIX_EPOCH)?, - )) - } - - #[inline] - pub fn as_secs(&self) -> u64 { - self.0.as_secs() - } -} - -/// This is a `ProducesTickets` implementation which uses -/// any *ring* `aead::Algorithm` to encrypt and authentication -/// the ticket payload. It does not enforce any lifetime -/// constraint. -struct AeadTicketer { - alg: &'static aead::Algorithm, - key: aead::LessSafeKey, - lifetime: u32, -} - -impl AeadTicketer { - /// Make a ticketer with recommended configuration and a random key. - fn new() -> Result { - let mut key = [0u8; 32]; - rand::fill_random(&mut key)?; - - let alg = &aead::CHACHA20_POLY1305; - let key = aead::UnboundKey::new(alg, &key).unwrap(); - - Ok(Self { - alg, - key: aead::LessSafeKey::new(key), - lifetime: 60 * 60 * 12, - }) - } -} - -impl ProducesTickets for AeadTicketer { - fn enabled(&self) -> bool { - true - } - fn lifetime(&self) -> u32 { - self.lifetime - } - - /// Encrypt `message` and return the ciphertext. - fn encrypt(&self, message: &[u8]) -> Option> { - // Random nonce, because a counter is a privacy leak. - let mut nonce_buf = [0u8; 12]; - rand::fill_random(&mut nonce_buf).ok()?; - let nonce = ring::aead::Nonce::assume_unique_for_key(nonce_buf); - let aad = ring::aead::Aad::empty(); - - let mut ciphertext = - Vec::with_capacity(nonce_buf.len() + message.len() + self.key.algorithm().tag_len()); - ciphertext.extend(nonce_buf); - ciphertext.extend(message); - self.key - .seal_in_place_separate_tag(nonce, aad, &mut ciphertext[nonce_buf.len()..]) - .map(|tag| { - ciphertext.extend(tag.as_ref()); - ciphertext - }) - .ok() - } - - /// Decrypt `ciphertext` and recover the original message. - fn decrypt(&self, ciphertext: &[u8]) -> Option> { - // Non-panicking `let (nonce, ciphertext) = ciphertext.split_at(...)`. - let nonce = ciphertext.get(..self.alg.nonce_len())?; - let ciphertext = ciphertext.get(nonce.len()..)?; - - // This won't fail since `nonce` has the required length. - let nonce = ring::aead::Nonce::try_assume_unique_for_key(nonce).ok()?; - - let mut out = Vec::from(ciphertext); - - let plain_len = self - .key - .open_in_place(nonce, aead::Aad::empty(), &mut out) - .ok()? - .len(); - out.truncate(plain_len); - - Some(out) - } -} - -struct TicketSwitcherState { - next: Option>, - current: Box, - previous: Option>, - next_switch_time: u64, -} - -/// A ticketer that has a 'current' sub-ticketer and a single -/// 'previous' ticketer. It creates a new ticketer every so -/// often, demoting the current ticketer. -struct TicketSwitcher { - generator: fn() -> Result, rand::GetRandomFailed>, - lifetime: u32, - state: Mutex, -} - -impl TicketSwitcher { - /// `lifetime` is in seconds, and is how long the current ticketer - /// is used to generate new tickets. Tickets are accepted for no - /// longer than twice this duration. `generator` produces a new - /// `ProducesTickets` implementation. - fn new( - lifetime: u32, - generator: fn() -> Result, rand::GetRandomFailed>, - ) -> Result { - let now = TimeBase::now()?; - Ok(Self { - generator, - lifetime, - state: Mutex::new(TicketSwitcherState { - next: Some(generator()?), - current: generator()?, - previous: None, - next_switch_time: now - .as_secs() - .saturating_add(u64::from(lifetime)), - }), - }) - } - - /// If it's time, demote the `current` ticketer to `previous` (so it - /// does no new encryptions but can do decryption) and use next for a - /// new `current` ticketer. - /// - /// Calling this regularly will ensure timely key erasure. Otherwise, - /// key erasure will be delayed until the next encrypt/decrypt call. - /// - /// For efficiency, this is also responsible for locking the state mutex - /// and returning the mutexguard. - fn maybe_roll(&self, now: TimeBase) -> Option> { - // The code below aims to make switching as efficient as possible - // in the common case that the generator never fails. To achieve this - // we run the following steps: - // 1. If no switch is necessary, just return the mutexguard - // 2. Shift over all of the ticketers (so current becomes previous, - // and next becomes current). After this, other threads can - // start using the new current ticketer. - // 3. unlock mutex and generate new ticketer. - // 4. Place new ticketer in next and return current - // - // There are a few things to note here. First, we don't check whether - // a new switch might be needed in step 4, even though, due to locking - // and entropy collection, significant amounts of time may have passed. - // This is to guarantee that the thread doing the switch will eventually - // make progress. - // - // Second, because next may be None, step 2 can fail. In that case - // we enter a recovery mode where we generate 2 new ticketers, one for - // next and one for the current ticketer. We then take the mutex a - // second time and redo the time check to see if a switch is still - // necessary. - // - // This somewhat convoluted approach ensures good availability of the - // mutex, by ensuring that the state is usable and the mutex not held - // during generation. It also ensures that, so long as the inner - // ticketer never generates panics during encryption/decryption, - // we are guaranteed to never panic when holding the mutex. - - let now = now.as_secs(); - let mut are_recovering = false; // Are we recovering from previous failure? - { - // Scope the mutex so we only take it for as long as needed - let mut state = self.state.lock().ok()?; - - // Fast path in case we do not need to switch to the next ticketer yet - if now <= state.next_switch_time { - return Some(state); - } - - // Make the switch, or mark for recovery if not possible - if let Some(next) = state.next.take() { - state.previous = Some(mem::replace(&mut state.current, next)); - state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); - } else { - are_recovering = true; - } - } - - // We always need a next, so generate it now - let next = (self.generator)().ok()?; - if !are_recovering { - // Normal path, generate new next and place it in the state - let mut state = self.state.lock().ok()?; - state.next = Some(next); - Some(state) - } else { - // Recovering, generate also a new current ticketer, and modify state - // as needed. (we need to redo the time check, otherwise this might - // result in very rapid switching of ticketers) - let new_current = (self.generator)().ok()?; - let mut state = self.state.lock().ok()?; - state.next = Some(next); - if now > state.next_switch_time { - state.previous = Some(mem::replace(&mut state.current, new_current)); - state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); - } - Some(state) - } - } -} - -impl ProducesTickets for TicketSwitcher { - fn lifetime(&self) -> u32 { - self.lifetime * 2 - } - - fn enabled(&self) -> bool { - true - } - - fn encrypt(&self, message: &[u8]) -> Option> { - let state = self.maybe_roll(TimeBase::now().ok()?)?; - - state.current.encrypt(message) - } - - fn decrypt(&self, ciphertext: &[u8]) -> Option> { - let state = self.maybe_roll(TimeBase::now().ok()?)?; - - // Decrypt with the current key; if that fails, try with the previous. - state - .current - .decrypt(ciphertext) - .or_else(|| { - state - .previous - .as_ref() - .and_then(|previous| previous.decrypt(ciphertext)) - }) - } -} - -/// A concrete, safe ticket creation mechanism. -pub struct Ticketer {} - -fn generate_inner() -> Result, rand::GetRandomFailed> { - Ok(Box::new(AeadTicketer::new()?)) -} - -impl Ticketer { - /// Make the recommended Ticketer. This produces tickets - /// with a 12 hour life and randomly generated keys. - /// - /// The encryption mechanism used in Chacha20Poly1305. - pub fn new() -> Result, Error> { - Ok(Arc::new(TicketSwitcher::new(6 * 60 * 60, generate_inner)?)) - } -} - -#[test] -fn basic_pairwise_test() { - let t = Ticketer::new().unwrap(); - assert!(t.enabled()); - let cipher = t.encrypt(b"hello world").unwrap(); - let plain = t.decrypt(&cipher).unwrap(); - assert_eq!(plain, b"hello world"); -} - -#[test] -fn ticketswitcher_switching_test() { - let t = Arc::new(TicketSwitcher::new(1, generate_inner).unwrap()); - let now = TimeBase::now().unwrap(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - { - // Trigger new ticketer - t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(10))); - } - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // Trigger new ticketer - t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(20))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); -} - -#[cfg(test)] -fn fail_generator() -> Result, rand::GetRandomFailed> { - Err(rand::GetRandomFailed) -} - -#[test] -fn ticketswitcher_recover_test() { - let mut t = TicketSwitcher::new(1, generate_inner).unwrap(); - let now = TimeBase::now().unwrap(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - t.generator = fail_generator; - { - // Failed new ticketer - t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(10))); - } - t.generator = generate_inner; - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // recover - t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_secs(20))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); -} diff --git a/third_party/rustls-fork-shadow-tls/src/tls12/cipher.rs b/third_party/rustls-fork-shadow-tls/src/tls12/cipher.rs deleted file mode 100644 index 2910c20..0000000 --- a/third_party/rustls-fork-shadow-tls/src/tls12/cipher.rs +++ /dev/null @@ -1,236 +0,0 @@ -use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; -use crate::enums::ProtocolVersion; -use crate::error::Error; -use crate::msgs::base::Payload; -use crate::msgs::codec; -use crate::msgs::enums::ContentType; -use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; -use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; - -use ring::aead; - -const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2; - -fn make_tls12_aad( - seq: u64, - typ: ContentType, - vers: ProtocolVersion, - len: usize, -) -> ring::aead::Aad<[u8; TLS12_AAD_SIZE]> { - let mut out = [0; TLS12_AAD_SIZE]; - codec::put_u64(seq, &mut out[0..]); - out[8] = typ.get_u8(); - codec::put_u16(vers.get_u16(), &mut out[9..]); - codec::put_u16(len as u16, &mut out[11..]); - ring::aead::Aad::from(out) -} - -pub(crate) struct AesGcm; - -impl Tls12AeadAlgorithm for AesGcm { - fn decrypter(&self, dec_key: aead::LessSafeKey, dec_iv: &[u8]) -> Box { - let mut ret = GcmMessageDecrypter { - dec_key, - dec_salt: [0u8; 4], - }; - - debug_assert_eq!(dec_iv.len(), 4); - ret.dec_salt.copy_from_slice(dec_iv); - Box::new(ret) - } - - fn encrypter( - &self, - enc_key: aead::LessSafeKey, - write_iv: &[u8], - explicit: &[u8], - ) -> Box { - debug_assert_eq!(write_iv.len(), 4); - debug_assert_eq!(explicit.len(), 8); - - // The GCM nonce is constructed from a 32-bit 'salt' derived - // from the master-secret, and a 64-bit explicit part, - // with no specified construction. Thanks for that. - // - // We use the same construction as TLS1.3/ChaCha20Poly1305: - // a starting point extracted from the key block, xored with - // the sequence number. - let mut iv = Iv(Default::default()); - iv.0[..4].copy_from_slice(write_iv); - iv.0[4..].copy_from_slice(explicit); - - Box::new(GcmMessageEncrypter { enc_key, iv }) - } -} - -pub(crate) struct ChaCha20Poly1305; - -impl Tls12AeadAlgorithm for ChaCha20Poly1305 { - fn decrypter(&self, dec_key: aead::LessSafeKey, iv: &[u8]) -> Box { - Box::new(ChaCha20Poly1305MessageDecrypter { - dec_key, - dec_offset: Iv::copy(iv), - }) - } - - fn encrypter( - &self, - enc_key: aead::LessSafeKey, - enc_iv: &[u8], - _: &[u8], - ) -> Box { - Box::new(ChaCha20Poly1305MessageEncrypter { - enc_key, - enc_offset: Iv::copy(enc_iv), - }) - } -} - -pub(crate) trait Tls12AeadAlgorithm: Send + Sync + 'static { - fn decrypter(&self, key: aead::LessSafeKey, iv: &[u8]) -> Box; - fn encrypter( - &self, - key: aead::LessSafeKey, - iv: &[u8], - extra: &[u8], - ) -> Box; -} - -/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. -struct GcmMessageEncrypter { - enc_key: aead::LessSafeKey, - iv: Iv, -} - -/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. -struct GcmMessageDecrypter { - dec_key: aead::LessSafeKey, - dec_salt: [u8; 4], -} - -const GCM_EXPLICIT_NONCE_LEN: usize = 8; -const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; - -impl MessageDecrypter for GcmMessageDecrypter { - fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { - let payload = &mut msg.payload.0; - if payload.len() < GCM_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = { - let mut nonce = [0u8; 12]; - nonce[..4].copy_from_slice(&self.dec_salt); - nonce[4..].copy_from_slice(&payload[..8]); - aead::Nonce::assume_unique_for_key(nonce) - }; - - let aad = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - GCM_OVERHEAD); - - let plain_len = self - .dec_key - .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - payload.truncate(plain_len); - Ok(msg.into_plain_message()) - } -} - -impl MessageEncrypter for GcmMessageEncrypter { - fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { - let nonce = make_nonce(&self.iv, seq); - let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); - - let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); - let mut payload = Vec::with_capacity(GCM_EXPLICIT_NONCE_LEN + total_len); - payload.extend_from_slice(&nonce.as_ref()[4..]); - payload.extend_from_slice(msg.payload); - - self.enc_key - .seal_in_place_separate_tag(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..]) - .map(|tag| payload.extend(tag.as_ref())) - .map_err(|_| Error::General("encrypt failed".to_string()))?; - - Ok(OpaqueMessage { - typ: msg.typ, - version: msg.version, - payload: Payload::new(payload), - }) - } -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageEncrypter`. -struct ChaCha20Poly1305MessageEncrypter { - enc_key: aead::LessSafeKey, - enc_offset: Iv, -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageDecrypter`. -struct ChaCha20Poly1305MessageDecrypter { - dec_key: aead::LessSafeKey, - dec_offset: Iv, -} - -const CHACHAPOLY1305_OVERHEAD: usize = 16; - -impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { - fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { - let payload = &mut msg.payload.0; - - if payload.len() < CHACHAPOLY1305_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = make_nonce(&self.dec_offset, seq); - let aad = make_tls12_aad( - seq, - msg.typ, - msg.version, - payload.len() - CHACHAPOLY1305_OVERHEAD, - ); - - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - payload.truncate(plain_len); - Ok(msg.into_plain_message()) - } -} - -impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { - fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { - let nonce = make_nonce(&self.enc_offset, seq); - let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); - - let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); - let mut buf = Vec::with_capacity(total_len); - buf.extend_from_slice(msg.payload); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut buf) - .map_err(|_| Error::General("encrypt failed".to_string()))?; - - Ok(OpaqueMessage { - typ: msg.typ, - version: msg.version, - payload: Payload::new(buf), - }) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/tls12/mod.rs b/third_party/rustls-fork-shadow-tls/src/tls12/mod.rs deleted file mode 100644 index 4024aee..0000000 --- a/third_party/rustls-fork-shadow-tls/src/tls12/mod.rs +++ /dev/null @@ -1,537 +0,0 @@ -use crate::cipher::{MessageDecrypter, MessageEncrypter}; -use crate::conn::{CommonState, ConnectionRandoms, Side}; -use crate::enums::{CipherSuite, SignatureScheme}; -use crate::kx; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{AlertDescription, ContentType}; -use crate::msgs::handshake::KeyExchangeAlgorithm; -use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; -#[cfg(feature = "secret_extraction")] -use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}; -use crate::Error; - -use ring::aead; -use ring::digest::Digest; - -use std::fmt; - -mod cipher; -pub(crate) use cipher::{AesGcm, ChaCha20Poly1305, Tls12AeadAlgorithm}; - -mod prf; - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. -pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - bulk: BulkAlgorithm::Chacha20Poly1305, - aead_algorithm: &ring::aead::CHACHA20_POLY1305, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - fixed_iv_len: 12, - explicit_nonce_len: 0, - aead_alg: &ChaCha20Poly1305, - hmac_algorithm: ring::hmac::HMAC_SHA256, - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 -pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - bulk: BulkAlgorithm::Chacha20Poly1305, - aead_algorithm: &ring::aead::CHACHA20_POLY1305, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - fixed_iv_len: 12, - explicit_nonce_len: 0, - aead_alg: &ChaCha20Poly1305, - hmac_algorithm: ring::hmac::HMAC_SHA256, - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - bulk: BulkAlgorithm::Aes128Gcm, - aead_algorithm: &ring::aead::AES_128_GCM, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - fixed_iv_len: 4, - explicit_nonce_len: 8, - aead_alg: &AesGcm, - hmac_algorithm: ring::hmac::HMAC_SHA256, - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - bulk: BulkAlgorithm::Aes256Gcm, - aead_algorithm: &ring::aead::AES_256_GCM, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - fixed_iv_len: 4, - explicit_nonce_len: 8, - aead_alg: &AesGcm, - hmac_algorithm: ring::hmac::HMAC_SHA384, - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - bulk: BulkAlgorithm::Aes128Gcm, - aead_algorithm: &ring::aead::AES_128_GCM, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - fixed_iv_len: 4, - explicit_nonce_len: 8, - aead_alg: &AesGcm, - hmac_algorithm: ring::hmac::HMAC_SHA256, - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - bulk: BulkAlgorithm::Aes256Gcm, - aead_algorithm: &ring::aead::AES_256_GCM, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - fixed_iv_len: 4, - explicit_nonce_len: 8, - aead_alg: &AesGcm, - hmac_algorithm: ring::hmac::HMAC_SHA384, - }); - -static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::ED25519, - SignatureScheme::ECDSA_NISTP521_SHA512, - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, -]; - -static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -/// A TLS 1.2 cipher suite supported by rustls. -pub struct Tls12CipherSuite { - /// Common cipher suite fields. - pub common: CipherSuiteCommon, - pub(crate) hmac_algorithm: ring::hmac::Algorithm, - /// How to exchange/agree keys. - pub kx: KeyExchangeAlgorithm, - - /// How to sign messages for authentication. - pub sign: &'static [SignatureScheme], - - /// How long the fixed part of the 'IV' is. - /// - /// This isn't usually an IV, but we continue the - /// terminology misuse to match the standard. - pub fixed_iv_len: usize, - - /// This is a non-standard extension which extends the - /// key block to provide an initial explicit nonce offset, - /// in a deterministic and safe way. GCM needs this, - /// chacha20poly1305 works this way by design. - pub explicit_nonce_len: usize, - - pub(crate) aead_alg: &'static dyn Tls12AeadAlgorithm, -} - -impl Tls12CipherSuite { - /// Resolve the set of supported `SignatureScheme`s from the - /// offered `SupportedSignatureSchemes`. If we return an empty - /// set, the handshake terminates. - pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec { - self.sign - .iter() - .filter(|pref| offered.contains(pref)) - .cloned() - .collect() - } - - /// Which hash function to use with this suite. - pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { - self.hmac_algorithm.digest_algorithm() - } -} - -impl From<&'static Tls12CipherSuite> for SupportedCipherSuite { - fn from(s: &'static Tls12CipherSuite) -> Self { - Self::Tls12(s) - } -} - -impl PartialEq for Tls12CipherSuite { - fn eq(&self, other: &Self) -> bool { - self.common.suite == other.common.suite - } -} - -impl fmt::Debug for Tls12CipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tls12CipherSuite") - .field("suite", &self.common.suite) - .field("bulk", &self.common.bulk) - .finish() - } -} - -/// TLS1.2 per-connection keying material -pub(crate) struct ConnectionSecrets { - pub(crate) randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - pub(crate) master_secret: [u8; 48], -} - -impl ConnectionSecrets { - pub(crate) fn from_key_exchange( - kx: kx::KeyExchange, - peer_pub_key: &[u8], - ems_seed: Option, - randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - ) -> Result { - let mut ret = Self { - randoms, - suite, - master_secret: [0u8; 48], - }; - - let (label, seed) = match ems_seed { - Some(seed) => ("extended master secret", Seed::Ems(seed)), - None => ( - "master secret", - Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)), - ), - }; - - kx.complete(peer_pub_key, |secret| { - prf::prf( - &mut ret.master_secret, - suite.hmac_algorithm, - secret, - label.as_bytes(), - seed.as_ref(), - ); - Ok(()) - })?; - - Ok(ret) - } - - pub(crate) fn new_resume( - randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - master_secret: &[u8], - ) -> Self { - let mut ret = Self { - randoms, - suite, - master_secret: [0u8; 48], - }; - ret.master_secret - .copy_from_slice(master_secret); - ret - } - - /// Make a `MessageCipherPair` based on the given supported ciphersuite `scs`, - /// and the session's `secrets`. - pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair { - fn split_key<'a>( - key_block: &'a [u8], - alg: &'static aead::Algorithm, - ) -> (aead::LessSafeKey, &'a [u8]) { - // Might panic if the key block is too small. - let (key, rest) = key_block.split_at(alg.key_len()); - // Won't panic because its only prerequisite is that `key` is `alg.key_len()` bytes long. - let key = aead::UnboundKey::new(alg, key).unwrap(); - (aead::LessSafeKey::new(key), rest) - } - - // Make a key block, and chop it up. - // nb. we don't implement any ciphersuites with nonzero mac_key_len. - let key_block = self.make_key_block(); - - let suite = self.suite; - let scs = &suite.common; - - let (client_write_key, key_block) = split_key(&key_block, scs.aead_algorithm); - let (server_write_key, key_block) = split_key(key_block, scs.aead_algorithm); - let (client_write_iv, key_block) = key_block.split_at(suite.fixed_iv_len); - let (server_write_iv, extra) = key_block.split_at(suite.fixed_iv_len); - - let (write_key, write_iv, read_key, read_iv) = match side { - Side::Client => ( - client_write_key, - client_write_iv, - server_write_key, - server_write_iv, - ), - Side::Server => ( - server_write_key, - server_write_iv, - client_write_key, - client_write_iv, - ), - }; - - ( - suite - .aead_alg - .decrypter(read_key, read_iv), - suite - .aead_alg - .encrypter(write_key, write_iv, extra), - ) - } - - fn make_key_block(&self) -> Vec { - let suite = &self.suite; - let common = &self.suite.common; - - let len = - (common.aead_algorithm.key_len() + suite.fixed_iv_len) * 2 + suite.explicit_nonce_len; - - let mut out = Vec::new(); - out.resize(len, 0u8); - - // NOTE: opposite order to above for no good reason. - // Don't design security protocols on drugs, kids. - let randoms = join_randoms(&self.randoms.server, &self.randoms.client); - prf::prf( - &mut out, - self.suite.hmac_algorithm, - &self.master_secret, - b"key expansion", - &randoms, - ); - - out - } - - pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { - self.suite - } - - pub(crate) fn get_master_secret(&self) -> Vec { - let mut ret = Vec::new(); - ret.extend_from_slice(&self.master_secret); - ret - } - - fn make_verify_data(&self, handshake_hash: &Digest, label: &[u8]) -> Vec { - let mut out = Vec::new(); - out.resize(12, 0u8); - - prf::prf( - &mut out, - self.suite.hmac_algorithm, - &self.master_secret, - label, - handshake_hash.as_ref(), - ); - out - } - - pub(crate) fn client_verify_data(&self, handshake_hash: &Digest) -> Vec { - self.make_verify_data(handshake_hash, b"client finished") - } - - pub(crate) fn server_verify_data(&self, handshake_hash: &Digest) -> Vec { - self.make_verify_data(handshake_hash, b"server finished") - } - - pub(crate) fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) { - let mut randoms = Vec::new(); - randoms.extend_from_slice(&self.randoms.client); - randoms.extend_from_slice(&self.randoms.server); - if let Some(context) = context { - assert!(context.len() <= 0xffff); - (context.len() as u16).encode(&mut randoms); - randoms.extend_from_slice(context); - } - - prf::prf( - output, - self.suite.hmac_algorithm, - &self.master_secret, - label, - &randoms, - ) - } - - #[cfg(feature = "secret_extraction")] - pub(crate) fn extract_secrets(&self, side: Side) -> Result { - // Make a key block, and chop it up - let key_block = self.make_key_block(); - - let suite = self.suite; - let algo = suite.common.aead_algorithm; - - let (client_key, key_block) = key_block.split_at(algo.key_len()); - let (server_key, key_block) = key_block.split_at(algo.key_len()); - let (client_iv, key_block) = key_block.split_at(suite.fixed_iv_len); - let (server_iv, extra) = key_block.split_at(suite.fixed_iv_len); - - // A key/IV pair (fixed IV len is 4 for GCM, 12 for Chacha) - struct Pair<'a> { - key: &'a [u8], - iv: &'a [u8], - } - - let client_pair = Pair { - key: client_key, - iv: client_iv, - }; - let server_pair = Pair { - key: server_key, - iv: server_iv, - }; - - let (client_secrets, server_secrets) = if algo == &ring::aead::AES_128_GCM { - let extract = |pair: Pair| -> ConnectionTrafficSecrets { - let mut key = [0u8; 16]; - key.copy_from_slice(pair.key); - - let mut salt = [0u8; 4]; - salt.copy_from_slice(pair.iv); - - let mut iv = [0u8; 8]; - iv.copy_from_slice(&extra[..8]); - - ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } - }; - - (extract(client_pair), extract(server_pair)) - } else if algo == &ring::aead::AES_256_GCM { - let extract = |pair: Pair| -> ConnectionTrafficSecrets { - let mut key = [0u8; 32]; - key.copy_from_slice(pair.key); - - let mut salt = [0u8; 4]; - salt.copy_from_slice(pair.iv); - - let mut iv = [0u8; 8]; - iv.copy_from_slice(&extra[..8]); - - ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } - }; - - (extract(client_pair), extract(server_pair)) - } else if algo == &ring::aead::CHACHA20_POLY1305 { - let extract = |pair: Pair| -> ConnectionTrafficSecrets { - let mut key = [0u8; 32]; - key.copy_from_slice(pair.key); - - let mut iv = [0u8; 12]; - iv.copy_from_slice(pair.iv); - - ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } - }; - - (extract(client_pair), extract(server_pair)) - } else { - return Err(Error::General(format!( - "exporting secrets for {:?}: unimplemented", - algo - ))); - }; - - let (tx, rx) = match side { - Side::Client => (client_secrets, server_secrets), - Side::Server => (server_secrets, client_secrets), - }; - Ok(PartiallyExtractedSecrets { tx, rx }) - } -} - -enum Seed { - Ems(Digest), - Randoms([u8; 64]), -} - -impl AsRef<[u8]> for Seed { - fn as_ref(&self) -> &[u8] { - match self { - Self::Ems(seed) => seed.as_ref(), - Self::Randoms(randoms) => randoms.as_ref(), - } - } -} - -fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] { - let mut randoms = [0u8; 64]; - randoms[..32].copy_from_slice(first); - randoms[32..].copy_from_slice(second); - randoms -} - -type MessageCipherPair = (Box, Box); - -pub(crate) fn decode_ecdh_params( - common: &mut CommonState, - kx_params: &[u8], -) -> Result { - decode_ecdh_params_::(kx_params).ok_or_else(|| { - common.send_fatal_alert(AlertDescription::DecodeError); - Error::CorruptMessagePayload(ContentType::Handshake) - }) -} - -fn decode_ecdh_params_(kx_params: &[u8]) -> Option { - let mut rd = Reader::init(kx_params); - let ecdh_params = T::read(&mut rd)?; - match rd.any_left() { - false => Some(ecdh_params), - true => None, - } -} - -pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01]; - -#[cfg(test)] -mod tests { - use super::*; - use crate::msgs::handshake::{ClientECDHParams, ServerECDHParams}; - - #[test] - fn server_ecdhe_remaining_bytes() { - let key = kx::KeyExchange::start(&kx::X25519).unwrap(); - let server_params = ServerECDHParams::new(key.group(), key.pubkey.as_ref()); - let mut server_buf = Vec::new(); - server_params.encode(&mut server_buf); - server_buf.push(34); - assert!(decode_ecdh_params_::(&server_buf).is_none()); - } - - #[test] - fn client_ecdhe_invalid() { - assert!(decode_ecdh_params_::(&[34]).is_none()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/tls12/prf.rs b/third_party/rustls-fork-shadow-tls/src/tls12/prf.rs deleted file mode 100644 index 24ff8ba..0000000 --- a/third_party/rustls-fork-shadow-tls/src/tls12/prf.rs +++ /dev/null @@ -1,67 +0,0 @@ -use ring::hmac; - -fn concat_sign(key: &hmac::Key, a: &[u8], b: &[u8]) -> hmac::Tag { - let mut ctx = hmac::Context::with_key(key); - ctx.update(a); - ctx.update(b); - ctx.sign() -} - -fn p(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], seed: &[u8]) { - let hmac_key = hmac::Key::new(alg, secret); - - // A(1) - let mut current_a = hmac::sign(&hmac_key, seed); - let chunk_size = alg.digest_algorithm().output_len; - for chunk in out.chunks_mut(chunk_size) { - // P_hash[i] = HMAC_hash(secret, A(i) + seed) - let p_term = concat_sign(&hmac_key, current_a.as_ref(), seed); - chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]); - - // A(i+1) = HMAC_hash(secret, A(i)) - current_a = hmac::sign(&hmac_key, current_a.as_ref()); - } -} - -fn concat(a: &[u8], b: &[u8]) -> Vec { - let mut ret = Vec::new(); - ret.extend_from_slice(a); - ret.extend_from_slice(b); - ret -} - -pub(crate) fn prf(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], label: &[u8], seed: &[u8]) { - let joined_seed = concat(label, seed); - p(out, alg, secret, &joined_seed); -} - -#[cfg(test)] -mod tests { - use ring::hmac::{HMAC_SHA256, HMAC_SHA512}; - - #[test] - fn check_sha256() { - let secret = b"\x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35"; - let seed = b"\xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c"; - let label = b"test label"; - let expect = include_bytes!("../testdata/prf-result.1.bin"); - let mut output = [0u8; 100]; - - super::prf(&mut output, HMAC_SHA256, secret, label, seed); - assert_eq!(expect.len(), output.len()); - assert_eq!(expect.to_vec(), output.to_vec()); - } - - #[test] - fn check_sha512() { - let secret = b"\xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb"; - let seed = b"\xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5"; - let label = b"test label"; - let expect = include_bytes!("../testdata/prf-result.2.bin"); - let mut output = [0u8; 196]; - - super::prf(&mut output, HMAC_SHA512, secret, label, seed); - assert_eq!(expect.len(), output.len()); - assert_eq!(expect.to_vec(), output.to_vec()); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/tls13/key_schedule.rs b/third_party/rustls-fork-shadow-tls/src/tls13/key_schedule.rs deleted file mode 100644 index 098c7b7..0000000 --- a/third_party/rustls-fork-shadow-tls/src/tls13/key_schedule.rs +++ /dev/null @@ -1,800 +0,0 @@ -use crate::cipher::{Iv, IvLen}; -use crate::error::Error; -use crate::msgs::base::PayloadU8; -use crate::KeyLog; -#[cfg(feature = "secret_extraction")] -use crate::{ - conn::Side, - suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}, -}; - -/// Key schedule maintenance for TLS1.3 -use ring::{ - aead, - digest::{self, Digest}, - hkdf::{self, KeyType as _}, - hmac, -}; - -/// The kinds of secret we can extract from `KeySchedule`. -#[derive(Debug, Clone, Copy, PartialEq)] -enum SecretKind { - ResumptionPskBinderKey, - ClientEarlyTrafficSecret, - ClientHandshakeTrafficSecret, - ServerHandshakeTrafficSecret, - ClientApplicationTrafficSecret, - ServerApplicationTrafficSecret, - ExporterMasterSecret, - ResumptionMasterSecret, - DerivedSecret, -} - -impl SecretKind { - fn to_bytes(self) -> &'static [u8] { - use self::SecretKind::*; - match self { - ResumptionPskBinderKey => b"res binder", - ClientEarlyTrafficSecret => b"c e traffic", - ClientHandshakeTrafficSecret => b"c hs traffic", - ServerHandshakeTrafficSecret => b"s hs traffic", - ClientApplicationTrafficSecret => b"c ap traffic", - ServerApplicationTrafficSecret => b"s ap traffic", - ExporterMasterSecret => b"exp master", - ResumptionMasterSecret => b"res master", - DerivedSecret => b"derived", - } - } - - fn log_label(self) -> Option<&'static str> { - use self::SecretKind::*; - Some(match self { - ClientEarlyTrafficSecret => "CLIENT_EARLY_TRAFFIC_SECRET", - ClientHandshakeTrafficSecret => "CLIENT_HANDSHAKE_TRAFFIC_SECRET", - ServerHandshakeTrafficSecret => "SERVER_HANDSHAKE_TRAFFIC_SECRET", - ClientApplicationTrafficSecret => "CLIENT_TRAFFIC_SECRET_0", - ServerApplicationTrafficSecret => "SERVER_TRAFFIC_SECRET_0", - ExporterMasterSecret => "EXPORTER_SECRET", - _ => { - return None; - } - }) - } -} - -/// This is the TLS1.3 key schedule. It stores the current secret and -/// the type of hash. This isn't used directly; but only through the -/// typestates. -struct KeySchedule { - current: hkdf::Prk, - algorithm: ring::hkdf::Algorithm, -} - -// We express the state of a contained KeySchedule using these -// typestates. This means we can write code that cannot accidentally -// (e.g.) encrypt application data using a KeySchedule solely constructed -// with an empty or trivial secret, or extract the wrong kind of secrets -// at a given point. - -/// KeySchedule for early data stage. -pub(crate) struct KeyScheduleEarly { - ks: KeySchedule, -} - -impl KeyScheduleEarly { - pub(crate) fn new(algorithm: hkdf::Algorithm, secret: &[u8]) -> Self { - Self { - ks: KeySchedule::new(algorithm, secret), - } - } - - pub(crate) fn client_early_traffic_secret( - &self, - hs_hash: &Digest, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> hkdf::Prk { - self.ks.derive_logged_secret( - SecretKind::ClientEarlyTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ) - } - - pub(crate) fn resumption_psk_binder_key_and_sign_verify_data( - &self, - hs_hash: &Digest, - ) -> hmac::Tag { - let resumption_psk_binder_key = self - .ks - .derive_for_empty_hash(SecretKind::ResumptionPskBinderKey); - self.ks - .sign_verify_data(&resumption_psk_binder_key, hs_hash) - } -} - -/// Pre-handshake key schedule -/// -/// The inner `KeySchedule` is either constructed without any secrets based on ths HKDF algorithm -/// or is extracted from a `KeyScheduleEarly`. This can then be used to derive the `KeyScheduleHandshakeStart`. -pub(crate) struct KeySchedulePreHandshake { - ks: KeySchedule, -} - -impl KeySchedulePreHandshake { - pub(crate) fn new(algorithm: hkdf::Algorithm) -> Self { - Self { - ks: KeySchedule::new_with_empty_secret(algorithm), - } - } - - pub(crate) fn into_handshake(mut self, secret: &[u8]) -> KeyScheduleHandshakeStart { - self.ks.input_secret(secret); - KeyScheduleHandshakeStart { ks: self.ks } - } -} - -impl From for KeySchedulePreHandshake { - fn from(KeyScheduleEarly { ks }: KeyScheduleEarly) -> Self { - Self { ks } - } -} - -/// KeySchedule during handshake. -pub(crate) struct KeyScheduleHandshakeStart { - ks: KeySchedule, -} - -impl KeyScheduleHandshakeStart { - pub(crate) fn derive_handshake_secrets( - self, - hs_hash: Digest, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> (KeyScheduleHandshake, hkdf::Prk, hkdf::Prk) { - // Use an empty handshake hash for the initial handshake. - let client_secret = self.ks.derive_logged_secret( - SecretKind::ClientHandshakeTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let server_secret = self.ks.derive_logged_secret( - SecretKind::ServerHandshakeTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let new = KeyScheduleHandshake { - ks: self.ks, - client_handshake_traffic_secret: client_secret.clone(), - server_handshake_traffic_secret: server_secret.clone(), - }; - - (new, client_secret, server_secret) - } -} - -pub(crate) struct KeyScheduleHandshake { - ks: KeySchedule, - client_handshake_traffic_secret: hkdf::Prk, - server_handshake_traffic_secret: hkdf::Prk, -} - -impl KeyScheduleHandshake { - pub(crate) fn sign_server_finish(&self, hs_hash: &Digest) -> hmac::Tag { - self.ks - .sign_finish(&self.server_handshake_traffic_secret, hs_hash) - } - - pub(crate) fn client_key(&self) -> &hkdf::Prk { - &self.client_handshake_traffic_secret - } - - pub(crate) fn into_traffic_with_client_finished_pending( - self, - hs_hash: Digest, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> ( - KeyScheduleTrafficWithClientFinishedPending, - hkdf::Prk, - hkdf::Prk, - ) { - let traffic = KeyScheduleTraffic::new(self.ks, hs_hash, key_log, client_random); - - let client_secret = traffic - .current_client_traffic_secret - .clone(); - let server_secret = traffic - .current_server_traffic_secret - .clone(); - - let new = KeyScheduleTrafficWithClientFinishedPending { - handshake_client_traffic_secret: self.client_handshake_traffic_secret, - traffic, - }; - - (new, client_secret, server_secret) - } -} - -/// KeySchedule during traffic stage, retaining the ability to calculate the client's -/// finished verify_data. The traffic stage key schedule can be extracted from it -/// through signing the client finished hash. -pub(crate) struct KeyScheduleTrafficWithClientFinishedPending { - handshake_client_traffic_secret: hkdf::Prk, - traffic: KeyScheduleTraffic, -} - -impl KeyScheduleTrafficWithClientFinishedPending { - pub(crate) fn client_key(&self) -> &hkdf::Prk { - &self.handshake_client_traffic_secret - } - - pub(crate) fn sign_client_finish( - self, - hs_hash: &Digest, - ) -> (KeyScheduleTraffic, hmac::Tag, hkdf::Prk) { - let tag = self - .traffic - .ks - .sign_finish(&self.handshake_client_traffic_secret, hs_hash); - - let client_secret = self - .traffic - .current_client_traffic_secret - .clone(); - - (self.traffic, tag, client_secret) - } -} - -/// KeySchedule during traffic stage. All traffic & exporter keys are guaranteed -/// to be available. -pub(crate) struct KeyScheduleTraffic { - ks: KeySchedule, - current_client_traffic_secret: hkdf::Prk, - current_server_traffic_secret: hkdf::Prk, - current_exporter_secret: hkdf::Prk, -} - -impl KeyScheduleTraffic { - fn new( - mut ks: KeySchedule, - hs_hash: Digest, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> Self { - ks.input_empty(); - - let current_client_traffic_secret = ks.derive_logged_secret( - SecretKind::ClientApplicationTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let current_server_traffic_secret = ks.derive_logged_secret( - SecretKind::ServerApplicationTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let current_exporter_secret = ks.derive_logged_secret( - SecretKind::ExporterMasterSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - Self { - ks, - current_client_traffic_secret, - current_server_traffic_secret, - current_exporter_secret, - } - } - - pub(crate) fn next_server_application_traffic_secret(&mut self) -> hkdf::Prk { - let secret = self - .ks - .derive_next(&self.current_server_traffic_secret); - self.current_server_traffic_secret = secret.clone(); - secret - } - - pub(crate) fn next_client_application_traffic_secret(&mut self) -> hkdf::Prk { - let secret = self - .ks - .derive_next(&self.current_client_traffic_secret); - self.current_client_traffic_secret = secret.clone(); - secret - } - - pub(crate) fn resumption_master_secret_and_derive_ticket_psk( - &self, - hs_hash: &Digest, - nonce: &[u8], - ) -> Vec { - let resumption_master_secret = self.ks.derive( - self.ks.algorithm(), - SecretKind::ResumptionMasterSecret, - hs_hash.as_ref(), - ); - self.ks - .derive_ticket_psk(&resumption_master_secret, nonce) - } - - pub(crate) fn export_keying_material( - &self, - out: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.ks - .export_keying_material(&self.current_exporter_secret, out, label, context) - } - - #[cfg(feature = "secret_extraction")] - pub(crate) fn extract_secrets( - &self, - algo: &ring::aead::Algorithm, - side: Side, - ) -> Result { - fn expand( - secret: &hkdf::Prk, - ) -> Result<([u8; KEY_LEN], [u8; IV_LEN]), Error> { - let mut key = [0u8; KEY_LEN]; - let mut iv = [0u8; IV_LEN]; - - hkdf_expand_info(secret, PayloadU8Len(key.len()), b"key", &[], |okm| { - okm.fill(&mut key) - }) - .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; - - hkdf_expand_info(secret, PayloadU8Len(iv.len()), b"iv", &[], |okm| { - okm.fill(&mut iv) - }) - .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; - - Ok((key, iv)) - } - - let client_secrets; - let server_secrets; - - if algo == &ring::aead::AES_128_GCM { - let extract = |secret: &hkdf::Prk| -> Result { - let (key, iv_in) = expand::<16, 12>(secret)?; - - let mut salt = [0u8; 4]; - salt.copy_from_slice(&iv_in[..4]); - - let mut iv = [0u8; 8]; - iv.copy_from_slice(&iv_in[4..]); - - Ok(ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv }) - }; - - client_secrets = extract(&self.current_client_traffic_secret)?; - server_secrets = extract(&self.current_server_traffic_secret)?; - } else if algo == &ring::aead::AES_256_GCM { - let extract = |secret: &hkdf::Prk| -> Result { - let (key, iv_in) = expand::<32, 12>(secret)?; - - let mut salt = [0u8; 4]; - salt.copy_from_slice(&iv_in[..4]); - - let mut iv = [0u8; 8]; - iv.copy_from_slice(&iv_in[4..]); - - Ok(ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv }) - }; - - client_secrets = extract(&self.current_client_traffic_secret)?; - server_secrets = extract(&self.current_server_traffic_secret)?; - } else if algo == &ring::aead::CHACHA20_POLY1305 { - let extract = |secret: &hkdf::Prk| -> Result { - let (key, iv) = expand::<32, 12>(secret)?; - Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) - }; - - client_secrets = extract(&self.current_client_traffic_secret)?; - server_secrets = extract(&self.current_server_traffic_secret)?; - } else { - return Err(Error::General(format!( - "exporting secrets for {:?}: unimplemented", - algo - ))); - } - - let (tx, rx) = match side { - crate::conn::Side::Client => (client_secrets, server_secrets), - crate::conn::Side::Server => (server_secrets, client_secrets), - }; - Ok(PartiallyExtractedSecrets { tx, rx }) - } -} - -impl KeySchedule { - fn new(algorithm: hkdf::Algorithm, secret: &[u8]) -> Self { - let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; - let salt = hkdf::Salt::new(algorithm, &zeroes[..algorithm.len()]); - Self { - current: salt.extract(secret), - algorithm, - } - } - - #[inline] - fn algorithm(&self) -> hkdf::Algorithm { - self.algorithm - } - - fn new_with_empty_secret(algorithm: hkdf::Algorithm) -> Self { - let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; - Self::new(algorithm, &zeroes[..algorithm.len()]) - } - - /// Input the empty secret. - fn input_empty(&mut self) { - let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; - self.input_secret(&zeroes[..self.algorithm.len()]); - } - - /// Input the given secret. - fn input_secret(&mut self, secret: &[u8]) { - let salt: hkdf::Salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); - self.current = salt.extract(secret); - } - - /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. - fn derive(&self, key_type: L, kind: SecretKind, hs_hash: &[u8]) -> T - where - T: for<'a> From>, - L: hkdf::KeyType, - { - hkdf_expand(&self.current, key_type, kind.to_bytes(), hs_hash) - } - - fn derive_logged_secret( - &self, - kind: SecretKind, - hs_hash: &[u8], - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> hkdf::Prk { - let log_label = kind - .log_label() - .expect("not a loggable secret"); - if key_log.will_log(log_label) { - let secret = self - .derive::(PayloadU8Len(self.algorithm.len()), kind, hs_hash) - .into_inner(); - key_log.log(log_label, client_random, &secret); - } - self.derive(self.algorithm, kind, hs_hash) - } - - /// Derive a secret of given `kind` using the hash of the empty string - /// for the handshake hash. Useful only for - /// `SecretKind::ResumptionPSKBinderKey` and - /// `SecretKind::DerivedSecret`. - fn derive_for_empty_hash(&self, kind: SecretKind) -> T - where - T: for<'a> From>, - { - let digest_alg = self - .algorithm - .hmac_algorithm() - .digest_algorithm(); - let empty_hash = digest::digest(digest_alg, &[]); - self.derive(self.algorithm, kind, empty_hash.as_ref()) - } - - /// Sign the finished message consisting of `hs_hash` using a current - /// traffic secret. - fn sign_finish(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { - self.sign_verify_data(base_key, hs_hash) - } - - /// Sign the finished message consisting of `hs_hash` using the key material - /// `base_key`. - fn sign_verify_data(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { - let hmac_alg = self.algorithm.hmac_algorithm(); - let hmac_key = hkdf_expand(base_key, hmac_alg, b"finished", &[]); - hmac::sign(&hmac_key, hs_hash.as_ref()) - } - - /// Derive the next application traffic secret, returning it. - fn derive_next(&self, base_key: &hkdf::Prk) -> hkdf::Prk { - hkdf_expand(base_key, self.algorithm, b"traffic upd", &[]) - } - - /// Derive the PSK to use given a resumption_master_secret and - /// ticket_nonce. - fn derive_ticket_psk(&self, rms: &hkdf::Prk, nonce: &[u8]) -> Vec { - let payload: PayloadU8 = hkdf_expand( - rms, - PayloadU8Len(self.algorithm.len()), - b"resumption", - nonce, - ); - payload.into_inner() - } - - fn export_keying_material( - &self, - current_exporter_secret: &hkdf::Prk, - out: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - let digest_alg = self - .algorithm - .hmac_algorithm() - .digest_algorithm(); - - let h_empty = digest::digest(digest_alg, &[]); - let secret: hkdf::Prk = hkdf_expand( - current_exporter_secret, - self.algorithm, - label, - h_empty.as_ref(), - ); - - let h_context = digest::digest(digest_alg, context.unwrap_or(&[])); - - // TODO: Test what happens when this fails - hkdf_expand_info( - &secret, - PayloadU8Len(out.len()), - b"exporter", - h_context.as_ref(), - |okm| okm.fill(out), - ) - .map_err(|_| Error::General("exporting too much".to_string())) - } -} - -pub(crate) fn hkdf_expand(secret: &hkdf::Prk, key_type: L, label: &[u8], context: &[u8]) -> T -where - T: for<'a> From>, - L: hkdf::KeyType, -{ - hkdf_expand_info(secret, key_type, label, context, |okm| okm.into()) -} - -fn hkdf_expand_info( - secret: &hkdf::Prk, - key_type: L, - label: &[u8], - context: &[u8], - f: F, -) -> T -where - F: for<'b> FnOnce(hkdf::Okm<'b, L>) -> T, - L: hkdf::KeyType, -{ - const LABEL_PREFIX: &[u8] = b"tls13 "; - - let output_len = u16::to_be_bytes(key_type.len() as u16); - let label_len = u8::to_be_bytes((LABEL_PREFIX.len() + label.len()) as u8); - let context_len = u8::to_be_bytes(context.len() as u8); - - let info = &[ - &output_len[..], - &label_len[..], - LABEL_PREFIX, - label, - &context_len[..], - context, - ]; - let okm = secret.expand(info, key_type).unwrap(); - - f(okm) -} - -pub(crate) struct PayloadU8Len(pub(crate) usize); -impl hkdf::KeyType for PayloadU8Len { - fn len(&self) -> usize { - self.0 - } -} - -impl From> for PayloadU8 { - fn from(okm: hkdf::Okm) -> Self { - let mut r = vec![0u8; okm.len().0]; - okm.fill(&mut r[..]).unwrap(); - Self::new(r) - } -} - -pub(crate) fn derive_traffic_key( - secret: &hkdf::Prk, - aead_algorithm: &'static aead::Algorithm, -) -> aead::UnboundKey { - hkdf_expand(secret, aead_algorithm, b"key", &[]) -} - -pub(crate) fn derive_traffic_iv(secret: &hkdf::Prk) -> Iv { - hkdf_expand(secret, IvLen, b"iv", &[]) -} - -#[cfg(test)] -mod test { - use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; - use crate::KeyLog; - use ring::{aead, hkdf}; - - #[test] - fn test_vectors() { - /* These test vectors generated with OpenSSL. */ - let hs_start_hash = [ - 0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e, 0x41, - 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74, 0x82, 0xaf, - 0x75, 0x88, 0x1c, 0x0a, - ]; - - let hs_full_hash = [ - 0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91, 0x8e, - 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30, 0xac, 0x30, - 0xbb, 0xeb, 0x23, 0xe2, - ]; - - let ecdhe_secret = [ - 0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6, 0x9d, - 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15, 0xe3, 0x12, - 0x71, 0xdf, 0x4b, 0x40, - ]; - - let client_hts = [ - 0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, 0x66, - 0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, 0x04, 0x01, - 0x35, 0xcf, 0x46, 0xab, - ]; - - let client_hts_key = [ - 0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, 0x95, - 0x85, 0xa7, - ]; - - let client_hts_iv = [ - 0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9, - ]; - - let server_hts = [ - 0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, 0x4e, - 0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, 0xdd, 0xcf, - 0x29, 0xa8, 0x87, 0x59, - ]; - - let server_hts_key = [ - 0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, 0xbc, - 0xbc, 0x54, - ]; - - let server_hts_iv = [ - 0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09, - ]; - - let client_ats = [ - 0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, 0x3f, - 0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, 0x71, 0xa8, - 0x20, 0x6d, 0xbd, 0xa5, - ]; - - let client_ats_key = [ - 0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, 0xd7, - 0x57, 0x2e, - ]; - - let client_ats_iv = [ - 0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b, - ]; - - let server_ats = [ - 0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, 0x48, - 0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, 0x29, 0x0d, - 0x4c, 0x23, 0x21, 0x92, - ]; - - let server_ats_key = [ - 0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, 0xe6, - 0x2b, 0xb3, - ]; - - let server_ats_iv = [ - 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c, - ]; - - let hkdf = hkdf::HKDF_SHA256; - let mut ks = KeySchedule::new_with_empty_secret(hkdf); - ks.input_secret(&ecdhe_secret); - - assert_traffic_secret( - &ks, - SecretKind::ClientHandshakeTrafficSecret, - &hs_start_hash, - &client_hts, - &client_hts_key, - &client_hts_iv, - ); - - assert_traffic_secret( - &ks, - SecretKind::ServerHandshakeTrafficSecret, - &hs_start_hash, - &server_hts, - &server_hts_key, - &server_hts_iv, - ); - - ks.input_empty(); - - assert_traffic_secret( - &ks, - SecretKind::ClientApplicationTrafficSecret, - &hs_full_hash, - &client_ats, - &client_ats_key, - &client_ats_iv, - ); - - assert_traffic_secret( - &ks, - SecretKind::ServerApplicationTrafficSecret, - &hs_full_hash, - &server_ats, - &server_ats_key, - &server_ats_iv, - ); - } - - fn assert_traffic_secret( - ks: &KeySchedule, - kind: SecretKind, - hash: &[u8], - expected_traffic_secret: &[u8], - expected_key: &[u8], - expected_iv: &[u8], - ) { - struct Log<'a>(&'a [u8]); - impl KeyLog for Log<'_> { - fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) { - assert_eq!(self.0, secret); - } - } - let log = Log(expected_traffic_secret); - let traffic_secret = ks.derive_logged_secret(kind, hash, &log, &[0; 32]); - - // Since we can't test key equality, we test the output of sealing with the key instead. - let aead_alg = &aead::AES_128_GCM; - let key = derive_traffic_key(&traffic_secret, aead_alg); - let seal_output = seal_zeroes(key); - let expected_key = aead::UnboundKey::new(aead_alg, expected_key).unwrap(); - let expected_seal_output = seal_zeroes(expected_key); - assert_eq!(seal_output, expected_seal_output); - assert!(seal_output.len() >= 48); // Sanity check. - - let iv = derive_traffic_iv(&traffic_secret); - assert_eq!(iv.value(), expected_iv); - } - - fn seal_zeroes(key: aead::UnboundKey) -> Vec { - let key = aead::LessSafeKey::new(key); - let mut seal_output = vec![0; 32]; - key.seal_in_place_append_tag( - aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]), - aead::Aad::empty(), - &mut seal_output, - ) - .unwrap(); - seal_output - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/tls13/mod.rs b/third_party/rustls-fork-shadow-tls/src/tls13/mod.rs deleted file mode 100644 index 3f5b27d..0000000 --- a/third_party/rustls-fork-shadow-tls/src/tls13/mod.rs +++ /dev/null @@ -1,224 +0,0 @@ -use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; -use crate::enums::{CipherSuite, ProtocolVersion}; -use crate::error::Error; -use crate::msgs::base::Payload; -use crate::msgs::codec::Codec; -use crate::msgs::enums::ContentType; -use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; -use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; -use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; - -use ring::{aead, hkdf}; - -use std::fmt; - -pub(crate) mod key_schedule; -use key_schedule::{derive_traffic_iv, derive_traffic_key}; - -/// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 -pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); - -pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, - bulk: BulkAlgorithm::Chacha20Poly1305, - aead_algorithm: &ring::aead::CHACHA20_POLY1305, - }, - hkdf_algorithm: ring::hkdf::HKDF_SHA256, - #[cfg(feature = "quic")] - confidentiality_limit: u64::MAX, - #[cfg(feature = "quic")] - integrity_limit: 1 << 36, -}; - -/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 -pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls13(&Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_256_GCM_SHA384, - bulk: BulkAlgorithm::Aes256Gcm, - aead_algorithm: &ring::aead::AES_256_GCM, - }, - hkdf_algorithm: ring::hkdf::HKDF_SHA384, - #[cfg(feature = "quic")] - confidentiality_limit: 1 << 23, - #[cfg(feature = "quic")] - integrity_limit: 1 << 52, - }); - -/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 -pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); - -pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_128_GCM_SHA256, - bulk: BulkAlgorithm::Aes128Gcm, - aead_algorithm: &ring::aead::AES_128_GCM, - }, - hkdf_algorithm: ring::hkdf::HKDF_SHA256, - #[cfg(feature = "quic")] - confidentiality_limit: 1 << 23, - #[cfg(feature = "quic")] - integrity_limit: 1 << 52, -}; - -/// A TLS 1.3 cipher suite supported by rustls. -pub struct Tls13CipherSuite { - /// Common cipher suite fields. - pub common: CipherSuiteCommon, - pub(crate) hkdf_algorithm: ring::hkdf::Algorithm, - #[cfg(feature = "quic")] - pub(crate) confidentiality_limit: u64, - #[cfg(feature = "quic")] - pub(crate) integrity_limit: u64, -} - -impl Tls13CipherSuite { - pub(crate) fn derive_encrypter(&self, secret: &hkdf::Prk) -> Box { - let key = derive_traffic_key(secret, self.common.aead_algorithm); - let iv = derive_traffic_iv(secret); - - Box::new(Tls13MessageEncrypter { - enc_key: aead::LessSafeKey::new(key), - iv, - }) - } - - /// Derive a `MessageDecrypter` object from the concerned TLS 1.3 - /// cipher suite. - pub fn derive_decrypter(&self, secret: &hkdf::Prk) -> Box { - let key = derive_traffic_key(secret, self.common.aead_algorithm); - let iv = derive_traffic_iv(secret); - - Box::new(Tls13MessageDecrypter { - dec_key: aead::LessSafeKey::new(key), - iv, - }) - } - - /// Which hash function to use with this suite. - pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { - self.hkdf_algorithm - .hmac_algorithm() - .digest_algorithm() - } - - /// Can a session using suite self resume from suite prev? - pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> { - (prev.hash_algorithm() == self.hash_algorithm()).then(|| prev) - } -} - -impl From<&'static Tls13CipherSuite> for SupportedCipherSuite { - fn from(s: &'static Tls13CipherSuite) -> Self { - Self::Tls13(s) - } -} - -impl PartialEq for Tls13CipherSuite { - fn eq(&self, other: &Self) -> bool { - self.common.suite == other.common.suite - } -} - -impl fmt::Debug for Tls13CipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tls13CipherSuite") - .field("suite", &self.common.suite) - .field("bulk", &self.common.bulk) - .finish() - } -} - -struct Tls13MessageEncrypter { - enc_key: aead::LessSafeKey, - iv: Iv, -} - -struct Tls13MessageDecrypter { - dec_key: aead::LessSafeKey, - iv: Iv, -} - -fn unpad_tls13(v: &mut Vec) -> ContentType { - loop { - match v.pop() { - Some(0) => {} - Some(content_type) => return ContentType::from(content_type), - None => return ContentType::Unknown(0), - } - } -} - -fn make_tls13_aad(len: usize) -> ring::aead::Aad<[u8; TLS13_AAD_SIZE]> { - ring::aead::Aad::from([ - 0x17, // ContentType::ApplicationData - 0x3, // ProtocolVersion (major) - 0x3, // ProtocolVersion (minor) - (len >> 8) as u8, - len as u8, - ]) -} - -// https://datatracker.ietf.org/doc/html/rfc8446#section-5.2 -const TLS13_AAD_SIZE: usize = 1 + 2 + 2; - -impl MessageEncrypter for Tls13MessageEncrypter { - fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { - let total_len = msg.payload.len() + 1 + self.enc_key.algorithm().tag_len(); - let mut payload = Vec::with_capacity(total_len); - payload.extend_from_slice(msg.payload); - msg.typ.encode(&mut payload); - - let nonce = make_nonce(&self.iv, seq); - let aad = make_tls13_aad(total_len); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::General("encrypt failed".to_string()))?; - - Ok(OpaqueMessage { - typ: ContentType::ApplicationData, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(payload), - }) - } -} - -impl MessageDecrypter for Tls13MessageDecrypter { - fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { - let payload = &mut msg.payload.0; - if payload.len() < self.dec_key.algorithm().tag_len() { - return Err(Error::DecryptError); - } - - let nonce = make_nonce(&self.iv, seq); - let aad = make_tls13_aad(payload.len()); - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - payload.truncate(plain_len); - - if payload.len() > MAX_FRAGMENT_LEN + 1 { - return Err(Error::PeerSentOversizedRecord); - } - - msg.typ = unpad_tls13(payload); - if msg.typ == ContentType::Unknown(0) { - let msg = "peer sent bad TLSInnerPlaintext".to_string(); - return Err(Error::PeerMisbehavedError(msg)); - } - - if payload.len() > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - msg.version = ProtocolVersion::TLSv1_3; - Ok(msg.into_plain_message()) - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/vecbuf.rs b/third_party/rustls-fork-shadow-tls/src/vecbuf.rs deleted file mode 100644 index 6126edd..0000000 --- a/third_party/rustls-fork-shadow-tls/src/vecbuf.rs +++ /dev/null @@ -1,200 +0,0 @@ -use std::cmp; -use std::collections::VecDeque; -use std::io; -use std::io::Read; - -/// This is a byte buffer that is built from a vector -/// of byte vectors. This avoids extra copies when -/// appending a new byte vector, at the expense of -/// more complexity when reading out. -pub(crate) struct ChunkVecBuffer { - chunks: VecDeque>, - limit: Option, -} - -impl ChunkVecBuffer { - pub(crate) fn new(limit: Option) -> Self { - Self { - chunks: VecDeque::new(), - limit, - } - } - - /// Sets the upper limit on how many bytes this - /// object can store. - /// - /// Setting a lower limit than the currently stored - /// data is not an error. - /// - /// A [`None`] limit is interpreted as no limit. - pub(crate) fn set_limit(&mut self, new_limit: Option) { - self.limit = new_limit; - } - - /// If we're empty - pub(crate) fn is_empty(&self) -> bool { - self.chunks.is_empty() - } - - pub(crate) fn is_full(&self) -> bool { - self.limit - .map(|limit| self.len() > limit) - .unwrap_or_default() - } - - /// How many bytes we're storing - pub(crate) fn len(&self) -> usize { - let mut len = 0; - for ch in &self.chunks { - len += ch.len(); - } - len - } - - /// For a proposed append of `len` bytes, how many - /// bytes should we actually append to adhere to the - /// currently set `limit`? - pub(crate) fn apply_limit(&self, len: usize) -> usize { - if let Some(limit) = self.limit { - let space = limit.saturating_sub(self.len()); - cmp::min(len, space) - } else { - len - } - } - - /// Append a copy of `bytes`, perhaps a prefix if - /// we're near the limit. - pub(crate) fn append_limited_copy(&mut self, bytes: &[u8]) -> usize { - let take = self.apply_limit(bytes.len()); - self.append(bytes[..take].to_vec()); - take - } - - /// Take and append the given `bytes`. - pub(crate) fn append(&mut self, bytes: Vec) -> usize { - let len = bytes.len(); - - if !bytes.is_empty() { - self.chunks.push_back(bytes); - } - - len - } - - /// Take one of the chunks from this object. This - /// function panics if the object `is_empty`. - pub(crate) fn pop(&mut self) -> Option> { - self.chunks.pop_front() - } - - /// Read data out of this object, writing it into `buf` - /// and returning how many bytes were written there. - pub(crate) fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut offs = 0; - - while offs < buf.len() && !self.is_empty() { - let used = self.chunks[0] - .as_slice() - .read(&mut buf[offs..])?; - - self.consume(used); - offs += used; - } - - Ok(offs) - } - - #[cfg(read_buf)] - /// Read data out of this object, writing it into `cursor`. - pub(crate) fn read_buf(&mut self, mut cursor: io::BorrowedCursor<'_>) -> io::Result<()> { - while !self.is_empty() && cursor.capacity() > 0 { - let chunk = self.chunks[0].as_slice(); - let used = std::cmp::min(chunk.len(), cursor.capacity()); - cursor.append(&chunk[..used]); - self.consume(used); - } - - Ok(()) - } - - fn consume(&mut self, mut used: usize) { - while let Some(mut buf) = self.chunks.pop_front() { - if used < buf.len() { - self.chunks - .push_front(buf.split_off(used)); - break; - } else { - used -= buf.len(); - } - } - } - - /// Read data out of this object, passing it `wr` - pub(crate) fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result { - if self.is_empty() { - return Ok(0); - } - - let mut bufs = [io::IoSlice::new(&[]); 64]; - for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) { - *iov = io::IoSlice::new(chunk); - } - let len = cmp::min(bufs.len(), self.chunks.len()); - let used = wr.write_vectored(&bufs[..len])?; - self.consume(used); - Ok(used) - } -} - -#[cfg(test)] -mod test { - use super::ChunkVecBuffer; - - #[test] - fn short_append_copy_with_limit() { - let mut cvb = ChunkVecBuffer::new(Some(12)); - assert_eq!(cvb.append_limited_copy(b"hello"), 5); - assert_eq!(cvb.append_limited_copy(b"world"), 5); - assert_eq!(cvb.append_limited_copy(b"hello"), 2); - assert_eq!(cvb.append_limited_copy(b"world"), 0); - - let mut buf = [0u8; 12]; - assert_eq!(cvb.read(&mut buf).unwrap(), 12); - assert_eq!(buf.to_vec(), b"helloworldhe".to_vec()); - } - - #[cfg(read_buf)] - #[test] - fn read_buf() { - use std::{io::BorrowedBuf, mem::MaybeUninit}; - - { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(b"test ".to_vec()); - cvb.append(b"fixture ".to_vec()); - cvb.append(b"data".to_vec()); - - let mut buf = [MaybeUninit::::uninit(); 8]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"test fix"); - buf.clear(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"ture dat"); - buf.clear(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"a"); - } - - { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(b"short message".to_vec()); - - let mut buf = [MaybeUninit::::uninit(); 1024]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"short message"); - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/verify.rs b/third_party/rustls-fork-shadow-tls/src/verify.rs deleted file mode 100644 index 58fd7dc..0000000 --- a/third_party/rustls-fork-shadow-tls/src/verify.rs +++ /dev/null @@ -1,809 +0,0 @@ -use std::fmt; - -use crate::anchors::{OwnedTrustAnchor, RootCertStore}; -use crate::client::ServerName; -use crate::enums::SignatureScheme; -use crate::error::Error; -use crate::key::Certificate; -#[cfg(feature = "logging")] -use crate::log::{debug, trace, warn}; -use crate::msgs::handshake::{DigitallySignedStruct, DistinguishedNames}; - -use ring::digest::Digest; - -use std::convert::TryFrom; -use std::sync::Arc; -use std::time::SystemTime; - -type SignatureAlgorithms = &'static [&'static webpki::SignatureAlgorithm]; - -/// Which signature verification mechanisms we support. No particular -/// order. -static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ - &webpki::ECDSA_P256_SHA256, - &webpki::ECDSA_P256_SHA384, - &webpki::ECDSA_P384_SHA256, - &webpki::ECDSA_P384_SHA384, - &webpki::ED25519, - &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, - &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, - &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, - &webpki::RSA_PKCS1_2048_8192_SHA256, - &webpki::RSA_PKCS1_2048_8192_SHA384, - &webpki::RSA_PKCS1_2048_8192_SHA512, - &webpki::RSA_PKCS1_3072_8192_SHA384, -]; - -// Marker types. These are used to bind the fact some verification -// (certificate chain or handshake signature) has taken place into -// protocol states. We use this to have the compiler check that there -// are no 'goto fail'-style elisions of important checks before we -// reach the traffic stage. -// -// These types are public, but cannot be directly constructed. This -// means their origins can be precisely determined by looking -// for their `assertion` constructors. - -/// Zero-sized marker type representing verification of a signature. -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct HandshakeSignatureValid(()); - -impl HandshakeSignatureValid { - /// Make a `HandshakeSignatureValid` - pub fn assertion() -> Self { - Self(()) - } -} - -#[derive(Debug)] -pub(crate) struct FinishedMessageVerified(()); - -impl FinishedMessageVerified { - pub(crate) fn assertion() -> Self { - Self(()) - } -} - -/// Zero-sized marker type representing verification of a server cert chain. -#[allow(unreachable_pub)] -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct ServerCertVerified(()); - -#[allow(unreachable_pub)] -impl ServerCertVerified { - /// Make a `ServerCertVerified` - pub fn assertion() -> Self { - Self(()) - } -} - -/// Zero-sized marker type representing verification of a client cert chain. -#[derive(Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct ClientCertVerified(()); - -impl ClientCertVerified { - /// Make a `ClientCertVerified` - pub fn assertion() -> Self { - Self(()) - } -} - -/// Something that can verify a server certificate chain, and verify -/// signatures made by certificates. -#[allow(unreachable_pub)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub trait ServerCertVerifier: Send + Sync { - /// Verify the end-entity certificate `end_entity` is valid for the - /// hostname `dns_name` and chains to at least one trust anchor. - /// - /// `intermediates` contains all certificates other than `end_entity` that - /// were sent as part of the server's [Certificate] message. It is in the - /// same order that the server sent them and may be empty. - /// - /// Note that none of the certificates have been parsed yet, so it is the responsibility of - /// the implementor to handle invalid data. It is recommended that the implementor returns - /// [`Error::InvalidCertificateEncoding`] when these cases are encountered. - /// - /// `scts` contains the Signed Certificate Timestamps (SCTs) the server - /// sent with the end-entity certificate, if any. - /// - /// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2 - fn verify_server_cert( - &self, - end_entity: &Certificate, - intermediates: &[Certificate], - server_name: &ServerName, - scts: &mut dyn Iterator, - ocsp_response: &[u8], - now: SystemTime, - ) -> Result; - - /// Verify a signature allegedly by the given server certificate. - /// - /// `message` is not hashed, and needs hashing during the verification. - /// The signature and algorithm are within `dss`. `cert` contains the - /// public key to use. - /// - /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - /// - /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, - /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not - /// in fact bound to the specific curve implied in their name. - /// - /// This trait method has a default implementation that uses webpki to verify - /// the signature. - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - verify_signed_struct(message, cert, dss) - } - - /// Verify a signature allegedly by the given server certificate. - /// - /// This method is only called for TLS1.3 handshakes. - /// - /// This method is very similar to `verify_tls12_signature`: but note the - /// tighter ECDSA SignatureScheme semantics -- e.g. `SignatureScheme::ECDSA_NISTP256_SHA256` - /// must only validate signatures using public keys on the right curve -- - /// rustls does not enforce this requirement for you. - /// - /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - /// - /// This trait method has a default implementation that uses webpki to verify - /// the signature. - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls13(message, cert, dss) - } - - /// Return the list of SignatureSchemes that this verifier will handle, - /// in `verify_tls12_signature` and `verify_tls13_signature` calls. - /// - /// This should be in priority order, with the most preferred first. - /// - /// This trait method has a default implementation that reflects the schemes - /// supported by webpki. - fn supported_verify_schemes(&self) -> Vec { - WebPkiVerifier::verification_schemes() - } - - /// Returns `true` if Rustls should ask the server to send SCTs. - /// - /// Signed Certificate Timestamps (SCTs) are used for Certificate - /// Transparency validation. - /// - /// The default implementation of this function returns true. - fn request_scts(&self) -> bool { - true - } -} - -impl fmt::Debug for dyn ServerCertVerifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "dyn ServerCertVerifier") - } -} - -/// A type which encapsulates a string that is a syntactically valid DNS name. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct DnsName(pub(crate) webpki::DnsName); - -impl AsRef for DnsName { - fn as_ref(&self) -> &str { - AsRef::::as_ref(&self.0) - } -} - -/// Something that can verify a client certificate chain -#[allow(unreachable_pub)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub trait ClientCertVerifier: Send + Sync { - /// Returns `true` to enable the server to request a client certificate and - /// `false` to skip requesting a client certificate. Defaults to `true`. - fn offer_client_auth(&self) -> bool { - true - } - - /// Return `Some(true)` to require a client certificate and `Some(false)` to make - /// client authentication optional. Return `None` to abort the connection. - /// Defaults to `Some(self.offer_client_auth())`. - fn client_auth_mandatory(&self) -> Option { - Some(self.offer_client_auth()) - } - - /// Returns the [Subjects] of the client authentication trust anchors to - /// share with the client when requesting client authentication. - /// - /// These must be DER-encoded X.500 distinguished names, per RFC 5280. - /// They are sent in the [`certificate_authorities`] extension of a - /// [`CertificateRequest`] message. - /// - /// [Subjects]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - /// [`CertificateRequest`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.3.2 - /// [`certificate_authorities`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 - /// - /// Return `None` to abort the connection. Return an empty `Vec` to continue - /// the handshake without sending a CertificateRequest message. - fn client_auth_root_subjects(&self) -> Option; - - /// Verify the end-entity certificate `end_entity` is valid, acceptable, - /// and chains to at least one of the trust anchors trusted by - /// this verifier. - /// - /// `intermediates` contains the intermediate certificates the - /// client sent along with the end-entity certificate; it is in the same - /// order that the peer sent them and may be empty. - /// - /// Note that none of the certificates have been parsed yet, so it is the responsibility of - /// the implementor to handle invalid data. It is recommended that the implementor returns - /// [`Error::InvalidCertificateEncoding`] when these cases are encountered. - fn verify_client_cert( - &self, - end_entity: &Certificate, - intermediates: &[Certificate], - now: SystemTime, - ) -> Result; - - /// Verify a signature allegedly by the given client certificate. - /// - /// `message` is not hashed, and needs hashing during the verification. - /// The signature and algorithm are within `dss`. `cert` contains the - /// public key to use. - /// - /// `cert` has already been validated by [`ClientCertVerifier::verify_client_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - /// - /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, - /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not - /// in fact bound to the specific curve implied in their name. - /// - /// This trait method has a default implementation that uses webpki to verify - /// the signature. - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - verify_signed_struct(message, cert, dss) - } - - /// Verify a signature allegedly by the given client certificate. - /// - /// This method is only called for TLS1.3 handshakes. - /// - /// This method is very similar to `verify_tls12_signature`, but note the - /// tighter ECDSA SignatureScheme semantics in TLS 1.3. For example, - /// `SignatureScheme::ECDSA_NISTP256_SHA256` - /// must only validate signatures using public keys on the right curve -- - /// rustls does not enforce this requirement for you. - /// - /// This trait method has a default implementation that uses webpki to verify - /// the signature. - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls13(message, cert, dss) - } - - /// Return the list of SignatureSchemes that this verifier will handle, - /// in `verify_tls12_signature` and `verify_tls13_signature` calls. - /// - /// This should be in priority order, with the most preferred first. - /// - /// This trait method has a default implementation that reflects the schemes - /// supported by webpki. - fn supported_verify_schemes(&self) -> Vec { - WebPkiVerifier::verification_schemes() - } -} - -impl fmt::Debug for dyn ClientCertVerifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "dyn ClientCertVerifier") - } -} - -impl ServerCertVerifier for WebPkiVerifier { - /// Will verify the certificate is valid in the following ways: - /// - Signed by a trusted `RootCertStore` CA - /// - Not Expired - /// - Valid for DNS entry - fn verify_server_cert( - &self, - end_entity: &Certificate, - intermediates: &[Certificate], - server_name: &ServerName, - scts: &mut dyn Iterator, - ocsp_response: &[u8], - now: SystemTime, - ) -> Result { - let (cert, chain, trustroots) = prepare(end_entity, intermediates, &self.roots)?; - let webpki_now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; - - let dns_name = match server_name { - ServerName::DnsName(dns_name) => dns_name, - ServerName::IpAddress(_) => { - return Err(Error::UnsupportedNameType); - } - }; - - let cert = cert - .verify_is_valid_tls_server_cert( - SUPPORTED_SIG_ALGS, - &webpki::TlsServerTrustAnchors(&trustroots), - &chain, - webpki_now, - ) - .map_err(pki_error) - .map(|_| cert)?; - - if let Some(policy) = &self.ct_policy { - policy.verify(end_entity, now, scts)?; - } - - if !ocsp_response.is_empty() { - trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec()); - } - - cert.verify_is_valid_for_dns_name(dns_name.0.as_ref()) - .map_err(pki_error) - .map(|_| ServerCertVerified::assertion()) - } -} - -/// Default `ServerCertVerifier`, see the trait impl for more information. -#[allow(unreachable_pub)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct WebPkiVerifier { - roots: RootCertStore, - ct_policy: Option, -} - -#[allow(unreachable_pub)] -impl WebPkiVerifier { - /// Constructs a new `WebPkiVerifier`. - /// - /// `roots` is the set of trust anchors to trust for issuing server certs. - /// - /// `ct_logs` is the list of logs that are trusted for Certificate - /// Transparency. Currently CT log enforcement is opportunistic; see - /// . - pub fn new(roots: RootCertStore, ct_policy: Option) -> Self { - Self { roots, ct_policy } - } - - /// Returns the signature verification methods supported by - /// webpki. - pub fn verification_schemes() -> Vec { - vec![ - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::ED25519, - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, - ] - } -} - -/// Policy for enforcing Certificate Transparency. -/// -/// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or -/// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will -/// be validated against the configured CT logs until the deadline expires. After the deadline, -/// certificates will no longer be validated, and a warning message will be logged. The deadline -/// may vary depending on how often you deploy builds with updated dependencies. -#[allow(unreachable_pub)] -#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] -pub struct CertificateTransparencyPolicy { - logs: &'static [&'static sct::Log<'static>], - validation_deadline: SystemTime, -} - -impl CertificateTransparencyPolicy { - /// Create a new policy. - #[allow(unreachable_pub)] - pub fn new( - logs: &'static [&'static sct::Log<'static>], - validation_deadline: SystemTime, - ) -> Self { - Self { - logs, - validation_deadline, - } - } - - fn verify( - &self, - cert: &Certificate, - now: SystemTime, - scts: &mut dyn Iterator, - ) -> Result<(), Error> { - if self.logs.is_empty() { - return Ok(()); - } else if self - .validation_deadline - .duration_since(now) - .is_err() - { - warn!("certificate transparency logs have expired, validation disabled"); - return Ok(()); - } - - let now = unix_time_millis(now)?; - let mut last_sct_error = None; - for sct in scts { - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - match sct::verify_sct(&cert.0, sct, now, self.logs) { - Ok(index) => { - debug!( - "Valid SCT signed by {} on {}", - self.logs[index].operated_by, self.logs[index].description - ); - return Ok(()); - } - Err(e) => { - if e.should_be_fatal() { - return Err(Error::InvalidSct(e)); - } - debug!("SCT ignored because {:?}", e); - last_sct_error = Some(e); - } - } - } - - /* If we were supplied with some logs, and some SCTs, - * but couldn't verify any of them, fail the handshake. */ - if let Some(last_sct_error) = last_sct_error { - warn!("No valid SCTs provided"); - return Err(Error::InvalidSct(last_sct_error)); - } - - Ok(()) - } -} - -type CertChainAndRoots<'a, 'b> = ( - webpki::EndEntityCert<'a>, - Vec<&'a [u8]>, - Vec>, -); - -fn prepare<'a, 'b>( - end_entity: &'a Certificate, - intermediates: &'a [Certificate], - roots: &'b RootCertStore, -) -> Result, Error> { - // EE cert must appear first. - let cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?; - - let intermediates: Vec<&'a [u8]> = intermediates - .iter() - .map(|cert| cert.0.as_ref()) - .collect(); - - let trustroots: Vec = roots - .roots - .iter() - .map(OwnedTrustAnchor::to_trust_anchor) - .collect(); - - Ok((cert, intermediates, trustroots)) -} - -/// A `ClientCertVerifier` that will ensure that every client provides a trusted -/// certificate, without any name checking. -pub struct AllowAnyAuthenticatedClient { - roots: RootCertStore, -} - -impl AllowAnyAuthenticatedClient { - /// Construct a new `AllowAnyAuthenticatedClient`. - /// - /// `roots` is the list of trust anchors to use for certificate validation. - pub fn new(roots: RootCertStore) -> Arc { - Arc::new(Self { roots }) - } -} - -impl ClientCertVerifier for AllowAnyAuthenticatedClient { - fn offer_client_auth(&self) -> bool { - true - } - - #[allow(deprecated)] - fn client_auth_root_subjects(&self) -> Option { - Some(self.roots.subjects()) - } - - fn verify_client_cert( - &self, - end_entity: &Certificate, - intermediates: &[Certificate], - now: SystemTime, - ) -> Result { - let (cert, chain, trustroots) = prepare(end_entity, intermediates, &self.roots)?; - let now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; - cert.verify_is_valid_tls_client_cert( - SUPPORTED_SIG_ALGS, - &webpki::TlsClientTrustAnchors(&trustroots), - &chain, - now, - ) - .map_err(pki_error) - .map(|_| ClientCertVerified::assertion()) - } -} - -/// A `ClientCertVerifier` that will allow both anonymous and authenticated -/// clients, without any name checking. -/// -/// Client authentication will be requested during the TLS handshake. If the -/// client offers a certificate then this acts like -/// `AllowAnyAuthenticatedClient`, otherwise this acts like `NoClientAuth`. -pub struct AllowAnyAnonymousOrAuthenticatedClient { - inner: AllowAnyAuthenticatedClient, -} - -impl AllowAnyAnonymousOrAuthenticatedClient { - /// Construct a new `AllowAnyAnonymousOrAuthenticatedClient`. - /// - /// `roots` is the list of trust anchors to use for certificate validation. - pub fn new(roots: RootCertStore) -> Arc { - Arc::new(Self { - inner: AllowAnyAuthenticatedClient { roots }, - }) - } -} - -impl ClientCertVerifier for AllowAnyAnonymousOrAuthenticatedClient { - fn offer_client_auth(&self) -> bool { - self.inner.offer_client_auth() - } - - fn client_auth_mandatory(&self) -> Option { - Some(false) - } - - fn client_auth_root_subjects(&self) -> Option { - self.inner.client_auth_root_subjects() - } - - fn verify_client_cert( - &self, - end_entity: &Certificate, - intermediates: &[Certificate], - now: SystemTime, - ) -> Result { - self.inner - .verify_client_cert(end_entity, intermediates, now) - } -} - -fn pki_error(error: webpki::Error) -> Error { - use webpki::Error::*; - match error { - BadDer | BadDerTime => Error::InvalidCertificateEncoding, - InvalidSignatureForPublicKey => Error::InvalidCertificateSignature, - UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => { - Error::InvalidCertificateSignatureType - } - e => Error::InvalidCertificateData(format!("invalid peer certificate: {}", e)), - } -} - -/// Turns off client authentication. -pub struct NoClientAuth; - -impl NoClientAuth { - /// Constructs a `NoClientAuth` and wraps it in an `Arc`. - pub fn new() -> Arc { - Arc::new(Self) - } -} - -impl ClientCertVerifier for NoClientAuth { - fn offer_client_auth(&self) -> bool { - false - } - - fn client_auth_root_subjects(&self) -> Option { - unimplemented!(); - } - - fn verify_client_cert( - &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _now: SystemTime, - ) -> Result { - unimplemented!(); - } -} - -static ECDSA_SHA256: SignatureAlgorithms = - &[&webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P384_SHA256]; - -static ECDSA_SHA384: SignatureAlgorithms = - &[&webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA384]; - -static ED25519: SignatureAlgorithms = &[&webpki::ED25519]; - -static RSA_SHA256: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA256]; -static RSA_SHA384: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA384]; -static RSA_SHA512: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA512]; -static RSA_PSS_SHA256: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY]; -static RSA_PSS_SHA384: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY]; -static RSA_PSS_SHA512: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY]; - -fn convert_scheme(scheme: SignatureScheme) -> Result { - match scheme { - // nb. for TLS1.2 the curve is not fixed by SignatureScheme. - SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ECDSA_SHA256), - SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ECDSA_SHA384), - - SignatureScheme::ED25519 => Ok(ED25519), - - SignatureScheme::RSA_PKCS1_SHA256 => Ok(RSA_SHA256), - SignatureScheme::RSA_PKCS1_SHA384 => Ok(RSA_SHA384), - SignatureScheme::RSA_PKCS1_SHA512 => Ok(RSA_SHA512), - - SignatureScheme::RSA_PSS_SHA256 => Ok(RSA_PSS_SHA256), - SignatureScheme::RSA_PSS_SHA384 => Ok(RSA_PSS_SHA384), - SignatureScheme::RSA_PSS_SHA512 => Ok(RSA_PSS_SHA512), - - _ => { - let error_msg = format!("received unadvertised sig scheme {:?}", scheme); - Err(Error::PeerMisbehavedError(error_msg)) - } - } -} - -fn verify_sig_using_any_alg( - cert: &webpki::EndEntityCert, - algs: SignatureAlgorithms, - message: &[u8], - sig: &[u8], -) -> Result<(), webpki::Error> { - // TLS doesn't itself give us enough info to map to a single webpki::SignatureAlgorithm. - // Therefore, convert_algs maps to several and we try them all. - for alg in algs { - match cert.verify_signature(alg, message, sig) { - Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) => continue, - res => return res, - } - } - - Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) -} - -fn verify_signed_struct( - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, -) -> Result { - let possible_algs = convert_scheme(dss.scheme)?; - let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; - - verify_sig_using_any_alg(&cert, possible_algs, message, dss.signature()) - .map_err(pki_error) - .map(|_| HandshakeSignatureValid::assertion()) -} - -fn convert_alg_tls13( - scheme: SignatureScheme, -) -> Result<&'static webpki::SignatureAlgorithm, Error> { - use crate::enums::SignatureScheme::*; - - match scheme { - ECDSA_NISTP256_SHA256 => Ok(&webpki::ECDSA_P256_SHA256), - ECDSA_NISTP384_SHA384 => Ok(&webpki::ECDSA_P384_SHA384), - ED25519 => Ok(&webpki::ED25519), - RSA_PSS_SHA256 => Ok(&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY), - RSA_PSS_SHA384 => Ok(&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY), - RSA_PSS_SHA512 => Ok(&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY), - _ => { - let error_msg = format!("received unsupported sig scheme {:?}", scheme); - Err(Error::PeerMisbehavedError(error_msg)) - } - } -} - -/// Constructs the signature message specified in section 4.4.3 of RFC8446. -pub(crate) fn construct_tls13_client_verify_message(handshake_hash: &Digest) -> Vec { - construct_tls13_verify_message(handshake_hash, b"TLS 1.3, client CertificateVerify\x00") -} - -/// Constructs the signature message specified in section 4.4.3 of RFC8446. -pub(crate) fn construct_tls13_server_verify_message(handshake_hash: &Digest) -> Vec { - construct_tls13_verify_message(handshake_hash, b"TLS 1.3, server CertificateVerify\x00") -} - -fn construct_tls13_verify_message( - handshake_hash: &Digest, - context_string_with_0: &[u8], -) -> Vec { - let mut msg = Vec::new(); - msg.resize(64, 0x20u8); - msg.extend_from_slice(context_string_with_0); - msg.extend_from_slice(handshake_hash.as_ref()); - msg -} - -fn verify_tls13( - msg: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, -) -> Result { - let alg = convert_alg_tls13(dss.scheme)?; - - let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; - - cert.verify_signature(alg, msg, dss.signature()) - .map_err(pki_error) - .map(|_| HandshakeSignatureValid::assertion()) -} - -fn unix_time_millis(now: SystemTime) -> Result { - now.duration_since(std::time::UNIX_EPOCH) - .map(|dur| dur.as_secs()) - .map_err(|_| Error::FailedToGetCurrentTime) - .and_then(|secs| { - secs.checked_mul(1000) - .ok_or(Error::FailedToGetCurrentTime) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn assertions_are_debug() { - assert_eq!( - format!("{:?}", ClientCertVerified::assertion()), - "ClientCertVerified(())" - ); - assert_eq!( - format!("{:?}", HandshakeSignatureValid::assertion()), - "HandshakeSignatureValid(())" - ); - assert_eq!( - format!("{:?}", FinishedMessageVerified::assertion()), - "FinishedMessageVerified(())" - ); - assert_eq!( - format!("{:?}", ServerCertVerified::assertion()), - "ServerCertVerified(())" - ); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/verifybench.rs b/third_party/rustls-fork-shadow-tls/src/verifybench.rs deleted file mode 100644 index 9ddb271..0000000 --- a/third_party/rustls-fork-shadow-tls/src/verifybench.rs +++ /dev/null @@ -1,245 +0,0 @@ -// This program does benchmarking of the functions in verify.rs, -// that do certificate chain validation and signature verification. -// -// Note: we don't use any of the standard 'cargo bench', 'test::Bencher', -// etc. because it's unstable at the time of writing. - -use std::convert::TryInto; -use std::time::{Duration, Instant, SystemTime}; - -use crate::key; -use crate::verify; -use crate::verify::ServerCertVerifier; -use crate::{anchors, OwnedTrustAnchor}; - -use webpki_roots; - -fn duration_nanos(d: Duration) -> u64 { - ((d.as_secs() as f64) * 1e9 + (d.subsec_nanos() as f64)) as u64 -} - -#[test] -fn test_reddit_cert() { - Context::new( - "reddit", - "reddit.com", - &[ - include_bytes!("testdata/cert-reddit.0.der"), - include_bytes!("testdata/cert-reddit.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_github_cert() { - Context::new( - "github", - "github.com", - &[ - include_bytes!("testdata/cert-github.0.der"), - include_bytes!("testdata/cert-github.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_arstechnica_cert() { - Context::new( - "arstechnica", - "arstechnica.com", - &[ - include_bytes!("testdata/cert-arstechnica.0.der"), - include_bytes!("testdata/cert-arstechnica.1.der"), - include_bytes!("testdata/cert-arstechnica.2.der"), - include_bytes!("testdata/cert-arstechnica.3.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_servo_cert() { - Context::new( - "servo", - "servo.org", - &[ - include_bytes!("testdata/cert-servo.0.der"), - include_bytes!("testdata/cert-servo.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_twitter_cert() { - Context::new( - "twitter", - "twitter.com", - &[ - include_bytes!("testdata/cert-twitter.0.der"), - include_bytes!("testdata/cert-twitter.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_wikipedia_cert() { - Context::new( - "wikipedia", - "wikipedia.org", - &[ - include_bytes!("testdata/cert-wikipedia.0.der"), - include_bytes!("testdata/cert-wikipedia.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_google_cert() { - Context::new( - "google", - "www.google.com", - &[ - include_bytes!("testdata/cert-google.0.der"), - include_bytes!("testdata/cert-google.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_hn_cert() { - Context::new( - "hn", - "news.ycombinator.com", - &[ - include_bytes!("testdata/cert-hn.0.der"), - include_bytes!("testdata/cert-hn.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_stackoverflow_cert() { - Context::new( - "stackoverflow", - "stackoverflow.com", - &[ - include_bytes!("testdata/cert-stackoverflow.0.der"), - include_bytes!("testdata/cert-stackoverflow.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_duckduckgo_cert() { - Context::new( - "duckduckgo", - "duckduckgo.com", - &[ - include_bytes!("testdata/cert-duckduckgo.0.der"), - include_bytes!("testdata/cert-duckduckgo.1.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_rustlang_cert() { - Context::new( - "rustlang", - "www.rust-lang.org", - &[ - include_bytes!("testdata/cert-rustlang.0.der"), - include_bytes!("testdata/cert-rustlang.1.der"), - include_bytes!("testdata/cert-rustlang.2.der"), - ], - ) - .bench(100) -} - -#[test] -fn test_wapo_cert() { - Context::new( - "wapo", - "www.washingtonpost.com", - &[ - include_bytes!("testdata/cert-wapo.0.der"), - include_bytes!("testdata/cert-wapo.1.der"), - ], - ) - .bench(100) -} - -struct Context { - name: &'static str, - domain: &'static str, - roots: anchors::RootCertStore, - chain: Vec, - now: SystemTime, -} - -impl Context { - fn new(name: &'static str, domain: &'static str, certs: &[&'static [u8]]) -> Self { - let mut roots = anchors::RootCertStore::empty(); - roots.add_server_trust_anchors( - webpki_roots::TLS_SERVER_ROOTS - .0 - .iter() - .map(|ta| { - OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ) - }), - ); - Self { - name, - domain, - roots, - chain: certs - .iter() - .copied() - .map(|bytes| key::Certificate(bytes.to_vec())) - .collect(), - now: SystemTime::UNIX_EPOCH + Duration::from_secs(1640870720), - } - } - - fn bench(&self, count: usize) { - let verifier = verify::WebPkiVerifier::new(self.roots.clone(), None); - const SCTS: &[&[u8]] = &[]; - const OCSP_RESPONSE: &[u8] = &[]; - let mut times = Vec::new(); - - let (end_entity, intermediates) = self.chain.split_first().unwrap(); - for _ in 0..count { - let start = Instant::now(); - let server_name = self.domain.try_into().unwrap(); - verifier - .verify_server_cert( - end_entity, - intermediates, - &server_name, - &mut SCTS.iter().copied(), - OCSP_RESPONSE, - self.now, - ) - .unwrap(); - times.push(duration_nanos(Instant::now().duration_since(start))); - } - - println!( - "verify_server_cert({}): min {:?}us", - self.name, - times.iter().min().unwrap() / 1000 - ); - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/versions.rs b/third_party/rustls-fork-shadow-tls/src/versions.rs deleted file mode 100644 index 738453f..0000000 --- a/third_party/rustls-fork-shadow-tls/src/versions.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::fmt; - -use crate::enums::ProtocolVersion; - -/// A TLS protocol version supported by rustls. -/// -/// All possible instances of this class are provided by the library in -/// the [`ALL_VERSIONS`] array, as well as individually as [`TLS12`] -/// and [`TLS13`]. -#[derive(Eq, PartialEq)] -pub struct SupportedProtocolVersion { - /// The TLS enumeration naming this version. - pub version: ProtocolVersion, - is_private: (), -} - -impl fmt::Debug for SupportedProtocolVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.version.fmt(f) - } -} - -/// TLS1.2 -#[cfg(feature = "tls12")] -pub static TLS12: SupportedProtocolVersion = SupportedProtocolVersion { - version: ProtocolVersion::TLSv1_2, - is_private: (), -}; - -/// TLS1.3 -pub static TLS13: SupportedProtocolVersion = SupportedProtocolVersion { - version: ProtocolVersion::TLSv1_3, - is_private: (), -}; - -/// A list of all the protocol versions supported by rustls. -pub static ALL_VERSIONS: &[&SupportedProtocolVersion] = &[ - &TLS13, - #[cfg(feature = "tls12")] - &TLS12, -]; - -/// The version configuration that an application should use by default. -/// -/// This will be [`ALL_VERSIONS`] for now, but gives space in the future -/// to remove a version from here and require users to opt-in to older -/// versions. -pub static DEFAULT_VERSIONS: &[&SupportedProtocolVersion] = ALL_VERSIONS; - -#[derive(Clone)] -pub(crate) struct EnabledVersions { - #[cfg(feature = "tls12")] - tls12: Option<&'static SupportedProtocolVersion>, - tls13: Option<&'static SupportedProtocolVersion>, -} - -impl fmt::Debug for EnabledVersions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = &mut f.debug_list(); - #[cfg(feature = "tls12")] - if let Some(v) = self.tls12 { - list = list.entry(v) - } - if let Some(v) = self.tls13 { - list = list.entry(v) - } - list.finish() - } -} - -impl EnabledVersions { - pub(crate) fn new(versions: &[&'static SupportedProtocolVersion]) -> Self { - let mut ev = Self { - #[cfg(feature = "tls12")] - tls12: None, - tls13: None, - }; - - for v in versions { - match v.version { - #[cfg(feature = "tls12")] - ProtocolVersion::TLSv1_2 => ev.tls12 = Some(v), - ProtocolVersion::TLSv1_3 => ev.tls13 = Some(v), - _ => {} - } - } - - ev - } - - pub(crate) fn contains(&self, version: ProtocolVersion) -> bool { - match version { - #[cfg(feature = "tls12")] - ProtocolVersion::TLSv1_2 => self.tls12.is_some(), - ProtocolVersion::TLSv1_3 => self.tls13.is_some(), - _ => false, - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/src/x509.rs b/third_party/rustls-fork-shadow-tls/src/x509.rs deleted file mode 100644 index 17239d7..0000000 --- a/third_party/rustls-fork-shadow-tls/src/x509.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Additional x509/asn1 functions to those provided in webpki/ring. - -use ring::io::der; - -pub(crate) fn wrap_in_asn1_len(bytes: &mut Vec) { - let len = bytes.len(); - - if len <= 0x7f { - bytes.insert(0, len as u8); - } else { - bytes.insert(0, 0x80u8); - let mut left = len; - while left > 0 { - let byte = (left & 0xff) as u8; - bytes.insert(1, byte); - bytes[0] += 1; - left >>= 8; - } - } -} - -/// Prepend stuff to `bytes` to put it in a DER SEQUENCE. -pub(crate) fn wrap_in_sequence(bytes: &mut Vec) { - wrap_in_asn1_len(bytes); - bytes.insert(0, der::Tag::Sequence as u8); -} - -#[test] -fn test_empty() { - let mut val = Vec::new(); - wrap_in_sequence(&mut val); - assert_eq!(vec![0x30, 0x00], val); -} - -#[test] -fn test_small() { - let mut val = Vec::new(); - val.insert(0, 0x00); - val.insert(1, 0x11); - val.insert(2, 0x22); - val.insert(3, 0x33); - wrap_in_sequence(&mut val); - assert_eq!(vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33], val); -} - -#[test] -fn test_medium() { - let mut val = Vec::new(); - val.resize(255, 0x12); - wrap_in_sequence(&mut val); - assert_eq!(vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12], val[..6].to_vec()); -} - -#[test] -fn test_large() { - let mut val = Vec::new(); - val.resize(4660, 0x12); - wrap_in_sequence(&mut val); - assert_eq!(vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12], val[..6].to_vec()); -} - -#[test] -fn test_huge() { - let mut val = Vec::new(); - val.resize(0xffff, 0x12); - wrap_in_sequence(&mut val); - assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], val[..6].to_vec()); - assert_eq!(val.len(), 0xffff + 4); -} - -#[test] -fn test_gigantic() { - let mut val = Vec::new(); - val.resize(0x100000, 0x12); - wrap_in_sequence(&mut val); - assert_eq!( - vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], - val[..7].to_vec() - ); - assert_eq!(val.len(), 0x100000 + 5); -} - -#[test] -fn test_ludicrous() { - let mut val = Vec::new(); - val.resize(0x1000000, 0x12); - wrap_in_sequence(&mut val); - assert_eq!( - vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12], - val[..8].to_vec() - ); - assert_eq!(val.len(), 0x1000000 + 6); -} diff --git a/third_party/rustls-fork-shadow-tls/tests/api.rs b/third_party/rustls-fork-shadow-tls/tests/api.rs deleted file mode 100644 index 5f47cc9..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/api.rs +++ /dev/null @@ -1,4382 +0,0 @@ -//! Assorted public API tests. -use std::cell::RefCell; -use std::convert::TryFrom; -#[cfg(feature = "tls12")] -use std::convert::TryInto; -use std::fmt; -use std::io::{self, IoSlice, Read, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; -use std::sync::Mutex; - -use log; - -use rustls::client::ResolvesClientCert; -use rustls::internal::msgs::base::Payload; -use rustls::internal::msgs::codec::Codec; -#[cfg(feature = "quic")] -use rustls::quic::{self, ClientQuicExt, QuicExt, ServerQuicExt}; -use rustls::server::{AllowAnyAnonymousOrAuthenticatedClient, ClientHello, ResolvesServerCert}; -#[cfg(feature = "secret_extraction")] -use rustls::ConnectionTrafficSecrets; -use rustls::{sign, ConnectionCommon, Error, KeyLog, SideData}; -use rustls::{CipherSuite, ProtocolVersion, SignatureScheme}; -use rustls::{ClientConfig, ClientConnection}; -use rustls::{ServerConfig, ServerConnection}; -use rustls::{Stream, StreamOwned}; -use rustls::{SupportedCipherSuite, ALL_CIPHER_SUITES}; - -mod common; -use crate::common::*; - -fn alpn_test_error( - server_protos: Vec>, - client_protos: Vec>, - agreed: Option<&[u8]>, - expected_error: Option, -) { - let mut server_config = make_server_config(KeyType::Rsa); - server_config.alpn_protocols = server_protos; - - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - client_config.alpn_protocols = client_protos.clone(); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!(client.alpn_protocol(), None); - assert_eq!(server.alpn_protocol(), None); - let error = do_handshake_until_error(&mut client, &mut server); - assert_eq!(client.alpn_protocol(), agreed); - assert_eq!(server.alpn_protocol(), agreed); - assert_eq!(error.err(), expected_error); - } -} - -fn alpn_test(server_protos: Vec>, client_protos: Vec>, agreed: Option<&[u8]>) { - alpn_test_error(server_protos, client_protos, agreed, None) -} - -#[test] -fn alpn() { - // no support - alpn_test(vec![], vec![], None); - - // server support - alpn_test(vec![b"server-proto".to_vec()], vec![], None); - - // client support - alpn_test(vec![], vec![b"client-proto".to_vec()], None); - - // no overlap - alpn_test_error( - vec![b"server-proto".to_vec()], - vec![b"client-proto".to_vec()], - None, - Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), - ); - - // server chooses preference - alpn_test( - vec![b"server-proto".to_vec(), b"client-proto".to_vec()], - vec![b"client-proto".to_vec(), b"server-proto".to_vec()], - Some(b"server-proto"), - ); - - // case sensitive - alpn_test_error( - vec![b"PROTO".to_vec()], - vec![b"proto".to_vec()], - None, - Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), - ); -} - -fn version_test( - client_versions: &[&'static rustls::SupportedProtocolVersion], - server_versions: &[&'static rustls::SupportedProtocolVersion], - result: Option, -) { - let client_versions = if client_versions.is_empty() { - &rustls::ALL_VERSIONS - } else { - client_versions - }; - let server_versions = if server_versions.is_empty() { - &rustls::ALL_VERSIONS - } else { - server_versions - }; - - let client_config = make_client_config_with_versions(KeyType::Rsa, client_versions); - let server_config = make_server_config_with_versions(KeyType::Rsa, server_versions); - - println!( - "version {:?} {:?} -> {:?}", - client_versions, server_versions, result - ); - - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - assert_eq!(client.protocol_version(), None); - assert_eq!(server.protocol_version(), None); - if result.is_none() { - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); - } else { - do_handshake(&mut client, &mut server); - assert_eq!(client.protocol_version(), result); - assert_eq!(server.protocol_version(), result); - } -} - -#[test] -fn versions() { - // default -> 1.3 - version_test(&[], &[], Some(ProtocolVersion::TLSv1_3)); - - // client default, server 1.2 -> 1.2 - #[cfg(feature = "tls12")] - version_test( - &[], - &[&rustls::version::TLS12], - Some(ProtocolVersion::TLSv1_2), - ); - - // client 1.2, server default -> 1.2 - #[cfg(feature = "tls12")] - version_test( - &[&rustls::version::TLS12], - &[], - Some(ProtocolVersion::TLSv1_2), - ); - - // client 1.2, server 1.3 -> fail - #[cfg(feature = "tls12")] - version_test(&[&rustls::version::TLS12], &[&rustls::version::TLS13], None); - - // client 1.3, server 1.2 -> fail - #[cfg(feature = "tls12")] - version_test(&[&rustls::version::TLS13], &[&rustls::version::TLS12], None); - - // client 1.3, server 1.2+1.3 -> 1.3 - #[cfg(feature = "tls12")] - version_test( - &[&rustls::version::TLS13], - &[&rustls::version::TLS12, &rustls::version::TLS13], - Some(ProtocolVersion::TLSv1_3), - ); - - // client 1.2+1.3, server 1.2 -> 1.2 - #[cfg(feature = "tls12")] - version_test( - &[&rustls::version::TLS13, &rustls::version::TLS12], - &[&rustls::version::TLS12], - Some(ProtocolVersion::TLSv1_2), - ); -} - -fn check_read(reader: &mut dyn io::Read, bytes: &[u8]) { - let mut buf = vec![0u8; bytes.len() + 1]; - assert_eq!(bytes.len(), reader.read(&mut buf).unwrap()); - assert_eq!(bytes, &buf[..bytes.len()]); -} - -#[test] -fn config_builder_for_client_rejects_empty_kx_groups() { - assert_eq!( - ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(&[]) - .with_safe_default_protocol_versions() - .err(), - Some(Error::General("no kx groups configured".into())) - ); -} - -#[test] -fn config_builder_for_client_rejects_empty_cipher_suites() { - assert_eq!( - ClientConfig::builder() - .with_cipher_suites(&[]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .err(), - Some(Error::General("no usable cipher suites configured".into())) - ); -} - -#[cfg(feature = "tls12")] -#[test] -fn config_builder_for_client_rejects_incompatible_cipher_suites() { - assert_eq!( - ClientConfig::builder() - .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[&rustls::version::TLS12]) - .err(), - Some(Error::General("no usable cipher suites configured".into())) - ); -} - -#[test] -fn config_builder_for_server_rejects_empty_kx_groups() { - assert_eq!( - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(&[]) - .with_safe_default_protocol_versions() - .err(), - Some(Error::General("no kx groups configured".into())) - ); -} - -#[test] -fn config_builder_for_server_rejects_empty_cipher_suites() { - assert_eq!( - ServerConfig::builder() - .with_cipher_suites(&[]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .err(), - Some(Error::General("no usable cipher suites configured".into())) - ); -} - -#[cfg(feature = "tls12")] -#[test] -fn config_builder_for_server_rejects_incompatible_cipher_suites() { - assert_eq!( - ServerConfig::builder() - .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[&rustls::version::TLS12]) - .err(), - Some(Error::General("no usable cipher suites configured".into())) - ); -} - -#[test] -fn buffered_client_data_sent() { - let server_config = Arc::new(make_server_config(KeyType::Rsa)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!(5, client.writer().write(b"hello").unwrap()); - - do_handshake(&mut client, &mut server); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - check_read(&mut server.reader(), b"hello"); - } -} - -#[test] -fn buffered_server_data_sent() { - let server_config = Arc::new(make_server_config(KeyType::Rsa)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!(5, server.writer().write(b"hello").unwrap()); - - do_handshake(&mut client, &mut server); - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - check_read(&mut client.reader(), b"hello"); - } -} - -#[test] -fn buffered_both_data_sent() { - let server_config = Arc::new(make_server_config(KeyType::Rsa)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!( - 12, - server - .writer() - .write(b"from-server!") - .unwrap() - ); - assert_eq!( - 12, - client - .writer() - .write(b"from-client!") - .unwrap() - ); - - do_handshake(&mut client, &mut server); - - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - check_read(&mut client.reader(), b"from-server!"); - check_read(&mut server.reader(), b"from-client!"); - } -} - -#[test] -fn client_can_get_server_cert() { - for kt in ALL_KEY_TYPES.iter() { - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_configs(client_config, make_server_config(*kt)); - do_handshake(&mut client, &mut server); - - let certs = client.peer_certificates(); - assert_eq!(certs, Some(kt.get_chain().as_slice())); - } - } -} - -#[test] -fn client_can_get_server_cert_after_resumption() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = make_server_config(*kt); - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_configs(client_config.clone(), server_config.clone()); - do_handshake(&mut client, &mut server); - - let original_certs = client.peer_certificates(); - - let (mut client, mut server) = - make_pair_for_configs(client_config.clone(), server_config.clone()); - do_handshake(&mut client, &mut server); - - let resumed_certs = client.peer_certificates(); - - assert_eq!(original_certs, resumed_certs); - } - } -} - -#[test] -fn server_can_get_client_cert() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - let certs = server.peer_certificates(); - assert_eq!(certs, Some(kt.get_client_chain().as_slice())); - } - } -} - -#[test] -fn server_can_get_client_cert_after_resumption() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let client_config = Arc::new(client_config); - let (mut client, mut server) = - make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - let original_certs = server.peer_certificates(); - - let (mut client, mut server) = - make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - let resumed_certs = server.peer_certificates(); - assert_eq!(original_certs, resumed_certs); - } - } -} - -#[test] -fn test_config_builders_debug() { - let b = ServerConfig::builder(); - assert_eq!( - "ConfigBuilder { state: WantsCipherSuites(()) }", - format!("{:?}", b) - ); - let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); - assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); - let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); - assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); - let b = b - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap(); - let b = b.with_no_client_auth(); - assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3], verifier: dyn ClientCertVerifier } }", format!("{:?}", b)); - - let b = ClientConfig::builder(); - assert_eq!( - "ConfigBuilder { state: WantsCipherSuites(()) }", - format!("{:?}", b) - ); - let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); - assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); - let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); - assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); - let b = b - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap(); - assert_eq!("ConfigBuilder { state: WantsVerifier { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3] } }", format!("{:?}", b)); -} - -/// Test that the server handles combination of `offer_client_auth()` returning true -/// and `client_auth_mandatory` returning `Some(false)`. This exercises both the -/// client's and server's ability to "recover" from the server asking for a client -/// certificate and not being given one. This also covers the implementation -/// of `AllowAnyAnonymousOrAuthenticatedClient`. -#[test] -fn server_allow_any_anonymous_or_authenticated_client() { - let kt = KeyType::Rsa; - for client_cert_chain in [None, Some(kt.get_client_chain())].iter() { - let client_auth_roots = get_client_root_store(kt); - let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots); - - let server_config = ServerConfig::builder() - .with_safe_defaults() - .with_client_cert_verifier(client_auth) - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap(); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = if client_cert_chain.is_some() { - make_client_config_with_versions_with_auth(kt, &[version]) - } else { - make_client_config_with_versions(kt, &[version]) - }; - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - let certs = server.peer_certificates(); - assert_eq!(certs, client_cert_chain.as_deref()); - } - } -} - -fn check_read_and_close(reader: &mut dyn io::Read, expect: &[u8]) { - check_read(reader, expect); - assert!(matches!(reader.read(&mut [0u8; 5]), Ok(0))); -} - -#[test] -fn server_close_notify() { - let kt = KeyType::Rsa; - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - // check that alerts don't overtake appdata - assert_eq!( - 12, - server - .writer() - .write(b"from-server!") - .unwrap() - ); - assert_eq!( - 12, - client - .writer() - .write(b"from-client!") - .unwrap() - ); - server.send_close_notify(); - - transfer(&mut server, &mut client); - let io_state = client.process_new_packets().unwrap(); - assert!(io_state.peer_has_closed()); - check_read_and_close(&mut client.reader(), b"from-server!"); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - check_read(&mut server.reader(), b"from-client!"); - } -} - -#[test] -fn client_close_notify() { - let kt = KeyType::Rsa; - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - // check that alerts don't overtake appdata - assert_eq!( - 12, - server - .writer() - .write(b"from-server!") - .unwrap() - ); - assert_eq!( - 12, - client - .writer() - .write(b"from-client!") - .unwrap() - ); - client.send_close_notify(); - - transfer(&mut client, &mut server); - let io_state = server.process_new_packets().unwrap(); - assert!(io_state.peer_has_closed()); - check_read_and_close(&mut server.reader(), b"from-client!"); - - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - check_read(&mut client.reader(), b"from-server!"); - } -} - -#[test] -fn server_closes_uncleanly() { - let kt = KeyType::Rsa; - let server_config = Arc::new(make_server_config(kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - // check that unclean EOF reporting does not overtake appdata - assert_eq!( - 12, - server - .writer() - .write(b"from-server!") - .unwrap() - ); - assert_eq!( - 12, - client - .writer() - .write(b"from-client!") - .unwrap() - ); - - transfer(&mut server, &mut client); - transfer_eof(&mut client); - let io_state = client.process_new_packets().unwrap(); - assert!(!io_state.peer_has_closed()); - check_read(&mut client.reader(), b"from-server!"); - - assert!(matches!(client.reader().read(&mut [0u8; 1]), - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof)); - - // may still transmit pending frames - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - check_read(&mut server.reader(), b"from-client!"); - } -} - -#[test] -fn client_closes_uncleanly() { - let kt = KeyType::Rsa; - let server_config = Arc::new(make_server_config(kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - - // check that unclean EOF reporting does not overtake appdata - assert_eq!( - 12, - server - .writer() - .write(b"from-server!") - .unwrap() - ); - assert_eq!( - 12, - client - .writer() - .write(b"from-client!") - .unwrap() - ); - - transfer(&mut client, &mut server); - transfer_eof(&mut server); - let io_state = server.process_new_packets().unwrap(); - assert!(!io_state.peer_has_closed()); - check_read(&mut server.reader(), b"from-client!"); - - assert!(matches!(server.reader().read(&mut [0u8; 1]), - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof)); - - // may still transmit pending frames - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - check_read(&mut client.reader(), b"from-server!"); - } -} - -#[derive(Default)] -struct ServerCheckCertResolve { - expected_sni: Option, - expected_sigalgs: Option>, - expected_alpn: Option>>, - expected_cipher_suites: Option>, -} - -impl ResolvesServerCert for ServerCheckCertResolve { - fn resolve(&self, client_hello: ClientHello) -> Option> { - if client_hello - .signature_schemes() - .is_empty() - { - panic!("no signature schemes shared by client"); - } - - if client_hello.cipher_suites().is_empty() { - panic!("no cipher suites shared by client"); - } - - if let Some(expected_sni) = &self.expected_sni { - let sni: &str = client_hello - .server_name() - .expect("sni unexpectedly absent"); - assert_eq!(expected_sni, sni); - } - - if let Some(expected_sigalgs) = &self.expected_sigalgs { - assert_eq!( - expected_sigalgs, - client_hello.signature_schemes(), - "unexpected signature schemes" - ); - } - - if let Some(expected_alpn) = &self.expected_alpn { - let alpn = client_hello - .alpn() - .expect("alpn unexpectedly absent") - .collect::>(); - assert_eq!(alpn.len(), expected_alpn.len()); - - for (got, wanted) in alpn.iter().zip(expected_alpn.iter()) { - assert_eq!(got, &wanted.as_slice()); - } - } - - if let Some(expected_cipher_suites) = &self.expected_cipher_suites { - assert_eq!( - expected_cipher_suites, - client_hello.cipher_suites(), - "unexpected cipher suites" - ); - } - - None - } -} - -#[test] -fn server_cert_resolve_with_sni() { - for kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config(*kt); - let mut server_config = make_server_config(*kt); - - server_config.cert_resolver = Arc::new(ServerCheckCertResolve { - expected_sni: Some("the-value-from-sni".into()), - ..Default::default() - }); - - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("the-value-from-sni")).unwrap(); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); - } -} - -#[test] -fn server_cert_resolve_with_alpn() { - for kt in ALL_KEY_TYPES.iter() { - let mut client_config = make_client_config(*kt); - client_config.alpn_protocols = vec!["foo".into(), "bar".into()]; - - let mut server_config = make_server_config(*kt); - server_config.cert_resolver = Arc::new(ServerCheckCertResolve { - expected_alpn: Some(vec![b"foo".to_vec(), b"bar".to_vec()]), - ..Default::default() - }); - - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("sni-value")).unwrap(); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); - } -} - -#[test] -fn client_trims_terminating_dot() { - for kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config(*kt); - let mut server_config = make_server_config(*kt); - - server_config.cert_resolver = Arc::new(ServerCheckCertResolve { - expected_sni: Some("some-host.com".into()), - ..Default::default() - }); - - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("some-host.com.")).unwrap(); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); - } -} - -#[cfg(feature = "tls12")] -fn check_sigalgs_reduced_by_ciphersuite( - kt: KeyType, - suite: CipherSuite, - expected_sigalgs: Vec, -) { - let client_config = finish_client_config( - kt, - ClientConfig::builder() - .with_cipher_suites(&[find_suite(suite)]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .unwrap(), - ); - - let mut server_config = make_server_config(kt); - - server_config.cert_resolver = Arc::new(ServerCheckCertResolve { - expected_sigalgs: Some(expected_sigalgs), - expected_cipher_suites: Some(vec![suite, CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV]), - ..Default::default() - }); - - let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); -} - -#[cfg(feature = "tls12")] -#[test] -fn server_cert_resolve_reduces_sigalgs_for_rsa_ciphersuite() { - check_sigalgs_reduced_by_ciphersuite( - KeyType::Rsa, - CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - vec![ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, - ], - ); -} - -#[cfg(feature = "tls12")] -#[test] -fn server_cert_resolve_reduces_sigalgs_for_ecdsa_ciphersuite() { - check_sigalgs_reduced_by_ciphersuite( - KeyType::Ecdsa, - CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - vec![ - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, - SignatureScheme::ED25519, - ], - ); -} - -struct ServerCheckNoSNI {} - -impl ResolvesServerCert for ServerCheckNoSNI { - fn resolve(&self, client_hello: ClientHello) -> Option> { - assert!(client_hello.server_name().is_none()); - - None - } -} - -#[test] -fn client_with_sni_disabled_does_not_send_sni() { - for kt in ALL_KEY_TYPES.iter() { - let mut server_config = make_server_config(*kt); - server_config.cert_resolver = Arc::new(ServerCheckNoSNI {}); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(*kt, &[version]); - client_config.enable_sni = false; - - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("value-not-sent")).unwrap(); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert!(err.is_err()); - } - } -} - -#[test] -fn client_checks_server_certificate_with_given_name() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = Arc::new(make_server_config(*kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let mut client = ClientConnection::new( - Arc::new(client_config), - dns_name("not-the-right-hostname.com"), - ) - .unwrap(); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - - let err = do_handshake_until_error(&mut client, &mut server); - assert_eq!( - err, - Err(ErrorFromPeer::Client(Error::InvalidCertificateData( - "invalid peer certificate: CertNotValidForName".into(), - ))) - ); - } - } -} - -struct ClientCheckCertResolve { - query_count: AtomicUsize, - expect_queries: usize, -} - -impl ClientCheckCertResolve { - fn new(expect_queries: usize) -> Self { - ClientCheckCertResolve { - query_count: AtomicUsize::new(0), - expect_queries, - } - } -} - -impl Drop for ClientCheckCertResolve { - fn drop(&mut self) { - if !std::thread::panicking() { - let count = self.query_count.load(Ordering::SeqCst); - assert_eq!(count, self.expect_queries); - } - } -} - -impl ResolvesClientCert for ClientCheckCertResolve { - fn resolve( - &self, - acceptable_issuers: &[&[u8]], - sigschemes: &[SignatureScheme], - ) -> Option> { - self.query_count - .fetch_add(1, Ordering::SeqCst); - - if acceptable_issuers.is_empty() { - panic!("no issuers offered by server"); - } - - if sigschemes.is_empty() { - panic!("no signature schemes shared by server"); - } - - None - } - - fn has_certs(&self) -> bool { - true - } -} - -#[test] -fn client_cert_resolve() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(*kt, &[version]); - client_config.client_auth_cert_resolver = Arc::new(ClientCheckCertResolve::new(1)); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!( - do_handshake_until_error(&mut client, &mut server), - Err(ErrorFromPeer::Server(Error::NoCertificatesPresented)) - ); - } - } -} - -#[test] -fn client_auth_works() { - for kt in ALL_KEY_TYPES.iter() { - let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - } - } -} - -#[test] -fn client_error_is_sticky() { - let (mut client, _) = make_pair(KeyType::Rsa); - client - .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) - .unwrap(); - let mut err = client.process_new_packets(); - assert!(err.is_err()); - err = client.process_new_packets(); - assert!(err.is_err()); -} - -#[test] -fn server_error_is_sticky() { - let (_, mut server) = make_pair(KeyType::Rsa); - server - .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) - .unwrap(); - let mut err = server.process_new_packets(); - assert!(err.is_err()); - err = server.process_new_packets(); - assert!(err.is_err()); -} - -#[test] -fn server_flush_does_nothing() { - let (_, mut server) = make_pair(KeyType::Rsa); - assert!(matches!(server.writer().flush(), Ok(()))); -} - -#[test] -fn client_flush_does_nothing() { - let (mut client, _) = make_pair(KeyType::Rsa); - assert!(matches!(client.writer().flush(), Ok(()))); -} - -#[test] -fn server_is_send_and_sync() { - let (_, server) = make_pair(KeyType::Rsa); - &server as &dyn Send; - &server as &dyn Sync; -} - -#[test] -fn client_is_send_and_sync() { - let (client, _) = make_pair(KeyType::Rsa); - &client as &dyn Send; - &client as &dyn Sync; -} - -#[test] -fn server_respects_buffer_limit_pre_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - server.set_buffer_limit(Some(32)); - - assert_eq!( - server - .writer() - .write(b"01234567890123456789") - .unwrap(), - 20 - ); - assert_eq!( - server - .writer() - .write(b"01234567890123456789") - .unwrap(), - 12 - ); - - do_handshake(&mut client, &mut server); - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - check_read(&mut client.reader(), b"01234567890123456789012345678901"); -} - -#[test] -fn server_respects_buffer_limit_pre_handshake_with_vectored_write() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - server.set_buffer_limit(Some(32)); - - assert_eq!( - server - .writer() - .write_vectored(&[ - IoSlice::new(b"01234567890123456789"), - IoSlice::new(b"01234567890123456789") - ]) - .unwrap(), - 32 - ); - - do_handshake(&mut client, &mut server); - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - check_read(&mut client.reader(), b"01234567890123456789012345678901"); -} - -#[test] -fn server_respects_buffer_limit_post_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - // this test will vary in behaviour depending on the default suites - do_handshake(&mut client, &mut server); - server.set_buffer_limit(Some(48)); - - assert_eq!( - server - .writer() - .write(b"01234567890123456789") - .unwrap(), - 20 - ); - assert_eq!( - server - .writer() - .write(b"01234567890123456789") - .unwrap(), - 6 - ); - - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - check_read(&mut client.reader(), b"01234567890123456789012345"); -} - -#[test] -fn client_respects_buffer_limit_pre_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - client.set_buffer_limit(Some(32)); - - assert_eq!( - client - .writer() - .write(b"01234567890123456789") - .unwrap(), - 20 - ); - assert_eq!( - client - .writer() - .write(b"01234567890123456789") - .unwrap(), - 12 - ); - - do_handshake(&mut client, &mut server); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - check_read(&mut server.reader(), b"01234567890123456789012345678901"); -} - -#[test] -fn client_respects_buffer_limit_pre_handshake_with_vectored_write() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - client.set_buffer_limit(Some(32)); - - assert_eq!( - client - .writer() - .write_vectored(&[ - IoSlice::new(b"01234567890123456789"), - IoSlice::new(b"01234567890123456789") - ]) - .unwrap(), - 32 - ); - - do_handshake(&mut client, &mut server); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - check_read(&mut server.reader(), b"01234567890123456789012345678901"); -} - -#[test] -fn client_respects_buffer_limit_post_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - do_handshake(&mut client, &mut server); - client.set_buffer_limit(Some(48)); - - assert_eq!( - client - .writer() - .write(b"01234567890123456789") - .unwrap(), - 20 - ); - assert_eq!( - client - .writer() - .write(b"01234567890123456789") - .unwrap(), - 6 - ); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - check_read(&mut server.reader(), b"01234567890123456789012345"); -} - -struct OtherSession<'a, C, S> -where - C: DerefMut + Deref>, - S: SideData, -{ - sess: &'a mut C, - pub reads: usize, - pub writevs: Vec>, - fail_ok: bool, - pub short_writes: bool, - pub last_error: Option, -} - -impl<'a, C, S> OtherSession<'a, C, S> -where - C: DerefMut + Deref>, - S: SideData, -{ - fn new(sess: &'a mut C) -> OtherSession<'a, C, S> { - OtherSession { - sess, - reads: 0, - writevs: vec![], - fail_ok: false, - short_writes: false, - last_error: None, - } - } - - fn new_fails(sess: &'a mut C) -> OtherSession<'a, C, S> { - let mut os = OtherSession::new(sess); - os.fail_ok = true; - os - } -} - -impl<'a, C, S> io::Read for OtherSession<'a, C, S> -where - C: DerefMut + Deref>, - S: SideData, -{ - fn read(&mut self, mut b: &mut [u8]) -> io::Result { - self.reads += 1; - self.sess.write_tls(b.by_ref()) - } -} - -impl<'a, C, S> io::Write for OtherSession<'a, C, S> -where - C: DerefMut + Deref>, - S: SideData, -{ - fn write(&mut self, _: &[u8]) -> io::Result { - unreachable!() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - - fn write_vectored<'b>(&mut self, b: &[io::IoSlice<'b>]) -> io::Result { - let mut total = 0; - let mut lengths = vec![]; - for bytes in b { - let write_len = if self.short_writes { - if bytes.len() > 5 { - bytes.len() / 2 - } else { - bytes.len() - } - } else { - bytes.len() - }; - - let l = self - .sess - .read_tls(&mut io::Cursor::new(&bytes[..write_len]))?; - lengths.push(l); - total += l; - if bytes.len() != l { - break; - } - } - - let rc = self.sess.process_new_packets(); - if !self.fail_ok { - rc.unwrap(); - } else if rc.is_err() { - self.last_error = rc.err(); - } - - self.writevs.push(lengths); - Ok(total) - } -} - -#[test] -fn server_read_returns_wouldblock_when_no_data() { - let (_, mut server) = make_pair(KeyType::Rsa); - assert!(matches!(server.reader().read(&mut [0u8; 1]), - Err(err) if err.kind() == io::ErrorKind::WouldBlock)); -} - -#[test] -fn client_read_returns_wouldblock_when_no_data() { - let (mut client, _) = make_pair(KeyType::Rsa); - assert!(matches!(client.reader().read(&mut [0u8; 1]), - Err(err) if err.kind() == io::ErrorKind::WouldBlock)); -} - -#[test] -fn new_server_returns_initial_io_state() { - let (_, mut server) = make_pair(KeyType::Rsa); - let io_state = server.process_new_packets().unwrap(); - println!("IoState is Debug {:?}", io_state); - assert_eq!(io_state.plaintext_bytes_to_read(), 0); - assert!(!io_state.peer_has_closed()); - assert_eq!(io_state.tls_bytes_to_write(), 0); -} - -#[test] -fn new_client_returns_initial_io_state() { - let (mut client, _) = make_pair(KeyType::Rsa); - let io_state = client.process_new_packets().unwrap(); - println!("IoState is Debug {:?}", io_state); - assert_eq!(io_state.plaintext_bytes_to_read(), 0); - assert!(!io_state.peer_has_closed()); - assert!(io_state.tls_bytes_to_write() > 200); -} - -#[test] -fn client_complete_io_for_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - assert!(client.is_handshaking()); - let (rdlen, wrlen) = client - .complete_io(&mut OtherSession::new(&mut server)) - .unwrap(); - assert!(rdlen > 0 && wrlen > 0); - assert!(!client.is_handshaking()); -} - -#[test] -fn client_complete_io_for_handshake_eof() { - let (mut client, _) = make_pair(KeyType::Rsa); - let mut input = io::Cursor::new(Vec::new()); - - assert!(client.is_handshaking()); - let err = client - .complete_io(&mut input) - .unwrap_err(); - assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); -} - -#[test] -fn client_complete_io_for_write() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - do_handshake(&mut client, &mut server); - - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut server); - let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); - assert!(rdlen == 0 && wrlen > 0); - println!("{:?}", pipe.writevs); - assert_eq!(pipe.writevs, vec![vec![42, 42]]); - } - check_read( - &mut server.reader(), - b"0123456789012345678901234567890123456789", - ); - } -} - -#[test] -fn client_complete_io_for_read() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - do_handshake(&mut client, &mut server); - - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut server); - let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); - assert!(rdlen > 0 && wrlen == 0); - assert_eq!(pipe.reads, 1); - } - check_read(&mut client.reader(), b"01234567890123456789"); - } -} - -#[test] -fn server_complete_io_for_handshake() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - assert!(server.is_handshaking()); - let (rdlen, wrlen) = server - .complete_io(&mut OtherSession::new(&mut client)) - .unwrap(); - assert!(rdlen > 0 && wrlen > 0); - assert!(!server.is_handshaking()); - } -} - -#[test] -fn server_complete_io_for_handshake_eof() { - let (_, mut server) = make_pair(KeyType::Rsa); - let mut input = io::Cursor::new(Vec::new()); - - assert!(server.is_handshaking()); - let err = server - .complete_io(&mut input) - .unwrap_err(); - assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); -} - -#[test] -fn server_complete_io_for_write() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - do_handshake(&mut client, &mut server); - - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); - assert!(rdlen == 0 && wrlen > 0); - assert_eq!(pipe.writevs, vec![vec![42, 42]]); - } - check_read( - &mut client.reader(), - b"0123456789012345678901234567890123456789", - ); - } -} - -#[test] -fn server_complete_io_for_read() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - do_handshake(&mut client, &mut server); - - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); - assert!(rdlen > 0 && wrlen == 0); - assert_eq!(pipe.reads, 1); - } - check_read(&mut server.reader(), b"01234567890123456789"); - } -} - -#[test] -fn client_stream_write() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - { - let mut pipe = OtherSession::new(&mut server); - let mut stream = Stream::new(&mut client, &mut pipe); - assert_eq!(stream.write(b"hello").unwrap(), 5); - } - check_read(&mut server.reader(), b"hello"); - } -} - -#[test] -fn client_streamowned_write() { - for kt in ALL_KEY_TYPES.iter() { - let (client, mut server) = make_pair(*kt); - - { - let pipe = OtherSession::new(&mut server); - let mut stream = StreamOwned::new(client, pipe); - assert_eq!(stream.write(b"hello").unwrap(), 5); - } - check_read(&mut server.reader(), b"hello"); - } -} - -#[test] -fn client_stream_read() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - server - .writer() - .write_all(b"world") - .unwrap(); - - { - let mut pipe = OtherSession::new(&mut server); - let mut stream = Stream::new(&mut client, &mut pipe); - check_read(&mut stream, b"world"); - } - } -} - -#[test] -fn client_streamowned_read() { - for kt in ALL_KEY_TYPES.iter() { - let (client, mut server) = make_pair(*kt); - - server - .writer() - .write_all(b"world") - .unwrap(); - - { - let pipe = OtherSession::new(&mut server); - let mut stream = StreamOwned::new(client, pipe); - check_read(&mut stream, b"world"); - } - } -} - -#[test] -fn server_stream_write() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - { - let mut pipe = OtherSession::new(&mut client); - let mut stream = Stream::new(&mut server, &mut pipe); - assert_eq!(stream.write(b"hello").unwrap(), 5); - } - check_read(&mut client.reader(), b"hello"); - } -} - -#[test] -fn server_streamowned_write() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, server) = make_pair(*kt); - - { - let pipe = OtherSession::new(&mut client); - let mut stream = StreamOwned::new(server, pipe); - assert_eq!(stream.write(b"hello").unwrap(), 5); - } - check_read(&mut client.reader(), b"hello"); - } -} - -#[test] -fn server_stream_read() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, mut server) = make_pair(*kt); - - client - .writer() - .write_all(b"world") - .unwrap(); - - { - let mut pipe = OtherSession::new(&mut client); - let mut stream = Stream::new(&mut server, &mut pipe); - check_read(&mut stream, b"world"); - } - } -} - -#[test] -fn server_streamowned_read() { - for kt in ALL_KEY_TYPES.iter() { - let (mut client, server) = make_pair(*kt); - - client - .writer() - .write_all(b"world") - .unwrap(); - - { - let pipe = OtherSession::new(&mut client); - let mut stream = StreamOwned::new(server, pipe); - check_read(&mut stream, b"world"); - } - } -} - -struct FailsWrites { - errkind: io::ErrorKind, - after: usize, -} - -impl io::Read for FailsWrites { - fn read(&mut self, _b: &mut [u8]) -> io::Result { - Ok(0) - } -} - -impl io::Write for FailsWrites { - fn write(&mut self, b: &[u8]) -> io::Result { - if self.after > 0 { - self.after -= 1; - Ok(b.len()) - } else { - Err(io::Error::new(self.errkind, "oops")) - } - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[test] -fn stream_write_reports_underlying_io_error_before_plaintext_processed() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - do_handshake(&mut client, &mut server); - - let mut pipe = FailsWrites { - errkind: io::ErrorKind::ConnectionAborted, - after: 0, - }; - client - .writer() - .write_all(b"hello") - .unwrap(); - let mut client_stream = Stream::new(&mut client, &mut pipe); - let rc = client_stream.write(b"world"); - assert!(rc.is_err()); - let err = rc.err().unwrap(); - assert_eq!(err.kind(), io::ErrorKind::ConnectionAborted); -} - -#[test] -fn stream_write_swallows_underlying_io_error_after_plaintext_processed() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - do_handshake(&mut client, &mut server); - - let mut pipe = FailsWrites { - errkind: io::ErrorKind::ConnectionAborted, - after: 1, - }; - client - .writer() - .write_all(b"hello") - .unwrap(); - let mut client_stream = Stream::new(&mut client, &mut pipe); - let rc = client_stream.write(b"world"); - assert_eq!(format!("{:?}", rc), "Ok(5)"); -} - -fn make_disjoint_suite_configs() -> (ClientConfig, ServerConfig) { - let kt = KeyType::Rsa; - let server_config = finish_server_config( - kt, - ServerConfig::builder() - .with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .unwrap(), - ); - - let client_config = finish_client_config( - kt, - ClientConfig::builder() - .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .unwrap(), - ); - - (client_config, server_config) -} - -#[test] -fn client_stream_handshake_error() { - let (client_config, server_config) = make_disjoint_suite_configs(); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - { - let mut pipe = OtherSession::new_fails(&mut server); - let mut client_stream = Stream::new(&mut client, &mut pipe); - let rc = client_stream.write(b"hello"); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" - ); - let rc = client_stream.write(b"hello"); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" - ); - } -} - -#[test] -fn client_streamowned_handshake_error() { - let (client_config, server_config) = make_disjoint_suite_configs(); - let (client, mut server) = make_pair_for_configs(client_config, server_config); - - let pipe = OtherSession::new_fails(&mut server); - let mut client_stream = StreamOwned::new(client, pipe); - let rc = client_stream.write(b"hello"); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" - ); - let rc = client_stream.write(b"hello"); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" - ); -} - -#[test] -fn server_stream_handshake_error() { - let (client_config, server_config) = make_disjoint_suite_configs(); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - client - .writer() - .write_all(b"world") - .unwrap(); - - { - let mut pipe = OtherSession::new_fails(&mut client); - let mut server_stream = Stream::new(&mut server, &mut pipe); - let mut bytes = [0u8; 5]; - let rc = server_stream.read(&mut bytes); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: PeerIncompatibleError(\"no ciphersuites in common\") })" - ); - } -} - -#[test] -fn server_streamowned_handshake_error() { - let (client_config, server_config) = make_disjoint_suite_configs(); - let (mut client, server) = make_pair_for_configs(client_config, server_config); - - client - .writer() - .write_all(b"world") - .unwrap(); - - let pipe = OtherSession::new_fails(&mut client); - let mut server_stream = StreamOwned::new(server, pipe); - let mut bytes = [0u8; 5]; - let rc = server_stream.read(&mut bytes); - assert!(rc.is_err()); - assert_eq!( - format!("{:?}", rc), - "Err(Custom { kind: InvalidData, error: PeerIncompatibleError(\"no ciphersuites in common\") })" - ); -} - -#[test] -fn server_config_is_clone() { - let _ = make_server_config(KeyType::Rsa); -} - -#[test] -fn client_config_is_clone() { - let _ = make_client_config(KeyType::Rsa); -} - -#[test] -fn client_connection_is_debug() { - let (client, _) = make_pair(KeyType::Rsa); - println!("{:?}", client); -} - -#[test] -fn server_connection_is_debug() { - let (_, server) = make_pair(KeyType::Rsa); - println!("{:?}", server); -} - -#[test] -fn server_complete_io_for_handshake_ending_with_alert() { - let (client_config, server_config) = make_disjoint_suite_configs(); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - assert!(server.is_handshaking()); - - let mut pipe = OtherSession::new_fails(&mut client); - let rc = server.complete_io(&mut pipe); - assert!(rc.is_err(), "server io failed due to handshake failure"); - assert!(!server.wants_write(), "but server did send its alert"); - assert_eq!( - format!("{:?}", pipe.last_error), - "Some(AlertReceived(HandshakeFailure))", - "which was received by client" - ); -} - -#[test] -fn server_exposes_offered_sni() { - let kt = KeyType::Rsa; - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(kt, &[version]); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("second.testserver.com")) - .unwrap(); - let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); - - assert_eq!(None, server.sni_hostname()); - do_handshake(&mut client, &mut server); - assert_eq!(Some("second.testserver.com"), server.sni_hostname()); - } -} - -#[test] -fn server_exposes_offered_sni_smashed_to_lowercase() { - // webpki actually does this for us in its DnsName type - let kt = KeyType::Rsa; - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(kt, &[version]); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("SECOND.TESTServer.com")) - .unwrap(); - let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); - - assert_eq!(None, server.sni_hostname()); - do_handshake(&mut client, &mut server); - assert_eq!(Some("second.testserver.com"), server.sni_hostname()); - } -} - -#[test] -fn server_exposes_offered_sni_even_if_resolver_fails() { - let kt = KeyType::Rsa; - let resolver = rustls::server::ResolvesServerCertUsingSni::new(); - - let mut server_config = make_server_config(kt); - server_config.cert_resolver = Arc::new(resolver); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("thisdoesNOTexist.com")) - .unwrap(); - - assert_eq!(None, server.sni_hostname()); - transfer(&mut client, &mut server); - assert_eq!( - server.process_new_packets(), - Err(Error::General( - "no server certificate chain resolved".to_string() - )) - ); - assert_eq!(Some("thisdoesnotexist.com"), server.sni_hostname()); - } -} - -#[test] -fn sni_resolver_works() { - let kt = KeyType::Rsa; - let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); - let signing_key: Arc = Arc::new(signing_key); - resolver - .add( - "localhost", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()), - ) - .unwrap(); - - let mut server_config = make_server_config(kt); - server_config.cert_resolver = Arc::new(resolver); - let server_config = Arc::new(server_config); - - let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client1 = - ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); - let err = do_handshake_until_error(&mut client1, &mut server1); - assert_eq!(err, Ok(())); - - let mut server2 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client2 = - ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("notlocalhost")).unwrap(); - let err = do_handshake_until_error(&mut client2, &mut server2); - assert_eq!( - err, - Err(ErrorFromPeer::Server(Error::General( - "no server certificate chain resolved".into() - ))) - ); -} - -#[test] -fn sni_resolver_rejects_wrong_names() { - let kt = KeyType::Rsa; - let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); - let signing_key: Arc = Arc::new(signing_key); - - assert_eq!( - Ok(()), - resolver.add( - "localhost", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) - ) - ); - assert_eq!( - Err(Error::General( - "The server certificate is not valid for the given name".into() - )), - resolver.add( - "not-localhost", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) - ) - ); - assert_eq!( - Err(Error::General("Bad DNS name".into())), - resolver.add( - "not ascii 🦀", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) - ) - ); -} - -#[test] -fn sni_resolver_lower_cases_configured_names() { - let kt = KeyType::Rsa; - let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); - let signing_key: Arc = Arc::new(signing_key); - - assert_eq!( - Ok(()), - resolver.add( - "LOCALHOST", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) - ) - ); - - let mut server_config = make_server_config(kt); - server_config.cert_resolver = Arc::new(resolver); - let server_config = Arc::new(server_config); - - let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client1 = - ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); - let err = do_handshake_until_error(&mut client1, &mut server1); - assert_eq!(err, Ok(())); -} - -#[test] -fn sni_resolver_lower_cases_queried_names() { - // actually, the handshake parser does this, but the effect is the same. - let kt = KeyType::Rsa; - let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); - let signing_key: Arc = Arc::new(signing_key); - - assert_eq!( - Ok(()), - resolver.add( - "localhost", - sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) - ) - ); - - let mut server_config = make_server_config(kt); - server_config.cert_resolver = Arc::new(resolver); - let server_config = Arc::new(server_config); - - let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client1 = - ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("LOCALHOST")).unwrap(); - let err = do_handshake_until_error(&mut client1, &mut server1); - assert_eq!(err, Ok(())); -} - -#[test] -fn sni_resolver_rejects_bad_certs() { - let kt = KeyType::Rsa; - let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); - let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); - let signing_key: Arc = Arc::new(signing_key); - - assert_eq!( - Err(Error::General( - "No end-entity certificate in certificate chain".into() - )), - resolver.add( - "localhost", - sign::CertifiedKey::new(vec![], signing_key.clone()) - ) - ); - - let bad_chain = vec![rustls::Certificate(vec![0xa0])]; - assert_eq!( - Err(Error::General( - "End-entity certificate in certificate chain is syntactically invalid".into() - )), - resolver.add( - "localhost", - sign::CertifiedKey::new(bad_chain, signing_key.clone()) - ) - ); -} - -fn do_exporter_test(client_config: ClientConfig, server_config: ServerConfig) { - let mut client_secret = [0u8; 64]; - let mut server_secret = [0u8; 64]; - - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - assert_eq!( - Err(Error::HandshakeNotComplete), - client.export_keying_material(&mut client_secret, b"label", Some(b"context")) - ); - assert_eq!( - Err(Error::HandshakeNotComplete), - server.export_keying_material(&mut server_secret, b"label", Some(b"context")) - ); - do_handshake(&mut client, &mut server); - - assert_eq!( - Ok(()), - client.export_keying_material(&mut client_secret, b"label", Some(b"context")) - ); - assert_eq!( - Ok(()), - server.export_keying_material(&mut server_secret, b"label", Some(b"context")) - ); - assert_eq!(client_secret.to_vec(), server_secret.to_vec()); - - assert_eq!( - Ok(()), - client.export_keying_material(&mut client_secret, b"label", None) - ); - assert_ne!(client_secret.to_vec(), server_secret.to_vec()); - assert_eq!( - Ok(()), - server.export_keying_material(&mut server_secret, b"label", None) - ); - assert_eq!(client_secret.to_vec(), server_secret.to_vec()); -} - -#[cfg(feature = "tls12")] -#[test] -fn test_tls12_exporter() { - for kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); - let server_config = make_server_config(*kt); - - do_exporter_test(client_config, server_config); - } -} - -#[test] -fn test_tls13_exporter() { - for kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); - let server_config = make_server_config(*kt); - - do_exporter_test(client_config, server_config); - } -} - -fn do_suite_test( - client_config: ClientConfig, - server_config: ServerConfig, - expect_suite: SupportedCipherSuite, - expect_version: ProtocolVersion, -) { - println!( - "do_suite_test {:?} {:?}", - expect_version, - expect_suite.suite() - ); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - assert_eq!(None, client.negotiated_cipher_suite()); - assert_eq!(None, server.negotiated_cipher_suite()); - assert_eq!(None, client.protocol_version()); - assert_eq!(None, server.protocol_version()); - assert!(client.is_handshaking()); - assert!(server.is_handshaking()); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - assert!(client.is_handshaking()); - assert!(server.is_handshaking()); - assert_eq!(None, client.protocol_version()); - assert_eq!(Some(expect_version), server.protocol_version()); - assert_eq!(None, client.negotiated_cipher_suite()); - assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); - - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); - assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - assert!(!client.is_handshaking()); - assert!(!server.is_handshaking()); - assert_eq!(Some(expect_version), client.protocol_version()); - assert_eq!(Some(expect_version), server.protocol_version()); - assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); - assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); -} - -fn find_suite(suite: CipherSuite) -> SupportedCipherSuite { - for scs in ALL_CIPHER_SUITES.iter().copied() { - if scs.suite() == suite { - return scs; - } - } - - panic!("find_suite given unsupported suite"); -} - -static TEST_CIPHERSUITES: &[(&rustls::SupportedProtocolVersion, KeyType, CipherSuite)] = &[ - ( - &rustls::version::TLS13, - KeyType::Rsa, - CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, - ), - ( - &rustls::version::TLS13, - KeyType::Rsa, - CipherSuite::TLS13_AES_256_GCM_SHA384, - ), - ( - &rustls::version::TLS13, - KeyType::Rsa, - CipherSuite::TLS13_AES_128_GCM_SHA256, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Ecdsa, - CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Rsa, - CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Ecdsa, - CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Ecdsa, - CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Rsa, - CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - ), - #[cfg(feature = "tls12")] - ( - &rustls::version::TLS12, - KeyType::Rsa, - CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - ), -]; - -#[test] -fn negotiated_ciphersuite_default() { - for kt in ALL_KEY_TYPES.iter() { - do_suite_test( - make_client_config(*kt), - make_server_config(*kt), - find_suite(CipherSuite::TLS13_AES_256_GCM_SHA384), - ProtocolVersion::TLSv1_3, - ); - } -} - -#[test] -fn all_suites_covered() { - assert_eq!(ALL_CIPHER_SUITES.len(), TEST_CIPHERSUITES.len()); -} - -#[test] -fn negotiated_ciphersuite_client() { - for item in TEST_CIPHERSUITES.iter() { - let (version, kt, suite) = *item; - let scs = find_suite(suite); - let client_config = finish_client_config( - kt, - ClientConfig::builder() - .with_cipher_suites(&[scs]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[version]) - .unwrap(), - ); - - do_suite_test(client_config, make_server_config(kt), scs, version.version); - } -} - -#[test] -fn negotiated_ciphersuite_server() { - for item in TEST_CIPHERSUITES.iter() { - let (version, kt, suite) = *item; - let scs = find_suite(suite); - let server_config = finish_server_config( - kt, - ServerConfig::builder() - .with_cipher_suites(&[scs]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[version]) - .unwrap(), - ); - - do_suite_test(make_client_config(kt), server_config, scs, version.version); - } -} - -#[derive(Debug, PartialEq)] -struct KeyLogItem { - label: String, - client_random: Vec, - secret: Vec, -} - -struct KeyLogToVec { - label: &'static str, - items: Mutex>, -} - -impl KeyLogToVec { - fn new(who: &'static str) -> Self { - KeyLogToVec { - label: who, - items: Mutex::new(vec![]), - } - } - - fn take(&self) -> Vec { - std::mem::take(&mut self.items.lock().unwrap()) - } -} - -impl KeyLog for KeyLogToVec { - fn log(&self, label: &str, client: &[u8], secret: &[u8]) { - let value = KeyLogItem { - label: label.into(), - client_random: client.into(), - secret: secret.into(), - }; - - println!("key log {:?}: {:?}", self.label, value); - - self.items.lock().unwrap().push(value); - } -} - -#[cfg(feature = "tls12")] -#[test] -fn key_log_for_tls12() { - let client_key_log = Arc::new(KeyLogToVec::new("client")); - let server_key_log = Arc::new(KeyLogToVec::new("server")); - - let kt = KeyType::Rsa; - let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS12]); - client_config.key_log = client_key_log.clone(); - let client_config = Arc::new(client_config); - - let mut server_config = make_server_config(kt); - server_config.key_log = server_key_log.clone(); - let server_config = Arc::new(server_config); - - // full handshake - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let client_full_log = client_key_log.take(); - let server_full_log = server_key_log.take(); - assert_eq!(client_full_log, server_full_log); - assert_eq!(1, client_full_log.len()); - assert_eq!("CLIENT_RANDOM", client_full_log[0].label); - - // resumed - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let client_resume_log = client_key_log.take(); - let server_resume_log = server_key_log.take(); - assert_eq!(client_resume_log, server_resume_log); - assert_eq!(1, client_resume_log.len()); - assert_eq!("CLIENT_RANDOM", client_resume_log[0].label); - assert_eq!(client_full_log[0].secret, client_resume_log[0].secret); -} - -#[test] -fn key_log_for_tls13() { - let client_key_log = Arc::new(KeyLogToVec::new("client")); - let server_key_log = Arc::new(KeyLogToVec::new("server")); - - let kt = KeyType::Rsa; - let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - client_config.key_log = client_key_log.clone(); - let client_config = Arc::new(client_config); - - let mut server_config = make_server_config(kt); - server_config.key_log = server_key_log.clone(); - let server_config = Arc::new(server_config); - - // full handshake - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let client_full_log = client_key_log.take(); - let server_full_log = server_key_log.take(); - - assert_eq!(5, client_full_log.len()); - assert_eq!("CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_full_log[0].label); - assert_eq!("SERVER_HANDSHAKE_TRAFFIC_SECRET", client_full_log[1].label); - assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_full_log[2].label); - assert_eq!("SERVER_TRAFFIC_SECRET_0", client_full_log[3].label); - assert_eq!("EXPORTER_SECRET", client_full_log[4].label); - - assert_eq!(client_full_log[0], server_full_log[0]); - assert_eq!(client_full_log[1], server_full_log[1]); - assert_eq!(client_full_log[2], server_full_log[2]); - assert_eq!(client_full_log[3], server_full_log[3]); - assert_eq!(client_full_log[4], server_full_log[4]); - - // resumed - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let client_resume_log = client_key_log.take(); - let server_resume_log = server_key_log.take(); - - assert_eq!(5, client_resume_log.len()); - assert_eq!( - "CLIENT_HANDSHAKE_TRAFFIC_SECRET", - client_resume_log[0].label - ); - assert_eq!( - "SERVER_HANDSHAKE_TRAFFIC_SECRET", - client_resume_log[1].label - ); - assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_resume_log[2].label); - assert_eq!("SERVER_TRAFFIC_SECRET_0", client_resume_log[3].label); - assert_eq!("EXPORTER_SECRET", client_resume_log[4].label); - - assert_eq!(6, server_resume_log.len()); - assert_eq!("CLIENT_EARLY_TRAFFIC_SECRET", server_resume_log[0].label); - assert_eq!( - "CLIENT_HANDSHAKE_TRAFFIC_SECRET", - server_resume_log[1].label - ); - assert_eq!( - "SERVER_HANDSHAKE_TRAFFIC_SECRET", - server_resume_log[2].label - ); - assert_eq!("CLIENT_TRAFFIC_SECRET_0", server_resume_log[3].label); - assert_eq!("SERVER_TRAFFIC_SECRET_0", server_resume_log[4].label); - assert_eq!("EXPORTER_SECRET", server_resume_log[5].label); - - assert_eq!(client_resume_log[0], server_resume_log[1]); - assert_eq!(client_resume_log[1], server_resume_log[2]); - assert_eq!(client_resume_log[2], server_resume_log[3]); - assert_eq!(client_resume_log[3], server_resume_log[4]); - assert_eq!(client_resume_log[4], server_resume_log[5]); -} - -#[test] -fn vectored_write_for_server_appdata() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - do_handshake(&mut client, &mut server); - - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - assert_eq!(84, wrlen); - assert_eq!(pipe.writevs, vec![vec![42, 42]]); - } - check_read( - &mut client.reader(), - b"0123456789012345678901234567890123456789", - ); -} - -#[test] -fn vectored_write_for_client_appdata() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - do_handshake(&mut client, &mut server); - - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut server); - let wrlen = client.write_tls(&mut pipe).unwrap(); - assert_eq!(84, wrlen); - assert_eq!(pipe.writevs, vec![vec![42, 42]]); - } - check_read( - &mut server.reader(), - b"0123456789012345678901234567890123456789", - ); -} - -#[test] -fn vectored_write_for_server_handshake_with_half_rtt_data() { - let mut server_config = make_server_config(KeyType::Rsa); - server_config.send_half_rtt_data = true; - let (mut client, mut server) = - make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); - - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - server - .writer() - .write_all(b"0123456789") - .unwrap(); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - // don't assert exact sizes here, to avoid a brittle test - assert!(wrlen > 4000); // its pretty big (contains cert chain) - assert_eq!(pipe.writevs.len(), 1); // only one writev - assert_eq!(pipe.writevs[0].len(), 8); // at least a server hello/ccs/cert/serverkx/0.5rtt data - } - - client.process_new_packets().unwrap(); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - assert_eq!(wrlen, 103); - assert_eq!(pipe.writevs, vec![vec![103]]); - } - - assert!(!server.is_handshaking()); - assert!(!client.is_handshaking()); - check_read(&mut client.reader(), b"012345678901234567890123456789"); -} - -fn check_half_rtt_does_not_work(server_config: ServerConfig) { - let (mut client, mut server) = - make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); - - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - server - .writer() - .write_all(b"0123456789") - .unwrap(); - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - // don't assert exact sizes here, to avoid a brittle test - assert!(wrlen > 4000); // its pretty big (contains cert chain) - assert_eq!(pipe.writevs.len(), 1); // only one writev - assert!(pipe.writevs[0].len() >= 6); // at least a server hello/ccs/cert/serverkx data - } - - // client second flight - client.process_new_packets().unwrap(); - transfer(&mut client, &mut server); - - // when client auth is enabled, we don't sent 0.5-rtt data, as we'd be sending - // it to an unauthenticated peer. so it happens here, in the server's second - // flight (42 and 32 are lengths of appdata sent above). - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - assert_eq!(wrlen, 177); - assert_eq!(pipe.writevs, vec![vec![103, 42, 32]]); - } - - assert!(!server.is_handshaking()); - assert!(!client.is_handshaking()); - check_read(&mut client.reader(), b"012345678901234567890123456789"); -} - -#[test] -fn vectored_write_for_server_handshake_no_half_rtt_with_client_auth() { - let mut server_config = make_server_config_with_mandatory_client_auth(KeyType::Rsa); - server_config.send_half_rtt_data = true; // ask even though it will be ignored - check_half_rtt_does_not_work(server_config); -} - -#[test] -fn vectored_write_for_server_handshake_no_half_rtt_by_default() { - let server_config = make_server_config(KeyType::Rsa); - assert!(!server_config.send_half_rtt_data); - check_half_rtt_does_not_work(server_config); -} - -#[test] -fn vectored_write_for_client_handshake() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - client - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - client - .writer() - .write_all(b"0123456789") - .unwrap(); - { - let mut pipe = OtherSession::new(&mut server); - let wrlen = client.write_tls(&mut pipe).unwrap(); - // don't assert exact sizes here, to avoid a brittle test - assert!(wrlen > 200); // just the client hello - assert_eq!(pipe.writevs.len(), 1); // only one writev - assert!(pipe.writevs[0].len() == 1); // only a client hello - } - - transfer(&mut server, &mut client); - client.process_new_packets().unwrap(); - - { - let mut pipe = OtherSession::new(&mut server); - let wrlen = client.write_tls(&mut pipe).unwrap(); - assert_eq!(wrlen, 154); - // CCS, finished, then two application datas - assert_eq!(pipe.writevs, vec![vec![6, 74, 42, 32]]); - } - - assert!(!server.is_handshaking()); - assert!(!client.is_handshaking()); - check_read(&mut server.reader(), b"012345678901234567890123456789"); -} - -#[test] -fn vectored_write_with_slow_client() { - let (mut client, mut server) = make_pair(KeyType::Rsa); - - client.set_buffer_limit(Some(32)); - - do_handshake(&mut client, &mut server); - server - .writer() - .write_all(b"01234567890123456789") - .unwrap(); - - { - let mut pipe = OtherSession::new(&mut client); - pipe.short_writes = true; - let wrlen = server.write_tls(&mut pipe).unwrap() - + server.write_tls(&mut pipe).unwrap() - + server.write_tls(&mut pipe).unwrap() - + server.write_tls(&mut pipe).unwrap() - + server.write_tls(&mut pipe).unwrap() - + server.write_tls(&mut pipe).unwrap(); - assert_eq!(42, wrlen); - assert_eq!( - pipe.writevs, - vec![vec![21], vec![10], vec![5], vec![3], vec![3]] - ); - } - check_read(&mut client.reader(), b"01234567890123456789"); -} - -struct ServerStorage { - storage: Arc, - put_count: AtomicUsize, - get_count: AtomicUsize, - take_count: AtomicUsize, -} - -impl ServerStorage { - fn new() -> Self { - ServerStorage { - storage: rustls::server::ServerSessionMemoryCache::new(1024), - put_count: AtomicUsize::new(0), - get_count: AtomicUsize::new(0), - take_count: AtomicUsize::new(0), - } - } - - fn puts(&self) -> usize { - self.put_count.load(Ordering::SeqCst) - } - fn gets(&self) -> usize { - self.get_count.load(Ordering::SeqCst) - } - fn takes(&self) -> usize { - self.take_count.load(Ordering::SeqCst) - } -} - -impl fmt::Debug for ServerStorage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(put: {:?}, get: {:?}, take: {:?})", - self.put_count, self.get_count, self.take_count - ) - } -} - -impl rustls::server::StoresServerSessions for ServerStorage { - fn put(&self, key: Vec, value: Vec) -> bool { - self.put_count - .fetch_add(1, Ordering::SeqCst); - self.storage.put(key, value) - } - - fn get(&self, key: &[u8]) -> Option> { - self.get_count - .fetch_add(1, Ordering::SeqCst); - self.storage.get(key) - } - - fn take(&self, key: &[u8]) -> Option> { - self.take_count - .fetch_add(1, Ordering::SeqCst); - self.storage.take(key) - } - - fn can_cache(&self) -> bool { - true - } -} - -struct ClientStorage { - storage: Arc, - put_count: AtomicUsize, - get_count: AtomicUsize, - last_put_key: Mutex>>, -} - -impl ClientStorage { - fn new() -> Self { - ClientStorage { - storage: rustls::client::ClientSessionMemoryCache::new(1024), - put_count: AtomicUsize::new(0), - get_count: AtomicUsize::new(0), - last_put_key: Mutex::new(None), - } - } - - fn puts(&self) -> usize { - self.put_count.load(Ordering::SeqCst) - } - fn gets(&self) -> usize { - self.get_count.load(Ordering::SeqCst) - } -} - -impl fmt::Debug for ClientStorage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(puts: {:?}, gets: {:?} )", - self.put_count, self.get_count - ) - } -} - -impl rustls::client::StoresClientSessions for ClientStorage { - fn put(&self, key: Vec, value: Vec) -> bool { - self.put_count - .fetch_add(1, Ordering::SeqCst); - *self.last_put_key.lock().unwrap() = Some(key.clone()); - self.storage.put(key, value) - } - - fn get(&self, key: &[u8]) -> Option> { - self.get_count - .fetch_add(1, Ordering::SeqCst); - self.storage.get(key) - } -} - -#[test] -fn tls13_stateful_resumption() { - let kt = KeyType::Rsa; - let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - let client_config = Arc::new(client_config); - - let mut server_config = make_server_config(kt); - let storage = Arc::new(ServerStorage::new()); - server_config.session_storage = storage.clone(); - let server_config = Arc::new(server_config); - - // full handshake - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); - assert_eq!(storage.puts(), 1); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 0); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); - - // resumed - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); - assert!(resume_c2s > full_c2s); - assert!(resume_s2c < full_s2c); - assert_eq!(storage.puts(), 2); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 1); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); - - // resumed again - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); - assert_eq!(resume_s2c, resume2_s2c); - assert_eq!(resume_c2s, resume2_c2s); - assert_eq!(storage.puts(), 3); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 2); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); -} - -#[test] -fn tls13_stateless_resumption() { - let kt = KeyType::Rsa; - let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - let client_config = Arc::new(client_config); - - let mut server_config = make_server_config(kt); - server_config.ticketer = rustls::Ticketer::new().unwrap(); - let storage = Arc::new(ServerStorage::new()); - server_config.session_storage = storage.clone(); - let server_config = Arc::new(server_config); - - // full handshake - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); - assert_eq!(storage.puts(), 0); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 0); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); - - // resumed - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); - assert!(resume_c2s > full_c2s); - assert!(resume_s2c < full_s2c); - assert_eq!(storage.puts(), 0); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 0); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); - - // resumed again - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); - assert_eq!(resume_s2c, resume2_s2c); - assert_eq!(resume_c2s, resume2_c2s); - assert_eq!(storage.puts(), 0); - assert_eq!(storage.gets(), 0); - assert_eq!(storage.takes(), 0); - assert_eq!( - client - .peer_certificates() - .map(|certs| certs.len()), - Some(3) - ); -} - -#[test] -fn early_data_not_available() { - let (mut client, _) = make_pair(KeyType::Rsa); - assert!(client.early_data().is_none()); -} - -fn early_data_configs() -> (Arc, Arc) { - let kt = KeyType::Rsa; - let mut client_config = make_client_config(kt); - client_config.enable_early_data = true; - client_config.session_storage = Arc::new(ClientStorage::new()); - - let mut server_config = make_server_config(kt); - server_config.max_early_data_size = 1234; - (Arc::new(client_config), Arc::new(server_config)) -} - -#[test] -fn early_data_is_available_on_resumption() { - let (client_config, server_config) = early_data_configs(); - - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - assert!(client.early_data().is_some()); - assert_eq!( - client - .early_data() - .unwrap() - .bytes_left(), - 1234 - ); - client - .early_data() - .unwrap() - .flush() - .unwrap(); - assert_eq!( - client - .early_data() - .unwrap() - .write(b"hello") - .unwrap(), - 5 - ); - do_handshake(&mut client, &mut server); - - let mut received_early_data = [0u8; 5]; - assert_eq!( - server - .early_data() - .expect("early_data didn't happen") - .read(&mut received_early_data) - .expect("early_data failed unexpectedly"), - 5 - ); - assert_eq!(&received_early_data[..], b"hello"); -} - -#[test] -fn early_data_not_available_on_server_before_client_hello() { - let mut server = ServerConnection::new(Arc::new(make_server_config(KeyType::Rsa))).unwrap(); - assert!(server.early_data().is_none()); -} - -#[test] -fn early_data_can_be_rejected_by_server() { - let (client_config, server_config) = early_data_configs(); - - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - assert!(client.early_data().is_some()); - assert_eq!( - client - .early_data() - .unwrap() - .bytes_left(), - 1234 - ); - client - .early_data() - .unwrap() - .flush() - .unwrap(); - assert_eq!( - client - .early_data() - .unwrap() - .write(b"hello") - .unwrap(), - 5 - ); - server.reject_early_data(); - do_handshake(&mut client, &mut server); - - assert!(!client.is_early_data_accepted()); -} - -#[cfg(feature = "quic")] -mod test_quic { - use super::*; - use rustls::Connection; - - // Returns the sender's next secrets to use, or the receiver's error. - fn step( - send: &mut dyn QuicExt, - recv: &mut dyn QuicExt, - ) -> Result, Error> { - let mut buf = Vec::new(); - let change = loop { - let prev = buf.len(); - if let Some(x) = send.write_hs(&mut buf) { - break Some(x); - } - if prev == buf.len() { - break None; - } - }; - if let Err(e) = recv.read_hs(&buf) { - return Err(e); - } else { - assert_eq!(recv.alert(), None); - } - - Ok(change) - } - - #[test] - fn test_quic_handshake() { - fn equal_packet_keys(x: &quic::PacketKey, y: &quic::PacketKey) -> bool { - // Check that these two sets of keys are equal. - let mut buf = vec![0; 32]; - let (header, payload_tag) = buf.split_at_mut(8); - let (payload, tag_buf) = payload_tag.split_at_mut(8); - let tag = x - .encrypt_in_place(42, &*header, payload) - .unwrap(); - tag_buf.copy_from_slice(tag.as_ref()); - - let result = y.decrypt_in_place(42, &*header, payload_tag); - match result { - Ok(payload) => payload == &[0; 8], - Err(_) => false, - } - } - - fn compatible_keys(x: &quic::KeyChange, y: &quic::KeyChange) -> bool { - fn keys(kc: &quic::KeyChange) -> &quic::Keys { - match kc { - quic::KeyChange::Handshake { keys } => keys, - quic::KeyChange::OneRtt { keys, .. } => keys, - } - } - - let (x, y) = (keys(x), keys(y)); - equal_packet_keys(&x.local.packet, &y.remote.packet) - && equal_packet_keys(&x.remote.packet, &y.local.packet) - } - - let kt = KeyType::Rsa; - let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - client_config.enable_early_data = true; - let client_config = Arc::new(client_config); - let mut server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); - server_config.max_early_data_size = 0xffffffff; - let server_config = Arc::new(server_config); - let client_params = &b"client params"[..]; - let server_params = &b"server params"[..]; - - // full handshake - let mut client = Connection::from( - ClientConnection::new_quic( - Arc::clone(&client_config), - quic::Version::V1, - dns_name("localhost"), - client_params.into(), - ) - .unwrap(), - ); - - let mut server = Connection::from( - ServerConnection::new_quic( - Arc::clone(&server_config), - quic::Version::V1, - server_params.into(), - ) - .unwrap(), - ); - - let client_initial = step(&mut client, &mut server).unwrap(); - assert!(client_initial.is_none()); - assert!(client.zero_rtt_keys().is_none()); - assert_eq!(server.quic_transport_parameters(), Some(client_params)); - let server_hs = step(&mut server, &mut client) - .unwrap() - .unwrap(); - assert!(server.zero_rtt_keys().is_none()); - let client_hs = step(&mut client, &mut server) - .unwrap() - .unwrap(); - assert!(compatible_keys(&server_hs, &client_hs)); - assert!(client.is_handshaking()); - let server_1rtt = step(&mut server, &mut client) - .unwrap() - .unwrap(); - assert!(!client.is_handshaking()); - assert_eq!(client.quic_transport_parameters(), Some(server_params)); - assert!(server.is_handshaking()); - let client_1rtt = step(&mut client, &mut server) - .unwrap() - .unwrap(); - assert!(!server.is_handshaking()); - assert!(compatible_keys(&server_1rtt, &client_1rtt)); - assert!(!compatible_keys(&server_hs, &server_1rtt)); - assert!(step(&mut client, &mut server) - .unwrap() - .is_none()); - assert!(step(&mut server, &mut client) - .unwrap() - .is_none()); - - // 0-RTT handshake - let mut client = ClientConnection::new_quic( - Arc::clone(&client_config), - quic::Version::V1, - dns_name("localhost"), - client_params.into(), - ) - .unwrap(); - assert!(client - .negotiated_cipher_suite() - .is_some()); - - let mut server = ServerConnection::new_quic( - Arc::clone(&server_config), - quic::Version::V1, - server_params.into(), - ) - .unwrap(); - - step(&mut client, &mut server).unwrap(); - assert_eq!(client.quic_transport_parameters(), Some(server_params)); - { - let client_early = client.zero_rtt_keys().unwrap(); - let server_early = server.zero_rtt_keys().unwrap(); - assert!(equal_packet_keys( - &client_early.packet, - &server_early.packet - )); - } - step(&mut server, &mut client) - .unwrap() - .unwrap(); - step(&mut client, &mut server) - .unwrap() - .unwrap(); - step(&mut server, &mut client) - .unwrap() - .unwrap(); - assert!(client.is_early_data_accepted()); - - // 0-RTT rejection - { - let client_config = (*client_config).clone(); - let mut client = ClientConnection::new_quic( - Arc::new(client_config), - quic::Version::V1, - dns_name("localhost"), - client_params.into(), - ) - .unwrap(); - - let mut server = ServerConnection::new_quic( - Arc::clone(&server_config), - quic::Version::V1, - server_params.into(), - ) - .unwrap(); - - step(&mut client, &mut server).unwrap(); - assert_eq!(client.quic_transport_parameters(), Some(server_params)); - assert!(client.zero_rtt_keys().is_some()); - assert!(server.zero_rtt_keys().is_none()); - step(&mut server, &mut client) - .unwrap() - .unwrap(); - step(&mut client, &mut server) - .unwrap() - .unwrap(); - step(&mut server, &mut client) - .unwrap() - .unwrap(); - assert!(!client.is_early_data_accepted()); - } - - // failed handshake - let mut client = ClientConnection::new_quic( - client_config, - quic::Version::V1, - dns_name("example.com"), - client_params.into(), - ) - .unwrap(); - - let mut server = - ServerConnection::new_quic(server_config, quic::Version::V1, server_params.into()) - .unwrap(); - - step(&mut client, &mut server).unwrap(); - step(&mut server, &mut client) - .unwrap() - .unwrap(); - assert!(step(&mut server, &mut client).is_err()); - assert_eq!( - client.alert(), - Some(rustls::AlertDescription::BadCertificate) - ); - - // Key updates - - let (mut client_secrets, mut server_secrets) = match (client_1rtt, server_1rtt) { - (quic::KeyChange::OneRtt { next: c, .. }, quic::KeyChange::OneRtt { next: s, .. }) => { - (c, s) - } - _ => unreachable!(), - }; - - let mut client_next = client_secrets.next_packet_keys(); - let mut server_next = server_secrets.next_packet_keys(); - assert!(equal_packet_keys(&client_next.local, &server_next.remote)); - assert!(equal_packet_keys(&server_next.local, &client_next.remote)); - - client_next = client_secrets.next_packet_keys(); - server_next = server_secrets.next_packet_keys(); - assert!(equal_packet_keys(&client_next.local, &server_next.remote)); - assert!(equal_packet_keys(&server_next.local, &client_next.remote)); - } - - #[test] - fn test_quic_rejects_missing_alpn() { - let client_params = &b"client params"[..]; - let server_params = &b"server params"[..]; - - for &kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - let client_config = Arc::new(client_config); - - let mut server_config = - make_server_config_with_versions(kt, &[&rustls::version::TLS13]); - server_config.alpn_protocols = vec!["foo".into()]; - let server_config = Arc::new(server_config); - - let mut client = ClientConnection::new_quic( - client_config, - quic::Version::V1, - dns_name("localhost"), - client_params.into(), - ) - .unwrap(); - let mut server = - ServerConnection::new_quic(server_config, quic::Version::V1, server_params.into()) - .unwrap(); - - assert_eq!( - step(&mut client, &mut server) - .err() - .unwrap(), - Error::NoApplicationProtocol - ); - - assert_eq!( - server.alert(), - Some(rustls::AlertDescription::NoApplicationProtocol) - ); - } - } - - #[cfg(feature = "tls12")] - #[test] - fn test_quic_no_tls13_error() { - let mut client_config = - make_client_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); - client_config.alpn_protocols = vec!["foo".into()]; - let client_config = Arc::new(client_config); - - assert!(ClientConnection::new_quic( - client_config, - quic::Version::V1, - dns_name("localhost"), - b"client params".to_vec(), - ) - .is_err()); - - let mut server_config = - make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); - server_config.alpn_protocols = vec!["foo".into()]; - let server_config = Arc::new(server_config); - - assert!(ServerConnection::new_quic( - server_config, - quic::Version::V1, - b"server params".to_vec(), - ) - .is_err()); - } - - #[test] - fn test_quic_invalid_early_data_size() { - let mut server_config = - make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); - server_config.alpn_protocols = vec!["foo".into()]; - - let cases = [ - (None, true), - (Some(0u32), true), - (Some(5), false), - (Some(0xffff_ffff), true), - ]; - - for &(size, ok) in cases.iter() { - println!("early data size case: {:?}", size); - if let Some(new) = size { - server_config.max_early_data_size = new; - } - - let wrapped = Arc::new(server_config.clone()); - assert_eq!( - ServerConnection::new_quic(wrapped, quic::Version::V1, b"server params".to_vec(),) - .is_ok(), - ok - ); - } - } - - #[test] - fn test_quic_server_no_params_received() { - let server_config = - make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); - let server_config = Arc::new(server_config); - - let mut server = - ServerConnection::new_quic(server_config, quic::Version::V1, b"server params".to_vec()) - .unwrap(); - - use ring::rand::SecureRandom; - use rustls::internal::msgs::base::PayloadU16; - use rustls::internal::msgs::enums::{Compression, HandshakeType, NamedGroup}; - use rustls::internal::msgs::handshake::{ - ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionID, - }; - use rustls::internal::msgs::message::PlainMessage; - use rustls::{CipherSuite, SignatureScheme}; - - let rng = ring::rand::SystemRandom::new(); - let mut random = [0; 32]; - rng.fill(&mut random).unwrap(); - let random = Random::from(random); - - let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) - .unwrap() - .compute_public_key() - .unwrap(); - - let client_hello = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ClientHello, - payload: HandshakePayload::ClientHello(ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_3, - random, - session_id: SessionID::random().unwrap(), - cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], - compression_methods: vec![Compression::Null], - extensions: vec![ - ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), - ClientExtension::NamedGroups(vec![NamedGroup::X25519]), - ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), - ClientExtension::KeyShare(vec![KeyShareEntry { - group: NamedGroup::X25519, - payload: PayloadU16::new(kx.as_ref().to_vec()), - }]), - ], - }), - }), - }; - - let buf = PlainMessage::from(client_hello) - .into_unencrypted_opaque() - .encode(); - server - .read_tls(&mut buf.as_slice()) - .unwrap(); - assert_eq!( - server.process_new_packets().err(), - Some(Error::PeerMisbehavedError( - "QUIC transport parameters not found".into(), - )), - ); - } - - #[test] - fn test_quic_server_no_tls12() { - let mut server_config = - make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); - server_config.alpn_protocols = vec!["foo".into()]; - let server_config = Arc::new(server_config); - - use ring::rand::SecureRandom; - use rustls::internal::msgs::base::PayloadU16; - use rustls::internal::msgs::enums::{Compression, HandshakeType, NamedGroup}; - use rustls::internal::msgs::handshake::{ - ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionID, - }; - use rustls::internal::msgs::message::PlainMessage; - use rustls::{CipherSuite, SignatureScheme}; - - let rng = ring::rand::SystemRandom::new(); - let mut random = [0; 32]; - rng.fill(&mut random).unwrap(); - let random = Random::from(random); - - let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) - .unwrap() - .compute_public_key() - .unwrap(); - - let mut server = - ServerConnection::new_quic(server_config, quic::Version::V1, b"server params".to_vec()) - .unwrap(); - - let client_hello = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload { - typ: HandshakeType::ClientHello, - payload: HandshakePayload::ClientHello(ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_2, - random: random.clone(), - session_id: SessionID::random().unwrap(), - cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], - compression_methods: vec![Compression::Null], - extensions: vec![ - ClientExtension::NamedGroups(vec![NamedGroup::X25519]), - ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), - ClientExtension::KeyShare(vec![KeyShareEntry { - group: NamedGroup::X25519, - payload: PayloadU16::new(kx.as_ref().to_vec()), - }]), - ], - }), - }), - }; - - let buf = PlainMessage::from(client_hello) - .into_unencrypted_opaque() - .encode(); - server - .read_tls(&mut buf.as_slice()) - .unwrap(); - assert_eq!( - server.process_new_packets().err(), - Some(Error::PeerIncompatibleError( - "Server requires TLS1.3, but client omitted versions ext".into(), - )), - ); - } - - #[test] - fn packet_key_api() { - use rustls::quic::{Keys, Version}; - - // Test vectors: https://www.rfc-editor.org/rfc/rfc9001.html#name-client-initial - const CONNECTION_ID: &[u8] = &[0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; - const PACKET_NUMBER: u64 = 2; - const PLAIN_HEADER: &[u8] = &[ - 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, - 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02, - ]; - - const PAYLOAD: &[u8] = &[ - 0x06, 0x00, 0x40, 0xf1, 0x01, 0x00, 0x00, 0xed, 0x03, 0x03, 0xeb, 0xf8, 0xfa, 0x56, - 0xf1, 0x29, 0x39, 0xb9, 0x58, 0x4a, 0x38, 0x96, 0x47, 0x2e, 0xc4, 0x0b, 0xb8, 0x63, - 0xcf, 0xd3, 0xe8, 0x68, 0x04, 0xfe, 0x3a, 0x47, 0xf0, 0x6a, 0x2b, 0x69, 0x48, 0x4c, - 0x00, 0x00, 0x04, 0x13, 0x01, 0x13, 0x02, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, - 0x63, 0x6f, 0x6d, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, - 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x10, 0x00, 0x07, 0x00, 0x05, 0x04, 0x61, - 0x6c, 0x70, 0x6e, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, - 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x93, 0x70, 0xb2, 0xc9, 0xca, 0xa4, - 0x7f, 0xba, 0xba, 0xf4, 0x55, 0x9f, 0xed, 0xba, 0x75, 0x3d, 0xe1, 0x71, 0xfa, 0x71, - 0xf5, 0x0f, 0x1c, 0xe1, 0x5d, 0x43, 0xe9, 0x94, 0xec, 0x74, 0xd7, 0x48, 0x00, 0x2b, - 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0e, 0x04, 0x03, 0x05, - 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x00, 0x2d, 0x00, - 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0x00, 0x39, 0x00, 0x32, 0x04, - 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x04, 0x80, 0x00, 0xff, - 0xff, 0x07, 0x04, 0x80, 0x00, 0xff, 0xff, 0x08, 0x01, 0x10, 0x01, 0x04, 0x80, 0x00, - 0x75, 0x30, 0x09, 0x01, 0x10, 0x0f, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, - 0x08, 0x06, 0x04, 0x80, 0x00, 0xff, 0xff, - ]; - - let client_keys = Keys::initial(Version::V1, &CONNECTION_ID, true); - assert_eq!( - client_keys - .local - .packet - .confidentiality_limit(), - 2u64.pow(23) - ); - assert_eq!( - client_keys - .local - .packet - .integrity_limit(), - 2u64.pow(52) - ); - assert_eq!(client_keys.local.packet.tag_len(), 16); - - let mut buf = Vec::new(); - buf.extend(PLAIN_HEADER); - buf.extend(PAYLOAD); - let header_len = PLAIN_HEADER.len(); - let tag_len = client_keys.local.packet.tag_len(); - let padding_len = 1200 - header_len - PAYLOAD.len() - tag_len; - buf.extend(std::iter::repeat(0).take(padding_len)); - let (header, payload) = buf.split_at_mut(header_len); - let tag = client_keys - .local - .packet - .encrypt_in_place(PACKET_NUMBER, &*header, payload) - .unwrap(); - - let sample_len = client_keys.local.header.sample_len(); - let sample = &payload[..sample_len]; - let (first, rest) = header.split_at_mut(1); - client_keys - .local - .header - .encrypt_in_place(sample, &mut first[0], &mut rest[17..21]) - .unwrap(); - buf.extend_from_slice(tag.as_ref()); - - const PROTECTED: &[u8] = &[ - 0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, - 0x00, 0x00, 0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68, - 0x9f, 0xb8, 0xec, 0x11, 0xd2, 0x42, 0xb1, 0x23, 0xdc, 0x9b, 0xd8, 0xba, 0xb9, 0x36, - 0xb4, 0x7d, 0x92, 0xec, 0x35, 0x6c, 0x0b, 0xab, 0x7d, 0xf5, 0x97, 0x6d, 0x27, 0xcd, - 0x44, 0x9f, 0x63, 0x30, 0x00, 0x99, 0xf3, 0x99, 0x1c, 0x26, 0x0e, 0xc4, 0xc6, 0x0d, - 0x17, 0xb3, 0x1f, 0x84, 0x29, 0x15, 0x7b, 0xb3, 0x5a, 0x12, 0x82, 0xa6, 0x43, 0xa8, - 0xd2, 0x26, 0x2c, 0xad, 0x67, 0x50, 0x0c, 0xad, 0xb8, 0xe7, 0x37, 0x8c, 0x8e, 0xb7, - 0x53, 0x9e, 0xc4, 0xd4, 0x90, 0x5f, 0xed, 0x1b, 0xee, 0x1f, 0xc8, 0xaa, 0xfb, 0xa1, - 0x7c, 0x75, 0x0e, 0x2c, 0x7a, 0xce, 0x01, 0xe6, 0x00, 0x5f, 0x80, 0xfc, 0xb7, 0xdf, - 0x62, 0x12, 0x30, 0xc8, 0x37, 0x11, 0xb3, 0x93, 0x43, 0xfa, 0x02, 0x8c, 0xea, 0x7f, - 0x7f, 0xb5, 0xff, 0x89, 0xea, 0xc2, 0x30, 0x82, 0x49, 0xa0, 0x22, 0x52, 0x15, 0x5e, - 0x23, 0x47, 0xb6, 0x3d, 0x58, 0xc5, 0x45, 0x7a, 0xfd, 0x84, 0xd0, 0x5d, 0xff, 0xfd, - 0xb2, 0x03, 0x92, 0x84, 0x4a, 0xe8, 0x12, 0x15, 0x46, 0x82, 0xe9, 0xcf, 0x01, 0x2f, - 0x90, 0x21, 0xa6, 0xf0, 0xbe, 0x17, 0xdd, 0xd0, 0xc2, 0x08, 0x4d, 0xce, 0x25, 0xff, - 0x9b, 0x06, 0xcd, 0xe5, 0x35, 0xd0, 0xf9, 0x20, 0xa2, 0xdb, 0x1b, 0xf3, 0x62, 0xc2, - 0x3e, 0x59, 0x6d, 0x11, 0xa4, 0xf5, 0xa6, 0xcf, 0x39, 0x48, 0x83, 0x8a, 0x3a, 0xec, - 0x4e, 0x15, 0xda, 0xf8, 0x50, 0x0a, 0x6e, 0xf6, 0x9e, 0xc4, 0xe3, 0xfe, 0xb6, 0xb1, - 0xd9, 0x8e, 0x61, 0x0a, 0xc8, 0xb7, 0xec, 0x3f, 0xaf, 0x6a, 0xd7, 0x60, 0xb7, 0xba, - 0xd1, 0xdb, 0x4b, 0xa3, 0x48, 0x5e, 0x8a, 0x94, 0xdc, 0x25, 0x0a, 0xe3, 0xfd, 0xb4, - 0x1e, 0xd1, 0x5f, 0xb6, 0xa8, 0xe5, 0xeb, 0xa0, 0xfc, 0x3d, 0xd6, 0x0b, 0xc8, 0xe3, - 0x0c, 0x5c, 0x42, 0x87, 0xe5, 0x38, 0x05, 0xdb, 0x05, 0x9a, 0xe0, 0x64, 0x8d, 0xb2, - 0xf6, 0x42, 0x64, 0xed, 0x5e, 0x39, 0xbe, 0x2e, 0x20, 0xd8, 0x2d, 0xf5, 0x66, 0xda, - 0x8d, 0xd5, 0x99, 0x8c, 0xca, 0xbd, 0xae, 0x05, 0x30, 0x60, 0xae, 0x6c, 0x7b, 0x43, - 0x78, 0xe8, 0x46, 0xd2, 0x9f, 0x37, 0xed, 0x7b, 0x4e, 0xa9, 0xec, 0x5d, 0x82, 0xe7, - 0x96, 0x1b, 0x7f, 0x25, 0xa9, 0x32, 0x38, 0x51, 0xf6, 0x81, 0xd5, 0x82, 0x36, 0x3a, - 0xa5, 0xf8, 0x99, 0x37, 0xf5, 0xa6, 0x72, 0x58, 0xbf, 0x63, 0xad, 0x6f, 0x1a, 0x0b, - 0x1d, 0x96, 0xdb, 0xd4, 0xfa, 0xdd, 0xfc, 0xef, 0xc5, 0x26, 0x6b, 0xa6, 0x61, 0x17, - 0x22, 0x39, 0x5c, 0x90, 0x65, 0x56, 0xbe, 0x52, 0xaf, 0xe3, 0xf5, 0x65, 0x63, 0x6a, - 0xd1, 0xb1, 0x7d, 0x50, 0x8b, 0x73, 0xd8, 0x74, 0x3e, 0xeb, 0x52, 0x4b, 0xe2, 0x2b, - 0x3d, 0xcb, 0xc2, 0xc7, 0x46, 0x8d, 0x54, 0x11, 0x9c, 0x74, 0x68, 0x44, 0x9a, 0x13, - 0xd8, 0xe3, 0xb9, 0x58, 0x11, 0xa1, 0x98, 0xf3, 0x49, 0x1d, 0xe3, 0xe7, 0xfe, 0x94, - 0x2b, 0x33, 0x04, 0x07, 0xab, 0xf8, 0x2a, 0x4e, 0xd7, 0xc1, 0xb3, 0x11, 0x66, 0x3a, - 0xc6, 0x98, 0x90, 0xf4, 0x15, 0x70, 0x15, 0x85, 0x3d, 0x91, 0xe9, 0x23, 0x03, 0x7c, - 0x22, 0x7a, 0x33, 0xcd, 0xd5, 0xec, 0x28, 0x1c, 0xa3, 0xf7, 0x9c, 0x44, 0x54, 0x6b, - 0x9d, 0x90, 0xca, 0x00, 0xf0, 0x64, 0xc9, 0x9e, 0x3d, 0xd9, 0x79, 0x11, 0xd3, 0x9f, - 0xe9, 0xc5, 0xd0, 0xb2, 0x3a, 0x22, 0x9a, 0x23, 0x4c, 0xb3, 0x61, 0x86, 0xc4, 0x81, - 0x9e, 0x8b, 0x9c, 0x59, 0x27, 0x72, 0x66, 0x32, 0x29, 0x1d, 0x6a, 0x41, 0x82, 0x11, - 0xcc, 0x29, 0x62, 0xe2, 0x0f, 0xe4, 0x7f, 0xeb, 0x3e, 0xdf, 0x33, 0x0f, 0x2c, 0x60, - 0x3a, 0x9d, 0x48, 0xc0, 0xfc, 0xb5, 0x69, 0x9d, 0xbf, 0xe5, 0x89, 0x64, 0x25, 0xc5, - 0xba, 0xc4, 0xae, 0xe8, 0x2e, 0x57, 0xa8, 0x5a, 0xaf, 0x4e, 0x25, 0x13, 0xe4, 0xf0, - 0x57, 0x96, 0xb0, 0x7b, 0xa2, 0xee, 0x47, 0xd8, 0x05, 0x06, 0xf8, 0xd2, 0xc2, 0x5e, - 0x50, 0xfd, 0x14, 0xde, 0x71, 0xe6, 0xc4, 0x18, 0x55, 0x93, 0x02, 0xf9, 0x39, 0xb0, - 0xe1, 0xab, 0xd5, 0x76, 0xf2, 0x79, 0xc4, 0xb2, 0xe0, 0xfe, 0xb8, 0x5c, 0x1f, 0x28, - 0xff, 0x18, 0xf5, 0x88, 0x91, 0xff, 0xef, 0x13, 0x2e, 0xef, 0x2f, 0xa0, 0x93, 0x46, - 0xae, 0xe3, 0x3c, 0x28, 0xeb, 0x13, 0x0f, 0xf2, 0x8f, 0x5b, 0x76, 0x69, 0x53, 0x33, - 0x41, 0x13, 0x21, 0x19, 0x96, 0xd2, 0x00, 0x11, 0xa1, 0x98, 0xe3, 0xfc, 0x43, 0x3f, - 0x9f, 0x25, 0x41, 0x01, 0x0a, 0xe1, 0x7c, 0x1b, 0xf2, 0x02, 0x58, 0x0f, 0x60, 0x47, - 0x47, 0x2f, 0xb3, 0x68, 0x57, 0xfe, 0x84, 0x3b, 0x19, 0xf5, 0x98, 0x40, 0x09, 0xdd, - 0xc3, 0x24, 0x04, 0x4e, 0x84, 0x7a, 0x4f, 0x4a, 0x0a, 0xb3, 0x4f, 0x71, 0x95, 0x95, - 0xde, 0x37, 0x25, 0x2d, 0x62, 0x35, 0x36, 0x5e, 0x9b, 0x84, 0x39, 0x2b, 0x06, 0x10, - 0x85, 0x34, 0x9d, 0x73, 0x20, 0x3a, 0x4a, 0x13, 0xe9, 0x6f, 0x54, 0x32, 0xec, 0x0f, - 0xd4, 0xa1, 0xee, 0x65, 0xac, 0xcd, 0xd5, 0xe3, 0x90, 0x4d, 0xf5, 0x4c, 0x1d, 0xa5, - 0x10, 0xb0, 0xff, 0x20, 0xdc, 0xc0, 0xc7, 0x7f, 0xcb, 0x2c, 0x0e, 0x0e, 0xb6, 0x05, - 0xcb, 0x05, 0x04, 0xdb, 0x87, 0x63, 0x2c, 0xf3, 0xd8, 0xb4, 0xda, 0xe6, 0xe7, 0x05, - 0x76, 0x9d, 0x1d, 0xe3, 0x54, 0x27, 0x01, 0x23, 0xcb, 0x11, 0x45, 0x0e, 0xfc, 0x60, - 0xac, 0x47, 0x68, 0x3d, 0x7b, 0x8d, 0x0f, 0x81, 0x13, 0x65, 0x56, 0x5f, 0xd9, 0x8c, - 0x4c, 0x8e, 0xb9, 0x36, 0xbc, 0xab, 0x8d, 0x06, 0x9f, 0xc3, 0x3b, 0xd8, 0x01, 0xb0, - 0x3a, 0xde, 0xa2, 0xe1, 0xfb, 0xc5, 0xaa, 0x46, 0x3d, 0x08, 0xca, 0x19, 0x89, 0x6d, - 0x2b, 0xf5, 0x9a, 0x07, 0x1b, 0x85, 0x1e, 0x6c, 0x23, 0x90, 0x52, 0x17, 0x2f, 0x29, - 0x6b, 0xfb, 0x5e, 0x72, 0x40, 0x47, 0x90, 0xa2, 0x18, 0x10, 0x14, 0xf3, 0xb9, 0x4a, - 0x4e, 0x97, 0xd1, 0x17, 0xb4, 0x38, 0x13, 0x03, 0x68, 0xcc, 0x39, 0xdb, 0xb2, 0xd1, - 0x98, 0x06, 0x5a, 0xe3, 0x98, 0x65, 0x47, 0x92, 0x6c, 0xd2, 0x16, 0x2f, 0x40, 0xa2, - 0x9f, 0x0c, 0x3c, 0x87, 0x45, 0xc0, 0xf5, 0x0f, 0xba, 0x38, 0x52, 0xe5, 0x66, 0xd4, - 0x45, 0x75, 0xc2, 0x9d, 0x39, 0xa0, 0x3f, 0x0c, 0xda, 0x72, 0x19, 0x84, 0xb6, 0xf4, - 0x40, 0x59, 0x1f, 0x35, 0x5e, 0x12, 0xd4, 0x39, 0xff, 0x15, 0x0a, 0xab, 0x76, 0x13, - 0x49, 0x9d, 0xbd, 0x49, 0xad, 0xab, 0xc8, 0x67, 0x6e, 0xef, 0x02, 0x3b, 0x15, 0xb6, - 0x5b, 0xfc, 0x5c, 0xa0, 0x69, 0x48, 0x10, 0x9f, 0x23, 0xf3, 0x50, 0xdb, 0x82, 0x12, - 0x35, 0x35, 0xeb, 0x8a, 0x74, 0x33, 0xbd, 0xab, 0xcb, 0x90, 0x92, 0x71, 0xa6, 0xec, - 0xbc, 0xb5, 0x8b, 0x93, 0x6a, 0x88, 0xcd, 0x4e, 0x8f, 0x2e, 0x6f, 0xf5, 0x80, 0x01, - 0x75, 0xf1, 0x13, 0x25, 0x3d, 0x8f, 0xa9, 0xca, 0x88, 0x85, 0xc2, 0xf5, 0x52, 0xe6, - 0x57, 0xdc, 0x60, 0x3f, 0x25, 0x2e, 0x1a, 0x8e, 0x30, 0x8f, 0x76, 0xf0, 0xbe, 0x79, - 0xe2, 0xfb, 0x8f, 0x5d, 0x5f, 0xbb, 0xe2, 0xe3, 0x0e, 0xca, 0xdd, 0x22, 0x07, 0x23, - 0xc8, 0xc0, 0xae, 0xa8, 0x07, 0x8c, 0xdf, 0xcb, 0x38, 0x68, 0x26, 0x3f, 0xf8, 0xf0, - 0x94, 0x00, 0x54, 0xda, 0x48, 0x78, 0x18, 0x93, 0xa7, 0xe4, 0x9a, 0xd5, 0xaf, 0xf4, - 0xaf, 0x30, 0x0c, 0xd8, 0x04, 0xa6, 0xb6, 0x27, 0x9a, 0xb3, 0xff, 0x3a, 0xfb, 0x64, - 0x49, 0x1c, 0x85, 0x19, 0x4a, 0xab, 0x76, 0x0d, 0x58, 0xa6, 0x06, 0x65, 0x4f, 0x9f, - 0x44, 0x00, 0xe8, 0xb3, 0x85, 0x91, 0x35, 0x6f, 0xbf, 0x64, 0x25, 0xac, 0xa2, 0x6d, - 0xc8, 0x52, 0x44, 0x25, 0x9f, 0xf2, 0xb1, 0x9c, 0x41, 0xb9, 0xf9, 0x6f, 0x3c, 0xa9, - 0xec, 0x1d, 0xde, 0x43, 0x4d, 0xa7, 0xd2, 0xd3, 0x92, 0xb9, 0x05, 0xdd, 0xf3, 0xd1, - 0xf9, 0xaf, 0x93, 0xd1, 0xaf, 0x59, 0x50, 0xbd, 0x49, 0x3f, 0x5a, 0xa7, 0x31, 0xb4, - 0x05, 0x6d, 0xf3, 0x1b, 0xd2, 0x67, 0xb6, 0xb9, 0x0a, 0x07, 0x98, 0x31, 0xaa, 0xf5, - 0x79, 0xbe, 0x0a, 0x39, 0x01, 0x31, 0x37, 0xaa, 0xc6, 0xd4, 0x04, 0xf5, 0x18, 0xcf, - 0xd4, 0x68, 0x40, 0x64, 0x7e, 0x78, 0xbf, 0xe7, 0x06, 0xca, 0x4c, 0xf5, 0xe9, 0xc5, - 0x45, 0x3e, 0x9f, 0x7c, 0xfd, 0x2b, 0x8b, 0x4c, 0x8d, 0x16, 0x9a, 0x44, 0xe5, 0x5c, - 0x88, 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0xe2, 0x21, 0xaf, 0x44, 0x86, 0x00, - 0x18, 0xab, 0x08, 0x56, 0x97, 0x2e, 0x19, 0x4c, 0xd9, 0x34, - ]; - - assert_eq!(&buf, PROTECTED); - - let (header, payload) = buf.split_at_mut(header_len); - let (first, rest) = header.split_at_mut(1); - let sample = &payload[..sample_len]; - - let server_keys = Keys::initial(Version::V1, &CONNECTION_ID, false); - server_keys - .remote - .header - .decrypt_in_place(sample, &mut first[0], &mut rest[17..21]) - .unwrap(); - let payload = server_keys - .remote - .packet - .decrypt_in_place(PACKET_NUMBER, &*header, payload) - .unwrap(); - - assert_eq!(&payload[..PAYLOAD.len()], PAYLOAD); - assert_eq!(payload.len(), buf.len() - header_len - tag_len); - } - - #[test] - fn test_quic_exporter() { - for &kt in ALL_KEY_TYPES.iter() { - let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); - let server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); - - do_exporter_test(client_config, server_config); - } - } -} // mod test_quic - -#[test] -fn test_client_does_not_offer_sha1() { - use rustls::internal::msgs::{ - codec::Reader, enums::HandshakeType, handshake::HandshakePayload, message::MessagePayload, - message::OpaqueMessage, - }; - - for kt in ALL_KEY_TYPES.iter() { - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let (mut client, _) = make_pair_for_configs(client_config, make_server_config(*kt)); - - assert!(client.wants_write()); - let mut buf = [0u8; 262144]; - let sz = client - .write_tls(&mut buf.as_mut()) - .unwrap(); - let msg = OpaqueMessage::read(&mut Reader::init(&buf[..sz])).unwrap(); - let msg = Message::try_from(msg.into_plain_message()).unwrap(); - assert!(msg.is_handshake_type(HandshakeType::ClientHello)); - - let client_hello = match msg.payload { - MessagePayload::Handshake { parsed, .. } => match parsed.payload { - HandshakePayload::ClientHello(ch) => ch, - _ => unreachable!(), - }, - _ => unreachable!(), - }; - - let sigalgs = client_hello - .get_sigalgs_extension() - .unwrap(); - assert!( - !sigalgs.contains(&SignatureScheme::RSA_PKCS1_SHA1), - "sha1 unexpectedly offered" - ); - } - } -} - -#[test] -fn test_client_config_keyshare() { - let client_config = - make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); - let server_config = - make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - do_handshake_until_error(&mut client, &mut server).unwrap(); -} - -#[test] -fn test_client_config_keyshare_mismatch() { - let client_config = - make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); - let server_config = - make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - assert!(do_handshake_until_error(&mut client, &mut server).is_err()); -} - -#[test] -fn test_client_sends_helloretryrequest() { - // client sends a secp384r1 key share - let mut client_config = make_client_config_with_kx_groups( - KeyType::Rsa, - &[&rustls::kx_group::SECP384R1, &rustls::kx_group::X25519], - ); - - let storage = Arc::new(ClientStorage::new()); - client_config.session_storage = storage.clone(); - - // but server only accepts x25519, so a HRR is required - let server_config = - make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); - - let (mut client, mut server) = make_pair_for_configs(client_config, server_config); - - // client sends hello - { - let mut pipe = OtherSession::new(&mut server); - let wrlen = client.write_tls(&mut pipe).unwrap(); - assert!(wrlen > 200); - assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0].len() == 1); - } - - // server sends HRR - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - assert!(wrlen < 100); // just the hello retry request - assert_eq!(pipe.writevs.len(), 1); // only one writev - assert!(pipe.writevs[0].len() == 2); // hello retry request and CCS - } - - // client sends fixed hello - { - let mut pipe = OtherSession::new(&mut server); - let wrlen = client.write_tls(&mut pipe).unwrap(); - assert!(wrlen > 200); // just the client hello retry - assert_eq!(pipe.writevs.len(), 1); // only one writev - assert!(pipe.writevs[0].len() == 2); // only a CCS & client hello retry - } - - // server completes handshake - { - let mut pipe = OtherSession::new(&mut client); - let wrlen = server.write_tls(&mut pipe).unwrap(); - assert!(wrlen > 200); - assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0].len() == 5); // server hello / encrypted exts / cert / cert-verify / finished - } - - do_handshake_until_error(&mut client, &mut server).unwrap(); - - // client only did two storage queries: one for a session, another for a kx type - assert_eq!(storage.gets(), 2); - assert_eq!(storage.puts(), 2); -} - -#[test] -fn test_client_attempts_to_use_unsupported_kx_group() { - // common to both client configs - let shared_storage = Arc::new(ClientStorage::new()); - - // first, client sends a x25519 and server agrees. x25519 is inserted - // into kx group cache. - let mut client_config_1 = - make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); - client_config_1.session_storage = shared_storage.clone(); - - // second, client only supports secp-384 and so kx group cache - // contains an unusable value. - let mut client_config_2 = - make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); - client_config_2.session_storage = shared_storage; - - let server_config = make_server_config(KeyType::Rsa); - - // first handshake - let (mut client_1, mut server) = make_pair_for_configs(client_config_1, server_config.clone()); - do_handshake_until_error(&mut client_1, &mut server).unwrap(); - - // second handshake - let (mut client_2, mut server) = make_pair_for_configs(client_config_2, server_config); - do_handshake_until_error(&mut client_2, &mut server).unwrap(); -} - -#[test] -fn test_client_mtu_reduction() { - struct CollectWrites { - writevs: Vec>, - } - - impl io::Write for CollectWrites { - fn write(&mut self, _: &[u8]) -> io::Result { - panic!() - } - fn flush(&mut self) -> io::Result<()> { - panic!() - } - fn write_vectored<'b>(&mut self, b: &[io::IoSlice<'b>]) -> io::Result { - let writes = b - .iter() - .map(|slice| slice.len()) - .collect::>(); - let len = writes.iter().sum(); - self.writevs.push(writes); - Ok(len) - } - } - - fn collect_write_lengths(client: &mut ClientConnection) -> Vec { - let mut collector = CollectWrites { writevs: vec![] }; - - client - .write_tls(&mut collector) - .unwrap(); - assert_eq!(collector.writevs.len(), 1); - collector.writevs[0].clone() - } - - for kt in ALL_KEY_TYPES.iter() { - let mut client_config = make_client_config(*kt); - client_config.max_fragment_size = Some(64); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); - let writes = collect_write_lengths(&mut client); - println!("writes at mtu=64: {:?}", writes); - assert!(writes.iter().all(|x| *x <= 64)); - assert!(writes.len() > 1); - } -} - -#[test] -fn test_server_mtu_reduction() { - let mut server_config = make_server_config(KeyType::Rsa); - server_config.max_fragment_size = Some(64); - server_config.send_half_rtt_data = true; - let (mut client, mut server) = - make_pair_for_configs(make_client_config(KeyType::Rsa), server_config); - - let big_data = [0u8; 2048]; - server - .writer() - .write_all(&big_data) - .unwrap(); - - let encryption_overhead = 20; // FIXME: see issue #991 - - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - server.write_tls(&mut pipe).unwrap(); - - assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0] - .iter() - .all(|x| *x <= 64 + encryption_overhead)); - } - - client.process_new_packets().unwrap(); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - { - let mut pipe = OtherSession::new(&mut client); - server.write_tls(&mut pipe).unwrap(); - assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0] - .iter() - .all(|x| *x <= 64 + encryption_overhead)); - } - - client.process_new_packets().unwrap(); - check_read(&mut client.reader(), &big_data); -} - -fn check_client_max_fragment_size(size: usize) -> Option { - let mut client_config = make_client_config(KeyType::Ed25519); - client_config.max_fragment_size = Some(size); - ClientConnection::new(Arc::new(client_config), dns_name("localhost")).err() -} - -#[test] -fn bad_client_max_fragment_sizes() { - assert_eq!( - check_client_max_fragment_size(31), - Some(Error::BadMaxFragmentSize) - ); - assert_eq!(check_client_max_fragment_size(32), None); - assert_eq!(check_client_max_fragment_size(64), None); - assert_eq!(check_client_max_fragment_size(1460), None); - assert_eq!(check_client_max_fragment_size(0x4000), None); - assert_eq!(check_client_max_fragment_size(0x4005), None); - assert_eq!( - check_client_max_fragment_size(0x4006), - Some(Error::BadMaxFragmentSize) - ); - assert_eq!( - check_client_max_fragment_size(0xffff), - Some(Error::BadMaxFragmentSize) - ); -} - -fn assert_lt(left: usize, right: usize) { - if left >= right { - panic!("expected {} < {}", left, right); - } -} - -#[test] -fn connection_types_are_not_huge() { - // Arbitrary sizes - assert_lt(mem::size_of::(), 1600); - assert_lt(mem::size_of::(), 1600); -} - -use rustls::internal::msgs::{ - handshake::ClientExtension, handshake::HandshakePayload, message::Message, - message::MessagePayload, -}; - -#[test] -fn test_server_rejects_duplicate_sni_names() { - fn duplicate_sni_payload(msg: &mut Message) -> Altered { - if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { - if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { - for mut ext in ch.extensions.iter_mut() { - if let ClientExtension::ServerName(snr) = &mut ext { - snr.push(snr[0].clone()); - } - } - } - - *encoded = Payload::new(parsed.get_encoding()); - } - Altered::InPlace - } - - let (client, server) = make_pair(KeyType::Rsa); - let (mut client, mut server) = (client.into(), server.into()); - transfer_altered(&mut client, duplicate_sni_payload, &mut server); - assert_eq!( - server.process_new_packets(), - Err(Error::PeerMisbehavedError( - "ClientHello SNI contains duplicate name types".into() - )) - ); -} - -#[test] -fn test_server_rejects_empty_sni_extension() { - fn empty_sni_payload(msg: &mut Message) -> Altered { - if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { - if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { - for mut ext in ch.extensions.iter_mut() { - if let ClientExtension::ServerName(snr) = &mut ext { - snr.clear(); - } - } - } - - *encoded = Payload::new(parsed.get_encoding()); - } - - Altered::InPlace - } - - let (client, server) = make_pair(KeyType::Rsa); - let (mut client, mut server) = (client.into(), server.into()); - transfer_altered(&mut client, empty_sni_payload, &mut server); - assert_eq!( - server.process_new_packets(), - Err(Error::PeerMisbehavedError( - "ClientHello SNI did not contain a hostname".into() - )) - ); -} - -#[test] -fn test_server_rejects_clients_without_any_kx_group_overlap() { - fn different_kx_group(msg: &mut Message) -> Altered { - if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { - if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { - for mut ext in ch.extensions.iter_mut() { - if let ClientExtension::NamedGroups(ngs) = &mut ext { - ngs.clear(); - } - if let ClientExtension::KeyShare(ks) = &mut ext { - ks.clear(); - } - } - } - - *encoded = Payload::new(parsed.get_encoding()); - } - Altered::InPlace - } - - let (client, server) = make_pair(KeyType::Rsa); - let (mut client, mut server) = (client.into(), server.into()); - transfer_altered(&mut client, different_kx_group, &mut server); - assert_eq!( - server.process_new_packets(), - Err(Error::PeerIncompatibleError( - "no kx group overlap with client".into() - )) - ); -} - -#[test] -fn test_client_rejects_illegal_tls13_ccs() { - fn corrupt_ccs(msg: &mut Message) -> Altered { - if let MessagePayload::ChangeCipherSpec(_) = &mut msg.payload { - println!("seen CCS {:?}", msg); - return Altered::Raw(vec![0x14, 0x03, 0x03, 0x00, 0x02, 0x01, 0x02]); - } - Altered::InPlace - } - - let (mut client, mut server) = make_pair(KeyType::Rsa); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - - let (mut server, mut client) = (server.into(), client.into()); - - transfer_altered(&mut server, corrupt_ccs, &mut client); - assert_eq!( - client.process_new_packets(), - Err(Error::PeerMisbehavedError( - "illegal middlebox CCS received".into() - )) - ); -} - -/// https://github.com/rustls/rustls/issues/797 -#[cfg(feature = "tls12")] -#[test] -fn test_client_tls12_no_resume_after_server_downgrade() { - let mut client_config = common::make_client_config(KeyType::Ed25519); - let client_storage = Arc::new(ClientStorage::new()); - client_config.session_storage = client_storage.clone(); - let client_config = Arc::new(client_config); - - let server_config_1 = Arc::new(common::finish_server_config( - KeyType::Ed25519, - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(&[&rustls::version::TLS13]) - .unwrap(), - )); - - let mut server_config_2 = common::finish_server_config( - KeyType::Ed25519, - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(&[&rustls::version::TLS12]) - .unwrap(), - ); - server_config_2.session_storage = Arc::new(rustls::server::NoServerSessionStorage {}); - - dbg!("handshake 1"); - let mut client_1 = - ClientConnection::new(client_config.clone(), "localhost".try_into().unwrap()).unwrap(); - let mut server_1 = ServerConnection::new(server_config_1).unwrap(); - common::do_handshake(&mut client_1, &mut server_1); - assert_eq!(client_storage.puts(), 2); - - dbg!("handshake 2"); - let mut client_2 = - ClientConnection::new(client_config, "localhost".try_into().unwrap()).unwrap(); - let mut server_2 = ServerConnection::new(Arc::new(server_config_2)).unwrap(); - common::do_handshake(&mut client_2, &mut server_2); - assert_eq!(client_storage.puts(), 2); -} - -#[test] -fn test_acceptor() { - use rustls::server::Acceptor; - - let client_config = Arc::new(make_client_config(KeyType::Ed25519)); - let mut client = ClientConnection::new(client_config, dns_name("localhost")).unwrap(); - let mut buf = Vec::new(); - client.write_tls(&mut buf).unwrap(); - - let server_config = Arc::new(make_server_config(KeyType::Ed25519)); - let mut acceptor = Acceptor::default(); - acceptor - .read_tls(&mut buf.as_slice()) - .unwrap(); - let accepted = acceptor.accept().unwrap().unwrap(); - let ch = accepted.client_hello(); - assert_eq!(ch.server_name(), Some("localhost")); - - let server = accepted - .into_connection(server_config) - .unwrap(); - assert!(server.wants_write()); - - // Reusing an acceptor is not allowed - assert_eq!( - acceptor - .read_tls(&mut [0u8].as_ref()) - .err() - .unwrap() - .kind(), - io::ErrorKind::Other, - ); - assert_eq!( - acceptor.accept().err(), - Some(Error::General("Acceptor polled after completion".into())) - ); - - let mut acceptor = Acceptor::default(); - assert!(acceptor.accept().unwrap().is_none()); - acceptor - .read_tls(&mut &buf[..3]) - .unwrap(); // incomplete message - assert!(acceptor.accept().unwrap().is_none()); - acceptor - .read_tls(&mut [0x80, 0x00].as_ref()) - .unwrap(); // invalid message (len = 32k bytes) - assert!(acceptor.accept().is_err()); - - let mut acceptor = Acceptor::default(); - // Minimal valid 1-byte application data message is not a handshake message - acceptor - .read_tls(&mut [0x17, 0x03, 0x03, 0x00, 0x01, 0x00].as_ref()) - .unwrap(); - assert!(acceptor.accept().is_err()); - - let mut acceptor = Acceptor::default(); - // Minimal 1-byte ClientHello message is not a legal handshake message - acceptor - .read_tls(&mut [0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00].as_ref()) - .unwrap(); - assert!(acceptor.accept().is_err()); -} - -#[derive(Default, Debug)] -struct LogCounts { - trace: usize, - debug: usize, - info: usize, - warn: usize, - error: usize, -} - -impl LogCounts { - fn new() -> Self { - Self { - ..Default::default() - } - } - - fn reset(&mut self) { - *self = Self::new(); - } - - fn add(&mut self, level: log::Level) { - match level { - log::Level::Trace => self.trace += 1, - log::Level::Debug => self.debug += 1, - log::Level::Info => self.info += 1, - log::Level::Warn => self.warn += 1, - log::Level::Error => self.error += 1, - } - } -} - -thread_local!(static COUNTS: RefCell = RefCell::new(LogCounts::new())); - -struct CountingLogger; - -static LOGGER: CountingLogger = CountingLogger; - -impl CountingLogger { - fn install() { - log::set_logger(&LOGGER).unwrap(); - log::set_max_level(log::LevelFilter::Trace); - } - - fn reset() { - COUNTS.with(|c| { - c.borrow_mut().reset(); - }); - } -} - -impl log::Log for CountingLogger { - fn enabled(&self, _metadata: &log::Metadata) -> bool { - true - } - - fn log(&self, record: &log::Record) { - println!("logging at {:?}: {:?}", record.level(), record.args()); - - COUNTS.with(|c| { - c.borrow_mut().add(record.level()); - }); - } - - fn flush(&self) {} -} - -#[test] -fn test_no_warning_logging_during_successful_sessions() { - CountingLogger::install(); - CountingLogger::reset(); - - for kt in ALL_KEY_TYPES.iter() { - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_configs(client_config, make_server_config(*kt)); - do_handshake(&mut client, &mut server); - } - } - - if cfg!(feature = "logging") { - COUNTS.with(|c| { - println!("After tests: {:?}", c.borrow()); - assert_eq!(c.borrow().warn, 0); - assert_eq!(c.borrow().error, 0); - assert_eq!(c.borrow().info, 0); - assert!(c.borrow().trace > 0); - assert!(c.borrow().debug > 0); - }); - } else { - COUNTS.with(|c| { - println!("After tests: {:?}", c.borrow()); - assert_eq!(c.borrow().warn, 0); - assert_eq!(c.borrow().error, 0); - assert_eq!(c.borrow().info, 0); - assert_eq!(c.borrow().trace, 0); - assert_eq!(c.borrow().debug, 0); - }); - } -} - -/// Test that secrets can be extracted and used for encryption/decryption. -#[cfg(feature = "secret_extraction")] -#[test] -fn test_secret_extraction_enabled() { - // Normally, secret extraction would be used to configure kTLS (TLS offload - // to the kernel). We want this test to run on any platform, though, so - // instead we just compare secrets for equality. - - // TLS 1.2 and 1.3 have different mechanisms for key exchange and handshake, - // and secrets are stored/extracted differently, so we want to test them both. - // We support 3 different AEAD algorithms (AES-128-GCM mode, AES-256-GCM, and - // Chacha20Poly1305), so that's 2*3 = 6 combinations to test. - let kt = KeyType::Rsa; - for suite in [ - rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, - rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, - rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - ] { - let version = suite.version(); - println!("Testing suite {:?}", suite.suite().as_str()); - - // Only offer the cipher suite (and protocol version) that we're testing - let mut server_config = ServerConfig::builder() - .with_cipher_suites(&[suite]) - .with_safe_default_kx_groups() - .with_protocol_versions(&[version]) - .unwrap() - .with_no_client_auth() - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap(); - // Opt into secret extraction from both sides - server_config.enable_secret_extraction = true; - let server_config = Arc::new(server_config); - - let mut client_config = make_client_config(kt); - client_config.enable_secret_extraction = true; - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - do_handshake(&mut client, &mut server); - - // The handshake is finished, we're now able to extract traffic secrets - let client_secrets = client.extract_secrets().unwrap(); - let server_secrets = server.extract_secrets().unwrap(); - - // Comparing secrets for equality is something you should never have to - // do in production code, so ConnectionTrafficSecrets doesn't implement - // PartialEq/Eq on purpose. Instead, we have to get creative. - fn explode_secrets(s: &ConnectionTrafficSecrets) -> (&[u8], &[u8], &[u8]) { - match s { - ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } => (key, salt, iv), - ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } => (key, salt, iv), - ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } => (key, &[], iv), - _ => panic!("unexpected secret type"), - } - } - - fn assert_secrets_equal( - (l_seq, l_sec): (u64, ConnectionTrafficSecrets), - (r_seq, r_sec): (u64, ConnectionTrafficSecrets), - ) { - assert_eq!(l_seq, r_seq); - assert_eq!(explode_secrets(&l_sec), explode_secrets(&r_sec)); - } - - assert_secrets_equal(client_secrets.tx, server_secrets.rx); - assert_secrets_equal(client_secrets.rx, server_secrets.tx); - } -} - -/// Test that secrets cannot be extracted unless explicitly enabled, and until -/// the handshake is done. -#[cfg(feature = "secret_extraction")] -#[test] -fn test_secret_extraction_disabled_or_too_early() { - let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; - let kt = KeyType::Rsa; - - for (server_enable, client_enable) in [(true, false), (false, true)] { - let mut server_config = ServerConfig::builder() - .with_cipher_suites(&[suite]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .unwrap() - .with_no_client_auth() - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap(); - server_config.enable_secret_extraction = server_enable; - let server_config = Arc::new(server_config); - - let mut client_config = make_client_config(kt); - client_config.enable_secret_extraction = client_enable; - - let client_config = Arc::new(client_config); - - let (client, server) = make_pair_for_arc_configs(&client_config, &server_config); - - assert!( - client.extract_secrets().is_err(), - "extraction should fail until handshake completes" - ); - assert!( - server.extract_secrets().is_err(), - "extraction should fail until handshake completes" - ); - - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - - do_handshake(&mut client, &mut server); - - assert_eq!(server_enable, server.extract_secrets().is_ok()); - assert_eq!(client_enable, client.extract_secrets().is_ok()); - } -} - -#[test] -fn test_received_plaintext_backpressure() { - let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; - let kt = KeyType::Rsa; - - let server_config = Arc::new( - ServerConfig::builder() - .with_cipher_suites(&[suite]) - .with_safe_default_kx_groups() - .with_safe_default_protocol_versions() - .unwrap() - .with_no_client_auth() - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap(), - ); - - let client_config = Arc::new(make_client_config(kt)); - let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); - do_handshake(&mut client, &mut server); - - // Fill the server's received plaintext buffer with 16k bytes - let client_buf = [0; 16_385]; - dbg!(client - .writer() - .write(&client_buf) - .unwrap()); - let mut network_buf = Vec::with_capacity(32_768); - let sent = dbg!(client - .write_tls(&mut network_buf) - .unwrap()); - assert_eq!( - sent, - dbg!(server - .read_tls(&mut &network_buf[..sent]) - .unwrap()) - ); - server.process_new_packets().unwrap(); - - // Send two more bytes from client to server - dbg!(client - .writer() - .write(&client_buf[..2]) - .unwrap()); - let sent = dbg!(client - .write_tls(&mut network_buf) - .unwrap()); - - // Get an error because the received plaintext buffer is full - assert!(server - .read_tls(&mut &network_buf[..sent]) - .is_err()); - - // Read out some of the plaintext - server - .reader() - .read_exact(&mut [0; 2]) - .unwrap(); - - // Now there's room again in the plaintext buffer - assert_eq!( - server - .read_tls(&mut &network_buf[..sent]) - .unwrap(), - 24 - ); -} diff --git a/third_party/rustls-fork-shadow-tls/tests/bogo.rs b/third_party/rustls-fork-shadow-tls/tests/bogo.rs deleted file mode 100644 index e96073d..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/bogo.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Runs the bogo test suite, in the form of a rust test. -// Note that bogo requires a golang environment to build -// and run. - -#[test] -#[cfg(all(coverage, feature = "quic", feature = "dangerous_configuration"))] -fn run_bogo_tests() { - use std::process::Command; - - let rc = Command::new("./runme") - .current_dir("../bogo") - .spawn() - .expect("cannot run bogo/runme") - .wait() - .expect("cannot wait for bogo"); - - assert!(rc.success(), "bogo exited non-zero"); -} diff --git a/third_party/rustls-fork-shadow-tls/tests/client_cert_verifier.rs b/third_party/rustls-fork-shadow-tls/tests/client_cert_verifier.rs deleted file mode 100644 index 5af9c2a..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/client_cert_verifier.rs +++ /dev/null @@ -1,324 +0,0 @@ -//! Tests for configuring and using a [`ClientCertVerifier`] for a server. - -#![cfg(feature = "dangerous_configuration")] - -mod common; - -use crate::common::{ - dns_name, do_handshake_until_both_error, do_handshake_until_error, get_client_root_store, - make_client_config_with_versions, make_client_config_with_versions_with_auth, - make_pair_for_arc_configs, ErrorFromPeer, KeyType, ALL_KEY_TYPES, -}; -use rustls::client::WebPkiVerifier; -use rustls::internal::msgs::base::PayloadU16; -use rustls::server::{ClientCertVerified, ClientCertVerifier}; -use rustls::AlertDescription; -use rustls::ContentType; -use rustls::{ - Certificate, ClientConnection, DistinguishedNames, Error, ServerConfig, ServerConnection, - SignatureScheme, -}; -use std::sync::Arc; - -// Client is authorized! -fn ver_ok() -> Result { - Ok(rustls::server::ClientCertVerified::assertion()) -} - -// Use when we shouldn't even attempt verification -fn ver_unreachable() -> Result { - unreachable!() -} - -// Verifier that returns an error that we can expect -fn ver_err() -> Result { - Err(Error::General("test err".to_string())) -} - -fn server_config_with_verifier( - kt: KeyType, - client_cert_verifier: MockClientVerifier, -) -> ServerConfig { - ServerConfig::builder() - .with_safe_defaults() - .with_client_cert_verifier(Arc::new(client_cert_verifier)) - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap() -} - -#[test] -// Happy path, we resolve to a root, it is verified OK, should be able to connect -fn client_verifier_works() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_ok, - subjects: Some( - get_client_root_store(*kt) - .roots - .iter() - .map(|r| PayloadU16(r.subject().to_vec())) - .collect(), - ), - mandatory: Some(true), - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); - let err = do_handshake_until_error(&mut client, &mut server); - assert_eq!(err, Ok(())); - } - } -} - -// Server offers no verification schemes -#[test] -fn client_verifier_no_schemes() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_ok, - subjects: Some( - get_client_root_store(*kt) - .roots - .iter() - .map(|r| PayloadU16(r.subject().to_vec())) - .collect(), - ), - mandatory: Some(true), - offered_schemes: Some(vec![]), - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); - let err = do_handshake_until_error(&mut client, &mut server); - assert_eq!( - err, - Err(ErrorFromPeer::Client(Error::CorruptMessagePayload( - ContentType::Handshake - ))) - ); - } - } -} - -// Common case, we do not find a root store to resolve to -#[test] -fn client_verifier_no_root() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_ok, - subjects: None, - mandatory: Some(true), - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("notlocalhost")).unwrap(); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Server(Error::General( - "client rejected by client_auth_root_subjects".into() - )), - ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::AccessDenied)) - ]) - ); - } - } -} - -// If we cannot resolve a root, we cannot decide if auth is mandatory -#[test] -fn client_verifier_no_auth_no_root() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_unreachable, - subjects: None, - mandatory: Some(true), - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("notlocalhost")).unwrap(); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Server(Error::General( - "client rejected by client_auth_root_subjects".into() - )), - ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::AccessDenied)) - ]) - ); - } - } -} - -// If we do have a root, we must do auth -#[test] -fn client_verifier_no_auth_yes_root() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_unreachable, - subjects: Some( - get_client_root_store(*kt) - .roots - .iter() - .map(|r| PayloadU16(r.subject().to_vec())) - .collect(), - ), - mandatory: Some(true), - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(*kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Server(Error::NoCertificatesPresented), - ErrorFromPeer::Client(Error::AlertReceived( - AlertDescription::CertificateRequired - )) - ]) - ); - } - } -} - -#[test] -// Triple checks we propagate the rustls::Error through -fn client_verifier_fails_properly() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_err, - subjects: Some( - get_client_root_store(*kt) - .roots - .iter() - .map(|r| PayloadU16(r.subject().to_vec())) - .collect(), - ), - mandatory: Some(true), - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); - let err = do_handshake_until_error(&mut client, &mut server); - assert_eq!( - err, - Err(ErrorFromPeer::Server(Error::General("test err".into()))) - ); - } - } -} - -#[test] -// If a verifier returns a None on Mandatory-ness, then we error out -fn client_verifier_must_determine_client_auth_requirement_to_continue() { - for kt in ALL_KEY_TYPES.iter() { - let client_verifier = MockClientVerifier { - verified: ver_ok, - subjects: Some( - get_client_root_store(*kt) - .roots - .iter() - .map(|r| PayloadU16(r.subject().to_vec())) - .collect(), - ), - mandatory: None, - offered_schemes: None, - }; - - let server_config = server_config_with_verifier(*kt, client_verifier); - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); - let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); - let mut client = - ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Server(Error::General( - "client rejected by client_auth_mandatory".into() - )), - ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::AccessDenied)) - ]) - ); - } - } -} - -pub struct MockClientVerifier { - pub verified: fn() -> Result, - pub subjects: Option, - pub mandatory: Option, - pub offered_schemes: Option>, -} - -impl ClientCertVerifier for MockClientVerifier { - fn client_auth_mandatory(&self) -> Option { - self.mandatory - } - - fn client_auth_root_subjects(&self) -> Option { - self.subjects.as_ref().cloned() - } - - fn verify_client_cert( - &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _now: std::time::SystemTime, - ) -> Result { - (self.verified)() - } - - fn supported_verify_schemes(&self) -> Vec { - if let Some(schemes) = &self.offered_schemes { - schemes.clone() - } else { - WebPkiVerifier::verification_schemes() - } - } -} diff --git a/third_party/rustls-fork-shadow-tls/tests/common/mod.rs b/third_party/rustls-fork-shadow-tls/tests/common/mod.rs deleted file mode 100644 index d176ed8..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/common/mod.rs +++ /dev/null @@ -1,474 +0,0 @@ -#![allow(dead_code)] - -use std::convert::{TryFrom, TryInto}; -use std::io; -use std::ops::{Deref, DerefMut}; -use std::sync::Arc; - -use rustls::internal::msgs::codec::Reader; -use rustls::internal::msgs::message::{Message, OpaqueMessage, PlainMessage}; -use rustls::server::AllowAnyAuthenticatedClient; -use rustls::Connection; -use rustls::Error; -use rustls::RootCertStore; -use rustls::{Certificate, PrivateKey}; -use rustls::{ClientConfig, ClientConnection}; -use rustls::{ConnectionCommon, ServerConfig, ServerConnection, SideData}; - -macro_rules! embed_files { - ( - $( - ($name:ident, $keytype:expr, $path:expr); - )+ - ) => { - $( - const $name: &'static [u8] = include_bytes!( - concat!("../../../test-ca/", $keytype, "/", $path)); - )+ - - pub fn bytes_for(keytype: &str, path: &str) -> &'static [u8] { - match (keytype, path) { - $( - ($keytype, $path) => $name, - )+ - _ => panic!("unknown keytype {} with path {}", keytype, path), - } - } - } -} - -embed_files! { - (ECDSA_CA_CERT, "ecdsa", "ca.cert"); - (ECDSA_CA_DER, "ecdsa", "ca.der"); - (ECDSA_CA_KEY, "ecdsa", "ca.key"); - (ECDSA_CLIENT_CERT, "ecdsa", "client.cert"); - (ECDSA_CLIENT_CHAIN, "ecdsa", "client.chain"); - (ECDSA_CLIENT_FULLCHAIN, "ecdsa", "client.fullchain"); - (ECDSA_CLIENT_KEY, "ecdsa", "client.key"); - (ECDSA_CLIENT_REQ, "ecdsa", "client.req"); - (ECDSA_END_CERT, "ecdsa", "end.cert"); - (ECDSA_END_CHAIN, "ecdsa", "end.chain"); - (ECDSA_END_FULLCHAIN, "ecdsa", "end.fullchain"); - (ECDSA_END_KEY, "ecdsa", "end.key"); - (ECDSA_END_REQ, "ecdsa", "end.req"); - (ECDSA_INTER_CERT, "ecdsa", "inter.cert"); - (ECDSA_INTER_KEY, "ecdsa", "inter.key"); - (ECDSA_INTER_REQ, "ecdsa", "inter.req"); - (ECDSA_NISTP256_PEM, "ecdsa", "nistp256.pem"); - (ECDSA_NISTP384_PEM, "ecdsa", "nistp384.pem"); - - (EDDSA_CA_CERT, "eddsa", "ca.cert"); - (EDDSA_CA_DER, "eddsa", "ca.der"); - (EDDSA_CA_KEY, "eddsa", "ca.key"); - (EDDSA_CLIENT_CERT, "eddsa", "client.cert"); - (EDDSA_CLIENT_CHAIN, "eddsa", "client.chain"); - (EDDSA_CLIENT_FULLCHAIN, "eddsa", "client.fullchain"); - (EDDSA_CLIENT_KEY, "eddsa", "client.key"); - (EDDSA_CLIENT_REQ, "eddsa", "client.req"); - (EDDSA_END_CERT, "eddsa", "end.cert"); - (EDDSA_END_CHAIN, "eddsa", "end.chain"); - (EDDSA_END_FULLCHAIN, "eddsa", "end.fullchain"); - (EDDSA_END_KEY, "eddsa", "end.key"); - (EDDSA_END_REQ, "eddsa", "end.req"); - (EDDSA_INTER_CERT, "eddsa", "inter.cert"); - (EDDSA_INTER_KEY, "eddsa", "inter.key"); - (EDDSA_INTER_REQ, "eddsa", "inter.req"); - - (RSA_CA_CERT, "rsa", "ca.cert"); - (RSA_CA_DER, "rsa", "ca.der"); - (RSA_CA_KEY, "rsa", "ca.key"); - (RSA_CLIENT_CERT, "rsa", "client.cert"); - (RSA_CLIENT_CHAIN, "rsa", "client.chain"); - (RSA_CLIENT_FULLCHAIN, "rsa", "client.fullchain"); - (RSA_CLIENT_KEY, "rsa", "client.key"); - (RSA_CLIENT_REQ, "rsa", "client.req"); - (RSA_CLIENT_RSA, "rsa", "client.rsa"); - (RSA_END_CERT, "rsa", "end.cert"); - (RSA_END_CHAIN, "rsa", "end.chain"); - (RSA_END_FULLCHAIN, "rsa", "end.fullchain"); - (RSA_END_KEY, "rsa", "end.key"); - (RSA_END_REQ, "rsa", "end.req"); - (RSA_END_RSA, "rsa", "end.rsa"); - (RSA_INTER_CERT, "rsa", "inter.cert"); - (RSA_INTER_KEY, "rsa", "inter.key"); - (RSA_INTER_REQ, "rsa", "inter.req"); -} - -pub fn transfer( - left: &mut (impl DerefMut + Deref>), - right: &mut (impl DerefMut + Deref>), -) -> usize { - let mut buf = [0u8; 262144]; - let mut total = 0; - - while left.wants_write() { - let sz = { - let into_buf: &mut dyn io::Write = &mut &mut buf[..]; - left.write_tls(into_buf).unwrap() - }; - total += sz; - if sz == 0 { - return total; - } - - let mut offs = 0; - loop { - let from_buf: &mut dyn io::Read = &mut &buf[offs..sz]; - offs += right.read_tls(from_buf).unwrap(); - if sz == offs { - break; - } - } - } - - total -} - -pub fn transfer_eof(conn: &mut (impl DerefMut + Deref>)) { - let empty_buf = [0u8; 0]; - let empty_cursor: &mut dyn io::Read = &mut &empty_buf[..]; - let sz = conn.read_tls(empty_cursor).unwrap(); - assert_eq!(sz, 0); -} - -pub enum Altered { - /// message has been edited in-place (or is unchanged) - InPlace, - /// send these raw bytes instead of the message. - Raw(Vec), -} - -pub fn transfer_altered(left: &mut Connection, filter: F, right: &mut Connection) -> usize -where - F: Fn(&mut Message) -> Altered, -{ - let mut buf = [0u8; 262144]; - let mut total = 0; - - while left.wants_write() { - let sz = { - let into_buf: &mut dyn io::Write = &mut &mut buf[..]; - left.write_tls(into_buf).unwrap() - }; - total += sz; - if sz == 0 { - return total; - } - - let mut reader = Reader::init(&buf[..sz]); - while reader.any_left() { - let message = OpaqueMessage::read(&mut reader).unwrap(); - let mut message = Message::try_from(message.into_plain_message()).unwrap(); - let message_enc = match filter(&mut message) { - Altered::InPlace => PlainMessage::from(message) - .into_unencrypted_opaque() - .encode(), - Altered::Raw(data) => data, - }; - - let message_enc_reader: &mut dyn io::Read = &mut &message_enc[..]; - let len = right - .read_tls(message_enc_reader) - .unwrap(); - assert_eq!(len, message_enc.len()); - } - } - - total -} - -#[derive(Clone, Copy, PartialEq)] -pub enum KeyType { - Rsa, - Ecdsa, - Ed25519, -} - -pub static ALL_KEY_TYPES: [KeyType; 3] = [KeyType::Rsa, KeyType::Ecdsa, KeyType::Ed25519]; - -impl KeyType { - fn bytes_for(&self, part: &str) -> &'static [u8] { - match self { - KeyType::Rsa => bytes_for("rsa", part), - KeyType::Ecdsa => bytes_for("ecdsa", part), - KeyType::Ed25519 => bytes_for("eddsa", part), - } - } - - pub fn get_chain(&self) -> Vec { - rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("end.fullchain"))) - .unwrap() - .iter() - .map(|v| Certificate(v.clone())) - .collect() - } - - pub fn get_key(&self) -> PrivateKey { - PrivateKey( - rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new(self.bytes_for("end.key"))) - .unwrap()[0] - .clone(), - ) - } - - pub fn get_client_chain(&self) -> Vec { - rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("client.fullchain"))) - .unwrap() - .iter() - .map(|v| Certificate(v.clone())) - .collect() - } - - fn get_client_key(&self) -> PrivateKey { - PrivateKey( - rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( - self.bytes_for("client.key"), - )) - .unwrap()[0] - .clone(), - ) - } -} - -pub fn finish_server_config( - kt: KeyType, - conf: rustls::ConfigBuilder, -) -> ServerConfig { - conf.with_no_client_auth() - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap() -} - -pub fn make_server_config(kt: KeyType) -> ServerConfig { - finish_server_config(kt, ServerConfig::builder().with_safe_defaults()) -} - -pub fn make_server_config_with_versions( - kt: KeyType, - versions: &[&'static rustls::SupportedProtocolVersion], -) -> ServerConfig { - finish_server_config( - kt, - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(versions) - .unwrap(), - ) -} - -pub fn make_server_config_with_kx_groups( - kt: KeyType, - kx_groups: &[&'static rustls::SupportedKxGroup], -) -> ServerConfig { - finish_server_config( - kt, - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(kx_groups) - .with_safe_default_protocol_versions() - .unwrap(), - ) -} - -pub fn get_client_root_store(kt: KeyType) -> RootCertStore { - let roots = kt.get_chain(); - let mut client_auth_roots = RootCertStore::empty(); - for root in roots { - client_auth_roots.add(&root).unwrap(); - } - client_auth_roots -} - -pub fn make_server_config_with_mandatory_client_auth(kt: KeyType) -> ServerConfig { - let client_auth_roots = get_client_root_store(kt); - - let client_auth = AllowAnyAuthenticatedClient::new(client_auth_roots); - - ServerConfig::builder() - .with_safe_defaults() - .with_client_cert_verifier(client_auth) - .with_single_cert(kt.get_chain(), kt.get_key()) - .unwrap() -} - -pub fn finish_client_config( - kt: KeyType, - config: rustls::ConfigBuilder, -) -> ClientConfig { - let mut root_store = RootCertStore::empty(); - let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); - root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); - - config - .with_root_certificates(root_store) - .with_no_client_auth() -} - -pub fn finish_client_config_with_creds( - kt: KeyType, - config: rustls::ConfigBuilder, -) -> ClientConfig { - let mut root_store = RootCertStore::empty(); - let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); - root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); - - config - .with_root_certificates(root_store) - .with_single_cert(kt.get_client_chain(), kt.get_client_key()) - .unwrap() -} - -pub fn make_client_config(kt: KeyType) -> ClientConfig { - finish_client_config(kt, ClientConfig::builder().with_safe_defaults()) -} - -pub fn make_client_config_with_kx_groups( - kt: KeyType, - kx_groups: &[&'static rustls::SupportedKxGroup], -) -> ClientConfig { - let builder = ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_kx_groups(kx_groups) - .with_safe_default_protocol_versions() - .unwrap(); - finish_client_config(kt, builder) -} - -pub fn make_client_config_with_versions( - kt: KeyType, - versions: &[&'static rustls::SupportedProtocolVersion], -) -> ClientConfig { - let builder = ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(versions) - .unwrap(); - finish_client_config(kt, builder) -} - -pub fn make_client_config_with_auth(kt: KeyType) -> ClientConfig { - finish_client_config_with_creds(kt, ClientConfig::builder().with_safe_defaults()) -} - -pub fn make_client_config_with_versions_with_auth( - kt: KeyType, - versions: &[&'static rustls::SupportedProtocolVersion], -) -> ClientConfig { - let builder = ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(versions) - .unwrap(); - finish_client_config_with_creds(kt, builder) -} - -pub fn make_pair(kt: KeyType) -> (ClientConnection, ServerConnection) { - make_pair_for_configs(make_client_config(kt), make_server_config(kt)) -} - -pub fn make_pair_for_configs( - client_config: ClientConfig, - server_config: ServerConfig, -) -> (ClientConnection, ServerConnection) { - make_pair_for_arc_configs(&Arc::new(client_config), &Arc::new(server_config)) -} - -pub fn make_pair_for_arc_configs( - client_config: &Arc, - server_config: &Arc, -) -> (ClientConnection, ServerConnection) { - ( - ClientConnection::new(Arc::clone(client_config), dns_name("localhost")).unwrap(), - ServerConnection::new(Arc::clone(server_config)).unwrap(), - ) -} - -pub fn do_handshake( - client: &mut (impl DerefMut + Deref>), - server: &mut (impl DerefMut + Deref>), -) -> (usize, usize) { - let (mut to_client, mut to_server) = (0, 0); - while server.is_handshaking() || client.is_handshaking() { - to_server += transfer(client, server); - server.process_new_packets().unwrap(); - to_client += transfer(server, client); - client.process_new_packets().unwrap(); - } - (to_server, to_client) -} - -#[derive(PartialEq, Debug)] -pub enum ErrorFromPeer { - Client(Error), - Server(Error), -} - -pub fn do_handshake_until_error( - client: &mut ClientConnection, - server: &mut ServerConnection, -) -> Result<(), ErrorFromPeer> { - while server.is_handshaking() || client.is_handshaking() { - transfer(client, server); - server - .process_new_packets() - .map_err(ErrorFromPeer::Server)?; - transfer(server, client); - client - .process_new_packets() - .map_err(ErrorFromPeer::Client)?; - } - - Ok(()) -} - -pub fn do_handshake_until_both_error( - client: &mut ClientConnection, - server: &mut ServerConnection, -) -> Result<(), Vec> { - match do_handshake_until_error(client, server) { - Err(server_err @ ErrorFromPeer::Server(_)) => { - let mut errors = vec![server_err]; - transfer(server, client); - let client_err = client - .process_new_packets() - .map_err(ErrorFromPeer::Client) - .expect_err("client didn't produce error after server error"); - errors.push(client_err); - Err(errors) - } - - Err(client_err @ ErrorFromPeer::Client(_)) => { - let mut errors = vec![client_err]; - transfer(client, server); - let server_err = server - .process_new_packets() - .map_err(ErrorFromPeer::Server) - .expect_err("server didn't produce error after client error"); - errors.push(server_err); - Err(errors) - } - - Ok(()) => Ok(()), - } -} - -pub fn dns_name(name: &'static str) -> rustls::ServerName { - name.try_into().unwrap() -} - -pub struct FailsReads { - errkind: io::ErrorKind, -} - -impl FailsReads { - pub fn new(errkind: io::ErrorKind) -> Self { - FailsReads { errkind } - } -} - -impl io::Read for FailsReads { - fn read(&mut self, _b: &mut [u8]) -> io::Result { - Err(io::Error::from(self.errkind)) - } -} diff --git a/third_party/rustls-fork-shadow-tls/tests/key_log_file_env.rs b/third_party/rustls-fork-shadow-tls/tests/key_log_file_env.rs deleted file mode 100644 index bc15f53..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/key_log_file_env.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Tests of [`rustls::KeyLogFile`] that require us to set environment variables. -//! -//! vvvv -//! Every test you add to this file MUST execute through `serialized()`. -//! ^^^^ -//! -//! See https://github.com/rust-lang/rust/issues/90308; despite not being marked -//! `unsafe`, `env::var::set_var` is an unsafe function. These tests are separated -//! from the rest of the tests so that their use of `set_ver` is less likely to -//! affect them; as of the time these tests were moved to this file, Cargo will -//! compile each test suite file to a separate executable, so these will be run -//! in a completely separate process. This way, executing every test through -//! `serialized()` will cause them to be run one at a time. -//! -//! Note: If/when we add new constructors to `KeyLogFile` to allow constructing -//! one from a path directly (without using an environment variable), then those -//! tests SHOULD NOT go in this file. -//! -//! XXX: These tests don't actually test the functionality; they just ensure -//! the code coverage doesn't complain it isn't covered. TODO: Verify that the -//! file was created successfully, with the right permissions, etc., and that it -//! contains something like what we expect. - -#[allow(dead_code)] -mod common; - -use crate::common::{ - do_handshake, make_client_config_with_versions, make_pair_for_arc_configs, make_server_config, - transfer, KeyType, -}; -use std::{ - env, - io::Write, - sync::{Arc, Mutex, Once}, -}; - -/// Approximates `#[serial]` from the `serial_test` crate. -/// -/// No attempt is made to recover from a poisoned mutex, which will -/// happen when `f` panics. In other words, all the tests that use -/// `serialized` will start failing after one test panics. -fn serialized(f: impl FnOnce()) { - // Ensure every test is run serialized - // TODO: Use `std::sync::Lazy` once that is stable. - static mut MUTEX: Option> = None; - static ONCE: Once = Once::new(); - ONCE.call_once(|| unsafe { - MUTEX = Some(Mutex::new(())); - }); - let mutex = unsafe { MUTEX.as_mut() }; - - let _guard = mutex.unwrap().lock().unwrap(); - - // XXX: NOT thread safe. - env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); - - f() -} - -#[test] -fn exercise_key_log_file_for_client() { - serialized(|| { - let server_config = Arc::new(make_server_config(KeyType::Rsa)); - env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - client_config.key_log = Arc::new(rustls::KeyLogFile::new()); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!(5, client.writer().write(b"hello").unwrap()); - - do_handshake(&mut client, &mut server); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - } - }) -} - -#[test] -fn exercise_key_log_file_for_server() { - serialized(|| { - let mut server_config = make_server_config(KeyType::Rsa); - - env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); - server_config.key_log = Arc::new(rustls::KeyLogFile::new()); - - let server_config = Arc::new(server_config); - - for version in rustls::ALL_VERSIONS { - let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - - assert_eq!(5, client.writer().write(b"hello").unwrap()); - - do_handshake(&mut client, &mut server); - transfer(&mut client, &mut server); - server.process_new_packets().unwrap(); - } - }) -} diff --git a/third_party/rustls-fork-shadow-tls/tests/server_cert_verifier.rs b/third_party/rustls-fork-shadow-tls/tests/server_cert_verifier.rs deleted file mode 100644 index 65d635c..0000000 --- a/third_party/rustls-fork-shadow-tls/tests/server_cert_verifier.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Tests for configuring and using a [`ServerCertVerifier`] for a client. - -#![cfg(feature = "dangerous_configuration")] - -mod common; -use crate::common::{ - do_handshake, do_handshake_until_both_error, make_client_config_with_versions, - make_pair_for_arc_configs, make_server_config, ErrorFromPeer, ALL_KEY_TYPES, -}; -use rustls::client::{ - HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, WebPkiVerifier, -}; -use rustls::internal::msgs::handshake::DigitallySignedStruct; -use rustls::AlertDescription; -use rustls::{Certificate, Error, SignatureScheme}; -use std::sync::Arc; - -#[test] -fn client_can_override_certificate_verification() { - for kt in ALL_KEY_TYPES.iter() { - let verifier = Arc::new(MockServerVerifier::accepts_anything()); - - let server_config = Arc::new(make_server_config(*kt)); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(*kt, &[version]); - client_config - .dangerous() - .set_certificate_verifier(verifier.clone()); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - do_handshake(&mut client, &mut server); - } - } -} - -#[test] -fn client_can_override_certificate_verification_and_reject_certificate() { - for kt in ALL_KEY_TYPES.iter() { - let verifier = Arc::new(MockServerVerifier::rejects_certificate( - Error::CorruptMessage, - )); - - let server_config = Arc::new(make_server_config(*kt)); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(*kt, &[version]); - client_config - .dangerous() - .set_certificate_verifier(verifier.clone()); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Client(Error::CorruptMessage), - ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::BadCertificate)) - ]) - ); - } - } -} - -#[cfg(feature = "tls12")] -#[test] -fn client_can_override_certificate_verification_and_reject_tls12_signatures() { - for kt in ALL_KEY_TYPES.iter() { - let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); - let verifier = Arc::new(MockServerVerifier::rejects_tls12_signatures( - Error::CorruptMessage, - )); - - client_config - .dangerous() - .set_certificate_verifier(verifier); - - let server_config = Arc::new(make_server_config(*kt)); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Client(Error::CorruptMessage), - ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::BadCertificate)) - ]) - ); - } -} - -#[test] -fn client_can_override_certificate_verification_and_reject_tls13_signatures() { - for kt in ALL_KEY_TYPES.iter() { - let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); - let verifier = Arc::new(MockServerVerifier::rejects_tls13_signatures( - Error::CorruptMessage, - )); - - client_config - .dangerous() - .set_certificate_verifier(verifier); - - let server_config = Arc::new(make_server_config(*kt)); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Client(Error::CorruptMessage), - ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::BadCertificate)) - ]) - ); - } -} - -#[test] -fn client_can_override_certificate_verification_and_offer_no_signature_schemes() { - for kt in ALL_KEY_TYPES.iter() { - let verifier = Arc::new(MockServerVerifier::offers_no_signature_schemes()); - - let server_config = Arc::new(make_server_config(*kt)); - - for version in rustls::ALL_VERSIONS { - let mut client_config = make_client_config_with_versions(*kt, &[version]); - client_config - .dangerous() - .set_certificate_verifier(verifier.clone()); - - let (mut client, mut server) = - make_pair_for_arc_configs(&Arc::new(client_config), &server_config); - let errs = do_handshake_until_both_error(&mut client, &mut server); - assert_eq!( - errs, - Err(vec![ - ErrorFromPeer::Server(Error::PeerIncompatibleError( - "no overlapping sigschemes".into() - )), - ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::HandshakeFailure)), - ]) - ); - } - } -} - -pub struct MockServerVerifier { - cert_rejection_error: Option, - tls12_signature_error: Option, - tls13_signature_error: Option, - wants_scts: bool, - signature_schemes: Vec, -} - -impl ServerCertVerifier for MockServerVerifier { - fn verify_server_cert( - &self, - end_entity: &rustls::Certificate, - intermediates: &[rustls::Certificate], - server_name: &rustls::ServerName, - scts: &mut dyn Iterator, - oscp_response: &[u8], - now: std::time::SystemTime, - ) -> Result { - let scts: Vec> = scts.map(|x| x.to_owned()).collect(); - println!( - "verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", - end_entity, intermediates, server_name, scts, oscp_response, now - ); - if let Some(error) = &self.cert_rejection_error { - Err(error.clone()) - } else { - Ok(ServerCertVerified::assertion()) - } - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - println!( - "verify_tls12_signature({:?}, {:?}, {:?})", - message, cert, dss - ); - if let Some(error) = &self.tls12_signature_error { - Err(error.clone()) - } else { - Ok(HandshakeSignatureValid::assertion()) - } - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &Certificate, - dss: &DigitallySignedStruct, - ) -> Result { - println!( - "verify_tls13_signature({:?}, {:?}, {:?})", - message, cert, dss - ); - if let Some(error) = &self.tls13_signature_error { - Err(error.clone()) - } else { - Ok(HandshakeSignatureValid::assertion()) - } - } - - fn supported_verify_schemes(&self) -> Vec { - self.signature_schemes.clone() - } - - fn request_scts(&self) -> bool { - println!("request_scts? {:?}", self.wants_scts); - self.wants_scts - } -} - -impl MockServerVerifier { - pub fn accepts_anything() -> Self { - MockServerVerifier { - cert_rejection_error: None, - ..Default::default() - } - } - - pub fn rejects_certificate(err: Error) -> Self { - MockServerVerifier { - cert_rejection_error: Some(err), - ..Default::default() - } - } - - pub fn rejects_tls12_signatures(err: Error) -> Self { - MockServerVerifier { - tls12_signature_error: Some(err), - ..Default::default() - } - } - - pub fn rejects_tls13_signatures(err: Error) -> Self { - MockServerVerifier { - tls13_signature_error: Some(err), - ..Default::default() - } - } - - pub fn offers_no_signature_schemes() -> Self { - MockServerVerifier { - signature_schemes: vec![], - ..Default::default() - } - } -} - -impl Default for MockServerVerifier { - fn default() -> Self { - MockServerVerifier { - cert_rejection_error: None, - tls12_signature_error: None, - tls13_signature_error: None, - wants_scts: false, - signature_schemes: WebPkiVerifier::verification_schemes(), - } - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/Cargo.lock b/third_party/tokio-rustls-fork-shadow-tls/Cargo.lock deleted file mode 100644 index fabac45..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/Cargo.lock +++ /dev/null @@ -1,523 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.45.0", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.45.0", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustls-fork-shadow-tls" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227b89ca93267855a168e5293f66c74d43afabcdf2239947d3b5904928388161" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.42.0", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-rustls-fork-shadow-tls" -version = "0.0.8" -dependencies = [ - "bytes", - "rustls-fork-shadow-tls", - "thiserror", - "tokio", - "webpki-roots", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml b/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml deleted file mode 100644 index b8fccbc..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "tokio-rustls-fork-shadow-tls" -version = "0.0.8" -authors = ["ChiHai "] -description = "Asynchronous TLS streams wrapper for Tokio based on Rustls." -homepage = "https://github.com/compdzwio/tokio-tls" -readme = "README.md" -categories = [ - "asynchronous", - "cryptography", - "network-programming", -] -license = "MIT/Apache-2.0" -repository = "https://github.com/compdzwio/tokio-tls" -resolver = "1" - -[dependencies.bytes] -version = "1" - -[dependencies.rustls-fork-shadow-tls] -version = "0.20.8" -default-features = false - -[dependencies.thiserror] -version = "1" - -[dependencies.tokio] -version = "1.25.0" -features = ["full"] - -[dev-dependencies.tokio] -version = "1.25.0" - -[dev-dependencies.webpki-roots] -version = "0.22" - -[features] -dangerous_configuration = ["rustls-fork-shadow-tls/dangerous_configuration"] -default = [ - "logging", - "tls12", -] -logging = ["rustls-fork-shadow-tls/logging"] -tls12 = ["rustls-fork-shadow-tls/tls12"] -unsafe_io = [] diff --git a/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml.orig b/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml.orig deleted file mode 100644 index 3d930e2..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/Cargo.toml.orig +++ /dev/null @@ -1,30 +0,0 @@ -[package] -authors = ["ChiHai "] -categories = ["asynchronous", "cryptography", "network-programming"] -description = "Asynchronous TLS streams wrapper for Tokio based on Rustls." -edition = "2021" -homepage = "https://github.com/compdzwio/tokio-tls" -license = "MIT/Apache-2.0" -name = "tokio-rustls-fork-shadow-tls" -readme = "README.md" -repository = "https://github.com/compdzwio/tokio-tls" -version = "0.0.8" - -[dependencies] -bytes = {version = "1"} -tokio = {version = "1.25.0", features = ["full"]} -rustls-fork-shadow-tls = {version = "0.20.8", default-features = false} -thiserror = {version = "1"} - -[features] -dangerous_configuration = ["rustls-fork-shadow-tls/dangerous_configuration"] -default = ["logging", "tls12"] -logging = ["rustls-fork-shadow-tls/logging"] -tls12 = ["rustls-fork-shadow-tls/tls12"] -# Once unsafe_io is enabled, you may not drop the future before it returns ready. -# It saves one buffer copy than disabled. -unsafe_io = [] - -[dev-dependencies] -tokio = {version = "1.25.0"} -webpki-roots = "0.22" diff --git a/third_party/tokio-rustls-fork-shadow-tls/README.md b/third_party/tokio-rustls-fork-shadow-tls/README.md deleted file mode 100644 index 20f67fd..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/README.md +++ /dev/null @@ -1 +0,0 @@ -# Tokio-rustls diff --git a/third_party/tokio-rustls-fork-shadow-tls/examples/connect.rs b/third_party/tokio-rustls-fork-shadow-tls/examples/connect.rs deleted file mode 100644 index 50e8711..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/examples/connect.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::sync::Arc; - -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::TcpStream, -}; - -use tokio_rustls_fork_shadow_tls::TlsConnector; -use rustls_fork_shadow_tls::{OwnedTrustAnchor, RootCertStore}; - -#[tokio::main] -async fn main() { - let mut root_store = RootCertStore::empty(); - root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { - OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ) - })); - let config = rustls_fork_shadow_tls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(root_store) - .with_no_client_auth(); - - let connector = TlsConnector::from(Arc::new(config)); - let stream = TcpStream::connect("rsproxy.cn:443").await.unwrap(); - println!("rsproxy.cn:443 connected"); - - let domain = rustls_fork_shadow_tls::ServerName::try_from("rsproxy.cn").unwrap(); - let mut stream = connector.connect(domain, stream).await.unwrap(); - println!("handshake success"); - - let content = b"GET / HTTP/1.0\r\nHost: rsproxy.cn\r\n\r\n"; - stream.write_all(content).await?; - println!("http request sent"); - - let buf = vec![0_u8; 64]; - let n = stream.read(buf).await?; - let resp = String::from_utf8(buf).unwrap(); - println!("http response recv: \n\n{resp}"); -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/client.rs b/third_party/tokio-rustls-fork-shadow-tls/src/client.rs deleted file mode 100644 index 1513090..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/client.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::sync::Arc; - -use tokio::io::{AsyncRead, AsyncWrite}; -use rustls_fork_shadow_tls::{ClientConfig, ClientConnection, ClientSessionIdGenerators}; - -use crate::{ - split::{ReadHalf, WriteHalf}, - stream::Stream, - TlsError, -}; - -/// A wrapper around an underlying raw stream which implements the TLS protocol. -pub type TlsStream = Stream; -/// TlsStream for read only. -pub type TlsStreamReadHalf = ReadHalf; -/// TlsStream for write only. -pub type TlsStreamWriteHalf = WriteHalf; - -/// A wrapper around a `rustls::ClientConfig`, providing an async `connect` method. -#[derive(Clone)] -pub struct TlsConnector { - inner: Arc, -} - -impl From> for TlsConnector { - fn from(inner: Arc) -> TlsConnector { - TlsConnector { inner } - } -} - -impl From for TlsConnector { - fn from(inner: ClientConfig) -> TlsConnector { - TlsConnector { - inner: Arc::new(inner), - } - } -} - -impl TlsConnector { - pub async fn connect( - &self, - domain: rustls_fork_shadow_tls::ServerName, - stream: IO, - ) -> Result, TlsError> - where - IO: AsyncRead + AsyncWrite + Unpin, - { - let session = ClientConnection::new(self.inner.clone(), domain)?; - let mut stream = Stream::new(stream, session); - stream.handshake().await?; - Ok(stream) - } - - pub async fn connect_with_session_id_generator( - &self, - domain: rustls_fork_shadow_tls::ServerName, - stream: IO, - generator: F, - ) -> Result, TlsError> - where - IO: AsyncRead + AsyncWrite + Unpin, - F: Fn(&[u8]) -> [u8; 32] + Send + Sync + 'static, - { - let session = - ClientConnection::new_with_session_id_generator(self.inner.clone(), domain, generator)?; - let mut stream = Stream::new(stream, session); - stream.handshake().await?; - Ok(stream) - } - - pub async fn connect_with_session_id_generators( - &self, - domain: rustls_fork_shadow_tls::ServerName, - stream: IO, - generators: ClientSessionIdGenerators, - ) -> Result, TlsError> - where - IO: AsyncRead + AsyncWrite + Unpin, - { - let session = - ClientConnection::new_with_session_id_generators(self.inner.clone(), domain, generators)?; - let mut stream = Stream::new(stream, session); - stream.handshake().await?; - Ok(stream) - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/error.rs b/third_party/tokio-rustls-fork-shadow-tls/src/error.rs deleted file mode 100644 index b34fad0..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/error.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::io; - -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum TlsError { - #[error("io error")] - Io(#[from] std::io::Error), - #[error("rustls error")] - Rustls(#[from] rustls_fork_shadow_tls::Error), -} - -impl From for io::Error { - fn from(e: TlsError) -> Self { - match e { - TlsError::Io(e) => e, - TlsError::Rustls(e) => io::Error::new(io::ErrorKind::Other, e), - } - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/lib.rs b/third_party/tokio-rustls-fork-shadow-tls/src/lib.rs deleted file mode 100644 index 2998b52..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(stable_features)] - -mod client; -mod error; -#[cfg(not(feature = "unsafe_io"))] -mod safe_io; -mod server; -mod split; -mod stream; -#[cfg(feature = "unsafe_io")] -mod unsafe_io; - -pub use client::{ - TlsConnector, TlsStream as ClientTlsStream, TlsStreamReadHalf as ClientTlsStreamReadHalf, - TlsStreamWriteHalf as ClientTlsStreamWriteHalf, -}; -pub use error::TlsError; -pub use server::{ - TlsAcceptor, TlsStream as ServerTlsStream, TlsStreamReadHalf as ServerTlsStreamReadHalf, - TlsStreamWriteHalf as ServerTlsStreamWriteHalf, -}; diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/safe_io.rs b/third_party/tokio-rustls-fork-shadow-tls/src/safe_io.rs deleted file mode 100644 index 2290d65..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/safe_io.rs +++ /dev/null @@ -1,227 +0,0 @@ -use std::{ - fmt::Debug, hint::unreachable_unchecked, io -}; - -use tokio::{ - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt} -}; - -const BUFFER_SIZE: usize = 16 * 1024; - -struct Buffer { - read: usize, - write: usize, - buf: Box<[u8]>, -} - -impl Buffer { - fn new() -> Self { - Self { - read: 0, - write: 0, - buf: vec![0; BUFFER_SIZE].into_boxed_slice(), - } - } - - fn len(&self) -> usize { - self.write - self.read - } - - fn is_empty(&self) -> bool { - self.len() == 0 - } - - fn available(&self) -> usize { - self.buf.len() - self.write - } - - fn is_full(&self) -> bool { - self.available() == 0 - } - - fn advance(&mut self, n: usize) { - assert!(self.write - self.read >= n); - self.read += n; - if self.read == self.write { - self.read = 0; - self.write = 0; - } - } -} - -pub(crate) struct SafeRead { - // the option is only meant for temporary take, it always should be some - buffer: Option, - status: ReadStatus, -} - -impl Debug for SafeRead { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("SafeRead") - .field("status", &self.status) - .finish() - } -} - -#[derive(Debug)] -enum ReadStatus { - Eof, - Err(io::Error), - Ok, -} - -impl Default for SafeRead { - fn default() -> Self { - Self { - buffer: Some(Buffer::new()), - status: ReadStatus::Ok, - } - } -} - -impl SafeRead { - pub(crate) async fn do_io(&mut self, mut io: IO) -> io::Result { - // if there are some data inside the buffer, just return. - let buffer = self.buffer.as_ref().expect("buffer ref expected"); - if !buffer.is_empty() { - return Ok(buffer.len()); - } - - // read from raw io - let buffer = self.buffer.as_mut().expect("buffer ownership expected"); - let buf = &mut buffer.buf.as_mut()[buffer.write..]; - let result = io.read(buf).await; - match result { - Ok(0) => { - self.status = ReadStatus::Eof; - result - } - Ok(n) => { - buffer.write += n; - self.status = ReadStatus::Ok; - result - } - Err(e) => { - let rerr = e.kind().into(); - self.status = ReadStatus::Err(e); - Err(rerr) - } - } - } -} - -impl io::Read for SafeRead { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // if buffer is empty, return WoundBlock. - let buffer = self.buffer.as_mut().expect("buffer mut expected"); - if buffer.is_empty() { - if !matches!(self.status, ReadStatus::Ok) { - match std::mem::replace(&mut self.status, ReadStatus::Ok) { - ReadStatus::Eof => return Ok(0), - ReadStatus::Err(e) => return Err(e), - ReadStatus::Ok => unsafe { unreachable_unchecked() }, - } - } - return Err(io::ErrorKind::WouldBlock.into()); - } - - // now buffer is not empty. copy it. - let to_copy = buffer.len().min(buf.len()); - unsafe { std::ptr::copy_nonoverlapping(buffer.buf.as_ptr().add(buffer.read), buf.as_mut_ptr(), to_copy) }; - buffer.advance(to_copy); - - Ok(to_copy) - } -} - -pub(crate) struct SafeWrite { - // the option is only meant for temporary take, it always should be some - buffer: Option, - status: WriteStatus, -} - -impl Debug for SafeWrite { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("SafeWrite") - .field("status", &self.status) - .finish() - } -} - -#[derive(Debug)] -enum WriteStatus { - Err(io::Error), - Ok, -} - -impl Default for SafeWrite { - fn default() -> Self { - Self { - buffer: Some(Buffer::new()), - status: WriteStatus::Ok, - } - } -} - -impl SafeWrite { - pub(crate) async fn do_io(&mut self, mut io: IO) -> io::Result { - // if the buffer is empty, just return. - let buffer = self.buffer.as_ref().expect("buffer ref expected"); - if buffer.is_empty() { - return Ok(0); - } - - // buffer is not empty now. write it. - let buffer = self.buffer.as_mut().expect("buffer ownership expected"); - let buf = &buffer.buf.as_ref()[buffer.read..buffer.write]; - let result = io.write_all(buf).await; - match result { - Ok(_) => { - let n = buffer.write - buffer.read; - buffer.advance(n); - Ok(n) - } - Err(e) => { - let rerr = e.kind().into(); - self.status = WriteStatus::Err(e); - Err(rerr) - } - } - } -} - -impl io::Write for SafeWrite { - fn write(&mut self, buf: &[u8]) -> io::Result { - // if there is too much data inside the buffer, return WoundBlock - let buffer = self.buffer.as_mut().expect("buffer mut expected"); - if !matches!(self.status, WriteStatus::Ok) { - match std::mem::replace(&mut self.status, WriteStatus::Ok) { - WriteStatus::Err(e) => return Err(e), - WriteStatus::Ok => unsafe { unreachable_unchecked() }, - } - } - if buffer.is_full() { - return Err(io::ErrorKind::WouldBlock.into()); - } - - // there is space inside the buffer, copy to it. - let to_copy = buf.len().min(buffer.available()); - unsafe { std::ptr::copy_nonoverlapping(buf.as_ptr(), buffer.buf.as_mut_ptr().add(buffer.write), to_copy); } - buffer.write += to_copy; - Ok(to_copy) - } - - fn flush(&mut self) -> io::Result<()> { - let buffer = self.buffer.as_mut().expect("buffer mut expected"); - if !matches!(self.status, WriteStatus::Ok) { - match std::mem::replace(&mut self.status, WriteStatus::Ok) { - WriteStatus::Err(e) => return Err(e), - WriteStatus::Ok => unsafe { unreachable_unchecked() }, - } - } - if !buffer.is_empty() { - return Err(io::ErrorKind::WouldBlock.into()); - } - Ok(()) - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/server.rs b/third_party/tokio-rustls-fork-shadow-tls/src/server.rs deleted file mode 100644 index b1db30f..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/server.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::sync::Arc; - -use tokio::io::{AsyncRead, AsyncWrite}; -use rustls_fork_shadow_tls::{ServerConfig, ServerConnection}; - -use crate::{ - split::{ReadHalf, WriteHalf}, - stream::Stream, - TlsError, -}; - -/// A wrapper around an underlying raw stream which implements the TLS protocol. -pub type TlsStream = Stream; -/// TlsStream for read only. -pub type TlsStreamReadHalf = ReadHalf; -/// TlsStream for write only. -pub type TlsStreamWriteHalf = WriteHalf; - -/// A wrapper around a `rustls::ServerConfig`, providing an async `accept` method. -#[derive(Clone)] -pub struct TlsAcceptor { - inner: Arc, -} - -impl From> for TlsAcceptor { - fn from(inner: Arc) -> TlsAcceptor { - TlsAcceptor { inner } - } -} - -impl From for TlsAcceptor { - fn from(inner: ServerConfig) -> TlsAcceptor { - TlsAcceptor { - inner: Arc::new(inner), - } - } -} - -impl TlsAcceptor { - pub async fn accept(&self, stream: IO) -> Result, TlsError> - where - IO: AsyncRead + AsyncWrite + Unpin, - { - let session = ServerConnection::new(self.inner.clone())?; - let mut stream = Stream::new(stream, session); - stream.handshake().await?; - Ok(stream) - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/split.rs b/third_party/tokio-rustls-fork-shadow-tls/src/split.rs deleted file mode 100644 index 188b59e..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/split.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! Split implement for TlsStream. -//! Note: Here we depends on the behavior of monoio TcpStream. -//! Though it is not a good assumption, it can really make it -//! more efficient with less code. The read and write will not -//! interfere each other. -use std::{ - cell::UnsafeCell, - future::Future, - io::IoSlice, - ops::{Deref, DerefMut}, - pin::Pin, - rc::Rc, - task::{Context, Poll}, -}; - -use tokio::{ - pin, - io::{AsyncRead, AsyncWrite, ReadBuf} -}; - -use rustls_fork_shadow_tls::{ConnectionCommon, SideData}; - -use crate::stream::Stream; - -#[derive(Debug)] -pub struct ReadHalf { - pub(crate) inner: Rc>>, -} - -#[derive(Debug)] -pub struct WriteHalf { - pub(crate) inner: Rc>>, -} - -impl AsyncRead - for ReadHalf -where - C: DerefMut + Deref>, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf<'_> - ) -> Poll> { - let inner = unsafe { &mut *self.inner.get() }; - let ex = inner.read_inner(buf, true); - pin!(ex); - ex.poll(cx) - } -} - -impl ReadHalf { - pub fn reunite(self, other: WriteHalf) -> Result, ReuniteError> { - reunite(self, other) - } -} - -impl AsyncWrite - for WriteHalf -where - C: DerefMut + Deref>, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8] - ) -> Poll> { - let inner = unsafe { &mut *self.inner.get() }; - Pin::new(inner).poll_write(cx, buf) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>] - ) -> Poll> { - let inner = unsafe { &mut *self.inner.get() }; - Pin::new(inner).poll_write_vectored(cx, bufs) - } - - fn poll_flush( - self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll> { - let inner = unsafe { &mut *self.inner.get() }; - Pin::new(inner).poll_flush(cx) - } - - fn poll_shutdown( - self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll> { - let inner = unsafe { &mut *self.inner.get() }; - Pin::new(inner).poll_shutdown(cx) - } - - fn is_write_vectored(&self) -> bool { - let inner = unsafe { &mut *self.inner.get() }; - Pin::new(inner).is_write_vectored() - } -} - -impl WriteHalf { - pub fn reunite(self, other: ReadHalf) -> Result, ReuniteError> { - reunite(other, self) - } -} - -pub(crate) fn reunite( - read: ReadHalf, - write: WriteHalf, -) -> Result, ReuniteError> { - if Rc::ptr_eq(&read.inner, &write.inner) { - drop(write); - // This unwrap cannot fail as the api does not allow creating more than two Rcs, - // and we just dropped the other half. - Ok(Rc::try_unwrap(read.inner) - .expect("TlsStream: try_unwrap failed in reunite") - .into_inner()) - } else { - Err(ReuniteError(read, write)) - } -} - -/// Error indicating that two halves were not from the same socket, and thus could -/// not be reunited. -#[derive(Debug)] -pub struct ReuniteError(pub ReadHalf, pub WriteHalf); - -impl std::fmt::Display for ReuniteError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "tried to reunite halves that are not from the same socket" - ) - } -} - -impl std::error::Error for ReuniteError {} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/stream.rs b/third_party/tokio-rustls-fork-shadow-tls/src/stream.rs deleted file mode 100644 index 5dd0f49..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/stream.rs +++ /dev/null @@ -1,297 +0,0 @@ -use std::{ - cell::UnsafeCell, - future::Future, - io::{IoSlice, Read, self, Write}, - ops::{Deref, DerefMut}, - pin::Pin, - rc::Rc, - task::{Context, Poll}, -}; - -use tokio::{ - pin, - io::{AsyncRead, AsyncWrite, ReadBuf} -}; - -use rustls_fork_shadow_tls::{ConnectionCommon, SideData}; - -use crate::split::{ReadHalf, WriteHalf}; - -#[derive(Debug)] -pub struct Stream { - pub(crate) io: IO, - pub(crate) session: C, - #[cfg(not(feature = "unsafe_io"))] - r_buffer: crate::safe_io::SafeRead, - #[cfg(not(feature = "unsafe_io"))] - w_buffer: crate::safe_io::SafeWrite, - #[cfg(feature = "unsafe_io")] - r_buffer: crate::unsafe_io::UnsafeRead, - #[cfg(feature = "unsafe_io")] - w_buffer: crate::unsafe_io::UnsafeWrite, -} - -impl Stream { - pub fn new(io: IO, session: C) -> Self { - Self { - io, - session, - r_buffer: Default::default(), - w_buffer: Default::default(), - } - } - - pub fn split(self) -> (ReadHalf, WriteHalf) { - let shared = Rc::new(UnsafeCell::new(self)); - ( - ReadHalf { - inner: shared.clone(), - }, - WriteHalf { inner: shared }, - ) - } - - pub fn into_parts(self) -> (IO, C) { - (self.io, self.session) - } -} - -impl Stream -where - C: DerefMut + Deref>, -{ - pub(crate) async fn read_io(&mut self, splitted: bool) -> io::Result { - let n = loop { - match self.session.read_tls(&mut self.r_buffer) { - Ok(n) => { - break n; - } - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => (), - Err(err) => return Err(err), - } - #[allow(unused_unsafe)] - unsafe { - self.r_buffer.do_io(&mut self.io).await? - }; - }; - - let state = match self.session.process_new_packets() { - Ok(state) => state, - Err(err) => { - // When to write_io? If we do this in read call, the UnsafeWrite may crash - // when we impl split in an UnsafeCell way. - // Here we choose not to do write when read. - // User should manually shutdown it on error. - if !splitted { - let _ = self.write_io().await; - } - return Err(io::Error::new(io::ErrorKind::InvalidData, err)); - } - }; - - if state.peer_has_closed() && self.session.is_handshaking() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "tls handshake alert", - )); - } - - Ok(n) - } - - pub(crate) async fn write_io(&mut self) -> io::Result { - let n = loop { - match self.session.write_tls(&mut self.w_buffer) { - Ok(n) => { - break n; - } - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => (), - Err(err) => return Err(err), - } - #[allow(unused_unsafe)] - unsafe { - self.w_buffer.do_io(&mut self.io).await? - }; - }; - // Flush buffered data, only needed for safe_io. - #[cfg(not(feature = "unsafe_io"))] - self.w_buffer.do_io(&mut self.io).await?; - - Ok(n) - } - - pub(crate) async fn handshake(&mut self) -> io::Result<(usize, usize)> { - let mut wrlen = 0; - let mut rdlen = 0; - let mut eof = false; - - loop { - while self.session.wants_write() && self.session.is_handshaking() { - wrlen += self.write_io().await?; - } - while !eof && self.session.wants_read() && self.session.is_handshaking() { - let n = self.read_io(false).await?; - rdlen += n; - if n == 0 { - eof = true; - } - } - - match (eof, self.session.is_handshaking()) { - (true, true) => { - let err = io::Error::new(io::ErrorKind::UnexpectedEof, "tls handshake eof"); - return Err(err); - } - (false, true) => (), - (_, false) => { - break; - } - } - } - - // flush buffer - while self.session.wants_write() { - wrlen += self.write_io().await?; - } - - Ok((rdlen, wrlen)) - } - - pub(crate) async fn read_inner( - &mut self, - buf: &mut ReadBuf<'_>, - splitted: bool, - ) -> std::io::Result<()> { - if buf.remaining() == 0 { - return Ok(()); - } - let slice = buf.initialize_unfilled(); - loop { - // read from rustls to buffer - match self.session.reader().read(slice) { - Ok(n) => { - buf.advance(n); - return Ok(()); - } - // we need more data, read something. - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => (), - Err(e) => { - return Err(e); - } - } - - // now we need data, read something into rustls - match self.read_io(splitted).await { - Ok(0) => { - return - Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "tls raw stream eof", - ), - ); - } - Ok(_) => (), - Err(e) => { - return Err(e); - } - } - } - } -} - -impl AsyncRead for Stream -where - C: DerefMut + Deref> + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf<'_> - ) -> Poll> { - let ex = self.read_inner(buf, false); - pin!(ex); - ex.poll(cx) - } -} - -impl AsyncWrite for Stream -where - C: DerefMut + Deref> + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8] - ) -> Poll> { - // write buf to rustls - let n = match self.session.writer().write(buf) { - Ok(n) => n, - Err(e) => return Poll::Ready(Err(e)), - }; - - // write from rustls to connection - while self.session.wants_write() { - let ex = self.write_io(); - pin!(ex); - match ex.poll(cx) { - Poll::Ready(Ok(0)) => { - break; - } - Poll::Ready(Ok(_)) => (), - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - } - } - Poll::Ready(Ok(n)) - } - - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>] - ) -> Poll> { - let buf = bufs - .iter() - .find(|b| !b.is_empty()) - .map_or(&[][..], |b| &**b); - self.poll_write(cx, buf) - } - - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll> { - self.session.writer().flush()?; - while self.session.wants_write() { - let ex = self.write_io(); - pin!(ex); - match ex.poll(cx) { - Poll::Ready(Ok(_)) => (), - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - } - } - Pin::new(&mut self.io).poll_flush(cx) - } - - fn poll_shutdown( - mut self: Pin<&mut Self>, - cx: &mut Context<'_> - ) -> Poll> { - self.session.send_close_notify(); - while self.session.wants_write() { - let ex = self.write_io(); - pin!(ex); - match ex.poll(cx) { - Poll::Ready(Ok(_)) => (), - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - } - } - Pin::new(&mut self.io).poll_shutdown(cx) - } - - fn is_write_vectored(&self) -> bool { - Pin::new(&self.io).is_write_vectored() - } -} diff --git a/third_party/tokio-rustls-fork-shadow-tls/src/unsafe_io.rs b/third_party/tokio-rustls-fork-shadow-tls/src/unsafe_io.rs deleted file mode 100644 index df34aa4..0000000 --- a/third_party/tokio-rustls-fork-shadow-tls/src/unsafe_io.rs +++ /dev/null @@ -1,124 +0,0 @@ -use std::{ - io, - slice::{from_raw_parts, from_raw_parts_mut} -}; - -use tokio::{ - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt} -}; - -/// Used by both UnsafeRead and UnsafeWrite. -#[derive(Debug)] -enum Status { - /// We haven't do real io, and maybe the dest is recorded. - WaitFill(Option<(*const u8, usize)>), - /// We have already do real io. The length maybe zero or non-zero. - Filled(usize), -} - -impl Default for Status { - fn default() -> Self { - Status::WaitFill(None) - } -} - -/// UnsafeRead is a wrapper of some meta data. -/// It implements std::io::Read trait. But it do real io in an async way. -/// On the first read, it may returns WouldBlock error, which means the -/// `fullfill` should be called to do real io. -/// The data is read directly into the dest that last std read passes. -/// Note that this action is an unsafe hack to avoid data copy. -/// You can only use this wrapper when you make sure the read dest is always -/// a valid buffer. -#[derive(Default, Debug)] -pub(crate) struct UnsafeRead { - status: Status, -} - -impl UnsafeRead { - /// `do_io` must be called after calling to io::Read::read. - pub(crate) async unsafe fn do_io( - &mut self, - mut io: IO, - ) -> io::Result { - match self.status { - Status::WaitFill(Some((ptr, len))) => { - let buf = unsafe { from_raw_parts_mut(ptr as *mut u8, len) }; - let n = io.read(buf).await?; - self.status = Status::Filled(n); - Ok(n) - } - Status::Filled(len) => Ok(len), - Status::WaitFill(None) => Err(io::ErrorKind::WouldBlock.into()), - } - } -} - -impl io::Read for UnsafeRead { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.status { - Status::WaitFill(_) => { - let ptr = buf.as_ptr(); - let len = buf.len(); - self.status = Status::WaitFill(Some((ptr, len))); - Err(io::ErrorKind::WouldBlock.into()) - } - Status::Filled(len) => { - if len != 0 { - // reset only when not eof - self.status = Status::WaitFill(None); - } - Ok(len) - } - } - } -} - -/// UnsafeWrite behaves like `UnsafeRead`. -#[derive(Default, Debug)] -pub(crate) struct UnsafeWrite { - status: Status, -} - -impl UnsafeWrite { - /// `do_io` must be called after calling to io::Write::write. - pub(crate) async unsafe fn do_io( - &mut self, - mut io: IO, - ) -> io::Result { - match self.status { - Status::WaitFill(Some((ptr, len))) => { - let buf = unsafe { from_raw_parts(ptr, len) }; - let n = io.write(buf).await?; - self.status = Status::Filled(n); - Ok(n) - } - Status::Filled(len) => Ok(len), - Status::WaitFill(None) => Err(io::ErrorKind::WouldBlock.into()), - } - } -} - -impl io::Write for UnsafeWrite { - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.status { - Status::WaitFill(_) => { - let ptr = buf.as_ptr(); - let len = buf.len(); - self.status = Status::WaitFill(Some((ptr, len))); - Err(io::ErrorKind::WouldBlock.into()) - } - Status::Filled(len) => { - if len != 0 { - // reset only when not eof - self.status = Status::WaitFill(None); - } - Ok(len) - } - } - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -}