Security Features of Iroh: Cryptographic Identity, TLS 1.3, and Zero-Trust Networking
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, 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 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, 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, 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 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, the implementation creates HeaderKey, PacketKey, and HandshakeTokenKey instances from the secret key material.
The RustlsTokenKey implementation in 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
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
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
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.
Verifying Peer Identity During Handshake
// 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
SecretKeymanaged by theBuilderiniroh/src/endpoint.rs, with the public key serving as the endpoint's identity. - Raw Public Key TLS: Implements RFC 7250 via
TlsConfigand custom verifiers iniroh/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 theOutgoingZeroRttandIncomingZeroRtttypes. - Relay Authentication: Supports opaque tokens via
RelayConfig::with_auth_token, validated by the relay server iniroh-relay/src/server/http_server.rs. - Packet Authentication: All QUIC packets carry signatures derived from the endpoint key via
HeaderKeyandPacketKeyiniroh/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. 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 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.
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 →