Skip to content

Commit

Permalink
chore(rumqttd): Update rustls and friends.
Browse files Browse the repository at this point in the history
  • Loading branch information
qwandor committed Feb 9, 2024
1 parent c719181 commit 4be351d
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 67 deletions.
86 changes: 75 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions rumqttd/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Public re-export `Strategy` for shared subscriptions
- Peer initiated disconnects logged as info rather than error.
- Update `tokio-rustls` to `0.25.0`, `rustls-webpki` to `0.102.1`, `tokio-native-tls` to `0.3.1` and
`rust-pemfile` to `2.0.0`.

### Deprecated

Expand Down
8 changes: 4 additions & 4 deletions rumqttd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ flume = { version = "0.11.0", default-features = false, features = ["async"]}
slab = "0.4.9"
thiserror = "1.0.49"
tokio-util = { version = "0.7", features = ["codec"], optional = true }
tokio-rustls = { version = "0.24", optional = true }
rustls-webpki = { version = "0.101.6", optional = true }
tokio-native-tls = { version = "0.3", optional = true }
rustls-pemfile = { version = "1", optional = true }
tokio-rustls = { version = "0.25.0", optional = true }
rustls-webpki = { version = "0.102.1", optional = true }
tokio-native-tls = { version = "0.3.1", optional = true }
rustls-pemfile = { version = "2.0.0", optional = true }
async-tungstenite = { version = "0.23", default-features = false, features = ["tokio-runtime"], optional = true }
ws_stream_tungstenite = { version= "0.11", default-features = false, features = ["tokio_io"], optional = true }
x509-parser = {version= "0.15.1", optional = true}
Expand Down
54 changes: 21 additions & 33 deletions rumqttd/src/link/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use tokio::{
#[cfg(feature = "use-rustls")]
use tokio_rustls::{
rustls::{
client::InvalidDnsNameError, Certificate, ClientConfig, Error as TLSError,
OwnedTrustAnchor, PrivateKey, RootCertStore, ServerName,
pki_types::{InvalidDnsNameError, ServerName},
ClientConfig, Error as TLSError, RootCertStore,
},
TlsConnector,
};
Expand Down Expand Up @@ -198,62 +198,50 @@ pub async fn tls_connect<P: AsRef<Path>>(
) -> Result<Box<dyn N>, BridgeError> {
let mut root_cert_store = RootCertStore::empty();

let ca_certs = rustls_pemfile::certs(&mut BufReader::new(Cursor::new(fs::read(ca_file)?)))?;
let trust_anchors = ca_certs.iter().map_while(|cert| {
if let Ok(ta) = webpki::TrustAnchor::try_from_cert_der(&cert[..]) {
Some(OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
))
} else {
None
}
});

root_cert_store.add_trust_anchors(trust_anchors);
let ca_certs = rustls_pemfile::certs(&mut BufReader::new(Cursor::new(fs::read(ca_file)?)))
.collect::<Result<Vec<_>, _>>()?;
root_cert_store.add_parsable_certificates(ca_certs);

if root_cert_store.is_empty() {
return Err(BridgeError::NoValidCertInChain);
}

let config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_cert_store);
let config = ClientConfig::builder().with_root_certificates(root_cert_store);

let config = if let Some(ClientAuth {
certs: certs_path,
key: key_path,
}) = client_auth_opt
{
let read_certs =
rustls_pemfile::certs(&mut BufReader::new(Cursor::new(fs::read(certs_path)?)))?;
rustls_pemfile::certs(&mut BufReader::new(Cursor::new(fs::read(certs_path)?)))
.collect::<Result<Vec<_>, _>>()?;

let read_keys = match rustls_pemfile::read_one(&mut BufReader::new(Cursor::new(fs::read(
let read_key = match rustls_pemfile::read_one(&mut BufReader::new(Cursor::new(fs::read(
key_path,
)?)))? {
Some(rustls_pemfile::Item::RSAKey(_)) => rustls_pemfile::rsa_private_keys(
Some(rustls_pemfile::Item::Pkcs1Key(_)) => rustls_pemfile::rsa_private_keys(
&mut BufReader::new(Cursor::new(fs::read(key_path)?)),
)?,
Some(rustls_pemfile::Item::PKCS8Key(_)) => rustls_pemfile::pkcs8_private_keys(
)
.next()
.ok_or(BridgeError::NoValidCertInChain)??
.into(),
Some(rustls_pemfile::Item::Pkcs8Key(_)) => rustls_pemfile::pkcs8_private_keys(
&mut BufReader::new(Cursor::new(fs::read(key_path)?)),
)?,
)
.next()
.ok_or(BridgeError::NoValidCertInChain)??
.into(),
None | Some(_) => return Err(BridgeError::NoValidCertInChain),
};

let read_key = match read_keys.first() {
Some(v) => v.clone(),
None => return Err(BridgeError::NoValidCertInChain),
};

let certs = read_certs.into_iter().map(Certificate).collect();
config.with_client_auth_cert(certs, PrivateKey(read_key))?
config.with_client_auth_cert(read_certs, read_key)?
} else {
config.with_no_client_auth()
};

let connector = TlsConnector::from(Arc::new(config));
let domain = ServerName::try_from(host).unwrap();
let domain = ServerName::try_from(host).unwrap().to_owned();
Ok(Box::new(connector.connect(domain, tcp).await?))
}

Expand Down
40 changes: 21 additions & 19 deletions rumqttd/src/server/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use {

use crate::TlsConfig;
#[cfg(feature = "verify-client-cert")]
use tokio_rustls::rustls::{server::AllowAnyAuthenticatedClient, RootCertStore};
use tokio_rustls::rustls::RootCertStore;
#[cfg(feature = "use-rustls")]
use {
rustls_pemfile::Item,
std::{io::BufReader, sync::Arc},
tokio_rustls::rustls::{Certificate, Error as RustlsError, PrivateKey, ServerConfig},
tokio_rustls::rustls::{pki_types::PrivateKeyDer, Error as RustlsError, ServerConfig},
tracing::error,
};

Expand Down Expand Up @@ -127,7 +127,7 @@ impl TLSAcceptor {
let peer_certificates = session
.peer_certificates()
.ok_or(Error::NoPeerCertificate)?;
extract_tenant_id(&peer_certificates[0].0)?
extract_tenant_id(&peer_certificates[0])?
};
#[cfg(not(feature = "verify-client-cert"))]
let tenant_id: Option<String> = None;
Expand Down Expand Up @@ -200,36 +200,32 @@ impl TLSAcceptor {
// Get certificates
let cert_file = File::open(cert_path);
let cert_file = cert_file.map_err(|_| Error::ServerCertNotFound(cert_path.clone()))?;
let certs = rustls_pemfile::certs(&mut BufReader::new(cert_file));
let certs = certs.map_err(|_| Error::InvalidServerCert(cert_path.to_string()))?;
let certs = certs
.iter()
.map(|cert| Certificate(cert.to_owned()))
.collect();
let certs = rustls_pemfile::certs(&mut BufReader::new(cert_file))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| Error::InvalidServerCert(cert_path.to_string()))?;

// Get private key
let key = first_private_key_in_pemfile(key_path)?;

(certs, key)
};

let builder = ServerConfig::builder().with_safe_defaults();
let builder = ServerConfig::builder();

// client authentication with a CA. CA isn't required otherwise
#[cfg(feature = "verify-client-cert")]
let builder = {
let ca_file = File::open(ca_path);
let ca_file = ca_file.map_err(|_| Error::CaFileNotFound(ca_path.clone()))?;
let ca_file = &mut BufReader::new(ca_file);
let ca_certs = rustls_pemfile::certs(ca_file)?;
let ca_cert = ca_certs
.first()
.map(|c| Certificate(c.to_owned()))
.ok_or_else(|| Error::InvalidCACert(ca_path.to_string()))?;
let ca_certs = rustls_pemfile::certs(ca_file).collect::<Result<Vec<_>, _>>()?;
let [ca_cert, ..] = ca_certs[..] else {
return Err(Error::InvalidCACert(ca_path.to_string()));
};

let mut store = RootCertStore::empty();
store
.add(&ca_cert)
.add(ca_cert)
.map_err(|_| Error::InvalidCACert(ca_path.to_string()))?;

builder.with_client_cert_verifier(Arc::new(AllowAnyAuthenticatedClient::new(store)))
Expand All @@ -247,7 +243,7 @@ impl TLSAcceptor {

#[cfg(feature = "use-rustls")]
/// Get the first private key in a PEM file
fn first_private_key_in_pemfile(key_path: &String) -> Result<PrivateKey, Error> {
fn first_private_key_in_pemfile(key_path: &String) -> Result<PrivateKeyDer<'static>, Error> {
// Get private key
let key_file = File::open(key_path);
let key_file = key_file.map_err(|_| Error::ServerKeyNotFound(key_path.clone()))?;
Expand All @@ -262,8 +258,14 @@ fn first_private_key_in_pemfile(key_path: &String) -> Result<PrivateKey, Error>
})?;

match item {
Some(Item::ECKey(key) | Item::RSAKey(key) | Item::PKCS8Key(key)) => {
return Ok(PrivateKey(key));
Some(Item::Sec1Key(key)) => {
return Ok(key.into());
}
Some(Item::Pkcs1Key(key)) => {
return Ok(key.into());
}
Some(Item::Pkcs8Key(key)) => {
return Ok(key.into());
}
None => {
error!("No private key found in {:?}", key_path);
Expand Down

0 comments on commit 4be351d

Please sign in to comment.