summaryrefslogtreecommitdiff
path: root/extensions/net/ops_tls.rs
diff options
context:
space:
mode:
authorJustin Chase <justin.m.chase@gmail.com>2021-08-07 07:49:38 -0500
committerGitHub <noreply@github.com>2021-08-07 14:49:38 +0200
commit02c74fb70970fcadb7d1e6dab857eeb2cea20e09 (patch)
tree03a1490e063bca34be660eee73bccc8342b0bff2 /extensions/net/ops_tls.rs
parentfddeb4cea2687b32a32f7829f336b7cf5092c714 (diff)
feat(tls): Optionally support loading native certs (#11491)
This commit adds "DENO_TLS_CA_STORE" env variable to support optionally loading certificates from the users local certificate store. This will allow them to successfully connect via tls with corporate and self signed certs provided they have them installed in their keystore. It also allows them to deal with revoked certs by simply updating their keystore without having to upgrade Deno. Currently supported values are "mozilla", "system" or empty value.
Diffstat (limited to 'extensions/net/ops_tls.rs')
-rw-r--r--extensions/net/ops_tls.rs128
1 files changed, 46 insertions, 82 deletions
diff --git a/extensions/net/ops_tls.rs b/extensions/net/ops_tls.rs
index a082f7f62..124da2f03 100644
--- a/extensions/net/ops_tls.rs
+++ b/extensions/net/ops_tls.rs
@@ -1,8 +1,5 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-pub use rustls;
-pub use webpki;
-
use crate::io::TcpStreamResource;
use crate::io::TlsStreamResource;
use crate::ops::IpAddr;
@@ -38,30 +35,29 @@ use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
+use deno_tls::create_client_config;
+use deno_tls::rustls::internal::pemfile::certs;
+use deno_tls::rustls::internal::pemfile::pkcs8_private_keys;
+use deno_tls::rustls::internal::pemfile::rsa_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::PrivateKey;
+use deno_tls::rustls::ServerConfig;
+use deno_tls::rustls::ServerSession;
+use deno_tls::rustls::Session;
+use deno_tls::webpki::DNSNameRef;
use io::Error;
use io::Read;
use io::Write;
-use rustls::internal::pemfile::certs;
-use rustls::internal::pemfile::pkcs8_private_keys;
-use rustls::internal::pemfile::rsa_private_keys;
-use rustls::Certificate;
-use rustls::ClientConfig;
-use rustls::ClientSession;
-use rustls::NoClientAuth;
-use rustls::PrivateKey;
-use rustls::ServerConfig;
-use rustls::ServerSession;
-use rustls::Session;
-use rustls::StoresClientSessions;
use serde::Deserialize;
use std::borrow::Cow;
use std::cell::RefCell;
-use std::collections::HashMap;
use std::convert::From;
use std::fs::File;
use std::io;
use std::io::BufReader;
-use std::io::Cursor;
use std::io::ErrorKind;
use std::ops::Deref;
use std::ops::DerefMut;
@@ -76,32 +72,6 @@ use tokio::io::ReadBuf;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
use tokio::task::spawn_local;
-use webpki::DNSNameRef;
-
-lazy_static::lazy_static! {
- static ref CLIENT_SESSION_MEMORY_CACHE: Arc<ClientSessionMemoryCache> =
- Arc::new(ClientSessionMemoryCache::default());
-}
-
-#[derive(Default)]
-struct ClientSessionMemoryCache(Mutex<HashMap<Vec<u8>, Vec<u8>>>);
-
-impl StoresClientSessions for ClientSessionMemoryCache {
- fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
- self.0.lock().get(key).cloned()
- }
-
- fn put(&self, key: Vec<u8>, value: Vec<u8>) -> 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
- }
-}
#[derive(Debug)]
enum TlsSession {
@@ -703,8 +673,6 @@ where
n => n,
};
let cert_file = args.cert_file.as_deref();
-
- let default_tls_options;
{
super::check_unstable2(&state, "Deno.startTls");
let mut s = state.borrow_mut();
@@ -713,12 +681,28 @@ where
if let Some(path) = cert_file {
permissions.check_read(Path::new(path))?;
}
- default_tls_options = s.borrow::<DefaultTlsOptions>().clone();
}
+ let ca_data = match cert_file {
+ Some(path) => {
+ let mut buf = Vec::new();
+ File::open(path)?.read_to_end(&mut buf)?;
+ Some(buf)
+ }
+ _ => None,
+ };
+
let hostname_dns = DNSNameRef::try_from_ascii_str(hostname)
.map_err(|_| invalid_hostname(hostname))?;
+ // TODO(@justinmchase): Ideally the certificate store is created once
+ // and not cloned. The store should be wrapped in Arc<T> to reduce
+ // copying memory unnecessarily.
+ let root_cert_store = state
+ .borrow()
+ .borrow::<DefaultTlsOptions>()
+ .root_cert_store
+ .clone();
let resource_rc = state
.borrow_mut()
.resource_table
@@ -732,22 +716,7 @@ where
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
- let mut tls_config = ClientConfig::new();
- tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone());
- tls_config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(ca_data) = default_tls_options.ca_data {
- let reader = &mut Cursor::new(ca_data);
- tls_config.root_store.add_pem_file(reader).unwrap();
- };
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- tls_config.root_store.add_pem_file(reader).unwrap();
- }
- let tls_config = Arc::new(tls_config);
-
+ let tls_config = Arc::new(create_client_config(root_cert_store, ca_data)?);
let tls_stream =
TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns);
@@ -786,8 +755,6 @@ where
};
let port = args.port;
let cert_file = args.cert_file.as_deref();
-
- let default_tls_options;
{
let mut s = state.borrow_mut();
let permissions = s.borrow_mut::<NP>();
@@ -795,9 +762,22 @@ where
if let Some(path) = cert_file {
permissions.check_read(Path::new(path))?;
}
- default_tls_options = s.borrow::<DefaultTlsOptions>().clone();
}
+ let ca_data = match cert_file {
+ Some(path) => {
+ let mut buf = Vec::new();
+ File::open(path)?.read_to_end(&mut buf)?;
+ Some(buf)
+ }
+ _ => None,
+ };
+
+ let root_cert_store = state
+ .borrow()
+ .borrow::<DefaultTlsOptions>()
+ .root_cert_store
+ .clone();
let hostname_dns = DNSNameRef::try_from_ascii_str(hostname)
.map_err(|_| invalid_hostname(hostname))?;
@@ -808,23 +788,7 @@ where
let tcp_stream = TcpStream::connect(connect_addr).await?;
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
-
- let mut tls_config = ClientConfig::new();
- tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone());
- tls_config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(ca_data) = default_tls_options.ca_data {
- let reader = &mut Cursor::new(ca_data);
- tls_config.root_store.add_pem_file(reader).unwrap();
- };
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- tls_config.root_store.add_pem_file(reader).unwrap();
- }
- let tls_config = Arc::new(tls_config);
-
+ let tls_config = Arc::new(create_client_config(root_cert_store, ca_data)?);
let tls_stream =
TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns);