use std::sync::Arc;
use iroh_base::SecretKey;
use noq::crypto::rustls::{QuicClientConfig, QuicServerConfig};
use tracing::warn;
use self::resolver::ResolveRawPublicKeyCert;
pub(crate) mod misc;
pub(crate) mod name;
mod resolver;
mod verifier;
pub use iroh_relay::tls::CaRootsConfig;
#[cfg(with_crypto_provider)]
pub use iroh_relay::tls::default_provider;
pub(crate) const DEFAULT_MAX_TLS_TICKETS: usize = 8 * 32;
#[derive(Debug)]
pub(crate) struct TlsConfig {
pub(crate) secret_key: SecretKey,
cert_resolver: Arc<ResolveRawPublicKeyCert>,
server_verifier: Arc<verifier::ServerCertificateVerifier>,
client_verifier: Arc<verifier::ClientCertificateVerifier>,
session_store: Arc<dyn rustls::client::ClientSessionStore>,
crypto_provider: Arc<rustls::crypto::CryptoProvider>,
}
impl TlsConfig {
pub(crate) fn new(
secret_key: SecretKey,
max_tls_tickets: usize,
crypto_provider: Arc<rustls::crypto::CryptoProvider>,
) -> Self {
Self {
cert_resolver: Arc::new(ResolveRawPublicKeyCert::new(&secret_key)),
server_verifier: Arc::new(verifier::ServerCertificateVerifier),
client_verifier: Arc::new(verifier::ClientCertificateVerifier),
session_store: Arc::new(rustls::client::ClientSessionMemoryCache::new(
max_tls_tickets,
)),
crypto_provider,
secret_key,
}
}
pub(crate) fn make_client_config(
&self,
keylog: bool,
) -> Result<QuicClientConfig, TlsConfigError> {
let mut crypto = rustls::ClientConfig::builder_with_provider(self.crypto_provider.clone())
.with_protocol_versions(verifier::PROTOCOL_VERSIONS)?
.dangerous()
.with_custom_certificate_verifier(self.server_verifier.clone())
.with_client_cert_resolver(self.cert_resolver.clone());
crypto.resumption = rustls::client::Resumption::store(self.session_store.clone());
crypto.enable_early_data = true;
if keylog {
warn!("enabling SSLKEYLOGFILE for TLS pre-master keys");
crypto.key_log = Arc::new(rustls::KeyLogFile::new());
}
let quic = QuicClientConfig::try_from(crypto)?;
Ok(quic)
}
pub(crate) fn make_server_config(
&self,
keylog: bool,
) -> Result<QuicServerConfig, TlsConfigError> {
let mut crypto = rustls::ServerConfig::builder_with_provider(self.crypto_provider.clone())
.with_protocol_versions(verifier::PROTOCOL_VERSIONS)?
.with_client_cert_verifier(self.client_verifier.clone())
.with_cert_resolver(self.cert_resolver.clone());
if keylog {
warn!("enabling SSLKEYLOGFILE for TLS pre-master keys");
crypto.key_log = Arc::new(rustls::KeyLogFile::new());
}
crypto.max_early_data_size = u32::MAX;
let quic = QuicServerConfig::try_from(crypto)?;
Ok(quic)
}
}
#[allow(missing_docs)]
#[n0_error::stack_error(derive, add_meta, from_sources)]
#[non_exhaustive]
pub enum TlsConfigError {
#[error(
"The configured crypto provider is missing support for TLS13_AES_128_GCM_SHA256, which is required for QUIC initial packets."
)]
CryptoProviderNoInitialCipherSuite {
#[error(std_err)]
source: noq::crypto::rustls::NoInitialCipherSuite,
},
#[error("The configured crypto provider is incompatible with iroh and QUIC encryption")]
CryptoProviderIncompatible {
#[error(std_err)]
source: rustls::Error,
},
}