Configuring TLS and Key Exchange in iroh Connections
iroh uses rustls as its TLS/QUIC stack, exposing configuration through TlsConfig for peer-to-peer connections and CaTlsConfig for external services, with customizable crypto providers that control key-exchange algorithms including post-quantum options.
iroh is a peer-to-peer networking library built on QUIC that relies on rustls for transport layer security. When configuring TLS and key exchange in iroh connections, you work with two distinct configuration layers: one for end-to-end encrypted peer connections using raw public keys, and another for verifying external services like relays and DNS. The library supports multiple crypto providers including ring and aws-lc-rs, allowing precise control over cipher suites and key-exchange groups.
Understanding iroh's TLS Architecture
iroh separates TLS concerns into two primary structures based on connection type.
CaTlsConfig for External Services
The CaTlsConfig structure in iroh-relay/src/tls.rs handles certificate verification for non-iroh connections such as relays, PKARR, and DNS-over-HTTPS. This configuration determines how the client validates server certificates when connecting to infrastructure services. By default, iroh uses EmbeddedWebPki which bundles Mozilla's root certificate store, but you can switch to system roots or custom verification logic.
TlsConfig for End-to-End Connections
For direct peer-to-peer connections, iroh uses TlsConfig located in iroh/src/tls.rs. This structure holds the crypto provider and raw-public-key verifier used to authenticate iroh nodes. Unlike traditional TLS with certificate authorities, iroh uses raw public keys for peer authentication, implemented through the ResolveRawPublicKeyCert resolver and custom verifiers (ServerCertificateVerifier / ClientCertificateVerifier).
The make_client_config and make_server_config methods in iroh/src/tls.rs build rustls configurations that use builder_with_provider to attach your selected crypto provider, along with protocol versions and the custom certificate resolver.
Crypto Provider and Key-Exchange Groups
The crypto_provider supplies all cryptographic primitives including cipher suites, HKDF implementations, and key-exchange groups. As defined in iroh/src/endpoint/presets.rs, iroh can compile with either the ring provider (tls-ring feature) or aws-lc-rs (tls-aws-lc-rs feature). The provider's kx_groups field determines which algorithms are offered during the TLS handshake.
Selecting Key-Exchange Algorithms
Key-exchange groups are configured by mutating the crypto provider before passing it to the endpoint builder.
Default Crypto Providers
By default, the ring provider offers classical groups like X25519 and SECP256R1. The aws-lc-rs provider includes these plus the post-quantum group X25519MLKEM768. You select the provider through builder presets or manual configuration in iroh/src/endpoint/presets.rs.
Preferring Post-Quantum Key Exchange
To prioritize post-quantum security while maintaining compatibility, reorder the kx_groups vector to place X25519MLKEM768 first, followed by classical fallbacks. This configuration, demonstrated in iroh/examples/prefer-pq-key-exchange.rs, allows connections with PQ-capable peers while falling back to classical algorithms otherwise.
let mut provider = aws_lc_rs::default_provider();
provider.kx_groups = vec![
kx_group::X25519MLKEM768, // PQ first
kx_group::X25519,
kx_group::SECP256R1,
];
let provider = Arc::new(provider);
Enforcing Post-Quantum Only
For environments requiring strict post-quantum security, replace the entire kx_groups list with only the PQ group. As shown in iroh/examples/pq-only-key-exchange.rs, this causes handshakes to fail if the remote peer does not support X25519MLKEM768.
fn pq_only_provider() -> Arc<rustls::crypto::CryptoProvider> {
let mut p = aws_lc_rs::default_provider();
p.kx_groups = vec![aws_lc_rs::kx_group::X25519MLKEM768];
Arc::new(p)
}
Configuring TLS for External Services
When connecting to relays or DNS services, use CaTlsConfig to control certificate verification. The client_config method in iroh-relay/src/tls.rs creates a rustls ClientConfig using your specified crypto provider and verification mode.
use iroh_relay::tls::{CaTlsConfig, default_provider};
let tls_cfg = CaTlsConfig::system(); // Use OS root store
let client_cfg = tls_cfg.client_config(default_provider())?;
Available modes include EmbeddedWebPki (Mozilla roots), System (OS store), CustomRoots (explicit certificates), and InsecureSkipVerify (testing only).
Complete Implementation Examples
Preferred Post-Quantum with Fallback
This example from iroh/examples/prefer-pq-key-exchange.rs builds an endpoint with PQ-preferred key exchange:
use std::sync::Arc;
use iroh::endpoint::{Endpoint, presets::N0};
use rustls::crypto::aws_lc_rs::{self, kx_group};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut provider = aws_lc_rs::default_provider();
provider.kx_groups = vec![
kx_group::X25519MLKEM768,
kx_group::X25519,
kx_group::SECP256R1,
];
let provider = Arc::new(provider);
let endpoint = Endpoint::builder(N0)
.crypto_provider(provider)
.alpns(vec![b"example".to_vec()])
.bind()
.await?;
Ok(())
}
Post-Quantum Only Mode
To enforce strict PQ requirements as in iroh/examples/pq-only-key-exchange.rs:
use std::sync::Arc;
use iroh::{RelayMode, endpoint::{Endpoint, presets::Empty}};
use rustls::crypto::aws_lc_rs;
fn pq_only_provider() -> Arc<rustls::crypto::CryptoProvider> {
let mut p = aws_lc_rs::default_provider();
p.kx_groups = vec![aws_lc_rs::kx_group::X25519MLKEM768];
Arc::new(p)
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let provider = pq_only_provider();
let server = Endpoint::builder(Empty)
.crypto_provider(provider)
.relay_mode(RelayMode::Disabled)
.bind()
.await?;
Ok(())
}
Custom Root Certificates
For air-gapped or enterprise environments requiring specific trust anchors:
use iroh_relay::tls::CaTlsConfig;
let tls_cfg = CaTlsConfig::custom_roots(vec![]); // Load your root certs
Summary
- iroh uses rustls for all TLS operations, separating external service verification (
CaTlsConfiginiroh-relay/src/tls.rs) from peer-to-peer authentication (TlsConfiginiroh/src/tls.rs). - Crypto providers control key-exchange algorithms through the
kx_groupsfield, withaws-lc-rsoffering post-quantumX25519MLKEM768. - Configure key exchange by mutating the provider's
kx_groupsvector before passing it toEndpoint::builder(). - External services use
CaTlsConfigwith options for Mozilla roots, system roots, or custom verification. - Source files implementing this logic include
iroh/src/tls.rs,iroh-relay/src/tls.rs, andiroh/src/endpoint/presets.rs.
Frequently Asked Questions
What crypto providers does iroh support?
iroh supports two rustls crypto providers: ring (via the tls-ring feature) and aws-lc-rs (via tls-aws-lc-rs). The ring provider offers classical key-exchange groups like X25519 and SECP256R1, while aws-lc-rs adds support for the post-quantum group X25519MLKEM768. You select the provider through endpoint builder presets or by manually constructing the crypto provider in iroh/src/endpoint/presets.rs.
How do I enable post-quantum key exchange?
Enable post-quantum key exchange by using the aws-lc-rs provider and including X25519MLKEM768 in the kx_groups vector. According to iroh/examples/prefer-pq-key-exchange.rs, place kx_group::X25519MLKEM768 first in the list to prefer PQ while keeping classical fallbacks, or use iroh/examples/pq-only-key-exchange.rs to enforce PQ-only mode by making it the only group in the list.
What's the difference between TlsConfig and CaTlsConfig?
TlsConfig in iroh/src/tls.rs handles rustls configuration for direct iroh peer-to-peer connections using raw public keys for authentication. CaTlsConfig in iroh-relay/src/tls.rs manages certificate verification for external services like relays, PKARR, and DNS-over-HTTPS using traditional certificate authorities. The former uses make_client_config and make_server_config with custom raw-public-key verifiers, while the latter provides client_config for standard TLS verification.
Can I use system certificates for relay connections?
Yes, configure CaTlsConfig::system() to use the operating system's root certificate store instead of the embedded Mozilla roots. Call client_config() on the resulting CaTlsConfig instance with your crypto provider to create a rustls ClientConfig suitable for connecting to iroh relays and other external services over standard TLS.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →