# How Iroh Ensures Security and TLS Encryption: Raw Public Keys and QUIC Implementation

> Learn how Iroh ensures security and TLS encryption using QUIC and raw public keys. Discover its PKI-free approach for robust end-to-end encryption and forward secrecy.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-07-15

---

**Iroh guarantees secure peer-to-peer communication by implementing TLS 1.3 over QUIC with raw public key authentication (RFC 7250), eliminating traditional PKI dependencies while maintaining end-to-end encryption and forward secrecy through a unified `TlsConfig` architecture.**

The n0-computer/iroh repository secures all network traffic using a zero-trust model that replaces X.509 certificates with cryptographic public key authentication. Understanding how Iroh ensures security and TLS encryption requires examining its rustls integration, centralized configuration management, and relay-side transport handling.

## Raw Public Key Authentication (RFC 7250)

Instead of relying on traditional X.509 certificates and Certificate Authorities, Iroh embeds **raw public keys** directly into the TLS handshake using the RFC 7250 extension. This approach eliminates PKI dependencies while maintaining strong peer authentication.

The `ResolveRawPublicKeyCert` resolver derives the public key from the node's `SecretKey` and supplies it to rustls during the handshake. This implementation appears in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) and ensures each node cryptographically proves its identity without certificate chains.

## Unified TLS Configuration Architecture

Iroh centralizes all TLS state within the `TlsConfig` struct to ensure consistency across client and server sessions. This configuration manages certificate verification, session caching, and cryptographic providers through a single source of truth.

### TlsConfig Structure

The `TlsConfig` struct holds the node's **secret key**, certificate resolver, and custom verifiers for both client and server authentication. Key components include:

- **Memory-based session-ticket cache**: Limited to `DEFAULT_MAX_TLS_TICKETS` (approximately 150 KB) to prevent unbounded memory growth
- **Injectable crypto provider**: The `crypto_provider` field accepts custom rustls cryptographic implementations
- **Dual verifier support**: Separate verifiers for client and server authentication ensure role-specific validation logic

Source reference: [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) (lines 45-52).

### Client Configuration

When initiating connections, the `make_client_config` method constructs a `rustls::ClientConfig` with security-hardened defaults:

- Restricts TLS to `verifier::PROTOCOL_VERSIONS` (TLS 1.3)
- Implements custom certificate verification via `server_verifier`
- Integrates the raw-public-key resolver (`cert_resolver`)
- Enables **early-data (0-RTT)** for connection resumption
- Supports optional key-logging via `SSLKEYLOGFILE` for debugging
- Wraps the result in a `QuicClientConfig` for QUIC transport

Source reference: [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) (lines 72-98).

### Server Configuration

The `make_server_config` method creates a symmetric `rustls::ServerConfig` for incoming connections:

- Uses identical protocol versions and crypto providers as the client
- Enforces client-certificate verification through `client_verifier`
- Supplies the same raw-public-key resolver for peer authentication
- Enables early-data with maximum size set to `u32::MAX` per RFC 9001 requirements
- Optionally enables key-logging for development environments

Source reference: [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) (lines 100-122).

## Relay-Side TLS Implementation

Iroh's relay client implements independent TLS handling for connections to relay servers, maintaining security guarantees even when traffic traverses intermediary nodes.

### Relay Client TLS

The relay client constructs its own `rustls::ClientConfig` and `tokio_rustls::TlsConnector` in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs). This implementation respects the same raw-public-key verification strategy used in direct peer connections while allowing TLS to be bypassed for non-secure schemes (`http`/`ws`).

Source references: lines 31-38 and 65-78.

### MaybeTlsStreamBuilder

The `MaybeTlsStreamBuilder` determines whether TLS is required based on the URL scheme, extracts the server name for verification, and performs the handshake via `TlsConnector`. The resulting `MaybeTlsStream` abstracts over plain TCP or TLS-wrapped transport, providing a unified interface for the QUIC stack.

Source reference: [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs) (lines 78-90).

## Security Guarantees

Iroh's TLS implementation provides four critical security properties:

- **End-to-end encryption**: All traffic is encrypted using TLS 1.3 cipher suites with no downgrade attacks possible
- **Authenticity**: Raw public keys ensure cryptographic peer identity without trusting third-party CAs
- **Forward secrecy**: QUIC's TLS 1.3 integration ensures session keys cannot be compromised retroactively
- **Replay protection**: 0-RTT session tickets are carefully bounded by the `DEFAULT_MAX_TLS_TICKETS` limit to prevent replay attacks

## Implementation Examples

The following examples demonstrate creating secure TLS configurations for Iroh nodes:

```rust
// Creating a TLS configuration for a node
use iroh_base::SecretKey;
use std::sync::Arc;
use iroh::tls::TlsConfig;

// Generate node identity and select crypto provider
let sk = SecretKey::generate();
let provider = rustls::crypto::CryptoProvider::default();
let tls_cfg = TlsConfig::new(
    sk.clone(), 
    TlsConfig::DEFAULT_MAX_TLS_TICKETS, 
    Arc::new(provider)
);

// Build client configuration
let client_cfg = tls_cfg.make_client_config(/*keylog=*/false)?;
let quic_client = client_cfg; // Ready for QUIC transport

// Build server configuration  
let server_cfg = tls_cfg.make_server_config(/*keylog=*/false)?;
let quic_server = server_cfg; // Ready for QUIC listener

```

For relay connections with custom TLS settings:

```rust
// Dialing a relay with TLS
use iroh_relay::client::MaybeTlsStreamBuilder;
use rustls::ClientConfig;

// Configure rustls with custom verification
let tls_cfg = ClientConfig::builder()
    .with_safe_defaults()
    .with_custom_certificate_verifier(Arc::new(my_verifier))
    .with_root_certificates(my_root_store)
    .with_no_client_auth();

let builder = MaybeTlsStreamBuilder::new(relay_url, dns_resolver, tls_cfg);
let stream = builder.connect().await?; // Returns MaybeTlsStream

```

## Summary

- Iroh uses **TLS 1.3 over QUIC** with **raw public key authentication (RFC 7250)** instead of X.509 certificates, implemented in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs)
- The **`TlsConfig`** struct centralizes security state including session ticket caching (~150 KB limit) and cryptographic providers
- **Client and server configurations** are generated via `make_client_config` and `make_server_config` with 0-RTT support and strict protocol version enforcement
- The **relay client** maintains TLS security through `MaybeTlsStreamBuilder` in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs), supporting scheme-aware connection logic
- All components provide **end-to-end encryption**, **forward secrecy**, and **replay attack resistance** without PKI infrastructure

## Frequently Asked Questions

### How does Iroh verify identity without Certificate Authorities?

Iroh implements **raw public key authentication** as defined in RFC 7250. Instead of validating X.509 certificate chains against trusted root CAs, the TLS handshake embeds the peer's public key directly. The `ResolveRawPublicKeyCert` resolver in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) derives this key from the node's `SecretKey`, ensuring cryptographic identity verification without PKI infrastructure.

### What TLS versions does Iroh support?

Iroh strictly enforces **TLS 1.3** through the `verifier::PROTOCOL_VERSIONS` configuration. The implementation in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) explicitly disables older TLS versions to prevent downgrade attacks and ensure forward secrecy through modern cipher suites.

### Can Iroh TLS traffic be decrypted for debugging purposes?

Yes, Iroh supports optional **key-logging** via the `SSLKEYLOGFILE` environment variable. When enabled in `make_client_config` or `make_server_config`, the system logs TLS session keys that can be imported into tools like Wireshark. This feature is disabled by default in production builds to prevent information leakage.

### How does Iroh prevent replay attacks with 0-RTT enabled?

While Iroh enables **0-RTT (early-data)** for performance, it mitigates replay attacks by strictly bounding the session ticket cache to `DEFAULT_MAX_TLS_TICKETS` (approximately 150 KB). This limit prevents attackers from accumulating large numbers of tickets for replay attacks, as implemented in the `TlsConfig` memory-based cache.