Skip to content

Commit

Permalink
Update rustls to v0.22 and related dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
paolobarbolini committed Dec 7, 2023
1 parent 02672fa commit 4f1a125
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 97 deletions.
11 changes: 4 additions & 7 deletions async-nats/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,19 @@ serde_json = "1.0.104"
serde_repr = "0.1.16"
tokio = { version = "1.29.0", features = ["macros", "rt", "fs", "net", "sync", "time", "io-util"] }
url = { version = "2"}
tokio-rustls = "0.24"
rustls-pemfile = "1.0.2"
tokio-rustls = "0.25"
rustls-pemfile = "2"
nuid = "0.5"
serde_nanos = "0.1.3"
time = { version = "0.3.24", features = ["parsing", "formatting", "serde", "serde-well-known"] }
rustls-native-certs = "0.6"
rustls-native-certs = "0.7"
tracing = "0.1"
thiserror = "1.0"
base64 = "0.21"
tokio-retry = "0.3"
ring = "0.17"
rand = "0.8"
webpki = { package = "rustls-webpki", version = "0.101.2", features = ["alloc", "std"] }

# for -Z minimal-versions
rustls = "0.21.6" # used by tokio-rustls 0.24.0
webpki = { package = "rustls-webpki", version = "0.102" }

[dev-dependencies]
criterion = { version = "0.5", features = ["async_tokio"]}
Expand Down
16 changes: 5 additions & 11 deletions async-nats/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use std::io;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use tokio::io::ErrorKind;
use tokio::net::TcpStream;
use tokio::time::sleep;
use tokio_rustls::rustls;
Expand Down Expand Up @@ -306,19 +305,14 @@ impl Connector {
.await
.map_err(|err| ConnectError::with_source(crate::ConnectErrorKind::Tls, err))?,
);
let tls_connector = tokio_rustls::TlsConnector::try_from(tls_config)
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("failed to create TLS connector from TLS config: {err}"),
)
})
.map_err(|err| ConnectError::with_source(crate::ConnectErrorKind::Tls, err))?;
let tls_connector = tokio_rustls::TlsConnector::from(tls_config);

let domain = rustls::ServerName::try_from(tls_host)
let domain = webpki::types::ServerName::try_from(tls_host)
.map_err(|err| ConnectError::with_source(crate::ConnectErrorKind::Tls, err))?;

let tls_stream = tls_connector.connect(domain, connection.stream).await?;
let tls_stream = tls_connector
.connect(domain.to_owned(), connection.stream)
.await?;

Ok::<Connection, ConnectError>(Connection::new(Box::new(tls_stream), 0))
};
Expand Down
9 changes: 1 addition & 8 deletions async-nats/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,16 +845,9 @@ impl ConnectOptions {
/// # async fn main() -> Result<(), async_nats::Error> {
/// let mut root_store = async_nats::rustls::RootCertStore::empty();
///
/// root_store.add_parsable_certificates(
/// rustls_native_certs::load_native_certs()?
/// .into_iter()
/// .map(|cert| cert.0)
/// .collect::<Vec<Vec<u8>>>()
/// .as_ref(),
/// );
/// root_store.add_parsable_certificates(rustls_native_certs::load_native_certs()?);
///
/// let tls_client = async_nats::rustls::ClientConfig::builder()
/// .with_safe_defaults()
/// .with_root_certificates(root_store)
/// .with_no_client_auth();
///
Expand Down
92 changes: 30 additions & 62 deletions async-nats/src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,48 @@

use crate::connector::ConnectorOptions;
use crate::tls;
use std::fs::File;
use std::io::{self, BufReader, ErrorKind};
use std::path::PathBuf;
use tokio_rustls::rustls::{self, Certificate, OwnedTrustAnchor, PrivateKey};
use webpki::TrustAnchor;
use tokio_rustls::rustls::{ClientConfig, RootCertStore};
use webpki::types::{CertificateDer, PrivateKeyDer};

/// Loads client certificates from a `.pem` file.
/// If the pem file is found, but does not contain any certificates, it will return
/// empty set of Certificates, not error.
/// Can be used to parse only client certificates from .pem file containing both client key and certs.
pub(crate) async fn load_certs(path: PathBuf) -> io::Result<Vec<Certificate>> {
pub(crate) async fn load_certs(path: PathBuf) -> io::Result<Vec<CertificateDer<'static>>> {
tokio::task::spawn_blocking(move || {
let file = std::fs::File::open(path)?;
let mut reader = BufReader::new(file);
let certs = rustls_pemfile::certs(&mut reader)?
.into_iter()
.map(Certificate)
.collect();
Ok(certs)
rustls_pemfile::certs(&mut reader).collect::<io::Result<Vec<_>>>()
})
.await?
}

/// Loads client key from a `.pem` file.
/// Can be used to parse only client key from .pem file containing both client key and certs.
pub(crate) async fn load_key(path: PathBuf) -> io::Result<PrivateKey> {
pub(crate) async fn load_key(path: PathBuf) -> io::Result<PrivateKeyDer<'static>> {
tokio::task::spawn_blocking(move || {
let file = std::fs::File::open(path)?;
let mut reader = BufReader::new(file);

loop {
match rustls_pemfile::read_one(&mut reader)? {
Some(rustls_pemfile::Item::RSAKey(key))
| Some(rustls_pemfile::Item::PKCS8Key(key))
| Some(rustls_pemfile::Item::ECKey(key)) => return Ok(PrivateKey(key)),
// if public key is found, don't error, just skip it and hope to find client key next.
Some(rustls_pemfile::Item::X509Certificate(_)) | Some(_) => {}
None => break,
}
}

Err(io::Error::new(
ErrorKind::NotFound,
"could not find client key in the path",
))
rustls_pemfile::private_key(&mut reader)?.ok_or_else(|| {
io::Error::new(ErrorKind::NotFound, "could not find client key in the path")
})
})
.await?
}

pub(crate) async fn config_tls(options: &ConnectorOptions) -> io::Result<rustls::ClientConfig> {
let mut root_store = tokio_rustls::rustls::RootCertStore::empty();
pub(crate) async fn config_tls(options: &ConnectorOptions) -> io::Result<ClientConfig> {
let mut root_store = RootCertStore::empty();
// load native system certs only if user did not specify them.
if options.tls_client_config.is_some() || options.certificates.is_empty() {
root_store.add_parsable_certificates(
rustls_native_certs::load_native_certs()
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("could not load platform certs: {err}"),
)
})?
.into_iter()
.map(|cert| cert.0)
.collect::<Vec<Vec<u8>>>()
.as_slice(),
);
let certs_iter = rustls_native_certs::load_native_certs().map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("could not load platform certs: {err}"),
)
})?;
root_store.add_parsable_certificates(certs_iter);
}

// use provided ClientConfig or built it from options.
Expand All @@ -88,28 +64,20 @@ pub(crate) async fn config_tls(options: &ConnectorOptions) -> io::Result<rustls:
} else {
// Include user-provided certificates.
for cafile in &options.certificates {
let mut pem = BufReader::new(File::open(cafile)?);
let certs = rustls_pemfile::certs(&mut pem)?;
let trust_anchors = certs.iter().map(|cert| {
let ta = TrustAnchor::try_from_cert_der(&cert[..])
.map_err(|err| {
io::Error::new(
ErrorKind::InvalidInput,
format!("could not load certs: {err}"),
)
})
.unwrap();
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
});
root_store.add_trust_anchors(trust_anchors);
let trust_anchors = load_certs(cafile.to_owned())
.await?
.into_iter()
.map(|cert| webpki::anchor_from_trusted_cert(&cert).map(|ta| ta.to_owned()))
.collect::<Result<Vec<_>, webpki::Error>>()
.map_err(|err| {
io::Error::new(
ErrorKind::InvalidInput,
format!("could not load certs: {err}"),
)
})?;
root_store.extend(trust_anchors);
}
let builder = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store);
let builder = ClientConfig::builder().with_root_certificates(root_store);
if let Some(cert) = options.client_cert.clone() {
if let Some(key) = options.client_key.clone() {
let key = tls::load_key(key).await?;
Expand Down
10 changes: 1 addition & 9 deletions async-nats/tests/tls_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,9 @@ mod client {
async fn custom_tls_client() {
let mut root_store = async_nats::rustls::RootCertStore::empty();

root_store.add_parsable_certificates(
rustls_native_certs::load_native_certs()
.unwrap()
.into_iter()
.map(|cert| cert.0)
.collect::<Vec<Vec<u8>>>()
.as_ref(),
);
root_store.add_parsable_certificates(rustls_native_certs::load_native_certs().unwrap());

let tls_client = async_nats::rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();

Expand Down

0 comments on commit 4f1a125

Please sign in to comment.