diff --git a/Cargo.lock b/Cargo.lock index 59e78c65ae3..fa79d967e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5222,8 +5222,7 @@ dependencies = [ [[package]] name = "tokio-rustls-acme" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31fcc374ec87d754358a5d0709ed1ab7671d51e0f70ddc3b17a11ac36604cfa" +source = "git+https://github.com/n0-computer/tokio-rustls-acme?branch=Frando%2Fcrypto-provider#bba7615c920ae0858904a41bf1a6c9ba7a20b9b5" dependencies = [ "async-trait", "axum-server", diff --git a/Cargo.toml b/Cargo.toml index 022fe2374f1..121b8ecd270 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,3 +40,6 @@ unexpected_cfgs = { level = "warn", check-cfg = ["cfg(iroh_docsrs)", "cfg(iroh_l [workspace.lints.clippy] unused-async = "warn" + +[patch.crates-io] +tokio-rustls-acme = { git = "https://github.com/n0-computer/tokio-rustls-acme", branch = "Frando/crypto-provider"} diff --git a/iroh-relay/Cargo.toml b/iroh-relay/Cargo.toml index b4c5e050556..4f637f107b7 100644 --- a/iroh-relay/Cargo.toml +++ b/iroh-relay/Cargo.toml @@ -131,7 +131,7 @@ vergen-gitcl = "1.0.8" default = ["metrics", "tls-ring"] # Enables fetching TLS trust anchors from the operating system platform-verifier = ["dep:rustls-platform-verifier"] -server = [ +server-no-tls = [ "metrics", "tokio/signal", "dep:clap", @@ -152,8 +152,8 @@ server = [ "noq/platform-verifier", "noq/runtime-tokio", "iroh-metrics/service", - "tls-ring", ] +server = ["server", "tls-ring"] metrics = ["iroh-metrics/metrics"] test-utils = [] tls-ring = [ diff --git a/iroh-relay/src/main.rs b/iroh-relay/src/main.rs index 372409a1606..8b75673a1e0 100644 --- a/iroh-relay/src/main.rs +++ b/iroh-relay/src/main.rs @@ -18,6 +18,7 @@ use iroh_relay::{ DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT, DEFAULT_METRICS_PORT, DEFAULT_RELAY_QUIC_PORT, }, server::{self as relay, ClientRateLimit, QuicConfig}, + tls::CaRootsConfig, }; use n0_error::{Result, StdResultExt, bail_any}; use n0_future::FutureExt; @@ -496,16 +497,6 @@ async fn main() -> Result<()> { .with(EnvFilter::from_default_env()) .init(); - // Install `ring` as default crypto provider for rustls. - // This helps when both the tls-ring and tls-aws-lc-rs features are enabled, - // otherwise some crypto operations would panic because rustls can't determine - // a default provider. - // `ring` is enabled by the `tls-ring` feature, which is included in the `server` feature, - // which is required for the main.rs binary. Therefore, this does not need any feature flags. - rustls::crypto::ring::default_provider() - .install_default() - .expect("failed to set default crypto provider"); - let cli = Cli::parse(); let mut cfg = Config::load(&cli).await?; if cfg.enable_quic_addr_discovery && cfg.tls.is_none() { @@ -544,12 +535,11 @@ async fn maybe_load_tls( let Some(ref tls) = cfg.tls else { return Ok(None); }; - let server_config = rustls::ServerConfig::builder_with_provider(std::sync::Arc::new( - rustls::crypto::ring::default_provider(), - )) - .with_safe_default_protocol_versions() - .expect("protocols supported by ring") - .with_no_client_auth(); + let crypto_provider = Arc::new(rustls::crypto::ring::default_provider()); + let server_config = rustls::ServerConfig::builder_with_provider(crypto_provider.clone()) + .with_safe_default_protocol_versions() + .expect("protocols supported by ring") + .with_no_client_auth(); let (cert_config, server_config) = match tls.cert_mode { CertMode::Manual => { let cert_path = tls.cert_path(); @@ -576,10 +566,14 @@ async fn maybe_load_tls( .contact .clone() .std_context("LetsEncrypt needs a contact email")?; - let config = AcmeConfig::new(vec![hostname.clone()]) - .contact([format!("mailto:{contact}")]) - .cache_option(Some(DirCache::new(tls.cert_dir()))) - .directory_lets_encrypt(tls.prod_tls); + let client_config = CaRootsConfig::default().client_config(crypto_provider.clone())?; + let config = AcmeConfig::new_with_client_tls_config( + vec![hostname.clone()], + Arc::new(client_config), + ) + .contact([format!("mailto:{contact}")]) + .cache_option(Some(DirCache::new(tls.cert_dir()))) + .directory_lets_encrypt(tls.prod_tls); let state = config.state(); let resolver = state.resolver().clone(); let server_config = server_config.with_cert_resolver(resolver); @@ -628,6 +622,7 @@ async fn maybe_load_tls( cert: cert_config, server_config, quic_bind_addr: tls.quic_bind_addr(cfg), + crypto_provider, })) } diff --git a/iroh-relay/src/server.rs b/iroh-relay/src/server.rs index e2a681097c4..f58b189b499 100644 --- a/iroh-relay/src/server.rs +++ b/iroh-relay/src/server.rs @@ -28,6 +28,7 @@ use iroh_base::EndpointId; use iroh_base::RelayUrl; use n0_error::{e, stack_error}; use n0_future::{StreamExt, future::Boxed}; +use rustls::crypto::CryptoProvider; use serde::Serialize; use tokio::{ net::TcpListener, @@ -194,6 +195,8 @@ pub struct TlsConfig { pub cert: CertConfig, /// The server configuration. pub server_config: rustls::ServerConfig, + /// The rustls crypto provider to use for all crypto. + pub crypto_provider: Arc, } /// Rate limits. @@ -394,8 +397,11 @@ impl Server { Some(tls_config) => { let server_tls_config = match tls_config.cert { CertConfig::LetsEncrypt { mut state } => { - let acceptor = - http_server::TlsAcceptor::LetsEncrypt(state.acceptor()); + let acceptor = http_server::TlsAcceptor::LetsEncrypt( + state.acceptor_with_crypto_provider( + tls_config.crypto_provider.clone(), + ), + ); tasks.spawn( async move { while let Some(event) = state.next().await { diff --git a/iroh-relay/src/server/testing.rs b/iroh-relay/src/server/testing.rs index 6a30f303e62..56aeb4c9f9b 100644 --- a/iroh-relay/src/server/testing.rs +++ b/iroh-relay/src/server/testing.rs @@ -1,5 +1,5 @@ //! Exposes functions to quickly configure a server suitable for testing. -use std::net::Ipv4Addr; +use std::{net::Ipv4Addr, sync::Arc}; use super::{AccessConfig, CertConfig, QuicConfig, RelayConfig, ServerConfig, TlsConfig}; @@ -44,6 +44,7 @@ pub fn tls_config() -> TlsConfig<()> { cert: CertConfig::<(), ()>::Manual { certs }, https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), quic_bind_addr: (Ipv4Addr::UNSPECIFIED, 0).into(), + crypto_provider: Arc::new(rustls::crypto::ring::default_provider()), } } diff --git a/iroh/src/test_utils.rs b/iroh/src/test_utils.rs index c97c7f48a3b..2d1d4fd62ad 100644 --- a/iroh/src/test_utils.rs +++ b/iroh/src/test_utils.rs @@ -1,5 +1,5 @@ //! Internal utilities to support testing. -use std::net::Ipv4Addr; +use std::{net::Ipv4Addr, sync::Arc}; use iroh_base::RelayUrl; use iroh_relay::{ @@ -49,6 +49,7 @@ pub async fn run_relay_server_with(quic: bool) -> Result<(RelayMap, RelayUrl, Se https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), quic_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(), server_config, + crypto_provider: Arc::new(rustls::crypto::ring::default_provider()), }; let quic = if quic { Some(QuicConfig { diff --git a/iroh/tests/patchbay/util.rs b/iroh/tests/patchbay/util.rs index 86fb2d1fee2..3e99728afc9 100644 --- a/iroh/tests/patchbay/util.rs +++ b/iroh/tests/patchbay/util.rs @@ -493,7 +493,10 @@ fn addr_relay_only(addr: EndpointAddr) -> EndpointAddr { } mod relay { - use std::net::{IpAddr, Ipv6Addr}; + use std::{ + net::{IpAddr, Ipv6Addr}, + sync::Arc, + }; use iroh_base::RelayUrl; use iroh_relay::{ @@ -520,6 +523,7 @@ mod relay { https_bind_addr: (bind_ip, 443).into(), quic_bind_addr: (bind_ip, 7842).into(), server_config, + crypto_provider: Arc::new(rustls::crypto::ring::default_provider()), }; let quic = Some(QuicConfig { server_config: tls.server_config.clone(),