diff --git a/Cargo.lock b/Cargo.lock index 246f904..368a09e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,6 +336,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + [[package]] name = "parking_lot" version = "0.12.2" @@ -539,14 +545,17 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" dependencies = [ "log", + "once_cell", "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] @@ -581,11 +590,12 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] @@ -595,16 +605,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", - "untrusted", -] - [[package]] name = "semver" version = "1.0.22" @@ -657,6 +657,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -917,3 +923,9 @@ checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index e509bd8..4d29b67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,11 @@ trace = [] [dependencies] tokio = { version = "1", features = [ "io-util", "net", "rt", "sync" ] } -rustls = "0.21" +rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12", "ring"] } futures = "0.3" socket2 = "0.5" -[dev_dependencies] +[dev-dependencies] tokio = { version = "1", features = [ "full" ] } rustls-pemfile = "2.0.0" ntest = "0.9" diff --git a/src/adapter.rs b/src/adapter.rs index 4662ec5..0bbe57b 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use crate::trace; +use rustls::server::AcceptedAlert; use rustls::server::Acceptor; use rustls::Connection; use std::io; @@ -107,3 +108,11 @@ pub fn read_acceptor( let mut read = ImplementReadTrait(tcp); acceptor.read_tls(&mut read) } + +pub fn write_acceptor_alert( + tcp: &TcpStream, + mut alert: AcceptedAlert, +) -> io::Result<()> { + let mut write = ImplementWriteTrait(tcp); + alert.write_all(&mut write) +} diff --git a/src/stream.rs b/src/stream.rs index 9ad5bf8..2db432b 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -4,6 +4,7 @@ use crate::adapter::clone_error; use crate::adapter::clone_result; use crate::adapter::read_acceptor; use crate::adapter::rustls_to_io_error; +use crate::adapter::write_acceptor_alert; use crate::connection_stream::ConnectionStream; use crate::handshake::handshake_task; use crate::handshake::HandshakeResult; @@ -178,42 +179,55 @@ impl TlsStream { server_config_provider: ServerConfigProvider, ) -> Result { let mut acceptor = Acceptor::default(); - let tls = loop { + loop { tcp_handshake.readable().await?; - read_acceptor(&tcp_handshake, &mut acceptor)?; - if let Some(accepted) = acceptor.accept().map_err(rustls_to_io_error)? { - let config = match server_config_provider(accepted.client_hello()).await - { - Ok(config) => config, - Err(err) => { - // This is a bad case. The provider was supposed to give us a config, but instead it failed. - // - // There's no easy way to reject an acceptor, and we only have an Arc for the stream so we can't close - // it. Instead we send a fatal alert manually which is effectively going to close the stream. - // - // Wireshark packet decode: - // TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Close Notify) - // Content Type: Alert (21) - // Version: TLS 1.2 (0x0303) - // Length: 2 - // Alert Message - // Level: Fatal (2) - // Description: Close Notify (0) - const FATAL_ALERT: &[u8] = b"\x15\x03\x03\x00\x02\x02\x00"; - for c in FATAL_ALERT { - tcp_handshake.writable().await?; - tcp_handshake.try_write(&[*c])?; - } - return Err(err); + read_acceptor(tcp_handshake, &mut acceptor)?; + + let accepted = match acceptor.accept() { + Ok(Some(accepted)) => accepted, + Ok(None) => continue, + Err((e, alert)) => { + tcp_handshake.writable().await?; + write_acceptor_alert(tcp_handshake, alert)?; + return Err(rustls_to_io_error(e)); + } + }; + + let config = match server_config_provider(accepted.client_hello()).await { + Ok(config) => config, + Err(err) => { + // This is a bad case. The provider was supposed to give us a config, but instead it failed. + // + // There's no easy way to reject an acceptor, and we only have an Arc for the stream so we can't close + // it. Instead we send a fatal alert manually which is effectively going to close the stream. + // + // Wireshark packet decode: + // TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Close Notify) + // Content Type: Alert (21) + // Version: TLS 1.2 (0x0303) + // Length: 2 + // Alert Message + // Level: Fatal (2) + // Description: Close Notify (0) + const FATAL_ALERT: &[u8] = b"\x15\x03\x03\x00\x02\x02\x00"; + for c in FATAL_ALERT { + tcp_handshake.writable().await?; + tcp_handshake.try_write(&[*c])?; } - }; - let tls = accepted - .into_connection(config) - .map_err(rustls_to_io_error)?; - break tls; + return Err(err); + } + }; + match accepted.into_connection(config) { + Ok(tls) => { + return Ok(tls); + } + Err((e, alert)) => { + tcp_handshake.writable().await?; + write_acceptor_alert(tcp_handshake, alert)?; + return Err(rustls_to_io_error(e)); + } } - }; - Ok(tls) + } } fn new_server_acceptor( @@ -2092,9 +2106,7 @@ pub(super) mod tests { #[rstest] #[case(true, 1024, 1024, 1024)] #[case(false, 1024, 1024, 1024)] - // Note that because we did the handshake first here, we lose a bit of buffer space due to - // TLS overhead on the first small write. - #[case(true, 1002, 16, 1024)] + #[case(true, 1024, 16, 1024)] #[case(false, 1024, 16, 1024)] #[case(true, 1024, 10000, 1)] #[case(false, 1024, 10000, 1)]