mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
chore: upgrade to rustls 0.20 (#12488)
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com> Co-authored-by: Bert Belder <bertbelder@gmail.com>
This commit is contained in:
parent
b91e6fd02f
commit
a2f1357fe8
15 changed files with 420 additions and 357 deletions
100
Cargo.lock
generated
100
Cargo.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
6
cli/tests/testdata/listen_tls_alpn.ts
vendored
6
cli/tests/testdata/listen_tls_alpn.ts
vendored
|
@ -7,6 +7,8 @@ const listener = Deno.listenTls({
|
|||
|
||||
console.log("READY");
|
||||
|
||||
for await (const conn of listener) {
|
||||
const conn = await listener.accept() as Deno.TlsConn;
|
||||
await conn.handshake();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
listener.close();
|
||||
|
|
20
cli/tests/testdata/listen_tls_alpn_fail.ts
vendored
Normal file
20
cli/tests/testdata/listen_tls_alpn_fail.ts
vendored
Normal file
|
@ -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();
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<ClientSession> for TlsSession {
|
||||
fn from(client_session: ClientSession) -> Self {
|
||||
TlsSession::Client(client_session)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ServerSession> 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<TlsStreamInner>);
|
||||
|
||||
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<ClientConfig>,
|
||||
hostname: DNSNameRef,
|
||||
tls_config: Arc<ClientConfig>,
|
||||
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<ServerConfig>,
|
||||
tls_config: Arc<ServerConfig>,
|
||||
) -> 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.
|
||||
// Keep trying to read from the TCP connection until the remote end
|
||||
// closes it gracefully.
|
||||
}
|
||||
_ => 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)),
|
||||
State::TlsClosed => break true,
|
||||
State::TcpClosed => break true,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
if self.rd_state != State::TlsError {
|
||||
// Receive ciphertext from the socket.
|
||||
// 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) => {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
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<Shared>,
|
||||
}
|
||||
|
@ -542,7 +481,6 @@ impl AsyncRead for ReadHalf {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WriteHalf {
|
||||
shared: Arc<Shared>,
|
||||
}
|
||||
|
@ -596,7 +534,6 @@ impl AsyncWrite for WriteHalf {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Shared {
|
||||
tls_stream: Mutex<TlsStream>,
|
||||
rd_waker: AtomicWaker,
|
||||
|
@ -851,8 +788,8 @@ where
|
|||
.map(|s| s.into_bytes())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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::<DefaultTlsOptions>()
|
||||
.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();
|
||||
|
|
|
@ -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"
|
||||
|
|
169
ext/tls/lib.rs
169
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,41 +43,34 @@ pub struct NoCertificateVerification(pub Vec<String>);
|
|||
impl ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
roots: &RootCertStore,
|
||||
presented_certs: &[Certificate],
|
||||
dns_name_ref: DNSNameRef<'_>,
|
||||
ocsp: &[u8],
|
||||
) -> Result<ServerCertVerified, TLSError> {
|
||||
let dns_name: &str = dns_name_ref.into();
|
||||
let dns_name: String = dns_name.to_owned();
|
||||
end_entity: &Certificate,
|
||||
intermediates: &[Certificate],
|
||||
server_name: &ServerName,
|
||||
scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
ocsp_response: &[u8],
|
||||
now: SystemTime,
|
||||
) -> Result<ServerCertVerified, Error> {
|
||||
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 {
|
||||
WebPKIVerifier::new().verify_server_cert(
|
||||
roots,
|
||||
presented_certs,
|
||||
dns_name_ref,
|
||||
ocsp,
|
||||
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 {
|
||||
// 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<HandshakeSignatureValid, TLSError> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
}
|
||||
|
||||
fn verify_tls13_signature(
|
||||
&self,
|
||||
_message: &[u8],
|
||||
_cert: &Certificate,
|
||||
_dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, TLSError> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Vec<String>>,
|
||||
client_cert_chain_and_key: Option<(String, String)>,
|
||||
) -> Result<ClientConfig, AnyError> {
|
||||
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);
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
if let Err(()) = tls_config.root_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);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ic_allowlist) = unsafely_ignore_certificate_errors {
|
||||
tls_config.dangerous().set_certificate_verifier(Arc::new(
|
||||
NoCertificateVerification(ic_allowlist),
|
||||
Err(e) => {
|
||||
return Err(anyhow!(
|
||||
"Unable to add pem file to certificate store: {}",
|
||||
e
|
||||
));
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
root_cert_store
|
||||
});
|
||||
|
||||
Ok(tls_config)
|
||||
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<Vec<PrivateKey>, 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<Vec<PrivateKey>, 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<Vec<PrivateKey>, AnyError> {
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 certs: Vec<Certificate> = {
|
||||
let mut cert_reader = io::BufReader::new(cert_file);
|
||||
let cert = rustls::internal::pemfile::certs(&mut cert_reader)
|
||||
.expect("Cannot load certificate");
|
||||
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)
|
||||
let pkcs8_key = rustls_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 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"); },
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue