summaryrefslogtreecommitdiff
path: root/ext/tls
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2024-10-12 16:53:38 -0700
committerGitHub <noreply@github.com>2024-10-12 16:53:38 -0700
commit64c304a45265705832ebb4ab4e9ef19f899ac911 (patch)
treeb918bdd40b092dd26ed3a83a55369488af28121c /ext/tls
parent2ac699fe6e5b69f656046c5a9657542dc1cf2e9d (diff)
refactor(ext/tls): use concrete error types (#26174)
Diffstat (limited to 'ext/tls')
-rw-r--r--ext/tls/Cargo.toml1
-rw-r--r--ext/tls/lib.rs87
-rw-r--r--ext/tls/tls_key.rs28
3 files changed, 63 insertions, 53 deletions
diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml
index 6c1554241..9f7bffe67 100644
--- a/ext/tls/Cargo.toml
+++ b/ext/tls/Cargo.toml
@@ -21,5 +21,6 @@ rustls-pemfile.workspace = true
rustls-tokio-stream.workspace = true
rustls-webpki.workspace = true
serde.workspace = true
+thiserror.workspace = true
tokio.workspace = true
webpki-roots.workspace = true
diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs
index c4d548ccf..883d2995e 100644
--- a/ext/tls/lib.rs
+++ b/ext/tls/lib.rs
@@ -9,17 +9,12 @@ pub use rustls_tokio_stream::*;
pub use webpki;
pub use webpki_roots;
-use deno_core::anyhow::anyhow;
-use deno_core::error::custom_error;
-use deno_core::error::AnyError;
-
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::RootCertStore;
use rustls_pemfile::certs;
use rustls_pemfile::ec_private_keys;
@@ -35,12 +30,30 @@ use std::sync::Arc;
mod tls_key;
pub use tls_key::*;
+#[derive(Debug, thiserror::Error)]
+pub enum TlsError {
+ #[error(transparent)]
+ Rustls(#[from] rustls::Error),
+ #[error("Unable to add pem file to certificate store: {0}")]
+ UnableAddPemFileToCert(std::io::Error),
+ #[error("Unable to decode certificate")]
+ CertInvalid,
+ #[error("No certificates found in certificate data")]
+ CertsNotFound,
+ #[error("No keys found in key data")]
+ KeysNotFound,
+ #[error("Unable to decode key")]
+ KeyDecode,
+}
+
/// Lazily resolves the root cert store.
///
/// This was done because the root cert store is not needed in all cases
/// and takes a bit of time to initialize.
pub trait RootCertStoreProvider: Send + Sync {
- fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError>;
+ fn get_or_try_init(
+ &self,
+ ) -> Result<&RootCertStore, deno_core::error::AnyError>;
}
// This extension has no runtime apis, it only exports some shared native functions.
@@ -77,7 +90,7 @@ impl ServerCertVerifier for NoCertificateVerification {
server_name: &rustls::pki_types::ServerName<'_>,
ocsp_response: &[u8],
now: rustls::pki_types::UnixTime,
- ) -> Result<ServerCertVerified, Error> {
+ ) -> Result<ServerCertVerified, rustls::Error> {
if self.ic_allowlist.is_empty() {
return Ok(ServerCertVerified::assertion());
}
@@ -89,7 +102,9 @@ impl ServerCertVerifier for NoCertificateVerification {
_ => {
// 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()));
+ return Err(rustls::Error::General(
+ "Unknown `ServerName` variant".to_string(),
+ ));
}
};
if self.ic_allowlist.contains(&dns_name_or_ip_address) {
@@ -110,7 +125,7 @@ impl ServerCertVerifier for NoCertificateVerification {
message: &[u8],
cert: &rustls::pki_types::CertificateDer,
dss: &DigitallySignedStruct,
- ) -> Result<HandshakeSignatureValid, Error> {
+ ) -> Result<HandshakeSignatureValid, rustls::Error> {
if self.ic_allowlist.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
@@ -126,7 +141,7 @@ impl ServerCertVerifier for NoCertificateVerification {
message: &[u8],
cert: &rustls::pki_types::CertificateDer,
dss: &DigitallySignedStruct,
- ) -> Result<HandshakeSignatureValid, Error> {
+ ) -> Result<HandshakeSignatureValid, rustls::Error> {
if self.ic_allowlist.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
@@ -178,7 +193,7 @@ pub fn create_client_config(
unsafely_ignore_certificate_errors: Option<Vec<String>>,
maybe_cert_chain_and_key: TlsKeys,
socket_use: SocketUse,
-) -> Result<ClientConfig, AnyError> {
+) -> Result<ClientConfig, TlsError> {
if let Some(ic_allowlist) = unsafely_ignore_certificate_errors {
let client_config = ClientConfig::builder()
.dangerous()
@@ -214,10 +229,7 @@ pub fn create_client_config(
root_cert_store.add(cert)?;
}
Err(e) => {
- return Err(anyhow!(
- "Unable to add pem file to certificate store: {}",
- e
- ));
+ return Err(TlsError::UnableAddPemFileToCert(e));
}
}
}
@@ -255,74 +267,61 @@ fn add_alpn(client: &mut ClientConfig, socket_use: SocketUse) {
pub fn load_certs(
reader: &mut dyn BufRead,
-) -> Result<Vec<CertificateDer<'static>>, AnyError> {
+) -> Result<Vec<CertificateDer<'static>>, TlsError> {
let certs: Result<Vec<_>, _> = certs(reader).collect();
- let certs = certs
- .map_err(|_| custom_error("InvalidData", "Unable to decode certificate"))?;
+ let certs = certs.map_err(|_| TlsError::CertInvalid)?;
if certs.is_empty() {
- return Err(cert_not_found_err());
+ return Err(TlsError::CertsNotFound);
}
Ok(certs)
}
-fn key_decode_err() -> AnyError {
- custom_error("InvalidData", "Unable to decode key")
-}
-
-fn key_not_found_err() -> AnyError {
- custom_error("InvalidData", "No keys found in key data")
-}
-
-fn cert_not_found_err() -> AnyError {
- custom_error("InvalidData", "No certificates found in certificate data")
-}
-
/// Starts with -----BEGIN RSA PRIVATE KEY-----
fn load_rsa_keys(
mut bytes: &[u8],
-) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+) -> Result<Vec<PrivateKeyDer<'static>>, TlsError> {
let keys: Result<Vec<_>, _> = rsa_private_keys(&mut bytes).collect();
- let keys = keys.map_err(|_| key_decode_err())?;
+ let keys = keys.map_err(|_| TlsError::KeyDecode)?;
Ok(keys.into_iter().map(PrivateKeyDer::Pkcs1).collect())
}
/// Starts with -----BEGIN EC PRIVATE KEY-----
fn load_ec_keys(
mut bytes: &[u8],
-) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+) -> Result<Vec<PrivateKeyDer<'static>>, TlsError> {
let keys: Result<Vec<_>, std::io::Error> =
ec_private_keys(&mut bytes).collect();
- let keys2 = keys.map_err(|_| key_decode_err())?;
+ let keys2 = keys.map_err(|_| TlsError::KeyDecode)?;
Ok(keys2.into_iter().map(PrivateKeyDer::Sec1).collect())
}
/// Starts with -----BEGIN PRIVATE KEY-----
fn load_pkcs8_keys(
mut bytes: &[u8],
-) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+) -> Result<Vec<PrivateKeyDer<'static>>, TlsError> {
let keys: Result<Vec<_>, std::io::Error> =
pkcs8_private_keys(&mut bytes).collect();
- let keys2 = keys.map_err(|_| key_decode_err())?;
+ let keys2 = keys.map_err(|_| TlsError::KeyDecode)?;
Ok(keys2.into_iter().map(PrivateKeyDer::Pkcs8).collect())
}
fn filter_invalid_encoding_err(
- to_be_filtered: Result<HandshakeSignatureValid, Error>,
-) -> Result<HandshakeSignatureValid, Error> {
+ to_be_filtered: Result<HandshakeSignatureValid, rustls::Error>,
+) -> Result<HandshakeSignatureValid, rustls::Error> {
match to_be_filtered {
- Err(Error::InvalidCertificate(rustls::CertificateError::BadEncoding)) => {
- Ok(HandshakeSignatureValid::assertion())
- }
+ Err(rustls::Error::InvalidCertificate(
+ rustls::CertificateError::BadEncoding,
+ )) => Ok(HandshakeSignatureValid::assertion()),
res => res,
}
}
pub fn load_private_keys(
bytes: &[u8],
-) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
+) -> Result<Vec<PrivateKeyDer<'static>>, TlsError> {
let mut keys = load_rsa_keys(bytes)?;
if keys.is_empty() {
@@ -334,7 +333,7 @@ pub fn load_private_keys(
}
if keys.is_empty() {
- return Err(key_not_found_err());
+ return Err(TlsError::KeysNotFound);
}
Ok(keys)
diff --git a/ext/tls/tls_key.rs b/ext/tls/tls_key.rs
index 66fac86f8..b7baa604b 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 deno_core::anyhow::anyhow;
-use deno_core::error::AnyError;
use deno_core::futures::future::poll_fn;
use deno_core::futures::future::Either;
use deno_core::futures::FutureExt;
@@ -33,7 +31,19 @@ use tokio::sync::oneshot;
use webpki::types::CertificateDer;
use webpki::types::PrivateKeyDer;
-type ErrorType = Rc<AnyError>;
+#[derive(Debug, thiserror::Error)]
+pub enum TlsKeyError {
+ #[error(transparent)]
+ Rustls(#[from] rustls::Error),
+ #[error("Failed: {0}")]
+ Failed(ErrorType),
+ #[error(transparent)]
+ JoinError(#[from] tokio::task::JoinError),
+ #[error(transparent)]
+ RecvError(#[from] tokio::sync::broadcast::error::RecvError),
+}
+
+type ErrorType = Arc<Box<str>>;
/// A TLS certificate/private key pair.
/// see https://docs.rs/rustls-pki-types/latest/rustls_pki_types/#cloning-private-keys
@@ -114,7 +124,7 @@ impl TlsKeyResolver {
&self,
sni: String,
alpn: Vec<Vec<u8>>,
- ) -> Result<Arc<ServerConfig>, AnyError> {
+ ) -> Result<Arc<ServerConfig>, TlsKeyError> {
let key = self.resolve(sni).await?;
let mut tls_config = ServerConfig::builder()
@@ -183,7 +193,7 @@ impl TlsKeyResolver {
pub fn resolve(
&self,
sni: String,
- ) -> impl Future<Output = Result<TlsKey, AnyError>> {
+ ) -> impl Future<Output = Result<TlsKey, TlsKeyError>> {
let mut cache = self.inner.cache.borrow_mut();
let mut recv = match cache.get(&sni) {
None => {
@@ -194,7 +204,7 @@ impl TlsKeyResolver {
}
Some(TlsKeyState::Resolving(recv)) => recv.resubscribe(),
Some(TlsKeyState::Resolved(res)) => {
- return Either::Left(ready(res.clone().map_err(|_| anyhow!("Failed"))));
+ return Either::Left(ready(res.clone().map_err(TlsKeyError::Failed)));
}
};
drop(cache);
@@ -212,7 +222,7 @@ impl TlsKeyResolver {
// Someone beat us to it
}
}
- res.map_err(|_| anyhow!("Failed"))
+ res.map_err(TlsKeyError::Failed)
});
Either::Right(async move { handle.await? })
}
@@ -247,13 +257,13 @@ impl TlsKeyLookup {
}
/// Resolve a previously polled item.
- pub fn resolve(&self, sni: String, res: Result<TlsKey, AnyError>) {
+ pub fn resolve(&self, sni: String, res: Result<TlsKey, String>) {
_ = self
.pending
.borrow_mut()
.remove(&sni)
.unwrap()
- .send(res.map_err(Rc::new));
+ .send(res.map_err(|e| Arc::new(e.into_boxed_str())));
}
}