Security Model for iroh Connections Using SecretKey/PublicKey Authentication: Ed25519, Raw Public Keys, and TLS 1.3

Iroh authenticates every connection using a permanent Ed25519 key pair where the PublicKey serves as the node’s endpoint ID and the SecretKey proves ownership through TLS 1.3 with the Raw Public Key extension, eliminating X.509 certificates and external certificate authorities.

The n0-computer/iroh project implements a PKI-free trust model for peer-to-peer and relay networking. In the security model for iroh connections using SecretKey/PublicKey authentication, each node generates a permanent Ed25519 identity that acts as both its cryptographic credential and its globally unique address. Every outbound and inbound QUIC connection verifies this identity through a lightweight TLS 1.3 handshake that relies on raw public keys rather than traditional X.509 certificates.

The Three-Layer Architecture of iroh’s Authentication Model

As implemented in n0-computer/iroh, the authentication stack is divided into three tightly coupled layers: identity, TLS handshake, and mutual verification. Each layer is responsible for a distinct phase of the connection lifecycle, from key generation to cryptographic proof.

Identity Layer: SecretKey and PublicKey as the Node ID

In iroh-base/src/key.rs, iroh defines SecretKey and PublicKey as wrappers around an Ed25519 key pair. SecretKey::generate() creates a fresh private key, and secret_key.public() derives the matching public key. This PublicKey becomes the node's immutable endpoint identifier and is used by higher-level protocols for discovery and routing.

TLS Handshake Layer: QUIC over TLS 1.3 with Raw Public Keys

All network traffic in iroh runs over QUIC wrapped in TLS 1.3. In iroh/src/tls.rs, the codebase constructs a TlsConfig that enables the Raw Public Key TLS extension (RFC 7250). This means the handshake carries the public key directly instead of an X.509 certificate, keeping the payload small and removing any dependency on certificate authorities.

Mutual Verification Layer: Custom Resolvers and Verifiers

iroh/src/tls/resolver.rs supplies the public key to rustls via ResolveRawPublicKeyCert, while iroh/src/tls/verifier.rs implements both ServerCertificateVerifier and ClientCertificateVerifier. During the handshake, the server presents its public key through the resolver, the client validates it using ServerCertificateVerifier, the client presents its public key, and the server validates it using ClientCertificateVerifier. Both sides compare the presented raw key against the expected PublicKey, ensuring each peer proves possession of its SecretKey without ever transmitting it.

How the iroh Handshake Establishes an Authenticated Connection

When an Endpoint is constructed in iroh/src/endpoint.rs, the builder accepts a secret key through Endpoint::builder().secret_key(...). The builder passes this key to TlsConfig::new, which initializes the raw-public-key infrastructure. The secret key remains in-process and is only used to sign TLS handshake data.

Connection Establishment and Key Verification

The QUIC stack, powered by rustls QuicClientConfig and QuicServerConfig, executes the handshake. Because the Raw Public Key extension is active, the proof of identity is simply a signature made with the node's SecretKey. After completion, both peers possess a cryptographically verified PublicKey that serves as the principal for all subsequent protocol operations.

Session Resumption and Zero-RTT Data

Iroh optionally caches TLS tickets (DEFAULT_MAX_TLS_TICKETS) to support 0-RTT data on subsequent connections. Each resumed session reuses the same public-key verification path, so the authentication guarantee remains intact even when the connection establishes in a single round trip.

Security Guarantees Provided by iroh’s SecretKey/PublicKey Model

  • Confidentiality and integrity: All payloads are encrypted with QUIC-TLS 1.3 using keys derived from the handshake.
  • Authentication without a PKI: No external certificate authorities are required; the PublicKey itself is the identity.
  • Forward secrecy: Ephemeral Diffie-Hellman keys are generated per QUIC connection, so compromise of a secret key does not retroactively expose past traffic.
  • Minimal secret-key exposure: The SecretKey never leaves the process and only signs raw-public-key TLS structures.

Rust Code Example: Authenticating an iroh Endpoint

The following example demonstrates how to generate a secret key, bind an endpoint, and connect to a verified peer using the APIs exposed in iroh/src/endpoint.rs and iroh-base/src/key.rs.

use iroh::endpoint::Endpoint;
use iroh_base::SecretKey;

// Generate a fresh Ed25519 secret key
let my_secret = SecretKey::generate();

// Build an endpoint that authenticates with that key
let ep = Endpoint::builder()
    .secret_key(my_secret.clone())
    .bind()
    .await?;

// Connect to a remote endpoint using its known PublicKey (peer_id)
let conn = ep
    .connect(peer_id, "example.com:443".parse()?)
    .await?;

// The connection is authenticated; retrieve the peer's verified identity
println!("Connected to {}", conn.remote_id().fmt_short());

// Open a stream and send encrypted data
let mut stream = conn.open_stream().await?;
stream.write_all(b"hello iroh").await?;

If you have already persisted a secret key through your application’s storage layer, pass it to the same builder before binding:

let secret = SecretKey::from_file("my-key.bin")?; // application-specific I/O
let ep = Endpoint::builder().secret_key(secret).bind().await?;

Summary

  • Each iroh node owns a permanent Ed25519 SecretKey and PublicKey, defined in iroh-base/src/key.rs, where the public key acts as the global endpoint ID.
  • All connections use QUIC wrapped in TLS 1.3 with the Raw Public Key extension (RFC 7250), configured centrally in iroh/src/tls.rs.
  • Mutual authentication is enforced by ServerCertificateVerifier and ClientCertificateVerifier in iroh/src/tls/verifier.rs, ensuring both peers verify each other’s raw public key.
  • The SecretKey never leaves the process and is only used to sign the raw-public-key TLS structure, delivering strong authentication without a PKI.
  • Optional 0-RTT session resumption via TLS tickets preserves these authentication guarantees across reconnections.

Frequently Asked Questions

What cryptographic algorithm does iroh use for SecretKey/PublicKey authentication?

Iroh uses Ed25519 for all node identity keys. The SecretKey and PublicKey types in iroh-base/src/key.rs wrap Ed25519 key material, and the TLS handshake produces signatures with this key pair to prove ownership without transmitting the secret key.

Does iroh require X.509 certificates or a certificate authority?

No. As implemented in iroh/src/tls.rs, the connection security model uses the TLS 1.3 Raw Public Key extension (RFC 7250) to send public keys directly, relying on the PublicKey itself as the trusted identity rather than X.509 certificates.

How does iroh verify the peer’s identity during a connection?

During the QUIC handshake, iroh/src/tls/resolver.rs presents the raw public key, and iroh/src/tls/verifier.rs validates it. Both the client and server run custom verifiers—ServerCertificateVerifier and ClientCertificateVerifier—that compare the presented raw public key against the expected endpoint ID, enforcing mutual authentication.

Is forward secrecy supported in iroh’s SecretKey/PublicKey security model?

Yes. Iroh achieves forward secrecy by generating ephemeral Diffie-Hellman keys for each QUIC connection during the TLS 1.3 handshake. Even if a long-term SecretKey is compromised later, past traffic remains secure because the session keys were derived from the ephemeral exchange, not from the static Ed25519 key pair.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →