summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2024-07-02 01:09:47 +0100
committerGitHub <noreply@github.com>2024-07-02 02:09:47 +0200
commit8db420d552bc1d480a21748d73b566b623a266c1 (patch)
tree4634447ec235f3d4f743a233c500425409236097 /ext
parent9c1f741112f87ba97125e19efb3abf918205ad23 (diff)
chore: upgrade to reqwest 0.12.4 and rustls 0.22 (#24388)
Reland of https://github.com/denoland/deno/pull/24056 that doesn't suffer from the problem that was discovered in https://github.com/denoland/deno/pull/24261. It uses upgraded `hyper` and `hyper-util` that fixed the previous problem in https://github.com/hyperium/hyper/pull/3691.
Diffstat (limited to 'ext')
-rw-r--r--ext/fetch/Cargo.toml2
-rw-r--r--ext/fetch/fs_fetch_handler.rs2
-rw-r--r--ext/fetch/lib.rs13
-rw-r--r--ext/kv/Cargo.toml2
-rw-r--r--ext/kv/remote.rs44
-rw-r--r--ext/net/ops_tls.rs28
-rw-r--r--ext/node/Cargo.toml4
-rw-r--r--ext/node/ops/http2.rs14
-rw-r--r--ext/tls/Cargo.toml4
-rw-r--r--ext/tls/lib.rs201
-rw-r--r--ext/tls/testdata/README4
-rw-r--r--ext/tls/testdata/example1_cert.derbin0 -> 929 bytes
-rw-r--r--ext/tls/testdata/example1_prikey.derbin0 -> 1190 bytes
-rw-r--r--ext/tls/testdata/example2_cert.derbin0 -> 929 bytes
-rw-r--r--ext/tls/testdata/example2_prikey.derbin0 -> 1191 bytes
-rw-r--r--ext/tls/tls_key.rs46
-rw-r--r--ext/websocket/lib.rs11
17 files changed, 220 insertions, 155 deletions
diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml
index 20b6e9bc3..7a60a6c64 100644
--- a/ext/fetch/Cargo.toml
+++ b/ext/fetch/Cargo.toml
@@ -20,7 +20,7 @@ deno_core.workspace = true
deno_permissions.workspace = true
deno_tls.workspace = true
dyn-clone = "1"
-http_v02.workspace = true
+http.workspace = true
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
diff --git a/ext/fetch/fs_fetch_handler.rs b/ext/fetch/fs_fetch_handler.rs
index 8f83cef88..29bad5992 100644
--- a/ext/fetch/fs_fetch_handler.rs
+++ b/ext/fetch/fs_fetch_handler.rs
@@ -31,7 +31,7 @@ impl FetchHandler for FsFetchHandler {
let file = tokio::fs::File::open(path).map_err(|_| ()).await?;
let stream = ReaderStream::new(file);
let body = reqwest::Body::wrap_stream(stream);
- let response = http_v02::Response::builder()
+ let response = http::Response::builder()
.status(StatusCode::OK)
.body(body)
.map_err(|_| ())?
diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs
index 066f1685b..75ceb86d9 100644
--- a/ext/fetch/lib.rs
+++ b/ext/fetch/lib.rs
@@ -47,8 +47,8 @@ use data_url::DataUrl;
use deno_tls::TlsKey;
use deno_tls::TlsKeys;
use deno_tls::TlsKeysHolder;
-use http_v02::header::CONTENT_LENGTH;
-use http_v02::Uri;
+use http::header::CONTENT_LENGTH;
+use http::Uri;
use reqwest::header::HeaderMap;
use reqwest::header::HeaderName;
use reqwest::header::HeaderValue;
@@ -449,12 +449,9 @@ where
.decode_to_vec()
.map_err(|e| type_error(format!("{e:?}")))?;
- let response = http_v02::Response::builder()
- .status(http_v02::StatusCode::OK)
- .header(
- http_v02::header::CONTENT_TYPE,
- data_url.mime_type().to_string(),
- )
+ let response = http::Response::builder()
+ .status(http::StatusCode::OK)
+ .header(http::header::CONTENT_TYPE, data_url.mime_type().to_string())
.body(reqwest::Body::from(body))?;
let fut = async move { Ok(Ok(Response::from(response))) };
diff --git a/ext/kv/Cargo.toml b/ext/kv/Cargo.toml
index 46c4a4ac4..4bb5d20eb 100644
--- a/ext/kv/Cargo.toml
+++ b/ext/kv/Cargo.toml
@@ -17,6 +17,7 @@ path = "lib.rs"
anyhow.workspace = true
async-trait.workspace = true
base64.workspace = true
+bytes.workspace = true
chrono = { workspace = true, features = ["now"] }
deno_core.workspace = true
deno_fetch.workspace = true
@@ -27,6 +28,7 @@ denokv_proto.workspace = true
denokv_remote.workspace = true
denokv_sqlite.workspace = true
faster-hex.workspace = true
+http.workspace = true
log.workspace = true
num-bigint.workspace = true
prost.workspace = true
diff --git a/ext/kv/remote.rs b/ext/kv/remote.rs
index a1273e78b..7541b5a06 100644
--- a/ext/kv/remote.rs
+++ b/ext/kv/remote.rs
@@ -8,10 +8,14 @@ use std::sync::Arc;
use crate::DatabaseHandler;
use anyhow::Context;
use async_trait::async_trait;
+use bytes::Bytes;
use deno_core::error::type_error;
use deno_core::error::AnyError;
+use deno_core::futures::Stream;
+use deno_core::futures::TryStreamExt as _;
use deno_core::OpState;
use deno_fetch::create_http_client;
+use deno_fetch::reqwest;
use deno_fetch::CreateHttpClientOptions;
use deno_tls::rustls::RootCertStore;
use deno_tls::Proxy;
@@ -19,6 +23,8 @@ use deno_tls::RootCertStoreProvider;
use deno_tls::TlsKeys;
use denokv_remote::MetadataEndpoint;
use denokv_remote::Remote;
+use denokv_remote::RemoteResponse;
+use denokv_remote::RemoteTransport;
use url::Url;
#[derive(Clone)]
@@ -102,11 +108,44 @@ impl<P: RemoteDbHandlerPermissions + 'static> denokv_remote::RemotePermissions
}
}
+#[derive(Clone)]
+pub struct ReqwestClient(reqwest::Client);
+pub struct ReqwestResponse(reqwest::Response);
+
+impl RemoteTransport for ReqwestClient {
+ type Response = ReqwestResponse;
+ async fn post(
+ &self,
+ url: Url,
+ headers: http::HeaderMap,
+ body: Bytes,
+ ) -> Result<(Url, http::StatusCode, Self::Response), anyhow::Error> {
+ let res = self.0.post(url).headers(headers).body(body).send().await?;
+ let url = res.url().clone();
+ let status = res.status();
+ Ok((url, status, ReqwestResponse(res)))
+ }
+}
+
+impl RemoteResponse for ReqwestResponse {
+ async fn bytes(self) -> Result<Bytes, anyhow::Error> {
+ Ok(self.0.bytes().await?)
+ }
+ fn stream(
+ self,
+ ) -> impl Stream<Item = Result<Bytes, anyhow::Error>> + Send + Sync {
+ self.0.bytes_stream().map_err(|e| e.into())
+ }
+ async fn text(self) -> Result<String, anyhow::Error> {
+ Ok(self.0.text().await?)
+ }
+}
+
#[async_trait(?Send)]
impl<P: RemoteDbHandlerPermissions + 'static> DatabaseHandler
for RemoteDbHandler<P>
{
- type DB = Remote<PermissionChecker<P>>;
+ type DB = Remote<PermissionChecker<P>, ReqwestClient>;
async fn open(
&self,
@@ -162,13 +201,14 @@ impl<P: RemoteDbHandlerPermissions + 'static> DatabaseHandler
http2: true,
},
)?;
+ let reqwest_client = ReqwestClient(client);
let permissions = PermissionChecker {
state: state.clone(),
_permissions: PhantomData,
};
- let remote = Remote::new(client, permissions, metadata_endpoint);
+ let remote = Remote::new(reqwest_client, permissions, metadata_endpoint);
Ok(remote)
}
diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs
index adfa8224c..a2a27c4ad 100644
--- a/ext/net/ops_tls.rs
+++ b/ext/net/ops_tls.rs
@@ -31,11 +31,11 @@ use deno_tls::create_client_config;
use deno_tls::load_certs;
use deno_tls::load_private_keys;
use deno_tls::new_resolver;
-use deno_tls::rustls::Certificate;
+use deno_tls::rustls::pki_types::ServerName;
use deno_tls::rustls::ClientConnection;
-use deno_tls::rustls::PrivateKey;
use deno_tls::rustls::ServerConfig;
-use deno_tls::rustls::ServerName;
+use deno_tls::webpki::types::CertificateDer;
+use deno_tls::webpki::types::PrivateKeyDer;
use deno_tls::ServerConfigProvider;
use deno_tls::SocketUse;
use deno_tls::TlsKey;
@@ -48,7 +48,6 @@ 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::BufReader;
use std::io::ErrorKind;
@@ -294,14 +293,14 @@ where
{
let rid = args.rid;
let hostname = match &*args.hostname {
- "" => "localhost",
- n => n,
+ "" => "localhost".to_string(),
+ n => n.to_string(),
};
{
let mut s = state.borrow_mut();
let permissions = s.borrow_mut::<NP>();
- permissions.check_net(&(hostname, Some(0)), "Deno.startTls()")?;
+ permissions.check_net(&(&hostname, Some(0)), "Deno.startTls()")?;
}
let ca_certs = args
@@ -310,8 +309,8 @@ where
.map(|s| s.into_bytes())
.collect::<Vec<_>>();
- let hostname_dns =
- ServerName::try_from(hostname).map_err(|_| invalid_hostname(hostname))?;
+ let hostname_dns = ServerName::try_from(hostname.to_string())
+ .map_err(|_| invalid_hostname(&hostname))?;
let unsafely_ignore_certificate_errors = state
.borrow()
@@ -412,9 +411,9 @@ where
.borrow::<DefaultTlsOptions>()
.root_cert_store()?;
let hostname_dns = if let Some(server_name) = args.server_name {
- ServerName::try_from(server_name.as_str())
+ ServerName::try_from(server_name)
} else {
- ServerName::try_from(&*addr.hostname)
+ ServerName::try_from(addr.hostname.clone())
}
.map_err(|_| invalid_hostname(&addr.hostname))?;
let connect_addr = resolve_addr(&addr.hostname, addr.port)
@@ -456,7 +455,9 @@ where
Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr)))
}
-fn load_certs_from_file(path: &str) -> Result<Vec<Certificate>, AnyError> {
+fn load_certs_from_file(
+ path: &str,
+) -> Result<Vec<CertificateDer<'static>>, AnyError> {
let cert_file = File::open(path)?;
let reader = &mut BufReader::new(cert_file);
load_certs(reader)
@@ -464,7 +465,7 @@ fn load_certs_from_file(path: &str) -> Result<Vec<Certificate>, AnyError> {
fn load_private_keys_from_file(
path: &str,
-) -> Result<Vec<PrivateKey>, AnyError> {
+) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
let key_bytes = std::fs::read(path)?;
load_private_keys(&key_bytes)
}
@@ -513,7 +514,6 @@ where
TlsKeys::Null => Err(anyhow!("Deno.listenTls requires a key")),
TlsKeys::Static(TlsKey(cert, key)) => {
let mut tls_config = ServerConfig::builder()
- .with_safe_defaults()
.with_no_client_auth()
.with_single_cert(cert, key)
.map_err(|e| anyhow!(e))?;
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index 425364792..b1d40756b 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -38,10 +38,10 @@ ecb.workspace = true
elliptic-curve.workspace = true
errno = "0.2.8"
faster-hex.workspace = true
-h2 = { version = "0.3.26", features = ["unstable"] }
+h2.workspace = true
hkdf.workspace = true
home = "0.5.9"
-http_v02.workspace = true
+http.workspace = true
idna = "0.3.0"
indexmap.workspace = true
ipnetwork = "0.20.0"
diff --git a/ext/node/ops/http2.rs b/ext/node/ops/http2.rs
index abf7eae5d..d12e108e6 100644
--- a/ext/node/ops/http2.rs
+++ b/ext/node/ops/http2.rs
@@ -26,11 +26,11 @@ use deno_net::raw::NetworkStream;
use h2;
use h2::Reason;
use h2::RecvStream;
-use http_v02;
-use http_v02::request::Parts;
-use http_v02::HeaderMap;
-use http_v02::Response;
-use http_v02::StatusCode;
+use http;
+use http::request::Parts;
+use http::HeaderMap;
+use http::Response;
+use http::StatusCode;
use reqwest::header::HeaderName;
use reqwest::header::HeaderValue;
use url::Url;
@@ -311,7 +311,7 @@ pub async fn op_http2_client_request(
let url = url.join(&pseudo_path)?;
- let mut req = http_v02::Request::builder()
+ let mut req = http::Request::builder()
.uri(url.as_str())
.method(pseudo_method.as_str());
@@ -383,7 +383,7 @@ pub async fn op_http2_client_send_trailers(
.get::<Http2ClientStream>(stream_rid)?;
let mut stream = RcRef::map(&resource, |r| &r.stream).borrow_mut().await;
- let mut trailers_map = http_v02::HeaderMap::new();
+ let mut trailers_map = http::HeaderMap::new();
for (name, value) in trailers {
trailers_map.insert(
HeaderName::from_bytes(&name).unwrap(),
diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml
index 579f90ce2..0eddee5ea 100644
--- a/ext/tls/Cargo.toml
+++ b/ext/tls/Cargo.toml
@@ -15,8 +15,8 @@ path = "lib.rs"
[dependencies]
deno_core.workspace = true
-deno_native_certs = "0.2.0"
-rustls = { workspace = true, features = ["dangerous_configuration"] }
+deno_native_certs = "0.3.0"
+rustls.workspace = true
rustls-pemfile.workspace = true
rustls-tokio-stream.workspace = true
rustls-webpki.workspace = true
diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs
index 5122264bf..c4d548ccf 100644
--- a/ext/tls/lib.rs
+++ b/ext/tls/lib.rs
@@ -1,7 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
pub use deno_native_certs;
pub use rustls;
+use rustls::pki_types::CertificateDer;
+use rustls::pki_types::PrivateKeyDer;
+use rustls::pki_types::ServerName;
pub use rustls_pemfile;
pub use rustls_tokio_stream::*;
pub use webpki;
@@ -11,14 +13,14 @@ use deno_core::anyhow::anyhow;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
-use rustls::client::HandshakeSignatureValid;
-use rustls::client::ServerCertVerified;
-use rustls::client::ServerCertVerifier;
-use rustls::client::WebPkiVerifier;
+use rustls::client::danger::HandshakeSignatureValid;
+use rustls::client::danger::ServerCertVerified;
+use rustls::client::danger::ServerCertVerifier;
+use rustls::client::WebPkiServerVerifier;
use rustls::ClientConfig;
use rustls::DigitallySignedStruct;
use rustls::Error;
-use rustls::ServerName;
+use rustls::RootCertStore;
use rustls_pemfile::certs;
use rustls_pemfile::ec_private_keys;
use rustls_pemfile::pkcs8_private_keys;
@@ -27,16 +29,12 @@ use serde::Deserialize;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Cursor;
+use std::net::IpAddr;
use std::sync::Arc;
-use std::time::SystemTime;
mod tls_key;
pub use tls_key::*;
-pub type Certificate = rustls::Certificate;
-pub type PrivateKey = rustls::PrivateKey;
-pub type RootCertStore = rustls::RootCertStore;
-
/// Lazily resolves the root cert store.
///
/// This was done because the root cert store is not needed in all cases
@@ -48,56 +46,59 @@ pub trait RootCertStoreProvider: Send + Sync {
// This extension has no runtime apis, it only exports some shared native functions.
deno_core::extension!(deno_tls);
-struct DefaultSignatureVerification;
+#[derive(Debug)]
+pub struct NoCertificateVerification {
+ pub ic_allowlist: Vec<String>,
+ default_verifier: Arc<WebPkiServerVerifier>,
+}
-impl ServerCertVerifier for DefaultSignatureVerification {
- fn verify_server_cert(
- &self,
- _end_entity: &Certificate,
- _intermediates: &[Certificate],
- _server_name: &ServerName,
- _scts: &mut dyn Iterator<Item = &[u8]>,
- _ocsp_response: &[u8],
- _now: SystemTime,
- ) -> Result<ServerCertVerified, Error> {
- Err(Error::General("Should not be used".to_string()))
+impl NoCertificateVerification {
+ pub fn new(ic_allowlist: Vec<String>) -> Self {
+ Self {
+ ic_allowlist,
+ default_verifier: WebPkiServerVerifier::builder(
+ create_default_root_cert_store().into(),
+ )
+ .build()
+ .unwrap(),
+ }
}
}
-pub struct NoCertificateVerification(pub Vec<String>);
-
impl ServerCertVerifier for NoCertificateVerification {
+ fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
+ self.default_verifier.supported_verify_schemes()
+ }
+
fn verify_server_cert(
&self,
- end_entity: &Certificate,
- intermediates: &[Certificate],
- server_name: &ServerName,
- scts: &mut dyn Iterator<Item = &[u8]>,
+ end_entity: &rustls::pki_types::CertificateDer<'_>,
+ intermediates: &[rustls::pki_types::CertificateDer<'_>],
+ server_name: &rustls::pki_types::ServerName<'_>,
ocsp_response: &[u8],
- now: SystemTime,
+ now: rustls::pki_types::UnixTime,
) -> Result<ServerCertVerified, Error> {
- if self.0.is_empty() {
+ if self.ic_allowlist.is_empty() {
return Ok(ServerCertVerified::assertion());
}
let dns_name_or_ip_address = match server_name {
ServerName::DnsName(dns_name) => dns_name.as_ref().to_owned(),
- ServerName::IpAddress(ip_address) => ip_address.to_string(),
+ ServerName::IpAddress(ip_address) => {
+ Into::<IpAddr>::into(*ip_address).to_string()
+ }
_ => {
// NOTE(bartlomieju): `ServerName` is a non-exhaustive enum
// so we have this catch all errors here.
return Err(Error::General("Unknown `ServerName` variant".to_string()));
}
};
- if self.0.contains(&dns_name_or_ip_address) {
+ if self.ic_allowlist.contains(&dns_name_or_ip_address) {
Ok(ServerCertVerified::assertion())
} else {
- let root_store = create_default_root_cert_store();
- let verifier = WebPkiVerifier::new(root_store, None);
- verifier.verify_server_cert(
+ self.default_verifier.verify_server_cert(
end_entity,
intermediates,
server_name,
- scts,
ocsp_response,
now,
)
@@ -107,28 +108,32 @@ impl ServerCertVerifier for NoCertificateVerification {
fn verify_tls12_signature(
&self,
message: &[u8],
- cert: &rustls::Certificate,
+ cert: &rustls::pki_types::CertificateDer,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
- if self.0.is_empty() {
+ if self.ic_allowlist.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
filter_invalid_encoding_err(
- DefaultSignatureVerification.verify_tls12_signature(message, cert, dss),
+ self
+ .default_verifier
+ .verify_tls12_signature(message, cert, dss),
)
}
fn verify_tls13_signature(
&self,
message: &[u8],
- cert: &rustls::Certificate,
+ cert: &rustls::pki_types::CertificateDer,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
- if self.0.is_empty() {
+ if self.ic_allowlist.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
filter_invalid_encoding_err(
- DefaultSignatureVerification.verify_tls13_signature(message, cert, dss),
+ self
+ .default_verifier
+ .verify_tls13_signature(message, cert, dss),
)
}
}
@@ -149,17 +154,10 @@ pub struct BasicAuth {
}
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_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(
- |ta| {
- rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
- ta.subject,
- ta.spki,
- ta.name_constraints,
- )
- },
- ));
+ let root_cert_store = rustls::RootCertStore {
+ roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
+ };
+ debug_assert!(!root_cert_store.is_empty());
root_cert_store
}
@@ -183,10 +181,10 @@ pub fn create_client_config(
) -> Result<ClientConfig, AnyError> {
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,
- )));
+ .dangerous()
+ .with_custom_certificate_verifier(Arc::new(
+ NoCertificateVerification::new(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
@@ -194,7 +192,7 @@ pub fn create_client_config(
// or client cert".
let mut client = match maybe_cert_chain_and_key {
TlsKeys::Static(TlsKey(cert_chain, private_key)) => client_config
- .with_client_auth_cert(cert_chain, private_key)
+ .with_client_auth_cert(cert_chain, private_key.clone_key())
.expect("invalid client key or certificate"),
TlsKeys::Null => client_config.with_no_client_auth(),
TlsKeys::Resolver(_) => unimplemented!(),
@@ -204,33 +202,33 @@ pub fn create_client_config(
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.
- 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
- ));
- }
+ 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.
+ for r in rustls_pemfile::certs(reader) {
+ match r {
+ Ok(cert) => {
+ root_cert_store.add(cert)?;
+ }
+ Err(e) => {
+ return Err(anyhow!(
+ "Unable to add pem file to certificate store: {}",
+ e
+ ));
}
}
- root_cert_store
- });
+ }
+ }
+
+ let client_config =
+ ClientConfig::builder().with_root_certificates(root_cert_store);
let mut client = match maybe_cert_chain_and_key {
TlsKeys::Static(TlsKey(cert_chain, private_key)) => client_config
- .with_client_auth_cert(cert_chain, private_key)
+ .with_client_auth_cert(cert_chain, private_key.clone_key())
.expect("invalid client key or certificate"),
TlsKeys::Null => client_config.with_no_client_auth(),
TlsKeys::Resolver(_) => unimplemented!(),
@@ -257,15 +255,17 @@ fn add_alpn(client: &mut ClientConfig, socket_use: SocketUse) {
pub fn load_certs(
reader: &mut dyn BufRead,
-) -> Result<Vec<Certificate>, AnyError> {
- let certs = certs(reader)
+) -> Result<Vec<CertificateDer<'static>>, AnyError> {
+ let certs: Result<Vec<_>, _> = certs(reader).collect();
+
+ let certs = certs
.map_err(|_| custom_error("InvalidData", "Unable to decode certificate"))?;
if certs.is_empty() {
return Err(cert_not_found_err());
}
- Ok(certs.into_iter().map(rustls::Certificate).collect())
+ Ok(certs)
}
fn key_decode_err() -> AnyError {
@@ -281,21 +281,32 @@ fn cert_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.into_iter().map(rustls::PrivateKey).collect())
+fn load_rsa_keys(
+ mut bytes: &[u8],
+) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+ let keys: Result<Vec<_>, _> = rsa_private_keys(&mut bytes).collect();
+ let keys = keys.map_err(|_| key_decode_err())?;
+ Ok(keys.into_iter().map(PrivateKeyDer::Pkcs1).collect())
}
/// Starts with -----BEGIN EC PRIVATE KEY-----
-fn load_ec_keys(mut bytes: &[u8]) -> Result<Vec<PrivateKey>, AnyError> {
- let keys = ec_private_keys(&mut bytes).map_err(|_| key_decode_err())?;
- Ok(keys.into_iter().map(rustls::PrivateKey).collect())
+fn load_ec_keys(
+ mut bytes: &[u8],
+) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+ let keys: Result<Vec<_>, std::io::Error> =
+ ec_private_keys(&mut bytes).collect();
+ let keys2 = keys.map_err(|_| key_decode_err())?;
+ Ok(keys2.into_iter().map(PrivateKeyDer::Sec1).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.into_iter().map(rustls::PrivateKey).collect())
+fn load_pkcs8_keys(
+ mut bytes: &[u8],
+) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+ let keys: Result<Vec<_>, std::io::Error> =
+ pkcs8_private_keys(&mut bytes).collect();
+ let keys2 = keys.map_err(|_| key_decode_err())?;
+ Ok(keys2.into_iter().map(PrivateKeyDer::Pkcs8).collect())
}
fn filter_invalid_encoding_err(
@@ -309,7 +320,9 @@ fn filter_invalid_encoding_err(
}
}
-pub fn load_private_keys(bytes: &[u8]) -> Result<Vec<PrivateKey>, AnyError> {
+pub fn load_private_keys(
+ bytes: &[u8],
+) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
let mut keys = load_rsa_keys(bytes)?;
if keys.is_empty() {
diff --git a/ext/tls/testdata/README b/ext/tls/testdata/README
new file mode 100644
index 000000000..12046561c
--- /dev/null
+++ b/ext/tls/testdata/README
@@ -0,0 +1,4 @@
+
+openssl req -x509 -newkey rsa:2048 -nodes -keyout example2_prikey.pem -out example2_cert.der -subj "/C=US/ST=State/L=Locality/O=Organization/CN=example2.com" -outform der
+
+openssl pkey -in example2_prikey.pem -out example2_prikey.der -outform der
diff --git a/ext/tls/testdata/example1_cert.der b/ext/tls/testdata/example1_cert.der
new file mode 100644
index 000000000..fb1b2e64b
--- /dev/null
+++ b/ext/tls/testdata/example1_cert.der
Binary files differ
diff --git a/ext/tls/testdata/example1_prikey.der b/ext/tls/testdata/example1_prikey.der
new file mode 100644
index 000000000..1cf7ef1d2
--- /dev/null
+++ b/ext/tls/testdata/example1_prikey.der
Binary files differ
diff --git a/ext/tls/testdata/example2_cert.der b/ext/tls/testdata/example2_cert.der
new file mode 100644
index 000000000..4428f3f6b
--- /dev/null
+++ b/ext/tls/testdata/example2_cert.der
Binary files differ
diff --git a/ext/tls/testdata/example2_prikey.der b/ext/tls/testdata/example2_prikey.der
new file mode 100644
index 000000000..8bdef8df3
--- /dev/null
+++ b/ext/tls/testdata/example2_prikey.der
Binary files differ
diff --git a/ext/tls/tls_key.rs b/ext/tls/tls_key.rs
index 47a8e0e57..66fac86f8 100644
--- a/ext/tls/tls_key.rs
+++ b/ext/tls/tls_key.rs
@@ -11,8 +11,6 @@
//! key lookup can handle closing one end of the pair, in which case they will just
//! attempt to clean up the associated resources.
-use crate::Certificate;
-use crate::PrivateKey;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::futures::future::poll_fn;
@@ -32,12 +30,21 @@ use std::sync::Arc;
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
+use webpki::types::CertificateDer;
+use webpki::types::PrivateKeyDer;
type ErrorType = Rc<AnyError>;
/// A TLS certificate/private key pair.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct TlsKey(pub Vec<Certificate>, pub PrivateKey);
+/// see https://docs.rs/rustls-pki-types/latest/rustls_pki_types/#cloning-private-keys
+#[derive(Debug, PartialEq, Eq)]
+pub struct TlsKey(pub Vec<CertificateDer<'static>>, pub PrivateKeyDer<'static>);
+
+impl Clone for TlsKey {
+ fn clone(&self) -> Self {
+ Self(self.0.clone(), self.1.clone_key())
+ }
+}
#[derive(Clone, Debug, Default)]
pub enum TlsKeys {
@@ -111,9 +118,8 @@ impl TlsKeyResolver {
let key = self.resolve(sni).await?;
let mut tls_config = ServerConfig::builder()
- .with_safe_defaults()
.with_no_client_auth()
- .with_single_cert(key.0, key.1)?;
+ .with_single_cert(key.0, key.1.clone_key())?;
tls_config.alpn_protocols = alpn;
Ok(tls_config.into())
}
@@ -255,14 +261,18 @@ impl TlsKeyLookup {
pub mod tests {
use super::*;
use deno_core::unsync::spawn;
- use rustls::Certificate;
- use rustls::PrivateKey;
fn tls_key_for_test(sni: &str) -> TlsKey {
- TlsKey(
- vec![Certificate(format!("{sni}-cert").into_bytes())],
- PrivateKey(format!("{sni}-key").into_bytes()),
- )
+ let manifest_dir =
+ std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
+ let sni = sni.replace(".com", "");
+ let cert_file = manifest_dir.join(format!("testdata/{}_cert.der", sni));
+ let prikey_file = manifest_dir.join(format!("testdata/{}_prikey.der", sni));
+ let cert = std::fs::read(cert_file).unwrap();
+ let prikey = std::fs::read(prikey_file).unwrap();
+ let cert = CertificateDer::from(cert);
+ let prikey = PrivateKeyDer::try_from(prikey).unwrap();
+ TlsKey(vec![cert], prikey)
}
#[tokio::test]
@@ -274,8 +284,8 @@ pub mod tests {
}
});
- let key = resolver.resolve("example.com".to_owned()).await.unwrap();
- assert_eq!(tls_key_for_test("example.com"), key);
+ let key = resolver.resolve("example1.com".to_owned()).await.unwrap();
+ assert_eq!(tls_key_for_test("example1.com"), key);
drop(resolver);
task.await.unwrap();
@@ -290,13 +300,13 @@ pub mod tests {
}
});
- let f1 = resolver.resolve("example.com".to_owned());
- let f2 = resolver.resolve("example.com".to_owned());
+ let f1 = resolver.resolve("example1.com".to_owned());
+ let f2 = resolver.resolve("example1.com".to_owned());
let key = f1.await.unwrap();
- assert_eq!(tls_key_for_test("example.com"), key);
+ assert_eq!(tls_key_for_test("example1.com"), key);
let key = f2.await.unwrap();
- assert_eq!(tls_key_for_test("example.com"), key);
+ assert_eq!(tls_key_for_test("example1.com"), key);
drop(resolver);
task.await.unwrap();
diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs
index 5c3e8d7b1..9e320040b 100644
--- a/ext/websocket/lib.rs
+++ b/ext/websocket/lib.rs
@@ -36,14 +36,13 @@ use http::Request;
use http::StatusCode;
use http::Uri;
use once_cell::sync::Lazy;
+use rustls_tokio_stream::rustls::pki_types::ServerName;
use rustls_tokio_stream::rustls::RootCertStore;
-use rustls_tokio_stream::rustls::ServerName;
use rustls_tokio_stream::TlsStream;
use serde::Serialize;
use std::borrow::Cow;
use std::cell::Cell;
use std::cell::RefCell;
-use std::convert::TryFrom;
use std::fmt;
use std::future::Future;
use std::num::NonZeroUsize;
@@ -245,8 +244,8 @@ async fn handshake_http1_wss(
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
let tcp_socket = TcpStream::connect(addr).await?;
let tls_config = create_ws_client_config(state, SocketUse::Http1Only)?;
- let dnsname =
- ServerName::try_from(domain).map_err(|_| invalid_hostname(domain))?;
+ let dnsname = ServerName::try_from(domain.to_string())
+ .map_err(|_| invalid_hostname(domain))?;
let mut tls_connector = TlsStream::new_client_side(
tcp_socket,
ClientConnection::new(tls_config.into(), dnsname)?,
@@ -270,8 +269,8 @@ async fn handshake_http2_wss(
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
let tcp_socket = TcpStream::connect(addr).await?;
let tls_config = create_ws_client_config(state, SocketUse::Http2Only)?;
- let dnsname =
- ServerName::try_from(domain).map_err(|_| invalid_hostname(domain))?;
+ let dnsname = ServerName::try_from(domain.to_string())
+ .map_err(|_| invalid_hostname(domain))?;
// We need to better expose the underlying errors here
let mut tls_connector = TlsStream::new_client_side(
tcp_socket,