# QUIC + TLS 1.3

quicproquo uses QUIC (RFC 9000) with mandatory TLS 1.3 (RFC 9001) as its transport layer. This page explains how the `quinn` and `rustls` crates are integrated and what security properties the transport provides.

## Why QUIC

QUIC provides several advantages over traditional TCP-based transports:

- **Multiplexed streams**: Native bidirectional streams; each RPC call gets its own stream without head-of-line blocking.
- **0-RTT resumption**: Returning clients can send data in the first flight, reducing connection setup latency.
- **Integrated encryption**: TLS 1.3 is integral to the QUIC handshake; no extra round-trips for transport security.
- **NAT traversal**: UDP-based; connection migration survives NAT rebinding.
- **Ecosystem support**: `capnp-rpc` can use QUIC bidirectional streams directly via the `tokio-util` compat layer.

## Crate integration

quicproquo uses the following crates for QUIC and TLS:

- **`quinn 0.11`** -- The async QUIC implementation for Tokio. Provides `Endpoint`, `Connection`, and bidirectional stream types.
- **`quinn-proto 0.11`** -- The protocol-level types, including `QuicServerConfig` and `QuicClientConfig` wrappers that bridge `rustls` into `quinn`.
- **`rustls 0.23`** -- The TLS implementation. quicproquo uses it in strict TLS 1.3 mode with no fallback to TLS 1.2.
- **`rcgen 0.13`** -- Self-signed certificate generation for development and testing.

### Server configuration

The server builds its QUIC endpoint configuration in `build_server_config()` (in `quicproquo-server/src/main.rs`):

```rust
let mut tls = rustls::ServerConfig::builder_with_protocol_versions(&[&TLS13])
    .with_no_client_auth()
    .with_single_cert(cert_chain, key)?;
tls.alpn_protocols = vec![b"capnp".to_vec()];

let crypto = QuicServerConfig::try_from(tls)?;
Ok(ServerConfig::with_crypto(Arc::new(crypto)))
```

Key points:

1. **TLS 1.3 strict mode**: `builder_with_protocol_versions(&[&TLS13])` ensures no TLS 1.2 fallback. This is a hard requirement: TLS 1.2 lacks the 0-RTT and full forward secrecy guarantees that quicproquo relies on.

2. **No client certificate authentication**: `with_no_client_auth()` means the server does not verify client certificates at the TLS layer. Client authentication is handled at the application layer via Ed25519 identity keys and MLS credentials. This is a deliberate design choice -- MLS provides stronger authentication properties than TLS client certificates.

3. **ALPN negotiation**: The Application-Layer Protocol Negotiation extension is set to `b"capnp"`, advertising that this endpoint speaks Cap'n Proto RPC. Both client and server must agree on this protocol identifier or the TLS handshake fails.

4. **`QuicServerConfig` bridge**: The `quinn-proto` crate provides `QuicServerConfig::try_from(tls)` to adapt the `rustls::ServerConfig` for use with QUIC. This handles the QUIC-specific TLS parameters (transport parameters, QUIC header protection keys) automatically.

### Client configuration

The client performs the mirror operation. It loads the server's DER-encoded certificate from a local file and constructs a `rustls::ClientConfig`:

```rust
let mut roots = rustls::RootCertStore::empty();
roots.add(CertificateDer::from(cert_bytes))?;

let tls = rustls::ClientConfig::builder_with_protocol_versions(&[&TLS13])
    .with_root_certificates(roots)
    .with_no_client_auth();
tls.alpn_protocols = vec![b"capnp".to_vec()];

let crypto = QuicClientConfig::try_from(tls)?;
```

The client trusts exactly one certificate: the server's self-signed cert loaded from disk. There is no system trust store involved, which simplifies the trust model but requires out-of-band distribution of the server certificate.

### Per-connection handling

Each accepted QUIC connection spawns a handler task:

```rust
let (send, recv) = connection.accept_bi().await?;
let (reader, writer) = (recv.compat(), send.compat_write());

let network = twoparty::VatNetwork::new(reader, writer, Side::Server, Default::default());
let service: node_service::Client = capnp_rpc::new_client(NodeServiceImpl { store, waiters });
RpcSystem::new(Box::new(network), Some(service.client)).await?;
```

The `tokio-util` compat layer (`compat()` and `compat_write()`) converts Quinn's `RecvStream` and `SendStream` into types that implement `futures::AsyncRead` and `futures::AsyncWrite`, which `capnp-rpc`'s `VatNetwork` requires. The entire Cap'n Proto RPC system then runs over this single QUIC bidirectional stream.

Because `capnp-rpc` uses `Rc<RefCell<>>` internally (making it `!Send`), all RPC tasks run on a `tokio::task::LocalSet`. The server spawns each connection handler via `tokio::task::spawn_local`.

## Certificate trust model

quicproquo currently uses a **trust-on-first-use (TOFU)** model with self-signed certificates:

1. On first start, the server generates a self-signed certificate using `rcgen::generate_simple_self_signed` with SANs for `localhost`, `127.0.0.1`, and `::1`.
2. The certificate and private key are persisted to disk as DER files (default: `data/server-cert.der` and `data/server-key.der`).
3. Clients must obtain the server's certificate file out-of-band and reference it via the `--ca-cert` flag or `QPQ_CA_CERT` environment variable.

This model is adequate for development and single-server deployments. The roadmap includes:

- **ACME integration** (Let's Encrypt) for production deployments with publicly-routable servers.
- **Certificate pinning** to detect MITM attacks even when a CA is compromised.
- **Certificate transparency** log monitoring for detecting misissued certificates.

## Self-signed certificate generation

The server's `generate_self_signed()` function:

```rust
let subject_alt_names = vec![
    "localhost".to_string(),
    "127.0.0.1".to_string(),
    "::1".to_string(),
];
let issued = generate_simple_self_signed(subject_alt_names)?;

fs::write(cert_path, issued.cert.der())?;
fs::write(key_path, &issued.key_pair.serialize_der())?;
```

The generated certificate includes both DNS and IP SANs so that clients can connect using either `localhost` or an IP address. The client specifies the expected server name via `--server-name` (default: `localhost`), which must match one of the certificate's SANs.

## Security properties

The QUIC + TLS 1.3 layer provides:

| Property | Mechanism |
|---|---|
| **Transport confidentiality** | All application data is encrypted with AES-128-GCM or ChaCha20-Poly1305 (negotiated during the TLS handshake) |
| **Server authentication** | The client verifies the server's certificate against the locally-trusted DER file |
| **Forward secrecy** | TLS 1.3 exclusively uses ephemeral Diffie-Hellman key exchange; session keys are not derivable from the server's long-term key |
| **Replay protection** | QUIC packet numbers and TLS 1.3's anti-replay mechanism prevent replay attacks |
| **Connection migration** | QUIC connection IDs allow the client to change IP addresses without re-handshaking |

### What TLS does *not* provide

- **Client authentication**: Handled by MLS identity credentials at the application layer. See [MLS (RFC 9420)](mls.md).
- **End-to-end encryption**: TLS terminates at the server. The server can read the Cap'n Proto RPC framing and message routing metadata. Payload confidentiality is provided by MLS. See [MLS (RFC 9420)](mls.md).
- **Post-quantum resistance**: TLS 1.3 key exchange uses classical ECDHE. Post-quantum protection of application data is provided by the [Hybrid KEM](hybrid-kem.md) layer (M5 milestone).

## Configuration reference

### Server

| Environment Variable | CLI Flag | Default | Description |
|---|---|---|---|
| `QPQ_LISTEN` | `--listen` | `0.0.0.0:7000` | QUIC listen address |
| `QPQ_TLS_CERT` | `--tls-cert` | `data/server-cert.der` | TLS certificate path |
| `QPQ_TLS_KEY` | `--tls-key` | `data/server-key.der` | TLS private key path |
| `QPQ_DATA_DIR` | `--data-dir` | `data` | Persistent storage directory |

### Client

| Environment Variable | CLI Flag | Default | Description |
|---|---|---|---|
| `QPQ_CA_CERT` | `--ca-cert` | `data/server-cert.der` | Server certificate to trust |
| `QPQ_SERVER_NAME` | `--server-name` | `localhost` | Expected TLS server name (must match certificate SAN) |
| `QPQ_SERVER` | `--server` | `127.0.0.1:7000` | Server address (per-subcommand) |

## Further reading

- [Cap'n Proto Serialisation and RPC](capn-proto.md) -- The RPC layer that runs on top of QUIC streams.
- [Service Architecture](../architecture/service-architecture.md) -- How the server's `NodeServiceImpl` binds to the QUIC endpoint.
