From 76deac271137823b999aabf99f6ef65627b9c25a Mon Sep 17 00:00:00 2001 From: Galileo Daras Date: Thu, 4 Apr 2024 13:57:26 -0400 Subject: [PATCH 1/7] Switch tokio-native-tls -> tokio-rustls - Resolves problem unique to macOS's SecureTransport resulting in users seeing: a TLS error occurred: Unknown format in import. - Enables using PEM with certificates and private key side-by-side --- Cargo.lock | 251 ++++++++++++++++++++++++++++++- data/src/server.rs | 1 + irc/Cargo.toml | 4 +- irc/src/connection.rs | 128 +++++++++++++--- irc/src/invalid_cert_verifier.rs | 58 +++++++ irc/src/lib.rs | 1 + 6 files changed, 418 insertions(+), 25 deletions(-) create mode 100644 irc/src/invalid_cert_verifier.rs diff --git a/Cargo.lock b/Cargo.lock index 538d0cbd4..fb2d50d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,6 +397,32 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aws-lc-rs" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f379c4e505c0692333bd90a334baa234990faa06bdabefd3261f765946aa920" +dependencies = [ + "aws-lc-sys", + "mirai-annotations", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68aa3d613f42dbf301dbbcaf3dc260805fd33ffd95f6d290ad7231a9e5d877a7" +dependencies = [ + "bindgen", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -418,6 +444,29 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.55", + "which", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -587,6 +636,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -620,6 +678,17 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading 0.8.3", +] + [[package]] name = "clipboard-win" version = "5.3.0" @@ -659,6 +728,15 @@ dependencies = [ "x11rb", ] +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + [[package]] name = "cocoa" version = "0.25.0" @@ -1098,6 +1176,12 @@ dependencies = [ "linux-raw-sys 0.6.4", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "either" version = "1.10.0" @@ -1414,6 +1498,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.30" @@ -1596,6 +1686,12 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "glow" version = "0.13.1" @@ -1802,6 +1898,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "1.1.0" @@ -2159,9 +2264,11 @@ dependencies = [ "bytes", "futures", "irc_proto", + "rustls-native-certs", + "rustls-pemfile 2.1.1", "thiserror", "tokio", - "tokio-native-tls", + "tokio-rustls", "tokio-util", ] @@ -2308,6 +2415,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "lebe" version = "0.5.2" @@ -2520,6 +2633,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mirai-annotations" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" + [[package]] name = "mutate_once" version = "0.1.1" @@ -3136,6 +3255,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn 2.0.55", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3395,7 +3524,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -3434,6 +3563,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "roxmltree" version = "0.19.0" @@ -3498,6 +3642,34 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4d6d8ad9f2492485e13453acbb291dd08f64441b6609c491f1c2cd2c6b4fe1" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.1", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3507,6 +3679,34 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustybuzz" version = "0.11.0" @@ -3699,6 +3899,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3870,6 +4076,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "svg_fmt" version = "0.4.2" @@ -4130,6 +4342,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -4375,6 +4598,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -4788,6 +5017,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.32", +] + [[package]] name = "widestring" version = "1.0.2" @@ -5411,6 +5652,12 @@ dependencies = [ "syn 2.0.55", ] +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + [[package]] name = "zune-inflate" version = "0.2.54" diff --git a/data/src/server.rs b/data/src/server.rs index b6ccd8a5f..e3a56e446 100644 --- a/data/src/server.rs +++ b/data/src/server.rs @@ -77,6 +77,7 @@ impl Map { *password = Some(pass); }, Sasl::Plain { password: Some(_), password_file: None, .. } => {}, + Sasl::External { .. } => {}, _ => { return Err(Error::Parse("Exactly one of sasl.plain.password or sasl.plain.password_file must be set.".to_string())); } diff --git a/irc/Cargo.toml b/irc/Cargo.toml index 13d1c39e9..06573024f 100644 --- a/irc/Cargo.toml +++ b/irc/Cargo.toml @@ -9,8 +9,10 @@ bytes = "1.4.0" futures = "0.3.28" thiserror = "1.0.30" tokio = { version = "1.29", features = ["net", "full"] } -tokio-native-tls = "0.3.1" +tokio-rustls = "0.26.0" tokio-util = { version = "0.7", features = ["codec"] } +rustls-native-certs = "0.7.0" +rustls-pemfile = "2.1.1" [dependencies.proto] path = "proto" diff --git a/irc/src/connection.rs b/irc/src/connection.rs index 66ffbb671..02139d238 100644 --- a/irc/src/connection.rs +++ b/irc/src/connection.rs @@ -1,14 +1,18 @@ -use std::io; +use std::io::Cursor; use std::net::IpAddr; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::sync::Arc; use futures::{Sink, SinkExt, Stream, StreamExt}; use tokio::fs; use tokio::io::AsyncWriteExt; use tokio::net::{TcpListener, TcpStream}; -use tokio_native_tls::native_tls::{Certificate, Identity}; -use tokio_native_tls::{native_tls, TlsConnector, TlsStream}; -use tokio_util::codec::{self, Framed}; +use tokio_rustls::rustls::pki_types::{self, CertificateDer, PrivateKeyDer}; +use tokio_rustls::{client::TlsStream, rustls, TlsConnector}; +use tokio_util::codec; +use tokio_util::codec::Framed; + +use crate::invalid_cert_verifier::InvalidServerCertVerifier; pub enum Connection { Tls(Framed, Codec>), @@ -44,25 +48,54 @@ impl Connection { client_key_path, } = config.security { - let mut builder = native_tls::TlsConnector::builder(); - builder.danger_accept_invalid_certs(accept_invalid_certs); - - if let Some(path) = root_cert_path { - let bytes = fs::read(path).await?; - let cert = Certificate::from_pem(&bytes)?; - builder.add_root_certificate(cert); + let mut roots = rustls::RootCertStore::empty(); + for cert in + rustls_native_certs::load_native_certs().expect("could not load platform certs") + { + roots.add(cert).unwrap(); } - if let (Some(cert_path), Some(pkcs8_key_path)) = (client_cert_path, client_key_path) { - let cert_bytes = fs::read(cert_path).await?; - let pkcs8_key_bytes = fs::read(pkcs8_key_path).await?; - let identity = Identity::from_pkcs8(&cert_bytes, &pkcs8_key_bytes)?; - builder.identity(identity); + if let Some(root_cert_path) = root_cert_path { + roots.add_parsable_certificates(read_certs_from_path(root_cert_path).await?); } - let tls = TlsConnector::from(builder.build()?) - .connect(config.server, tcp) - .await?; + let builder = rustls::ClientConfig::builder(); + let builder = if accept_invalid_certs { + builder + .dangerous() + .with_custom_certificate_verifier(Arc::new(InvalidServerCertVerifier::new( + roots, + ))) + } else { + builder.with_root_certificates(roots) + }; + + let client_config = if let (None, None) = (client_cert_path, client_key_path) { + builder.with_no_client_auth() + } else { + let (certs, key) = match (client_cert_path, client_key_path) { + (Some(cert_path), None) => read_certs_and_key_from_path(cert_path).await?, + (Some(cert_path), Some(key_path)) if cert_path == key_path => { + read_certs_and_key_from_path(cert_path).await? + } + (Some(cert_path), Some(key_path)) => ( + read_certs_from_path(cert_path).await?, + read_key_from_path(key_path).await?, + ), + (None, Some(_)) => { + return Err(Error::ClientCertificate( + CertificateError::BadCertificateFile, + )) + } + (None, None) => unreachable!(), + }; + builder.with_client_auth_cert(certs, key)? + }; + + let server_name = pki_types::ServerName::try_from(config.server.to_owned()) + .expect("invalid server name"); + let tls = TlsConnector::from(Arc::new(client_config)); + let tls = tls.connect(server_name, tcp).await?; Ok(Self::Tls(Framed::new(tls, codec))) } else { @@ -103,12 +136,63 @@ impl Connection { } } +async fn read_certs_and_key_from_path>( + path: P, +) -> Result<(Vec>, PrivateKeyDer<'static>), Error> { + let pem_bytes = fs::read(path).await?; + let mut pem_reader = Cursor::new(pem_bytes); + + let certs = rustls_pemfile::certs(&mut pem_reader) + .map(Result::unwrap) + .collect(); + + pem_reader.set_position(0); + + let key = rustls_pemfile::private_key(&mut pem_reader)? + .ok_or_else(|| Error::ClientCertificate(CertificateError::BadPrivateKey))?; + + Ok((certs, key)) +} + +async fn read_certs_from_path>( + path: P, +) -> Result>, Error> { + let pem_bytes = fs::read(path).await?; + let mut pem_reader = Cursor::new(pem_bytes); + + let certs = rustls_pemfile::certs(&mut pem_reader) + .map(Result::unwrap) + .collect(); + + Ok(certs) +} + +async fn read_key_from_path>(path: P) -> Result, Error> { + let pem_bytes = fs::read(path).await?; + let mut pem_reader = Cursor::new(pem_bytes); + + let key = rustls_pemfile::private_key(&mut pem_reader)? + .ok_or_else(|| Error::ClientCertificate(CertificateError::BadPrivateKey))?; + + Ok(key) +} + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("tls error: {0}")] - Tls(#[from] tokio_native_tls::native_tls::Error), + Tls(#[from] rustls::Error), #[error("io error: {0}")] - Io(#[from] io::Error), + Io(#[from] std::io::Error), + #[error("client certificate error: {0}")] + ClientCertificate(CertificateError), +} + +#[derive(Debug, thiserror::Error)] +pub enum CertificateError { + #[error("missing or invalid private key")] + BadPrivateKey, + #[error("missing or invalid certificate file")] + BadCertificateFile, } macro_rules! delegate { diff --git a/irc/src/invalid_cert_verifier.rs b/irc/src/invalid_cert_verifier.rs new file mode 100644 index 000000000..b0c53276f --- /dev/null +++ b/irc/src/invalid_cert_verifier.rs @@ -0,0 +1,58 @@ +use std::sync::Arc; + +use tokio_rustls::rustls::{ + self, + client::{ + danger::{self, ServerCertVerifier}, + WebPkiServerVerifier, + }, + RootCertStore, +}; + +#[derive(Debug)] +pub(crate) struct InvalidServerCertVerifier { + verifier: Arc, +} + +impl InvalidServerCertVerifier { + pub fn new(roots: impl Into>) -> InvalidServerCertVerifier { + Self { + verifier: WebPkiServerVerifier::builder(roots.into()).build().unwrap(), + } + } +} + +impl ServerCertVerifier for InvalidServerCertVerifier { + fn verify_server_cert( + &self, + _end_entity: &rustls::pki_types::CertificateDer<'_>, + _intermediates: &[rustls::pki_types::CertificateDer<'_>], + _server_name: &rustls::pki_types::ServerName<'_>, + _ocsp_response: &[u8], + _now: rustls::pki_types::UnixTime, + ) -> Result { + Ok(danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &rustls::pki_types::CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + self.verifier.verify_tls12_signature(message, cert, dss) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &rustls::pki_types::CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + self.verifier.verify_tls13_signature(message, cert, dss) + } + + fn supported_verify_schemes(&self) -> Vec { + self.verifier.supported_verify_schemes() + } +} diff --git a/irc/src/lib.rs b/irc/src/lib.rs index 0f291812a..59b380fa0 100644 --- a/irc/src/lib.rs +++ b/irc/src/lib.rs @@ -5,4 +5,5 @@ pub use self::connection::Connection; pub mod codec; pub mod connection; +mod invalid_cert_verifier; pub use proto; From 37e5206a5aed4e43b1f361b50c2afecf67d3aa44 Mon Sep 17 00:00:00 2001 From: Galileo Daras Date: Thu, 4 Apr 2024 16:30:27 -0400 Subject: [PATCH 2/7] Make accept_invalid_certs more permissive --- irc/src/connection.rs | 4 +-- irc/src/invalid_cert_verifier.rs | 52 +++++++++++++++----------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/irc/src/connection.rs b/irc/src/connection.rs index 02139d238..68181d916 100644 --- a/irc/src/connection.rs +++ b/irc/src/connection.rs @@ -63,9 +63,7 @@ impl Connection { let builder = if accept_invalid_certs { builder .dangerous() - .with_custom_certificate_verifier(Arc::new(InvalidServerCertVerifier::new( - roots, - ))) + .with_custom_certificate_verifier(Arc::new(InvalidServerCertVerifier {})) } else { builder.with_root_certificates(roots) }; diff --git a/irc/src/invalid_cert_verifier.rs b/irc/src/invalid_cert_verifier.rs index b0c53276f..34319bd3b 100644 --- a/irc/src/invalid_cert_verifier.rs +++ b/irc/src/invalid_cert_verifier.rs @@ -1,26 +1,10 @@ -use std::sync::Arc; - use tokio_rustls::rustls::{ self, - client::{ - danger::{self, ServerCertVerifier}, - WebPkiServerVerifier, - }, - RootCertStore, + client::danger::{self, ServerCertVerifier}, }; #[derive(Debug)] -pub(crate) struct InvalidServerCertVerifier { - verifier: Arc, -} - -impl InvalidServerCertVerifier { - pub fn new(roots: impl Into>) -> InvalidServerCertVerifier { - Self { - verifier: WebPkiServerVerifier::builder(roots.into()).build().unwrap(), - } - } -} +pub(crate) struct InvalidServerCertVerifier; impl ServerCertVerifier for InvalidServerCertVerifier { fn verify_server_cert( @@ -36,23 +20,37 @@ impl ServerCertVerifier for InvalidServerCertVerifier { fn verify_tls12_signature( &self, - message: &[u8], - cert: &rustls::pki_types::CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, ) -> Result { - self.verifier.verify_tls12_signature(message, cert, dss) + Ok(danger::HandshakeSignatureValid::assertion()) } fn verify_tls13_signature( &self, - message: &[u8], - cert: &rustls::pki_types::CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, ) -> Result { - self.verifier.verify_tls13_signature(message, cert, dss) + Ok(danger::HandshakeSignatureValid::assertion()) } fn supported_verify_schemes(&self) -> Vec { - self.verifier.supported_verify_schemes() + vec![ + rustls::SignatureScheme::RSA_PKCS1_SHA1, + rustls::SignatureScheme::ECDSA_SHA1_Legacy, + rustls::SignatureScheme::RSA_PKCS1_SHA256, + rustls::SignatureScheme::ECDSA_NISTP256_SHA256, + rustls::SignatureScheme::RSA_PKCS1_SHA384, + rustls::SignatureScheme::ECDSA_NISTP384_SHA384, + rustls::SignatureScheme::RSA_PKCS1_SHA512, + rustls::SignatureScheme::ECDSA_NISTP521_SHA512, + rustls::SignatureScheme::RSA_PSS_SHA256, + rustls::SignatureScheme::RSA_PSS_SHA384, + rustls::SignatureScheme::RSA_PSS_SHA512, + rustls::SignatureScheme::ED25519, + rustls::SignatureScheme::ED448, + ] } } From f47da01c3c1782d2d195fab89ddfa7d9f15b15db Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Thu, 4 Apr 2024 14:00:36 -0700 Subject: [PATCH 3/7] Refactor to TLS module --- data/src/server.rs | 19 +++-- irc/src/connection.rs | 118 +++------------------------- irc/src/connection/tls.rs | 131 +++++++++++++++++++++++++++++++ irc/src/invalid_cert_verifier.rs | 56 ------------- irc/src/lib.rs | 1 - 5 files changed, 157 insertions(+), 168 deletions(-) create mode 100644 irc/src/connection/tls.rs delete mode 100644 irc/src/invalid_cert_verifier.rs diff --git a/data/src/server.rs b/data/src/server.rs index e3a56e446..6307ee9b7 100644 --- a/data/src/server.rs +++ b/data/src/server.rs @@ -72,15 +72,22 @@ impl Map { } if let Some(sasl) = &mut config.sasl { match sasl { - Sasl::Plain { password: password @ None, password_file: Some(pass_file), .. } => { + Sasl::Plain { + password: Some(_), + password_file: Some(_), + .. + } => { + return Err(Error::Parse("Exactly one of sasl.plain.password or sasl.plain.password_file must be set.".to_string())); + } + Sasl::Plain { + password: password @ None, + password_file: Some(pass_file), + .. + } => { let pass = fs::read_to_string(pass_file)?; *password = Some(pass); - }, - Sasl::Plain { password: Some(_), password_file: None, .. } => {}, - Sasl::External { .. } => {}, - _ => { - return Err(Error::Parse("Exactly one of sasl.plain.password or sasl.plain.password_file must be set.".to_string())); } + _ => {} } } } diff --git a/irc/src/connection.rs b/irc/src/connection.rs index 68181d916..7b7eeeda0 100644 --- a/irc/src/connection.rs +++ b/irc/src/connection.rs @@ -1,18 +1,14 @@ -use std::io::Cursor; use std::net::IpAddr; -use std::path::{Path, PathBuf}; -use std::sync::Arc; +use std::path::PathBuf; use futures::{Sink, SinkExt, Stream, StreamExt}; -use tokio::fs; use tokio::io::AsyncWriteExt; use tokio::net::{TcpListener, TcpStream}; -use tokio_rustls::rustls::pki_types::{self, CertificateDer, PrivateKeyDer}; -use tokio_rustls::{client::TlsStream, rustls, TlsConnector}; +use tokio_rustls::client::TlsStream; use tokio_util::codec; use tokio_util::codec::Framed; -use crate::invalid_cert_verifier::InvalidServerCertVerifier; +mod tls; pub enum Connection { Tls(Framed, Codec>), @@ -48,52 +44,15 @@ impl Connection { client_key_path, } = config.security { - let mut roots = rustls::RootCertStore::empty(); - for cert in - rustls_native_certs::load_native_certs().expect("could not load platform certs") - { - roots.add(cert).unwrap(); - } - - if let Some(root_cert_path) = root_cert_path { - roots.add_parsable_certificates(read_certs_from_path(root_cert_path).await?); - } - - let builder = rustls::ClientConfig::builder(); - let builder = if accept_invalid_certs { - builder - .dangerous() - .with_custom_certificate_verifier(Arc::new(InvalidServerCertVerifier {})) - } else { - builder.with_root_certificates(roots) - }; - - let client_config = if let (None, None) = (client_cert_path, client_key_path) { - builder.with_no_client_auth() - } else { - let (certs, key) = match (client_cert_path, client_key_path) { - (Some(cert_path), None) => read_certs_and_key_from_path(cert_path).await?, - (Some(cert_path), Some(key_path)) if cert_path == key_path => { - read_certs_and_key_from_path(cert_path).await? - } - (Some(cert_path), Some(key_path)) => ( - read_certs_from_path(cert_path).await?, - read_key_from_path(key_path).await?, - ), - (None, Some(_)) => { - return Err(Error::ClientCertificate( - CertificateError::BadCertificateFile, - )) - } - (None, None) => unreachable!(), - }; - builder.with_client_auth_cert(certs, key)? - }; - - let server_name = pki_types::ServerName::try_from(config.server.to_owned()) - .expect("invalid server name"); - let tls = TlsConnector::from(Arc::new(client_config)); - let tls = tls.connect(server_name, tcp).await?; + let tls = tls::connect( + tcp, + config.server, + accept_invalid_certs, + root_cert_path, + client_cert_path, + client_key_path, + ) + .await?; Ok(Self::Tls(Framed::new(tls, codec))) } else { @@ -134,63 +93,12 @@ impl Connection { } } -async fn read_certs_and_key_from_path>( - path: P, -) -> Result<(Vec>, PrivateKeyDer<'static>), Error> { - let pem_bytes = fs::read(path).await?; - let mut pem_reader = Cursor::new(pem_bytes); - - let certs = rustls_pemfile::certs(&mut pem_reader) - .map(Result::unwrap) - .collect(); - - pem_reader.set_position(0); - - let key = rustls_pemfile::private_key(&mut pem_reader)? - .ok_or_else(|| Error::ClientCertificate(CertificateError::BadPrivateKey))?; - - Ok((certs, key)) -} - -async fn read_certs_from_path>( - path: P, -) -> Result>, Error> { - let pem_bytes = fs::read(path).await?; - let mut pem_reader = Cursor::new(pem_bytes); - - let certs = rustls_pemfile::certs(&mut pem_reader) - .map(Result::unwrap) - .collect(); - - Ok(certs) -} - -async fn read_key_from_path>(path: P) -> Result, Error> { - let pem_bytes = fs::read(path).await?; - let mut pem_reader = Cursor::new(pem_bytes); - - let key = rustls_pemfile::private_key(&mut pem_reader)? - .ok_or_else(|| Error::ClientCertificate(CertificateError::BadPrivateKey))?; - - Ok(key) -} - #[derive(Debug, thiserror::Error)] pub enum Error { #[error("tls error: {0}")] - Tls(#[from] rustls::Error), + Tls(#[from] tls::Error), #[error("io error: {0}")] Io(#[from] std::io::Error), - #[error("client certificate error: {0}")] - ClientCertificate(CertificateError), -} - -#[derive(Debug, thiserror::Error)] -pub enum CertificateError { - #[error("missing or invalid private key")] - BadPrivateKey, - #[error("missing or invalid certificate file")] - BadCertificateFile, } macro_rules! delegate { diff --git a/irc/src/connection/tls.rs b/irc/src/connection/tls.rs new file mode 100644 index 000000000..27182fb8a --- /dev/null +++ b/irc/src/connection/tls.rs @@ -0,0 +1,131 @@ +use std::{io::Cursor, path::PathBuf, sync::Arc}; + +use bytes::Bytes; +use tokio::{fs, net::TcpStream}; +use tokio_rustls::{ + client::TlsStream, + rustls::{ + self, + client::danger::{self, ServerCertVerifier}, + pki_types, + }, + TlsConnector, +}; + +pub async fn connect<'a>( + tcp: TcpStream, + server: &str, + accept_invalid_certs: bool, + root_cert_path: Option<&'a PathBuf>, + client_cert_path: Option<&'a PathBuf>, + client_key_path: Option<&'a PathBuf>, +) -> Result, Error> { + let mut roots = rustls::RootCertStore::empty(); + + for cert in rustls_native_certs::load_native_certs()? { + roots.add(cert).unwrap(); + } + if let Some(cert_path) = root_cert_path { + let cert_bytes = fs::read(&cert_path).await?; + let certs = + rustls_pemfile::certs(&mut Cursor::new(&cert_bytes)).collect::, _>>()?; + roots.add_parsable_certificates(certs); + } + + let builder = if accept_invalid_certs { + rustls::ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(AcceptInvalidCerts)) + } else { + rustls::ClientConfig::builder().with_root_certificates(roots) + }; + + let client_config = if let Some(cert_path) = client_cert_path { + let cert_bytes = Bytes::from(fs::read(&cert_path).await?); + + let key_bytes = if let Some(key_path) = client_key_path { + Bytes::from(fs::read(&key_path).await?) + } else { + cert_bytes.clone() + }; + + let certs = + rustls_pemfile::certs(&mut Cursor::new(&cert_bytes)).collect::, _>>()?; + let key = rustls_pemfile::private_key(&mut Cursor::new(&key_bytes))? + .ok_or(Error::BadPrivateKey)?; + + builder.with_client_auth_cert(certs, key)? + } else { + builder.with_no_client_auth() + }; + + let server_name = pki_types::ServerName::try_from(server.to_string())?; + + Ok(TlsConnector::from(Arc::new(client_config)) + .connect(server_name, tcp) + .await?) +} + +#[derive(Debug)] +pub struct AcceptInvalidCerts; + +impl ServerCertVerifier for AcceptInvalidCerts { + fn verify_server_cert( + &self, + _end_entity: &rustls::pki_types::CertificateDer<'_>, + _intermediates: &[rustls::pki_types::CertificateDer<'_>], + _server_name: &rustls::pki_types::ServerName<'_>, + _ocsp_response: &[u8], + _now: rustls::pki_types::UnixTime, + ) -> Result { + Ok(danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(danger::HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(danger::HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + vec![ + rustls::SignatureScheme::RSA_PKCS1_SHA1, + rustls::SignatureScheme::ECDSA_SHA1_Legacy, + rustls::SignatureScheme::RSA_PKCS1_SHA256, + rustls::SignatureScheme::ECDSA_NISTP256_SHA256, + rustls::SignatureScheme::RSA_PKCS1_SHA384, + rustls::SignatureScheme::ECDSA_NISTP384_SHA384, + rustls::SignatureScheme::RSA_PKCS1_SHA512, + rustls::SignatureScheme::ECDSA_NISTP521_SHA512, + rustls::SignatureScheme::RSA_PSS_SHA256, + rustls::SignatureScheme::RSA_PSS_SHA384, + rustls::SignatureScheme::RSA_PSS_SHA512, + rustls::SignatureScheme::ED25519, + rustls::SignatureScheme::ED448, + ] + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("rustls error: {0}")] + Tls(#[from] rustls::Error), + #[error("io error: {0}")] + Io(#[from] std::io::Error), + #[error("invalid DNS name: {0}")] + Dns(#[from] pki_types::InvalidDnsNameError), + #[error("missing or invalid private key")] + BadPrivateKey, +} diff --git a/irc/src/invalid_cert_verifier.rs b/irc/src/invalid_cert_verifier.rs deleted file mode 100644 index 34319bd3b..000000000 --- a/irc/src/invalid_cert_verifier.rs +++ /dev/null @@ -1,56 +0,0 @@ -use tokio_rustls::rustls::{ - self, - client::danger::{self, ServerCertVerifier}, -}; - -#[derive(Debug)] -pub(crate) struct InvalidServerCertVerifier; - -impl ServerCertVerifier for InvalidServerCertVerifier { - fn verify_server_cert( - &self, - _end_entity: &rustls::pki_types::CertificateDer<'_>, - _intermediates: &[rustls::pki_types::CertificateDer<'_>], - _server_name: &rustls::pki_types::ServerName<'_>, - _ocsp_response: &[u8], - _now: rustls::pki_types::UnixTime, - ) -> Result { - Ok(danger::ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &rustls::pki_types::CertificateDer<'_>, - _dss: &rustls::DigitallySignedStruct, - ) -> Result { - Ok(danger::HandshakeSignatureValid::assertion()) - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &rustls::pki_types::CertificateDer<'_>, - _dss: &rustls::DigitallySignedStruct, - ) -> Result { - Ok(danger::HandshakeSignatureValid::assertion()) - } - - fn supported_verify_schemes(&self) -> Vec { - vec![ - rustls::SignatureScheme::RSA_PKCS1_SHA1, - rustls::SignatureScheme::ECDSA_SHA1_Legacy, - rustls::SignatureScheme::RSA_PKCS1_SHA256, - rustls::SignatureScheme::ECDSA_NISTP256_SHA256, - rustls::SignatureScheme::RSA_PKCS1_SHA384, - rustls::SignatureScheme::ECDSA_NISTP384_SHA384, - rustls::SignatureScheme::RSA_PKCS1_SHA512, - rustls::SignatureScheme::ECDSA_NISTP521_SHA512, - rustls::SignatureScheme::RSA_PSS_SHA256, - rustls::SignatureScheme::RSA_PSS_SHA384, - rustls::SignatureScheme::RSA_PSS_SHA512, - rustls::SignatureScheme::ED25519, - rustls::SignatureScheme::ED448, - ] - } -} diff --git a/irc/src/lib.rs b/irc/src/lib.rs index 59b380fa0..0f291812a 100644 --- a/irc/src/lib.rs +++ b/irc/src/lib.rs @@ -5,5 +5,4 @@ pub use self::connection::Connection; pub mod codec; pub mod connection; -mod invalid_cert_verifier; pub use proto; From 7554c63e22fa2bfe963bfb09542c5f53ec6632b2 Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Thu, 4 Apr 2024 14:10:43 -0700 Subject: [PATCH 4/7] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39d6b674f..aef504b02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Fixed: - Accept '@' in usernames to support bouncers that use the user@identifier/network convention - Prevent rare scenario where broadcast messages' timestamp would not match time the messages are received +- Fix SASL on macos by using RUSTLS backend Changed: From 45f3e77aa92b759ba06558d5230f3a94e6f897ab Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Thu, 4 Apr 2024 14:38:30 -0700 Subject: [PATCH 5/7] Use ring over aws-lc-rs --- Cargo.lock | 149 +------------------------------------------------ irc/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 149 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb2d50d65..774723b05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,32 +397,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "aws-lc-rs" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f379c4e505c0692333bd90a334baa234990faa06bdabefd3261f765946aa920" -dependencies = [ - "aws-lc-sys", - "mirai-annotations", - "paste", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68aa3d613f42dbf301dbbcaf3dc260805fd33ffd95f6d290ad7231a9e5d877a7" -dependencies = [ - "bindgen", - "cmake", - "dunce", - "fs_extra", - "libc", - "paste", -] - [[package]] name = "backtrace" version = "0.3.71" @@ -444,29 +418,6 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.55", - "which", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -636,15 +587,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -678,17 +620,6 @@ dependencies = [ "windows-targets 0.52.4", ] -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading 0.8.3", -] - [[package]] name = "clipboard-win" version = "5.3.0" @@ -728,15 +659,6 @@ dependencies = [ "x11rb", ] -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - [[package]] name = "cocoa" version = "0.25.0" @@ -1176,12 +1098,6 @@ dependencies = [ "linux-raw-sys 0.6.4", ] -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "either" version = "1.10.0" @@ -1498,12 +1414,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.30" @@ -1686,12 +1596,6 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "glow" version = "0.13.1" @@ -1898,15 +1802,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "http" version = "1.1.0" @@ -2415,12 +2310,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "lebe" version = "0.5.2" @@ -2633,12 +2522,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "mutate_once" version = "0.1.1" @@ -3255,16 +3138,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" -[[package]] -name = "prettyplease" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" -dependencies = [ - "proc-macro2", - "syn 2.0.55", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3648,9 +3521,8 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c4d6d8ad9f2492485e13453acbb291dd08f64441b6609c491f1c2cd2c6b4fe1" dependencies = [ - "aws-lc-rs", - "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3701,7 +3573,6 @@ version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ - "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3899,12 +3770,6 @@ dependencies = [ "digest", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -5017,18 +4882,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.32", -] - [[package]] name = "widestring" version = "1.0.2" diff --git a/irc/Cargo.toml b/irc/Cargo.toml index 06573024f..0a5fb41b1 100644 --- a/irc/Cargo.toml +++ b/irc/Cargo.toml @@ -9,7 +9,7 @@ bytes = "1.4.0" futures = "0.3.28" thiserror = "1.0.30" tokio = { version = "1.29", features = ["net", "full"] } -tokio-rustls = "0.26.0" +tokio-rustls = { version = "0.26.0", default-features = false, features = ["tls12", "ring"] } tokio-util = { version = "0.7", features = ["codec"] } rustls-native-certs = "0.7.0" rustls-pemfile = "2.1.1" From 364db2e07852f66bd3858f1f32e76a27d04836be Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Thu, 4 Apr 2024 14:43:26 -0700 Subject: [PATCH 6/7] Only load roots & root cert if using cert validation --- irc/src/connection/tls.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/irc/src/connection/tls.rs b/irc/src/connection/tls.rs index 27182fb8a..ce929bcc7 100644 --- a/irc/src/connection/tls.rs +++ b/irc/src/connection/tls.rs @@ -20,23 +20,24 @@ pub async fn connect<'a>( client_cert_path: Option<&'a PathBuf>, client_key_path: Option<&'a PathBuf>, ) -> Result, Error> { - let mut roots = rustls::RootCertStore::empty(); - - for cert in rustls_native_certs::load_native_certs()? { - roots.add(cert).unwrap(); - } - if let Some(cert_path) = root_cert_path { - let cert_bytes = fs::read(&cert_path).await?; - let certs = - rustls_pemfile::certs(&mut Cursor::new(&cert_bytes)).collect::, _>>()?; - roots.add_parsable_certificates(certs); - } - let builder = if accept_invalid_certs { rustls::ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(Arc::new(AcceptInvalidCerts)) } else { + let mut roots = rustls::RootCertStore::empty(); + + for cert in rustls_native_certs::load_native_certs()? { + roots.add(cert).unwrap(); + } + + if let Some(cert_path) = root_cert_path { + let cert_bytes = fs::read(&cert_path).await?; + let certs = rustls_pemfile::certs(&mut Cursor::new(&cert_bytes)) + .collect::, _>>()?; + roots.add_parsable_certificates(certs); + } + rustls::ClientConfig::builder().with_root_certificates(roots) }; From 2d7d21f5f70cb1b47527b137df12a57b30e71474 Mon Sep 17 00:00:00 2001 From: Cory Forsstrom Date: Thu, 4 Apr 2024 14:52:23 -0700 Subject: [PATCH 7/7] Don't reread cert path when key is missing --- data/src/config/server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/src/config/server.rs b/data/src/config/server.rs index cb147efbe..1325ea4c9 100644 --- a/data/src/config/server.rs +++ b/data/src/config/server.rs @@ -164,8 +164,8 @@ impl Sasl { } fn external_key(&self) -> Option<&PathBuf> { - if let Self::External { cert, key, .. } = self { - Some(key.as_ref().unwrap_or(cert)) + if let Self::External { key, .. } = self { + key.as_ref() } else { None }