diff --git a/Cargo.lock b/Cargo.lock index 12fe956b35caf..2c400099e3be6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -956,9 +956,10 @@ dependencies = [ "lazy_static", "rustls", "rustls-native-certs", + "rustls-pemfile", "serde", - "webpki", - "webpki-roots", + "webpki 0.22.0", + "webpki-roots 0.22.1", ] [[package]] @@ -1791,17 +1792,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ - "futures-util", + "http", "hyper", - "log", "rustls", "tokio", "tokio-rustls", - "webpki", ] [[package]] @@ -1877,15 +1876,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" -[[package]] -name = "input_buffer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" -dependencies = [ - "bytes", -] - [[package]] name = "instant" version = "0.1.11" @@ -2961,9 +2951,9 @@ checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" [[package]] name = "reqwest" -version = "0.11.5" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c732d463dd300362ffb44b7b125f299c23d2990411a4253824630ebc7467fb" +checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" dependencies = [ "async-compression", "base64 0.13.0", @@ -2983,6 +2973,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", @@ -2993,7 +2984,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.21.1", "winreg 0.7.0", ] @@ -3100,29 +3091,37 @@ dependencies = [ [[package]] name = "rustls" -version = "0.19.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "base64 0.13.0", "log", "ring", "sct", - "webpki", + "webpki 0.22.0", ] [[package]] name = "rustls-native-certs" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" dependencies = [ "openssl-probe", - "rustls", + "rustls-pemfile", "schannel", "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64 0.13.0", +] + [[package]] name = "rustyline" version = "9.0.0" @@ -3195,9 +3194,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ "ring", "untrusted", @@ -4037,6 +4036,7 @@ dependencies = [ "os_pipe", "pty", "regex", + "rustls-pemfile", "serde", "serde_json", "tempfile", @@ -4149,13 +4149,13 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +checksum = "d49194a46b06a69f2498a34a595ab4a9c1babd2642ffa3dbccf6c6778d1426f2" dependencies = [ "rustls", "tokio", - "webpki", + "webpki 0.22.0", ] [[package]] @@ -4171,19 +4171,18 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e96bb520beab540ab664bd5a9cfeaa1fcd846fa68c830b42e2c8963071251d2" +checksum = "e057364a4dd37870b33bf8dc1885d29187d90770f488d599d3ee8d9e4916fbd3" dependencies = [ "futures-util", "log", - "pin-project", "rustls", "tokio", "tokio-rustls", "tungstenite", - "webpki", - "webpki-roots", + "webpki 0.22.0", + "webpki-roots 0.22.1", ] [[package]] @@ -4345,16 +4344,15 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "tungstenite" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8dada8c1a3aeca77d6b51a4f1314e0f4b8e438b7b1b71e3ddaca8080e4093" +checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" dependencies = [ "base64 0.13.0", "byteorder", "bytes", "http", "httparse", - "input_buffer", "log", "rand 0.8.4", "rustls", @@ -4362,8 +4360,7 @@ dependencies = [ "thiserror", "url", "utf-8", - "webpki", - "webpki-roots", + "webpki 0.22.0", ] [[package]] @@ -4693,13 +4690,32 @@ dependencies = [ "untrusted", ] +[[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.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "webpki-roots" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c475786c6f47219345717a043a37ec04cb4bc185e28853adcc4fa0a947eba630" +dependencies = [ + "webpki 0.22.0", ] [[package]] diff --git a/cli/proc_state.rs b/cli/proc_state.rs index be3213a62d0b1..220138e6f4cc5 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -38,9 +38,11 @@ use deno_graph::MediaType; use deno_graph::ModuleGraphError; use deno_graph::Range; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; +use deno_runtime::deno_tls::rustls; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::rustls_native_certs::load_native_certs; -use deno_runtime::deno_tls::webpki_roots::TLS_SERVER_ROOTS; +use deno_runtime::deno_tls::rustls_pemfile; +use deno_runtime::deno_tls::webpki_roots; use deno_runtime::deno_web::BlobStore; use deno_runtime::inspector_server::InspectorServer; use deno_runtime::permissions::Permissions; @@ -206,13 +208,24 @@ impl ProcState { for store in ca_stores.iter() { match store.as_str() { "mozilla" => { - root_cert_store.add_server_trust_anchors(&TLS_SERVER_ROOTS); + root_cert_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, + ) + }), + ); } "system" => { - let roots = load_native_certs() - .expect("could not load platform certs") - .roots; - root_cert_store.roots.extend(roots); + let roots = + load_native_certs().expect("could not load platform certs"); + for root in roots { + root_cert_store + .add(&rustls::Certificate(root.0)) + .expect("Failed to add platform cert to root cert store"); + } } _ => { return Err(anyhow!("Unknown certificate store \"{}\" specified (allowed: \"system,mozilla\")", store)); @@ -225,9 +238,16 @@ impl ProcState { let certfile = File::open(&ca_file)?; let mut reader = BufReader::new(certfile); - // This function does not return specific errors, if it fails give a generic message. - if let Err(_err) = root_cert_store.add_pem_file(&mut reader) { - return Err(anyhow!("Unable to add pem file to certificate store")); + match rustls_pemfile::certs(&mut reader) { + Ok(certs) => { + root_cert_store.add_parsable_certificates(&certs); + } + Err(e) => { + return Err(anyhow!( + "Unable to add pem file to certificate store: {}", + e + )); + } } } diff --git a/cli/standalone.rs b/cli/standalone.rs index 464ff2c2d2ef4..47b0e2aa8fb11 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -22,6 +22,7 @@ use deno_core::ModuleLoader; use deno_core::ModuleSpecifier; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_tls::create_default_root_cert_store; +use deno_runtime::deno_tls::rustls_pemfile; use deno_runtime::deno_web::BlobStore; use deno_runtime::permissions::Permissions; use deno_runtime::permissions::PermissionsOptions; @@ -221,9 +222,16 @@ pub async fn run( if let Some(cert) = metadata.ca_data { let reader = &mut BufReader::new(Cursor::new(cert)); - // This function does not return specific errors, if it fails give a generic message. - if let Err(_err) = root_cert_store.add_pem_file(reader) { - return Err(anyhow!("Unable to add pem file to certificate store")); + match rustls_pemfile::certs(reader) { + Ok(certs) => { + root_cert_store.add_parsable_certificates(&certs); + } + Err(e) => { + return Err(anyhow!( + "Unable to add pem file to certificate store: {}", + e + )); + } } } diff --git a/cli/tests/integration/mod.rs b/cli/tests/integration/mod.rs index cfb9509012f53..9cd1b2c11d748 100644 --- a/cli/tests/integration/mod.rs +++ b/cli/tests/integration/mod.rs @@ -5,7 +5,7 @@ use deno_core::url; use deno_runtime::deno_fetch::reqwest; use deno_runtime::deno_net::ops_tls::TlsStream; use deno_runtime::deno_tls::rustls; -use deno_runtime::deno_tls::webpki; +use deno_runtime::deno_tls::rustls_pemfile; use std::fs; use std::io::BufReader; use std::io::Cursor; @@ -1143,36 +1143,40 @@ async fn listen_tls_alpn() { .spawn() .unwrap(); let stdout = child.stdout.as_mut().unwrap(); - let mut buffer = [0; 5]; - let read = stdout.read(&mut buffer).unwrap(); + let mut msg = [0; 5]; + let read = stdout.read(&mut msg).unwrap(); assert_eq!(read, 5); - let msg = std::str::from_utf8(&buffer).unwrap(); - assert_eq!(msg, "READY"); + assert_eq!(&msg, b"READY"); - let mut cfg = rustls::ClientConfig::new(); - let reader = &mut BufReader::new(Cursor::new(include_bytes!( + let mut reader = &mut BufReader::new(Cursor::new(include_bytes!( "../testdata/tls/RootCA.crt" ))); - cfg.root_store.add_pem_file(reader).unwrap(); - cfg.alpn_protocols.push("foobar".as_bytes().to_vec()); + let certs = rustls_pemfile::certs(&mut reader).unwrap(); + let mut root_store = rustls::RootCertStore::empty(); + root_store.add_parsable_certificates(&certs); + let mut cfg = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); + cfg.alpn_protocols.push(b"foobar".to_vec()); let cfg = Arc::new(cfg); - let hostname = - webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap(); + let hostname = rustls::ServerName::try_from("localhost").unwrap(); let tcp_stream = tokio::net::TcpStream::connect("localhost:4504") .await .unwrap(); let mut tls_stream = - TlsStream::new_client_side(tcp_stream, &cfg, hostname); + TlsStream::new_client_side(tcp_stream, cfg, hostname); + tls_stream.handshake().await.unwrap(); - let (_, session) = tls_stream.get_ref(); - let alpn = session.get_alpn_protocol().unwrap(); - assert_eq!(std::str::from_utf8(alpn).unwrap(), "foobar"); + let (_, rustls_connection) = tls_stream.get_ref(); + let alpn = rustls_connection.alpn_protocol().unwrap(); + assert_eq!(alpn, b"foobar"); - child.kill().unwrap(); - child.wait().unwrap(); + let status = child.wait().unwrap(); + assert!(status.success()); }) .await; } @@ -1190,41 +1194,45 @@ async fn listen_tls_alpn_fail() { .arg("--quiet") .arg("--allow-net") .arg("--allow-read") - .arg("./listen_tls_alpn.ts") + .arg("./listen_tls_alpn_fail.ts") .arg("4505") .stdout(std::process::Stdio::piped()) .spawn() .unwrap(); let stdout = child.stdout.as_mut().unwrap(); - let mut buffer = [0; 5]; - let read = stdout.read(&mut buffer).unwrap(); + let mut msg = [0; 5]; + let read = stdout.read(&mut msg).unwrap(); assert_eq!(read, 5); - let msg = std::str::from_utf8(&buffer).unwrap(); - assert_eq!(msg, "READY"); + assert_eq!(&msg, b"READY"); - let mut cfg = rustls::ClientConfig::new(); - let reader = &mut BufReader::new(Cursor::new(include_bytes!( + let mut reader = &mut BufReader::new(Cursor::new(include_bytes!( "../testdata/tls/RootCA.crt" ))); - cfg.root_store.add_pem_file(reader).unwrap(); - cfg.alpn_protocols.push("boofar".as_bytes().to_vec()); + let certs = rustls_pemfile::certs(&mut reader).unwrap(); + let mut root_store = rustls::RootCertStore::empty(); + root_store.add_parsable_certificates(&certs); + let mut cfg = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); + cfg.alpn_protocols.push(b"boofar".to_vec()); let cfg = Arc::new(cfg); - let hostname = - webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap(); + let hostname = rustls::ServerName::try_from("localhost").unwrap(); let tcp_stream = tokio::net::TcpStream::connect("localhost:4505") .await .unwrap(); let mut tls_stream = - TlsStream::new_client_side(tcp_stream, &cfg, hostname); - tls_stream.handshake().await.unwrap(); - let (_, session) = tls_stream.get_ref(); + TlsStream::new_client_side(tcp_stream, cfg, hostname); - assert!(session.get_alpn_protocol().is_none()); + tls_stream.handshake().await.unwrap_err(); - child.kill().unwrap(); - child.wait().unwrap(); + let (_, rustls_connection) = tls_stream.get_ref(); + assert!(rustls_connection.alpn_protocol().is_none()); + + let status = child.wait().unwrap(); + assert!(status.success()); }) .await; } diff --git a/cli/tests/testdata/listen_tls_alpn.ts b/cli/tests/testdata/listen_tls_alpn.ts index 5d58065d99fc2..b3ade686ed22e 100644 --- a/cli/tests/testdata/listen_tls_alpn.ts +++ b/cli/tests/testdata/listen_tls_alpn.ts @@ -7,6 +7,8 @@ const listener = Deno.listenTls({ console.log("READY"); -for await (const conn of listener) { - conn.close(); -} +const conn = await listener.accept() as Deno.TlsConn; +await conn.handshake(); +conn.close(); + +listener.close(); diff --git a/cli/tests/testdata/listen_tls_alpn_fail.ts b/cli/tests/testdata/listen_tls_alpn_fail.ts new file mode 100644 index 0000000000000..04f9ec11f59fe --- /dev/null +++ b/cli/tests/testdata/listen_tls_alpn_fail.ts @@ -0,0 +1,20 @@ +import { assertRejects } from "../../../test_util/std/testing/asserts.ts"; + +const listener = Deno.listenTls({ + port: Number(Deno.args[0]), + certFile: "./tls/localhost.crt", + keyFile: "./tls/localhost.key", + alpnProtocols: ["h2", "http/1.1", "foobar"], +}); + +console.log("READY"); + +const conn = await listener.accept() as Deno.TlsConn; +await assertRejects( + () => conn.handshake(), + Deno.errors.InvalidData, + "peer doesn't support any known protocol", +); +conn.close(); + +listener.close(); diff --git a/cli/tests/testdata/localhost_unsafe_ssl.ts.out b/cli/tests/testdata/localhost_unsafe_ssl.ts.out index 66c19941753cb..0bfaeb25d1be0 100644 --- a/cli/tests/testdata/localhost_unsafe_ssl.ts.out +++ b/cli/tests/testdata/localhost_unsafe_ssl.ts.out @@ -1,3 +1,3 @@ DANGER: TLS certificate validation is disabled for: deno.land -error: error sending request for url (https://localhost:5545/subdir/mod2.ts): error trying to connect: invalid certificate: UnknownIssuer +error: error sending request for url (https://localhost:5545/subdir/mod2.ts): error trying to connect: invalid peer certificate contents: invalid peer certificate: UnknownIssuer at file:///[WILDCARD]/cafile_url_imports.ts:[WILDCARD] diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index 1f688b1eb43f1..64eee28ebe261 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -20,7 +20,7 @@ deno_core = { version = "0.110.0", path = "../../core" } deno_tls = { version = "0.15.0", path = "../tls" } dyn-clone = "1" http = "0.2.4" -reqwest = { version = "0.11.4", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] } +reqwest = { version = "0.11.7", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] } serde = { version = "1.0.129", features = ["derive"] } tokio = { version = "1.10.1", features = ["full"] } tokio-stream = "0.1.7" diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index 3de5d84766fcb..036aab5e628cf 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -44,13 +44,12 @@ use deno_tls::load_certs; use deno_tls::load_private_keys; use deno_tls::rustls::Certificate; use deno_tls::rustls::ClientConfig; -use deno_tls::rustls::ClientSession; -use deno_tls::rustls::NoClientAuth; +use deno_tls::rustls::ClientConnection; +use deno_tls::rustls::Connection; use deno_tls::rustls::PrivateKey; use deno_tls::rustls::ServerConfig; -use deno_tls::rustls::ServerSession; -use deno_tls::rustls::Session; -use deno_tls::webpki::DNSNameRef; +use deno_tls::rustls::ServerConnection; +use deno_tls::rustls::ServerName; use io::Error; use io::Read; use io::Write; @@ -58,12 +57,11 @@ use serde::Deserialize; use std::borrow::Cow; use std::cell::RefCell; use std::convert::From; +use std::convert::TryFrom; use std::fs::File; use std::io; use std::io::BufReader; use std::io::ErrorKind; -use std::ops::Deref; -use std::ops::DerefMut; use std::path::Path; use std::pin::Pin; use std::rc::Rc; @@ -78,44 +76,6 @@ use tokio::net::TcpListener; use tokio::net::TcpStream; use tokio::task::spawn_local; -#[derive(Debug)] -enum TlsSession { - Client(ClientSession), - Server(ServerSession), -} - -impl Deref for TlsSession { - type Target = dyn Session; - - fn deref(&self) -> &Self::Target { - match self { - TlsSession::Client(client_session) => client_session, - TlsSession::Server(server_session) => server_session, - } - } -} - -impl DerefMut for TlsSession { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - TlsSession::Client(client_session) => client_session, - TlsSession::Server(server_session) => server_session, - } - } -} - -impl From for TlsSession { - fn from(client_session: ClientSession) -> Self { - TlsSession::Client(client_session) - } -} - -impl From for TlsSession { - fn from(server_session: ServerSession) -> Self { - TlsSession::Server(server_session) - } -} - #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Flow { Handshake, @@ -129,15 +89,15 @@ enum State { StreamClosed, TlsClosing, TlsClosed, - TlsError, TcpClosed, } -#[derive(Debug)] pub struct TlsStream(Option); impl TlsStream { - fn new(tcp: TcpStream, tls: TlsSession) -> Self { + fn new(tcp: TcpStream, mut tls: Connection) -> Self { + tls.set_buffer_limit(None); + let inner = TlsStreamInner { tcp, tls, @@ -149,19 +109,19 @@ impl TlsStream { pub fn new_client_side( tcp: TcpStream, - tls_config: &Arc, - hostname: DNSNameRef, + tls_config: Arc, + server_name: ServerName, ) -> Self { - let tls = TlsSession::Client(ClientSession::new(tls_config, hostname)); - Self::new(tcp, tls) + let tls = ClientConnection::new(tls_config, server_name).unwrap(); + Self::new(tcp, Connection::Client(tls)) } pub fn new_server_side( tcp: TcpStream, - tls_config: &Arc, + tls_config: Arc, ) -> Self { - let tls = TlsSession::Server(ServerSession::new(tls_config)); - Self::new(tcp, tls) + let tls = ServerConnection::new(tls_config).unwrap(); + Self::new(tcp, Connection::Server(tls)) } fn into_split(self) -> (ReadHalf, WriteHalf) { @@ -174,10 +134,10 @@ impl TlsStream { } /// Tokio-rustls compatibility: returns a reference to the underlying TCP - /// stream, and a reference to the Rustls `Session` object. - pub fn get_ref(&self) -> (&TcpStream, &dyn Session) { + /// stream, and a reference to the Rustls `Connection` object. + pub fn get_ref(&self) -> (&TcpStream, &Connection) { let inner = self.0.as_ref().unwrap(); - (&inner.tcp, &*inner.tls) + (&inner.tcp, &inner.tls) } fn inner_mut(&mut self) -> &mut TlsStreamInner { @@ -196,7 +156,7 @@ impl TlsStream { self .inner_mut() .tls - .get_alpn_protocol() + .alpn_protocol() .map(|s| ByteString(s.to_owned())) } } @@ -251,9 +211,8 @@ impl Drop for TlsStream { } } -#[derive(Debug)] pub struct TlsStreamInner { - tls: TlsSession, + tls: Connection, tcp: TcpStream, rd_state: State, wr_state: State, @@ -275,7 +234,7 @@ impl TlsStreamInner { State::StreamOpen if !self.tls.wants_write() => break true, State::StreamClosed => { // Rustls will enqueue the 'CloseNotify' alert and send it after - // flusing the data that is already in the queue. + // flushing the data that is already in the queue. self.tls.send_close_notify(); self.wr_state = State::TlsClosing; continue; @@ -318,19 +277,30 @@ impl TlsStreamInner { }; let rd_ready = loop { + // Interpret and decrypt unprocessed TLS protocol data. + let tls_state = self + .tls + .process_new_packets() + .map_err(|e| Error::new(ErrorKind::InvalidData, e))?; + match self.rd_state { State::TcpClosed if self.tls.is_handshaking() => { let err = Error::new(ErrorKind::UnexpectedEof, "tls handshake eof"); return Poll::Ready(Err(err)); } - State::TlsError => {} _ if self.tls.is_handshaking() && !self.tls.wants_read() => { break true; } _ if self.tls.is_handshaking() => {} - State::StreamOpen if !self.tls.wants_read() => break true, + State::StreamOpen if tls_state.plaintext_bytes_to_read() > 0 => { + break true; + } + State::StreamOpen if tls_state.peer_has_closed() => { + self.rd_state = State::TlsClosed; + continue; + } State::StreamOpen => {} - State::StreamClosed if !self.tls.wants_read() => { + State::StreamClosed if tls_state.plaintext_bytes_to_read() > 0 => { // Rustls has more incoming cleartext buffered up, but the TLS // session is closing so this data will never be processed by the // application layer. Just like what would happen if this were a raw @@ -339,60 +309,30 @@ impl TlsStreamInner { } State::StreamClosed => {} State::TlsClosed if self.wr_state == State::TcpClosed => { - // Wait for the remote end to gracefully close the TCP connection. - // TODO(piscisaureus): this is unnecessary; remove when stable. - } - _ => break true, - } - - if self.rd_state < State::TlsClosed { - // Do a zero-length plaintext read so we can detect the arrival of - // 'CloseNotify' messages, even if only the write half is open. - // Actually reading data from the socket is done in `poll_read()`. - match self.tls.read(&mut []) { - Ok(0) => {} - Err(err) if err.kind() == ErrorKind::ConnectionAborted => { - // `Session::read()` returns `ConnectionAborted` when a - // 'CloseNotify' alert has been received, which indicates that - // the remote peer wants to gracefully end the TLS session. - self.rd_state = State::TlsClosed; - continue; - } - Err(err) => return Poll::Ready(Err(err)), - _ => unreachable!(), + // Keep trying to read from the TCP connection until the remote end + // closes it gracefully. } + State::TlsClosed => break true, + State::TcpClosed => break true, + _ => unreachable!(), } - if self.rd_state != State::TlsError { - // Receive ciphertext from the socket. - let mut wrapped_tcp = ImplementReadTrait(&mut self.tcp); - match self.tls.read_tls(&mut wrapped_tcp) { - Ok(0) => { - // End of TCP stream. - self.rd_state = State::TcpClosed; - continue; - } - Err(err) if err.kind() == ErrorKind::WouldBlock => { - // Get notified when more ciphertext becomes available in the - // socket receive buffer. - if self.tcp.poll_read_ready(cx)?.is_pending() { - break false; - } else { - continue; - } - } - Err(err) => return Poll::Ready(Err(err)), - _ => {} + // Try to read more TLS protocol data from the TCP socket. + let mut wrapped_tcp = ImplementReadTrait(&mut self.tcp); + match self.tls.read_tls(&mut wrapped_tcp) { + Ok(0) => { + self.rd_state = State::TcpClosed; + continue; } + Ok(_) => continue, + Err(err) if err.kind() == ErrorKind::WouldBlock => {} + Err(err) => return Poll::Ready(Err(err)), } - // Interpret and decrypt TLS protocol data. - match self.tls.process_new_packets() { - Ok(_) => assert!(self.rd_state < State::TcpClosed), - Err(err) => { - self.rd_state = State::TlsError; - return Poll::Ready(Err(Error::new(ErrorKind::InvalidData, err))); - } + // Get notified when more ciphertext becomes available to read from the + // TCP socket. + if self.tcp.poll_read_ready(cx)?.is_pending() { + break false; } }; @@ -438,7 +378,7 @@ impl TlsStreamInner { if self.rd_state == State::StreamOpen { let buf_slice = unsafe { &mut *(buf.unfilled_mut() as *mut [_] as *mut [u8]) }; - let bytes_read = self.tls.read(buf_slice)?; + let bytes_read = self.tls.reader().read(buf_slice)?; assert_ne!(bytes_read, 0); unsafe { buf.assume_init(bytes_read) }; buf.advance(bytes_read); @@ -460,7 +400,7 @@ impl TlsStreamInner { ready!(self.poll_io(cx, Flow::Write))?; // Copy data from `buf` to the Rustls cleartext send queue. - let bytes_written = self.tls.write(buf)?; + let bytes_written = self.tls.writer().write(buf)?; assert_ne!(bytes_written, 0); // Try to flush as much ciphertext as possible. However, since we just @@ -511,7 +451,6 @@ impl TlsStreamInner { } } -#[derive(Debug)] pub struct ReadHalf { shared: Arc, } @@ -542,7 +481,6 @@ impl AsyncRead for ReadHalf { } } -#[derive(Debug)] pub struct WriteHalf { shared: Arc, } @@ -596,7 +534,6 @@ impl AsyncWrite for WriteHalf { } } -#[derive(Debug)] struct Shared { tls_stream: Mutex, rd_waker: AtomicWaker, @@ -851,8 +788,8 @@ where .map(|s| s.into_bytes()) .collect::>(); - let hostname_dns = DNSNameRef::try_from_ascii_str(hostname) - .map_err(|_| invalid_hostname(hostname))?; + let hostname_dns = + ServerName::try_from(hostname).map_err(|_| invalid_hostname(hostname))?; let unsafely_ignore_certificate_errors = state .borrow() @@ -895,7 +832,7 @@ where let tls_config = Arc::new(tls_config); let tls_stream = - TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns); + TlsStream::new_client_side(tcp_stream, tls_config, hostname_dns); let rid = { let mut state_ = state.borrow_mut(); @@ -970,8 +907,8 @@ where .borrow::() .root_cert_store .clone(); - let hostname_dns = DNSNameRef::try_from_ascii_str(hostname) - .map_err(|_| invalid_hostname(hostname))?; + let hostname_dns = + ServerName::try_from(hostname).map_err(|_| invalid_hostname(hostname))?; let connect_addr = resolve_addr(hostname, port) .await? @@ -980,11 +917,25 @@ where let tcp_stream = TcpStream::connect(connect_addr).await?; let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; + + let cert_chain_and_key = + if args.cert_chain.is_some() || args.private_key.is_some() { + let cert_chain = args + .cert_chain + .ok_or_else(|| type_error("No certificate chain provided"))?; + let private_key = args + .private_key + .ok_or_else(|| type_error("No private key provided"))?; + Some((cert_chain, private_key)) + } else { + None + }; + let mut tls_config = create_client_config( root_cert_store, ca_certs, unsafely_ignore_certificate_errors, - None, + cert_chain_and_key, )?; if let Some(alpn_protocols) = args.alpn_protocols { @@ -993,27 +944,10 @@ where alpn_protocols.into_iter().map(|s| s.into_bytes()).collect(); } - if args.cert_chain.is_some() || args.private_key.is_some() { - let cert_chain = args - .cert_chain - .ok_or_else(|| type_error("No certificate chain provided"))?; - let private_key = args - .private_key - .ok_or_else(|| type_error("No private key provided"))?; - - // The `remove` is safe because load_private_keys checks that there is at least one key. - let private_key = load_private_keys(private_key.as_bytes())?.remove(0); - - tls_config.set_single_client_cert( - load_certs(&mut cert_chain.as_bytes())?, - private_key, - )?; - } - let tls_config = Arc::new(tls_config); let tls_stream = - TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns); + TlsStream::new_client_side(tcp_stream, tls_config, hostname_dns); let rid = { let mut state_ = state.borrow_mut(); @@ -1096,18 +1030,19 @@ where permissions.check_read(Path::new(key_file))?; } - let mut tls_config = ServerConfig::new(NoClientAuth::new()); + let mut tls_config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert( + load_certs_from_file(cert_file)?, + load_private_keys_from_file(key_file)?.remove(0), + ) + .expect("invalid key or certificate"); if let Some(alpn_protocols) = args.alpn_protocols { super::check_unstable(state, "Deno.listenTls#alpn_protocols"); tls_config.alpn_protocols = alpn_protocols.into_iter().map(|s| s.into_bytes()).collect(); } - tls_config - .set_single_cert( - load_certs_from_file(cert_file)?, - load_private_keys_from_file(key_file)?.remove(0), - ) - .expect("invalid key or certificate"); let bind_addr = resolve_addr_sync(hostname, port)? .next() @@ -1163,7 +1098,8 @@ pub async fn op_tls_accept( let local_addr = tcp_stream.local_addr()?; - let tls_stream = TlsStream::new_server_side(tcp_stream, &resource.tls_config); + let tls_stream = + TlsStream::new_server_side(tcp_stream, resource.tls_config.clone()); let rid = { let mut state_ = state.borrow_mut(); diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml index c2746a7538ed7..4146ff9cead1f 100644 --- a/ext/tls/Cargo.toml +++ b/ext/tls/Cargo.toml @@ -16,8 +16,9 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.110.0", path = "../../core" } lazy_static = "1.4.0" -rustls = { version = "0.19.1", features = ["dangerous_configuration"] } -rustls-native-certs = "0.5.0" +rustls = { version = "0.20", features = ["dangerous_configuration"] } +rustls-native-certs = "0.6.1" +rustls-pemfile = "0.2.1" serde = { version = "1.0.129", features = ["derive"] } -webpki = "0.21.4" -webpki-roots = "0.21.1" +webpki = "0.22" +webpki-roots = "0.22" diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs index 68bd2fcc187d0..bcaf0f1be12d6 100644 --- a/ext/tls/lib.rs +++ b/ext/tls/lib.rs @@ -2,6 +2,7 @@ pub use rustls; pub use rustls_native_certs; +pub use rustls_pemfile; pub use webpki; pub use webpki_roots; @@ -11,27 +12,26 @@ use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; use deno_core::Extension; -use rustls::internal::msgs::handshake::DigitallySignedStruct; -use rustls::internal::pemfile::certs; -use rustls::internal::pemfile::pkcs8_private_keys; -use rustls::internal::pemfile::rsa_private_keys; +use rustls::client::ServerCertVerified; +use rustls::client::ServerCertVerifier; +use rustls::client::StoresClientSessions; +use rustls::client::WebPkiVerifier; use rustls::Certificate; use rustls::ClientConfig; -use rustls::HandshakeSignatureValid; +use rustls::Error; use rustls::PrivateKey; use rustls::RootCertStore; -use rustls::ServerCertVerified; -use rustls::ServerCertVerifier; -use rustls::StoresClientSessions; -use rustls::TLSError; -use rustls::WebPKIVerifier; +use rustls::ServerName; +use rustls_pemfile::certs; +use rustls_pemfile::pkcs8_private_keys; +use rustls_pemfile::rsa_private_keys; use serde::Deserialize; use std::collections::HashMap; use std::io::BufRead; use std::io::BufReader; use std::io::Cursor; use std::sync::Arc; -use webpki::DNSNameRef; +use std::time::SystemTime; /// This extension has no runtime apis, it only exports some shared native functions. pub fn init() -> Extension { @@ -43,42 +43,35 @@ pub struct NoCertificateVerification(pub Vec); impl ServerCertVerifier for NoCertificateVerification { fn verify_server_cert( &self, - roots: &RootCertStore, - presented_certs: &[Certificate], - dns_name_ref: DNSNameRef<'_>, - ocsp: &[u8], - ) -> Result { - let dns_name: &str = dns_name_ref.into(); - let dns_name: String = dns_name.to_owned(); - if self.0.is_empty() || self.0.contains(&dns_name) { - Ok(ServerCertVerified::assertion()) + end_entity: &Certificate, + intermediates: &[Certificate], + server_name: &ServerName, + scts: &mut dyn Iterator, + ocsp_response: &[u8], + now: SystemTime, + ) -> Result { + if let ServerName::DnsName(dns_name) = server_name { + let dns_name = dns_name.as_ref().to_owned(); + if self.0.is_empty() || self.0.contains(&dns_name) { + Ok(ServerCertVerified::assertion()) + } else { + let root_store = create_default_root_cert_store(); + let verifier = WebPkiVerifier::new(root_store, None); + verifier.verify_server_cert( + end_entity, + intermediates, + server_name, + scts, + ocsp_response, + now, + ) + } } else { - WebPKIVerifier::new().verify_server_cert( - roots, - presented_certs, - dns_name_ref, - ocsp, - ) + // NOTE(bartlomieju): `ServerName` is a non-exhaustive enum + // so we have this catch all error here. + Err(Error::General("Unknown `ServerName` variant".to_string())) } } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &Certificate, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &Certificate, - _dss: &DigitallySignedStruct, - ) -> Result { - Ok(HandshakeSignatureValid::assertion()) - } } #[derive(Deserialize, Default, Debug, Clone)] @@ -124,7 +117,15 @@ impl StoresClientSessions for ClientSessionMemoryCache { pub fn create_default_root_cert_store() -> RootCertStore { let mut root_cert_store = RootCertStore::empty(); // TODO(@justinmchase): Consider also loading the system keychain here - root_cert_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + root_cert_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, + ) + }), + ); root_cert_store } @@ -134,39 +135,73 @@ pub fn create_client_config( unsafely_ignore_certificate_errors: Option>, client_cert_chain_and_key: Option<(String, String)>, ) -> Result { - let mut tls_config = ClientConfig::new(); - tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone()); - tls_config.root_store = - root_cert_store.unwrap_or_else(create_default_root_cert_store); - - // If custom certs are specified, add them to the store - for cert in ca_certs { - let reader = &mut BufReader::new(Cursor::new(cert)); - // This function does not return specific errors, if it fails give a generic message. - if let Err(()) = tls_config.root_store.add_pem_file(reader) { - return Err(anyhow!("Unable to add pem file to certificate store")); - } - } + let maybe_cert_chain_and_key = + if let Some((cert_chain, private_key)) = client_cert_chain_and_key { + // The `remove` is safe because load_private_keys checks that there is at least one key. + let private_key = load_private_keys(private_key.as_bytes())?.remove(0); + let cert_chain = load_certs(&mut cert_chain.as_bytes())?; + Some((cert_chain, private_key)) + } else { + None + }; if let Some(ic_allowlist) = unsafely_ignore_certificate_errors { - tls_config.dangerous().set_certificate_verifier(Arc::new( - NoCertificateVerification(ic_allowlist), - )); - } - - if let Some((cert_chain, private_key)) = client_cert_chain_and_key { - // The `remove` is safe because load_private_keys checks that there is at least one key. - let private_key = load_private_keys(private_key.as_bytes())?.remove(0); - - tls_config - .set_single_client_cert( - load_certs(&mut cert_chain.as_bytes())?, - private_key, - ) - .expect("invalid client key or certificate"); + let client_config = ClientConfig::builder() + .with_safe_defaults() + .with_custom_certificate_verifier(Arc::new(NoCertificateVerification( + ic_allowlist, + ))); + + // NOTE(bartlomieju): this if/else is duplicated at the end of the body of this function. + // However it's not really feasible to deduplicate it as the `client_config` instances + // are not type-compatible - one wants "client cert", the other wants "transparency policy + // or client cert". + let client = + if let Some((cert_chain, private_key)) = maybe_cert_chain_and_key { + client_config + .with_single_cert(cert_chain, private_key) + .expect("invalid client key or certificate") + } else { + client_config.with_no_client_auth() + }; + + return Ok(client); } - Ok(tls_config) + let client_config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates({ + let mut root_cert_store = + root_cert_store.unwrap_or_else(create_default_root_cert_store); + // If custom certs are specified, add them to the store + for cert in ca_certs { + let reader = &mut BufReader::new(Cursor::new(cert)); + // This function does not return specific errors, if it fails give a generic message. + match rustls_pemfile::certs(reader) { + Ok(certs) => { + root_cert_store.add_parsable_certificates(&certs); + } + Err(e) => { + return Err(anyhow!( + "Unable to add pem file to certificate store: {}", + e + )); + } + } + } + root_cert_store + }); + + let client = if let Some((cert_chain, private_key)) = maybe_cert_chain_and_key + { + client_config + .with_single_cert(cert_chain, private_key) + .expect("invalid client key or certificate") + } else { + client_config.with_no_client_auth() + }; + + Ok(client) } pub fn load_certs( @@ -180,7 +215,7 @@ pub fn load_certs( return Err(e); } - Ok(certs) + Ok(certs.into_iter().map(Certificate).collect()) } fn key_decode_err() -> AnyError { @@ -194,13 +229,13 @@ fn key_not_found_err() -> AnyError { /// Starts with -----BEGIN RSA PRIVATE KEY----- fn load_rsa_keys(mut bytes: &[u8]) -> Result, AnyError> { let keys = rsa_private_keys(&mut bytes).map_err(|_| key_decode_err())?; - Ok(keys) + Ok(keys.into_iter().map(PrivateKey).collect()) } /// Starts with -----BEGIN PRIVATE KEY----- fn load_pkcs8_keys(mut bytes: &[u8]) -> Result, AnyError> { let keys = pkcs8_private_keys(&mut bytes).map_err(|_| key_decode_err())?; - Ok(keys) + Ok(keys.into_iter().map(PrivateKey).collect()) } pub fn load_private_keys(bytes: &[u8]) -> Result, AnyError> { diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 0dc2f2378f1a9..b7426c792914f 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -20,5 +20,5 @@ http = "0.2.4" hyper = { version = "0.14.12" } serde = { version = "1.0.129", features = ["derive"] } tokio = { version = "1.10.1", features = ["full"] } -tokio-rustls = "0.22.0" -tokio-tungstenite = { version = "0.14.0", features = ["rustls-tls"] } +tokio-rustls = "0.23.0" +tokio-tungstenite = { version = "0.16.0", features = ["rustls-tls-webpki-roots"] } diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index cf2ab6cacfff5..13d3ddfca8d65 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -20,25 +20,28 @@ use deno_core::Resource; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; use deno_tls::create_client_config; -use deno_tls::webpki::DNSNameRef; - -use http::{Method, Request, Uri}; +use http::Method; +use http::Request; +use http::Uri; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; use std::cell::RefCell; +use std::convert::TryFrom; use std::fmt; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; use tokio::net::TcpStream; use tokio_rustls::rustls::RootCertStore; +use tokio_rustls::rustls::ServerName; use tokio_rustls::TlsConnector; use tokio_tungstenite::client_async; -use tokio_tungstenite::tungstenite::{ - handshake::client::Response, protocol::frame::coding::CloseCode, - protocol::CloseFrame, protocol::Role, Message, -}; +use tokio_tungstenite::tungstenite::handshake::client::Response; +use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode; +use tokio_tungstenite::tungstenite::protocol::CloseFrame; +use tokio_tungstenite::tungstenite::protocol::Message; +use tokio_tungstenite::tungstenite::protocol::Role; use tokio_tungstenite::MaybeTlsStream; use tokio_tungstenite::WebSocketStream; @@ -284,7 +287,7 @@ where None, )?; let tls_connector = TlsConnector::from(Arc::new(tls_config)); - let dnsname = DNSNameRef::try_from_ascii_str(domain) + let dnsname = ServerName::try_from(domain.as_str()) .map_err(|_| invalid_hostname(domain))?; let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?; MaybeTlsStream::Rustls(tls_socket) diff --git a/test_util/Cargo.toml b/test_util/Cargo.toml index 279cb4d304f0d..c545fcfea8c43 100644 --- a/test_util/Cargo.toml +++ b/test_util/Cargo.toml @@ -21,12 +21,13 @@ hyper = { version = "0.14.12", features = ["server", "http1", "http2", "runtime" lazy_static = "1.4.0" os_pipe = "0.9.2" regex = "1.5.4" +rustls-pemfile = "0.2.1" serde = { version = "1.0.126", features = ["derive"] } serde_json = "1.0.65" tempfile = "3.2.0" tokio = { version = "1.10.1", features = ["full"] } -tokio-rustls = "0.22.0" -tokio-tungstenite = "0.14.0" +tokio-rustls = "0.23" +tokio-tungstenite = "0.16" [target.'cfg(unix)'.dependencies] pty = "0.2.2" diff --git a/test_util/src/lib.rs b/test_util/src/lib.rs index 857884efcf2bf..3cae1d7e1385d 100644 --- a/test_util/src/lib.rs +++ b/test_util/src/lib.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // Usage: provide a port as argument to run hyper_hello benchmark server // otherwise this starts multiple servers on many ports for test endpoints. +use anyhow::anyhow; use futures::FutureExt; use futures::Stream; use futures::StreamExt; @@ -15,6 +16,8 @@ use hyper::StatusCode; use lazy_static::lazy_static; use os_pipe::pipe; use regex::Regex; +use rustls::Certificate; +use rustls::PrivateKey; use serde::Serialize; use std::collections::HashMap; use std::convert::Infallible; @@ -40,7 +43,7 @@ use tempfile::TempDir; use tokio::io::AsyncWriteExt; use tokio::net::TcpListener; use tokio::net::TcpStream; -use tokio_rustls::rustls::{self, Session}; +use tokio_rustls::rustls; use tokio_rustls::TlsAcceptor; use tokio_tungstenite::accept_async; @@ -321,21 +324,25 @@ async fn get_tls_config( let key_file = std::fs::File::open(key_path)?; let ca_file = std::fs::File::open(ca_path)?; - let mut cert_reader = io::BufReader::new(cert_file); - let cert = rustls::internal::pemfile::certs(&mut cert_reader) - .expect("Cannot load certificate"); + let certs: Vec = { + let mut cert_reader = io::BufReader::new(cert_file); + rustls_pemfile::certs(&mut cert_reader) + .unwrap() + .into_iter() + .map(Certificate) + .collect() + }; let mut ca_cert_reader = io::BufReader::new(ca_file); - let ca_cert = rustls::internal::pemfile::certs(&mut ca_cert_reader) + let ca_cert = rustls_pemfile::certs(&mut ca_cert_reader) .expect("Cannot load CA certificate") .remove(0); let mut key_reader = io::BufReader::new(key_file); let key = { - let pkcs8_key = - rustls::internal::pemfile::pkcs8_private_keys(&mut key_reader) - .expect("Cannot load key file"); - let rsa_key = rustls::internal::pemfile::rsa_private_keys(&mut key_reader) + let pkcs8_key = rustls_pemfile::pkcs8_private_keys(&mut key_reader) + .expect("Cannot load key file"); + let rsa_key = rustls_pemfile::rsa_private_keys(&mut key_reader) .expect("Cannot load key file"); if !pkcs8_key.is_empty() { Some(pkcs8_key[0].clone()) @@ -349,26 +356,32 @@ async fn get_tls_config( match key { Some(key) => { let mut root_cert_store = rustls::RootCertStore::empty(); - root_cert_store.add(&ca_cert).unwrap(); + root_cert_store.add(&rustls::Certificate(ca_cert)).unwrap(); + // Allow (but do not require) client authentication. - let allow_client_auth = - rustls::AllowAnyAnonymousOrAuthenticatedClient::new(root_cert_store); - let mut config = rustls::ServerConfig::new(allow_client_auth); + + let mut config = rustls::ServerConfig::builder() + .with_safe_defaults() + .with_client_cert_verifier( + rustls::server::AllowAnyAnonymousOrAuthenticatedClient::new( + root_cert_store, + ), + ) + .with_single_cert(certs, PrivateKey(key)) + .map_err(|e| { + anyhow!("Error setting cert: {:?}", e); + }) + .unwrap(); + match http_versions { SupportedHttpVersions::All => { - config.set_protocols(&["h2".into(), "http/1.1".into()]); + config.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; } SupportedHttpVersions::Http1Only => {} SupportedHttpVersions::Http2Only => { - config.set_protocols(&["h2".into()]); + config.alpn_protocols = vec!["h2".into()]; } } - config - .set_single_cert(cert, key) - .map_err(|e| { - eprintln!("Error setting cert: {:?}", e); - }) - .unwrap(); Ok(Arc::new(config)) } @@ -466,7 +479,7 @@ async fn run_tls_client_auth_server() { let (_, tls_session) = tls_stream.get_mut(); // We only need to check for the presence of client certificates // here. Rusttls ensures that they are valid and signed by the CA. - let response = match tls_session.get_peer_certificates() { + let response = match tls_session.peer_certificates() { Some(_certs) => b"PASS", None => b"FAIL", }; @@ -1173,7 +1186,7 @@ async fn wrap_client_auth_https_server() { let (_, tls_session) = tls_stream.get_mut(); // We only need to check for the presence of client certificates // here. Rusttls ensures that they are valid and signed by the CA. - match tls_session.get_peer_certificates() { + match tls_session.peer_certificates() { Some(_certs) => { yield Ok(tls_stream); }, None => { eprintln!("https_client_auth: no valid client certificate"); }, };