From cb87cb0283fbe95ace2317b0617e7e74382bf4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 17 May 2023 02:19:23 +0200 Subject: [PATCH] fix: support "fetch" over HTTPS for IP addresses (#18499) This commit adds support for connecting to IP addresses over HTTPS. This is done by updating "rustls" to "0.21.0" and other related crates. Closes https://github.com/denoland/deno/issues/7660 Closes https://github.com/denoland/deno/issues/17967 --------- Co-authored-by: Divy Srivastava --- Cargo.lock | 47 ++++++++++++++----- Cargo.toml | 6 +-- .../testdata/cert/localhost_unsafe_ssl.ts.out | 2 +- cli/tests/testdata/run/websocket_test.ts | 5 +- cli/tests/unit/fetch_test.ts | 12 +++++ cli/tests/unit/tls_test.ts | 4 +- ext/tls/lib.rs | 27 +---------- test_util/src/lib.rs | 4 +- 8 files changed, 61 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6aeb321cb79524..19821855a45be6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-compression" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0122885821398cc923ece939e24d1056a2384ee719432397fa9db87230ff11" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-stream" version = "0.3.4" @@ -1025,7 +1039,7 @@ dependencies = [ name = "deno_http" version = "0.99.0" dependencies = [ - "async-compression", + "async-compression 0.3.15", "async-trait", "base64 0.13.1", "bencher", @@ -2400,9 +2414,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ "http", "hyper 0.14.26", @@ -3775,11 +3789,11 @@ checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" [[package]] name = "reqwest" -version = "0.11.14" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "async-compression", + "async-compression 0.4.0", "base64 0.21.0", "bytes", "encoding_rs", @@ -3955,14 +3969,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "07180898a28ed6a7f7ba2311594308f595e3dd2e3c3812fa0a80a47b45f17e5d" dependencies = [ "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] @@ -3986,6 +4000,16 @@ dependencies = [ "base64 0.21.0", ] +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.12" @@ -5233,13 +5257,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6f4d15b918529c..a45c2b2fd459bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,10 +116,10 @@ pretty_assertions = "=1.3.0" rand = "=0.8.5" regex = "^1.7.0" lazy-regex = "2.5.0" -reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks"] } +reqwest = { version = "0.11.18", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks"] } ring = "=0.16.20" rusqlite = { version = "=0.28.0", features = ["unlock_notify", "bundled"] } -rustls = "0.20.5" +rustls = "0.21.0" rustls-pemfile = "1.0.0" serde = { version = "1.0.149", features = ["derive"] } serde_bytes = "0.11" @@ -136,7 +136,7 @@ thiserror = "1.0.40" tokio = { version = "1.28.1", features = ["full"] } tikv-jemallocator = "0.5.0" tikv-jemalloc-sys = "0.5.3" -tokio-rustls = "0.23.3" +tokio-rustls = "0.24.0" tokio-util = "0.7.4" tower-lsp = { version = "=0.17.0", features = ["proposed"] } url = { version = "2.3.1", features = ["serde", "expose_internals"] } diff --git a/cli/tests/testdata/cert/localhost_unsafe_ssl.ts.out b/cli/tests/testdata/cert/localhost_unsafe_ssl.ts.out index 0bfaeb25d1be0c..4b95c1136a1070 100644 --- a/cli/tests/testdata/cert/localhost_unsafe_ssl.ts.out +++ b/cli/tests/testdata/cert/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 peer certificate contents: invalid peer certificate: UnknownIssuer +error: error sending request for url (https://localhost:5545/subdir/mod2.ts): error trying to connect: invalid peer certificate: UnknownIssuer at file:///[WILDCARD]/cafile_url_imports.ts:[WILDCARD] diff --git a/cli/tests/testdata/run/websocket_test.ts b/cli/tests/testdata/run/websocket_test.ts index 27bc5adf92e493..d80f03c92aa126 100644 --- a/cli/tests/testdata/run/websocket_test.ts +++ b/cli/tests/testdata/run/websocket_test.ts @@ -161,7 +161,10 @@ Deno.test("websocket error", async () => { assert(err instanceof ErrorEvent); // Error message got changed because we don't use warp in test_util - assertEquals(err.message, "InvalidData: received corrupt message"); + assertEquals( + err.message, + "InvalidData: received corrupt message of type InvalidContentType", + ); promise1.resolve(); }; await promise1; diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts index a92a7a05162c2c..7de04013ea5907 100644 --- a/cli/tests/unit/fetch_test.ts +++ b/cli/tests/unit/fetch_test.ts @@ -1495,6 +1495,18 @@ Deno.test( }, ); +Deno.test( + { permissions: { net: true, read: true } }, + async function fetchSupportsHttpsOverIpAddress() { + const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem"); + const client = Deno.createHttpClient({ caCerts: [caCert] }); + const res = await fetch("https://localhost:5546/http_version", { client }); + assert(res.ok); + assertEquals(await res.text(), "HTTP/1.1"); + client.close(); + }, +); + Deno.test( { permissions: { net: true, read: true } }, async function fetchSupportsHttp1Only() { diff --git a/cli/tests/unit/tls_test.ts b/cli/tests/unit/tls_test.ts index b7cde102089551..c8dd7ddbeb4027 100644 --- a/cli/tests/unit/tls_test.ts +++ b/cli/tests/unit/tls_test.ts @@ -1337,7 +1337,7 @@ Deno.test( await assertRejects( () => conn.handshake(), Deno.errors.InvalidData, - "BadCertificate", + "received fatal alert", ); } conn.close(); @@ -1368,7 +1368,7 @@ Deno.test( await assertRejects( () => tlsConn.handshake(), Deno.errors.InvalidData, - "CertNotValidForName", + "NotValidForName", ); tlsConn.close(); } diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs index 3034e2ae98f108..dded1b38598145 100644 --- a/ext/tls/lib.rs +++ b/ext/tls/lib.rs @@ -9,16 +9,14 @@ pub use webpki_roots; use deno_core::anyhow::anyhow; use deno_core::error::custom_error; use deno_core::error::AnyError; -use deno_core::parking_lot::Mutex; use rustls::client::HandshakeSignatureValid; use rustls::client::ServerCertVerified; use rustls::client::ServerCertVerifier; -use rustls::client::StoresClientSessions; use rustls::client::WebPkiVerifier; -use rustls::internal::msgs::handshake::DigitallySignedStruct; use rustls::Certificate; use rustls::ClientConfig; +use rustls::DigitallySignedStruct; use rustls::Error; use rustls::PrivateKey; use rustls::RootCertStore; @@ -27,7 +25,6 @@ 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; @@ -145,26 +142,6 @@ pub struct BasicAuth { pub password: String, } -#[derive(Default)] -struct ClientSessionMemoryCache(Mutex, Vec>>); - -impl StoresClientSessions for ClientSessionMemoryCache { - fn get(&self, key: &[u8]) -> Option> { - self.0.lock().get(key).cloned() - } - - fn put(&self, key: Vec, value: Vec) -> bool { - let mut sessions = self.0.lock(); - // TODO(bnoordhuis) Evict sessions LRU-style instead of arbitrarily. - while sessions.len() >= 1024 { - let key = sessions.keys().next().unwrap().clone(); - sessions.remove(&key); - } - sessions.insert(key, value); - true - } -} - pub fn create_default_root_cert_store() -> RootCertStore { let mut root_cert_store = RootCertStore::empty(); // TODO(@justinmchase): Consider also loading the system keychain here @@ -293,7 +270,7 @@ fn filter_invalid_encoding_err( to_be_filtered: Result, ) -> Result { match to_be_filtered { - Err(Error::InvalidCertificateEncoding) => { + Err(Error::InvalidCertificate(rustls::CertificateError::BadEncoding)) => { Ok(HandshakeSignatureValid::assertion()) } res => res, diff --git a/test_util/src/lib.rs b/test_util/src/lib.rs index e647c0a4cb56b5..054298b5472bc5 100644 --- a/test_util/src/lib.rs +++ b/test_util/src/lib.rs @@ -488,11 +488,11 @@ async fn get_tls_config( let mut config = rustls::ServerConfig::builder() .with_safe_defaults() - .with_client_cert_verifier( + .with_client_cert_verifier(Arc::new( rustls::server::AllowAnyAnonymousOrAuthenticatedClient::new( root_cert_store, ), - ) + )) .with_single_cert(certs, PrivateKey(key)) .map_err(|e| anyhow!("Error setting cert: {:?}", e)) .unwrap();