# How to Configure Custom TLS Settings and Certificate Validation in Iroh

> Learn to configure custom TLS settings and certificate validation in Iroh. Customize cipher suites, crypto providers, and root certificates with CaTlsConfig builder.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-06-22

---

**Iroh exposes its underlying rustls configuration through the `CaTlsConfig` helper and builder methods like `tls_client_config`, allowing you to customize cipher suites, cryptographic providers, and root certificate stores when building relay clients or endpoints.**

Iroh uses **rustls** for all TLS connections, including relay sessions and DNS-over-HTTPS queries. To configure custom TLS settings and certificate validation in iroh, you construct a `rustls::ClientConfig` (or use the `CaTlsConfig` wrapper) and inject it into component builders such as `ClientBuilder` or `Endpoint::builder`.

## Understanding Iroh's TLS Architecture

The TLS stack follows a clear path from configuration to handshake. First, components obtain a `rustls::ClientConfig` from the caller. This config is optionally wrapped in `CaTlsConfig` (defined in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs)) to handle root certificate verification. Finally, the `MaybeTlsStreamBuilder::connect` method in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs) consumes this configuration to create a `tokio_rustls::TlsConnector` and perform the handshake.

Key source locations:
- **[`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs)** – Defines `CaTlsConfig` and its `client_config` method for converting to `rustls::ClientConfig`.
- **[`iroh-relay/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client.rs)** – Implements `ClientBuilder::tls_client_config` to store custom TLS configurations.
- **[`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs)** – Contains `MaybeTlsStreamBuilder::connect`, which clones the stored config and initiates the TLS session.
- **[`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs)** – Re-exports `CaTlsConfig` for the top-level `iroh` crate.

## Creating a Custom rustls::ClientConfig

You have full control over the cryptographic provider, cipher suites, and protocol versions. The default provider uses **Ring**, but you can substitute **AWS-LC-RS** or another compatible provider.

```rust
use std::sync::Arc;
use iroh_relay::client::ClientBuilder;
use rustls::{
    client::ClientConfig,
    crypto::CryptoProvider,
    version::TLS13,
};

// Select the cryptographic provider (Ring is the default).
let provider: Arc<CryptoProvider> = iroh_relay::tls::default_provider();

// Build a custom client configuration.
let mut rustls_cfg = ClientConfig::builder_with_provider(provider.clone())
    .with_safe_defaults()
    .with_custom_certificate_verifier(Arc::new(
        rustls::client::WebPkiServerVerifier::builder_with_provider(
            rustls::RootCertStore::empty(),
            provider.clone(),
        )
        .with_allowed_versions(&[TLS13])
        .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384])
        .build()
        .unwrap(),
    ))
    .with_no_client_auth();

// Apply to a relay client builder.
let client = ClientBuilder::new(
        "https://my.relay.example".parse::<iroh_relay::RelayUrl>().unwrap(),
        SecretKey::generate(),
        DnsResolver::new(),
    )
    .tls_client_config(rustls_cfg)
    .build()
    .await?;

```

## Customizing Root Certificate Validation

For scenarios requiring custom root stores or test environments, use `CaTlsConfig` to manage certificate authority trust. This helper is located in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs) and provides methods for custom roots, OS store integration, or disabling verification.

```rust
use iroh_relay::tls::CaTlsConfig;
use rustls::RootCertStore;
use rustls::internal::pemfile::certs;
use std::fs::File;

// Load PEM-encoded root certificates.
let mut file = File::open("my_root.pem").unwrap();
let mut root_store = RootCertStore::empty();
root_store.add_parsable_certificates(
    certs(&mut file).unwrap().into_iter().map(|c| c.into()),
);

// Create a CaTlsConfig with custom roots.
let ca_cfg = CaTlsConfig::custom_roots(root_store.roots.clone());

// Convert to rustls::ClientConfig using the default provider.
let client_cfg = ca_cfg.client_config(iroh_relay::tls::default_provider())?;

```

For testing only, you can disable certificate verification entirely:

```rust
let insecure_cfg = CaTlsConfig::insecure_skip_verify();

```

## Applying TLS Configurations to Iroh Components

Different components accept TLS configurations through specific builder methods:

- **`ClientBuilder::tls_client_config`** – Configures the relay client.
- **`EndpointBuilder::tls_client_config`** – Configures the high-level Iroh endpoint.
- **`DnsBuilder::tls_client_config`** – Configures DNS-over-HTTPS resolution.

When the connection is established, `MaybeTlsStreamBuilder::connect` (in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs)) clones the supplied `ClientConfig` and creates the `tokio_rustls::TlsConnector` to perform the handshake.

```rust
use iroh::{Endpoint, tls::CaTlsConfig};

let endpoint = Endpoint::builder()
    .tls_client_config(client_cfg)
    .ca_tls_config(CaTlsConfig::insecure_skip_verify()) // Testing only
    .build()
    .await?;

```

## Summary

- Iroh uses **rustls** for all TLS operations, exposing configuration through `rustls::ClientConfig`.
- The **`CaTlsConfig`** struct in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs) simplifies root certificate management and conversion to client configs.
- Component builders including **`ClientBuilder`** and **`Endpoint::builder`** accept custom TLS settings via the **`tls_client_config`** method.
- The actual TLS handshake occurs in **`MaybeTlsStreamBuilder::connect`** ([`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs)), which uses the provided configuration to initialize the connection.
- You can select cryptographic providers (Ring or AWS-LC-RS), restrict cipher suites, and customize root certificate stores.

## Frequently Asked Questions

### How do I disable certificate verification for local testing?

Use **`CaTlsConfig::insecure_skip_verify()`** when building your endpoint or client. This creates a configuration that accepts any server certificate. According to the source in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs), this bypasses all verification checks and should only be used in development environments.

### Can I use a cryptographic provider other than Ring?

Yes. Construct an `Arc<CryptoProvider>` using the **`aws-lc-rs`** crate (or another compatible provider) and pass it to `CaTlsConfig::client_config()` or use it with `ClientConfig::builder_with_provider()`. The default provider is Ring, but the architecture supports pluggable cryptography.

### Where does the actual TLS handshake happen in the code?

The handshake is performed in **`MaybeTlsStreamBuilder::connect`** within [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs). This method clones the stored `rustls::ClientConfig`, creates a `tokio_rustls::TlsConnector`, and initiates the TLS session when establishing relay connections.

### How do I add custom root certificates for a private CA?

Load your PEM-encoded certificates into a `rustls::RootCertStore`, then pass the roots to **`CaTlsConfig::custom_roots()`**. Call the **`client_config`** method on the resulting `CaTlsConfig` to generate a `rustls::ClientConfig` that trusts only your specified certificates, then supply this config to your component builder.