# Security Features of Iroh: Cryptographic Identity, TLS 1.3, and Zero-Trust Networking

> Explore Iroh's security features, including zero-trust networking, Ed25519 crypto identities, and TLS 1.3. Discover end-to-end encryption without certificate authorities.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: security-features
- Published: 2026-07-12

---

**Iroh implements a zero-trust security model using Ed25519 cryptographic identities, TLS 1.3 with raw public-key certificates (RFC 7250), and authenticated packet payloads, eliminating reliance on external certificate authorities while providing end-to-end encryption for every connection.**

The n0-computer/iroh repository provides a peer-to-peer networking stack built on cryptographic authentication rather than traditional PKI infrastructure. Understanding the security features of iroh requires examining how the codebase handles identity verification through raw public keys, transport encryption via TLS 1.3, and optional relay authentication without centralized trust anchors.

## Cryptographic Identity and Endpoint Authentication

Every iroh node derives its identity from a permanent **Ed25519 secret key** created during endpoint initialization. In [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), the `Builder` struct maintains a `secret_key: Option<SecretKey>` field that generates or receives the node's cryptographic identity. The public portion of this key, referred to as the `EndpointId`, serves as the node's permanent identifier and is used to prove identity on every connection.

When establishing connections, the node extracts the public key from the TLS server name and verifies it against the certificate presented by the remote peer. This mechanism ensures that the cryptographic identity remains consistent across network address changes and prevents identity spoofing without requiring external certificate authorities.

## TLS 1.3 with Raw Public Keys (RFC 7250)

Rather than relying on X.509 certificate chains, iroh uses **TLS 1.3 with the RFC 7250 raw-public-key extension**. The `TlsConfig` struct in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) builds client and server configurations through `make_client_config` and `make_server_config`, specifically enabling raw public key certificates instead of traditional PKIX validation.

The verification logic resides in [`iroh/src/tls/verifier.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/verifier.rs), where `ServerCertificateVerifier` and `ClientCertificateVerifier` implement strict validation rules. Both verifiers return `true` from `requires_raw_public_keys()`, and explicitly reject any intermediate certificates by checking `intermediates.is_empty()`. This design eliminates the attack surface of PKI-based validation by refusing to trust external CAs, using only the raw Ed25519 public key embedded in the endpoint ID as the trust anchor.

### Strict Cipher Suite Selection

Iroh enforces a minimal cipher suite policy to reduce complexity and potential vulnerabilities. The configuration specifically requires the **TLS 1.3 AES-128-GCM-SHA256** suite for QUIC initial packets. If the crypto provider lacks this suite, `TlsConfig::new` returns `TlsConfigError::CryptoProviderNoInitialCipherSuite`, preventing the endpoint from operating with unsupported cryptographic primitives.

## Zero-RTT Support and Security Trade-offs

For performance-critical applications, iroh supports **0-RTT (zero-round-trip time)** data transmission, allowing data to be sent before the TLS handshake completes. In [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs), the `make_client_config` and `make_server_config` functions set `crypto.enable_early_data = true` when 0-RTT is enabled.

However, the codebase explicitly flags this as weakened security. The `OutgoingZeroRtt` and `IncomingZeroRtt` types document the reduced security guarantees, and the `Builder` provides an `allow_0rtt` method that lets developers opt into this performance trade-off with full awareness of the security implications.

## Relay Authentication and Access Control

When communicating through relay servers, iroh supports optional **authentication tokens** for additional access control. The `RelayConfig::with_auth_token` method in [`iroh-relay/src/server/http_server.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/server/http_server.rs) stores an opaque token that the relay validates before allowing connections.

The relay server extracts the token from the `CLIENT_AUTH_HEADER` HTTP header and validates it against the configured access-control policy. This mechanism prevents unauthorized nodes from utilizing relay infrastructure while maintaining the end-to-end encryption properties of the peer-to-peer connection.

## Packet-Level Cryptographic Integrity

All QUIC packets carry cryptographic signatures derived from the endpoint's secret key through the `noq::crypto` primitives. In [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs), the implementation creates `HeaderKey`, `PacketKey`, and `HandshakeTokenKey` instances from the secret key material.

The `RustlsTokenKey` implementation in [`iroh/src/tls/misc.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/misc.rs) provides the `HandshakeTokenKey` functionality, ensuring that every packet's authenticity and integrity can be verified on receipt. This guarantees that payload data originates from the claimed endpoint and has not been modified in transit.

## Practical Implementation Examples

### Creating an Endpoint with Cryptographic Identity

```rust
use iroh::endpoint::{Builder, Preset};

let endpoint = Builder::new(Preset::default())
    .keylog(true)                 // enable SSLKEYLOGFILE (debug only)
    .build()
    .await?;                      // TLS config is derived automatically

```

The builder internally calls `TlsConfig::new` and registers the `ServerCertificateVerifier` that validates the raw public key against the endpoint ID.

### Enabling Zero-RTT for Low-Latency Connections

```rust
use iroh::endpoint::{Builder, Preset};

let endpoint = Builder::new(Preset::default())
    .allow_0rtt(true)            // sets crypto.enable_early_data = true
    .build()
    .await?;

```

This toggles the `enable_early_data` flag in `TlsConfig::make_client_config` and `TlsConfig::make_server_config`, allowing data transmission during the handshake phase.

### Configuring Relay Authentication Tokens

```rust
use iroh::endpoint::{Builder, Preset, RelayConfig};

let relay_cfg = RelayConfig::default()
    .with_auth_token("my-secret-token".to_string());

let endpoint = Builder::new(Preset::default())
    .relay(relay_cfg)            // attach the relay config
    .build()
    .await?;

let remote = endpoint.connect("iroh://peer-id@host:port".parse()?).await?;

```

The token is stored in `RelayConfig` and forwarded to the relay server, which validates it against the `CLIENT_AUTH_HEADER` in [`http_server.rs`](https://github.com/n0-computer/iroh/blob/main/http_server.rs).

### Verifying Peer Identity During Handshake

```rust
// Inside a connection handler
match conn.handshake().await {
    Ok(handshake) => {
        // peer_id() is derived from the TLS raw public key
        println!("Connected to {}", handshake.peer_id());
    }
    Err(e) => eprintln!("Handshake failed: {e:?}"),
}

```

The verification executes in `ServerCertificateVerifier::verify_server_cert`, which decodes the server name, extracts the raw public key, and compares it with the certificate's SPKI to confirm the peer's cryptographic identity.

## Summary

- **Cryptographic Identity**: Every node uses a permanent Ed25519 `SecretKey` managed by the `Builder` in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), with the public key serving as the endpoint's identity.
- **Raw Public Key TLS**: Implements RFC 7250 via `TlsConfig` and custom verifiers in [`iroh/src/tls/verifier.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/verifier.rs), rejecting X.509 chains and trusting only raw public keys.
- **Strict Cipher Policy**: Requires TLS 1.3 AES-128-GCM-SHA256, failing initialization if the crypto provider lacks support.
- **Optional 0-RTT**: Supports early data transmission through `allow_0rtt`, explicitly marked as reduced security in the `OutgoingZeroRtt` and `IncomingZeroRtt` types.
- **Relay Authentication**: Supports opaque tokens via `RelayConfig::with_auth_token`, validated by the relay server in [`iroh-relay/src/server/http_server.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/server/http_server.rs).
- **Packet Authentication**: All QUIC packets carry signatures derived from the endpoint key via `HeaderKey` and `PacketKey` in [`iroh/src/endpoint/quic.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/quic.rs).

## Frequently Asked Questions

### How does iroh verify peer identity without X.509 certificates?

Iroh uses the RFC 7250 raw-public-key extension for TLS 1.3, implemented in [`iroh/src/tls/verifier.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/verifier.rs). The `ServerCertificateVerifier` extracts the public key from the TLS server name and compares it directly to the raw key in the certificate's SPKI, rejecting any intermediate certificates. This eliminates the need for certificate authorities while ensuring the peer possesses the private key corresponding to the claimed `EndpointId`.

### Is 0-RTT safe to enable in production iroh applications?

Enabling 0-RTT via `allow_0rtt(true)` allows data transmission before the TLS handshake completes, which the codebase explicitly documents as weakened security in the `OutgoingZeroRtt` and `IncomingZeroRtt` types. While this improves latency, it should only be used for idempotent operations or when the performance gain outweighs the risk of replay attacks.

### What happens if my system doesn't support the required TLS cipher suite?

The `TlsConfig::new` function checks for the AES-128-GCM-SHA256 cipher suite required for QUIC initial packets. If your crypto provider lacks this suite, the function returns `TlsConfigError::CryptoProviderNoInitialCipherSuite` and the endpoint will fail to initialize. This strict requirement ensures all nodes use the same hardened cryptographic primitives.

### How does relay authentication prevent unauthorized access?

The `RelayConfig::with_auth_token` method attaches an opaque token to relay connections, which the relay server validates in [`iroh-relay/src/server/http_server.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/server/http_server.rs) by checking the `CLIENT_AUTH_HEADER`. This allows relay operators to restrict infrastructure access to nodes possessing valid tokens, while maintaining end-to-end encryption between peers.