feat: add post-quantum hybrid KEM + SQLCipher persistence
Feature 1 — Post-Quantum Hybrid KEM (X25519 + ML-KEM-768): - Create hybrid_kem.rs with keygen, encrypt, decrypt + 11 unit tests - Wire format: version(1) | x25519_eph_pk(32) | mlkem_ct(1088) | nonce(12) | ct - Add uploadHybridKey/fetchHybridKey RPCs to node.capnp schema - Server: hybrid key storage in FileBackedStore + RPC handlers - Client: hybrid keypair in StoredState, auto-wrap/unwrap in send/recv/invite/join - demo-group runs full hybrid PQ envelope round-trip Feature 2 — SQLCipher Persistence: - Extract Store trait from FileBackedStore API - Create SqlStore (rusqlite + bundled-sqlcipher) with encrypted-at-rest SQLite - Schema: key_packages, deliveries, hybrid_keys tables with indexes - Server CLI: --store-backend=sql, --db-path, --db-key flags - 5 unit tests for SqlStore (FIFO, round-trip, upsert, channel isolation) Also includes: client lib.rs refactor, auth config, TOML config file support, mdBook documentation, and various cleanups by user. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
166
docs/src/getting-started/running-the-server.md
Normal file
166
docs/src/getting-started/running-the-server.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Running the Server
|
||||
|
||||
The quicnprotochat server is a single binary (`quicnprotochat-server`) that exposes a unified **NodeService** endpoint combining Authentication Service (KeyPackage management) and Delivery Service (message relay) operations over a single QUIC + TLS 1.3 connection.
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cargo run -p quicnprotochat-server
|
||||
```
|
||||
|
||||
On first launch the server will:
|
||||
|
||||
1. Create the `data/` directory if it does not exist.
|
||||
2. Generate a self-signed TLS certificate and private key (`data/server-cert.der`, `data/server-key.der`) with SANs `localhost`, `127.0.0.1`, and `::1`.
|
||||
3. Open a QUIC endpoint on `0.0.0.0:7000`.
|
||||
4. Begin accepting connections.
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```
|
||||
2025-01-01T00:00:00.000000Z INFO quicnprotochat_server: generated self-signed TLS certificate cert="data/server-cert.der" key="data/server-key.der"
|
||||
2025-01-01T00:00:00.000000Z INFO quicnprotochat_server: accepting QUIC connections addr="0.0.0.0:7000"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
All configuration is available via CLI flags and environment variables. Environment variables take precedence when both are specified.
|
||||
|
||||
| Purpose | CLI flag | Env var | Default |
|
||||
|---|---|---|---|
|
||||
| QUIC listen address | `--listen` | `QUICNPROTOCHAT_LISTEN` | `0.0.0.0:7000` |
|
||||
| TLS certificate (DER) | `--tls-cert` | `QUICNPROTOCHAT_TLS_CERT` | `data/server-cert.der` |
|
||||
| TLS private key (DER) | `--tls-key` | `QUICNPROTOCHAT_TLS_KEY` | `data/server-key.der` |
|
||||
| Data directory | `--data-dir` | `QUICNPROTOCHAT_DATA_DIR` | `data` |
|
||||
| Log level | -- | `RUST_LOG` | `info` |
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Listen on a custom port
|
||||
cargo run -p quicnprotochat-server -- --listen 0.0.0.0:9000
|
||||
|
||||
# Use pre-existing TLS credentials
|
||||
cargo run -p quicnprotochat-server -- \
|
||||
--tls-cert /etc/quicnprotochat/cert.der \
|
||||
--tls-key /etc/quicnprotochat/key.der
|
||||
|
||||
# Via environment variables
|
||||
QUICNPROTOCHAT_LISTEN=0.0.0.0:9000 \
|
||||
RUST_LOG=debug \
|
||||
cargo run -p quicnprotochat-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TLS certificate handling
|
||||
|
||||
### Self-signed certificate auto-generation
|
||||
|
||||
If the files at `--tls-cert` and `--tls-key` do not exist when the server starts, it generates a self-signed certificate using the `rcgen` crate. The generated certificate includes three Subject Alternative Names:
|
||||
|
||||
- `localhost`
|
||||
- `127.0.0.1`
|
||||
- `::1`
|
||||
|
||||
The certificate and key are written in DER format. Parent directories are created automatically.
|
||||
|
||||
### Using your own certificate
|
||||
|
||||
To use a certificate issued by a CA or a custom self-signed certificate:
|
||||
|
||||
1. Convert your certificate and key to DER format if they are in PEM:
|
||||
```bash
|
||||
openssl x509 -in cert.pem -outform DER -out cert.der
|
||||
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -out key.der -nocrypt
|
||||
```
|
||||
2. Point the server at them:
|
||||
```bash
|
||||
cargo run -p quicnprotochat-server -- \
|
||||
--tls-cert cert.der \
|
||||
--tls-key key.der
|
||||
```
|
||||
3. Distribute the certificate (or its CA root) to clients so they can verify the server. The client's `--ca-cert` flag accepts a DER file.
|
||||
|
||||
### TLS configuration details
|
||||
|
||||
The server's TLS stack is configured as follows:
|
||||
|
||||
- **Protocol versions**: TLS 1.3 only (`rustls::version::TLS13`). TLS 1.2 and below are rejected.
|
||||
- **Client authentication**: Disabled (`with_no_client_auth()`). The server does not request a client certificate. Client identity is established at the MLS layer via Ed25519 credentials, not at the TLS layer.
|
||||
- **ALPN**: The server advertises `b"capnp"` as the application-layer protocol.
|
||||
|
||||
---
|
||||
|
||||
## ALPN negotiation
|
||||
|
||||
Both the server and client must agree on the ALPN token `b"capnp"` during the TLS handshake. This token is hardcoded in the server's TLS configuration:
|
||||
|
||||
```rust
|
||||
tls.alpn_protocols = vec![b"capnp".to_vec()];
|
||||
```
|
||||
|
||||
If a client connects with a different (or no) ALPN token, the QUIC handshake will fail with an ALPN mismatch error.
|
||||
|
||||
---
|
||||
|
||||
## Storage
|
||||
|
||||
The server persists its state to the data directory (`--data-dir`, default `data/`):
|
||||
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| `data/server-cert.der` | TLS certificate (DER) |
|
||||
| `data/server-key.der` | TLS private key (DER) |
|
||||
| `data/keypackages.bin` | `bincode`-serialised map of identity keys to KeyPackage queues |
|
||||
| `data/deliveries.bin` | `bincode`-serialised map of `(channelId, recipientKey)` to message queues |
|
||||
| `data/hybridkeys.bin` | `bincode`-serialised map of identity keys to hybrid (X25519 + ML-KEM-768) public keys |
|
||||
|
||||
Storage is implemented by the `FileBackedStore` in `crates/quicnprotochat-server/src/storage.rs`. Every mutation (upload, enqueue, fetch) flushes the entire map to disk synchronously. This is suitable for proof-of-concept workloads but not production traffic. See [Storage Backend](../internals/storage-backend.md) for details.
|
||||
|
||||
---
|
||||
|
||||
## Connection handling
|
||||
|
||||
Each incoming QUIC connection is handled in a `tokio::task::spawn_local` task on a shared `LocalSet`. The `capnp-rpc` library uses `Rc<RefCell<>>` internally, making it `!Send`, which is why all RPC tasks must run on a `LocalSet` rather than being spawned with `tokio::spawn`.
|
||||
|
||||
The connection lifecycle:
|
||||
|
||||
1. Accept incoming QUIC connection.
|
||||
2. Complete TLS 1.3 handshake.
|
||||
3. Accept a bidirectional QUIC stream.
|
||||
4. Wrap the stream in a `capnp_rpc::twoparty::VatNetwork`.
|
||||
5. Bootstrap a `NodeService` RPC endpoint.
|
||||
6. Serve requests until the client disconnects or an error occurs.
|
||||
|
||||
---
|
||||
|
||||
## Logging
|
||||
|
||||
The server uses `tracing` with `tracing-subscriber` and respects the `RUST_LOG` environment variable:
|
||||
|
||||
```bash
|
||||
# Default: info level
|
||||
RUST_LOG=info cargo run -p quicnprotochat-server
|
||||
|
||||
# Debug level for detailed RPC tracing
|
||||
RUST_LOG=debug cargo run -p quicnprotochat-server
|
||||
|
||||
# Trace level for maximum verbosity
|
||||
RUST_LOG=trace cargo run -p quicnprotochat-server
|
||||
|
||||
# Filter to specific crates
|
||||
RUST_LOG=quicnprotochat_server=debug,quinn=warn cargo run -p quicnprotochat-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Running the Client](running-the-client.md) -- connect to the server and exercise the CLI
|
||||
- [Demo Walkthrough](demo-walkthrough.md) -- step-by-step Alice-and-Bob group messaging scenario
|
||||
- [Service Architecture](../architecture/service-architecture.md) -- how the NodeService combines AS and DS
|
||||
Reference in New Issue
Block a user