diff --git a/Cargo.lock b/Cargo.lock index 76c7eea3d..9522b1b68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,7 +184,7 @@ dependencies = [ "pin-project-lite", "rustls-native-certs", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", ] @@ -1835,13 +1835,13 @@ dependencies = [ "pretty_assertions", "pretty_env_logger", "rustls-native-certs", - "rustls-pemfile", - "rustls-webpki", + "rustls-pemfile 1.0.4", + "rustls-webpki 0.101.7", "serde", "thiserror", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "url", "ws_stream_tungstenite", ] @@ -1863,15 +1863,15 @@ dependencies = [ "pretty_assertions", "pretty_env_logger", "rand", - "rustls-pemfile", - "rustls-webpki", + "rustls-pemfile 2.0.0", + "rustls-webpki 0.102.2", "serde", "serde_json", "slab", "thiserror", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.25.0", "tokio-util", "tracing", "tracing-subscriber", @@ -1934,10 +1934,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -1945,7 +1959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] @@ -1959,6 +1973,22 @@ dependencies = [ "base64 0.21.5", ] +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64 0.21.5", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -1969,6 +1999,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -2207,6 +2248,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "symbolic-common" version = "12.8.0" @@ -2412,7 +2459,18 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.10", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.2", + "rustls-pki-types", "tokio", ] @@ -2548,7 +2606,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.10", "sha1", "thiserror", "url", @@ -2972,3 +3030,9 @@ dependencies = [ "quote", "syn 2.0.40", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/rumqttd/CHANGELOG.md b/rumqttd/CHANGELOG.md index 6088c2b23..e429b0a72 100644 --- a/rumqttd/CHANGELOG.md +++ b/rumqttd/CHANGELOG.md @@ -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 diff --git a/rumqttd/Cargo.toml b/rumqttd/Cargo.toml index e8d96dfbc..62c9f5f51 100644 --- a/rumqttd/Cargo.toml +++ b/rumqttd/Cargo.toml @@ -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} diff --git a/rumqttd/src/link/bridge.rs b/rumqttd/src/link/bridge.rs index 7898ac5df..05bc7b741 100644 --- a/rumqttd/src/link/bridge.rs +++ b/rumqttd/src/link/bridge.rs @@ -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, }; @@ -198,28 +198,15 @@ pub async fn tls_connect>( ) -> Result, 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::, _>>()?; + 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, @@ -227,33 +214,34 @@ pub async fn tls_connect>( }) = 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::, _>>()?; - 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?)) } diff --git a/rumqttd/src/server/tls.rs b/rumqttd/src/server/tls.rs index d402c8440..528655e53 100644 --- a/rumqttd/src/server/tls.rs +++ b/rumqttd/src/server/tls.rs @@ -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, }; @@ -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 = None; @@ -200,12 +200,9 @@ 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::, _>>() + .map_err(|_| Error::InvalidServerCert(cert_path.to_string()))?; // Get private key let key = first_private_key_in_pemfile(key_path)?; @@ -213,7 +210,7 @@ impl TLSAcceptor { (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")] @@ -221,15 +218,14 @@ impl TLSAcceptor { 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::, _>>()?; + 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))) @@ -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 { +fn first_private_key_in_pemfile(key_path: &String) -> Result, Error> { // Get private key let key_file = File::open(key_path); let key_file = key_file.map_err(|_| Error::ServerKeyNotFound(key_path.clone()))?; @@ -262,8 +258,14 @@ fn first_private_key_in_pemfile(key_path: &String) -> Result })?; 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);