# Certificate lifecycle and CA-signed TLS

This page describes how to use CA-issued certificates with quicproquo and how to think about certificate pinning, rotation, and lifecycle.

For basic server TLS setup (self-signed certs, generation), see [Running the Server](running-the-server.md#tls-certificate-handling).

---

## Current behaviour

- **Server:** Uses a single TLS certificate and private key (DER format). If the files are missing and the server is not in production mode, it generates a self-signed certificate. Production mode (`QPQ_PRODUCTION=1`) requires existing cert and key files.
- **Client:** Trusts exactly the roots in the file given by `--ca-cert` (or `QPQ_CA_CERT`). Typically this is the server's own certificate (pinning) or a CA that signed the server cert.

---

## Certificate pinning (recommended for single-server)

To pin the server so the client only connects to that server:

1. Copy the server's certificate file (e.g. `data/server-cert.der`) from the server (or your deployment).
2. Use that file as the client's CA cert:
   ```bash
   qpq --ca-cert /path/to/server-cert.der ...
   ```
3. The client will only accept a connection if the server presents that exact certificate (or a chain ending in it). No separate CA bundle is required.

This is **trust-on-first-use**: whoever deploys the server and distributes the cert to clients is the trust anchor. Suitable for single-server or small deployments.

---

## CA-issued certificates (e.g. Let's Encrypt)

To use a certificate issued by a public CA (e.g. Let's Encrypt):

1. **Obtain the certificate and key** using your preferred method (e.g. certbot, acme-client). The server expects:
   - Certificate in **DER** format (not PEM). Convert if needed:
     ```bash
     openssl x509 -in fullchain.pem -outform DER -out server-cert.der
     ```
   - Private key in **DER** format (PKCS#8). Convert if needed:
     ```bash
     openssl pkcs8 -topk8 -inform PEM -outform DER -in privkey.pem -out server-key.der -nocrypt
     ```
2. **Configure the server** to use those paths:
   ```bash
   export QPQ_TLS_CERT=/etc/quicproquo/server-cert.der
   export QPQ_TLS_KEY=/etc/quicproquo/server-key.der
   ```
3. **Configure the client** to trust the CA that signed the server cert. Use the CA’s certificate (or the CA bundle) as `--ca-cert`:
   ```bash
   qpq --ca-cert /etc/ssl/certs/your-ca.der --server-name your.server.example ...
   ```
   The `--server-name` must match the certificate’s SAN (e.g. DNS name).

**Note:** The server does not currently reload the certificate on SIGHUP or on a timer. Certificate rotation is done by replacing the cert/key files and restarting the server (or by adding a future “reload” mechanism).

---

## Certificate rotation

- **Manual rotation:** Replace `server-cert.der` and `server-key.der` on disk, then restart the server. Clients that pin the new cert must be updated with the new cert file.
- **Let’s Encrypt renewal:** After renewing (e.g. via certbot), convert the new cert and key to DER, replace the files, and restart the server. If clients use the CA cert (e.g. ISRG Root X1) as `--ca-cert`, they do not need updates when the server cert is renewed.
- **OCSP / CRL:** The quicproquo server does not currently perform OCSP stapling or CRL checks. Revocation is handled by the client or by operational procedures (e.g. short-lived certs, rotation on compromise).

---

## Summary

| Deployment style | Server cert | Client `--ca-cert` |
|------------------|-------------|--------------------|
| Pinned (single server) | Self-signed or any | Server’s cert file |
| CA-issued | Let’s Encrypt (or other CA) | CA cert (or bundle) |
| Production | Always use existing cert/key; set `QPQ_PRODUCTION=1` | CA or pinned server cert |

For production, prefer either (a) certificate pinning with the server’s cert or (b) a CA-issued server cert with clients trusting the CA, and plan for rotation and restart (or future reload support).
