diff --git a/src/config.rs b/src/config.rs index db911b7..85aa44c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ #[cfg(feature = "rustls-native-certs")] use std::io; +use std::sync::Arc; #[cfg(any( feature = "rustls-platform-verifier", @@ -7,7 +8,7 @@ use std::io; feature = "webpki-roots" ))] use rustls::client::WantsClientCert; -use rustls::{ClientConfig, ConfigBuilder, WantsVerifier}; +use rustls::{ClientConfig, ConfigBuilder, KeyLog, KeyLogFile, WantsVerifier}; #[cfg(feature = "rustls-native-certs")] use rustls_native_certs::CertificateResult; #[cfg(feature = "rustls-platform-verifier")] @@ -125,6 +126,38 @@ impl ConfigBuilderExt for ConfigBuilder { } } +/// Methods for enabling TLS key logging on a `ClientConfig`. +/// +/// Naturally, secrets passed over the interface are *extremely* +/// sensitive and can break the security of past, present and +/// future sessions. +pub trait ClientConfigKeyLogExt { + /// Replace the `key_log` sink with a custom implementation. + fn with_key_log(self, key_log: Arc) -> Self; + + /// Replace the `key_log` sink with NSS-style key logging to the file + /// named by `SSLKEYLOGFILE`. + /// + /// If `SSLKEYLOGFILE` is unset, this is a no-op (matches `rustls`’ behavior). + fn with_key_log_file(self) -> Self; +} + +impl ClientConfigKeyLogExt for ClientConfig { + fn with_key_log(mut self, key_log: Arc) -> Self { + self.key_log = key_log; + + self + } + + fn with_key_log_file(mut self) -> Self { + // `KeyLogFile::new()` internally reads SSLKEYLOGFILE and either opens the file + // or becomes a sink that does nothing. Safe to enable unconditionally. + self.key_log = Arc::new(KeyLogFile::new()); + + self + } +} + mod sealed { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 89e355a..9e1cfbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ mod log { pub(crate) use warn_ as warn; } -pub use crate::config::ConfigBuilderExt; +pub use crate::config::{ClientConfigKeyLogExt, ConfigBuilderExt}; pub use crate::connector::builder::ConnectorBuilder as HttpsConnectorBuilder; pub use crate::connector::{ DefaultServerNameResolver, FixedServerNameResolver, HttpsConnector, ResolveServerName,