Files
quicproquo/docs/src/wire-format/auth-schema.md
Christian Nennemann f334ed3d43 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>
2026-02-22 08:07:48 +01:00

7.3 KiB

Auth Schema

Schema file: schemas/auth.capnp File ID: @0xb3a8f1c2e4d97650

The AuthenticationService interface defines the RPC contract for uploading and fetching MLS KeyPackages. It is the standalone version of the Authentication Service; in the current architecture, these methods are integrated into the unified NodeService interface.


Full schema listing

# auth.capnp -- Authentication Service RPC interface.
#
# Clients call uploadKeyPackage before joining any group so that peers can
# fetch their key material to add them. Each KeyPackage is single-use (MLS
# requirement): fetchKeyPackage removes and returns one package atomically.
#
# The server indexes packages by the raw Ed25519 public key bytes (32 bytes),
# not a fingerprint, so callers must know the target's identity public key
# out-of-band (e.g. from a directory or QR code scan).
#
# ID generated with: capnp id
@0xb3a8f1c2e4d97650;

interface AuthenticationService {
  # Upload a single-use KeyPackage for later retrieval by peers.
  #
  # identityKey : Ed25519 public key bytes (exactly 32 bytes).
  # package     : openmls-serialised KeyPackage blob (TLS encoding).
  #
  # Returns the SHA-256 fingerprint of `package`. Clients should record this
  # and compare it against the fingerprint returned by a peer's fetchKeyPackage
  # to detect tampering.
  uploadKeyPackage @0 (identityKey :Data, package :Data) -> (fingerprint :Data);

  # Fetch and atomically remove one KeyPackage for a given identity key.
  #
  # Returns empty Data if no KeyPackage is currently stored for this identity.
  # Callers should handle the empty case by asking the target to upload more
  # packages before retrying.
  fetchKeyPackage  @1 (identityKey :Data) -> (package :Data);
}

Method-by-method analysis

uploadKeyPackage @0

uploadKeyPackage (identityKey :Data, package :Data) -> (fingerprint :Data)

Purpose: A client uploads a single-use MLS KeyPackage so that peers can later fetch it to add the client to a group.

Parameters:

Parameter Type Size Description
identityKey Data Exactly 32 bytes The uploader's raw Ed25519 public key bytes. This is the index key under which the package is stored.
package Data Variable (bounded by transport max) An openmls-serialised KeyPackage blob in TLS encoding. Contains the client's HPKE init key, credential, and signature.

Return value:

Field Type Size Description
fingerprint Data 32 bytes SHA-256 digest of the uploaded package bytes.

Fingerprint semantics: The returned fingerprint allows the uploading client to verify that the server stored the package correctly. More importantly, when a peer later fetches a KeyPackage, it can compare the fetched package's SHA-256 hash against the fingerprint (communicated out-of-band) to detect tampering by a malicious server.

Idempotency: Uploading the same package twice appends a second copy to the queue. The server does not deduplicate. Clients should avoid uploading duplicates to conserve their KeyPackage supply.

fetchKeyPackage @1

fetchKeyPackage (identityKey :Data) -> (package :Data)

Purpose: Fetch and atomically remove one KeyPackage for a given identity. This is the mechanism by which a group creator obtains a peer's key material in order to add them to a group via MLS add_members().

Parameters:

Parameter Type Size Description
identityKey Data Exactly 32 bytes The raw Ed25519 public key of the target peer whose KeyPackage is being requested.

Return value:

Field Type Size Description
package Data Variable, or 0 bytes The fetched KeyPackage blob, or empty Data if no packages are stored for this identity.

Atomic removal: The fetch operation is destructive: it removes the returned KeyPackage from the server's store in the same operation that returns it. This guarantees MLS's single-use requirement -- a KeyPackage is never served to two different requesters.

Empty response handling: Callers must check for an empty response. An empty package means the target has no KeyPackages available. The caller should either:

  1. Retry after a delay, hoping the target uploads more packages.
  2. Signal the user that the target is unreachable for group addition.

Indexing by raw Ed25519 public key

The Authentication Service indexes KeyPackages by the raw 32-byte Ed25519 public key, not by a fingerprint or any higher-level identifier. This design choice has several implications:

  1. No directory service required for lookup. The caller must already know the target's Ed25519 public key (obtained out-of-band via QR code scan, manual exchange, or a future directory service).

  2. Consistent with DS indexing. The Delivery Service uses the same 32-byte Ed25519 key as its queue index, so a single key serves as the universal identifier across both services.

  3. No ambiguity. Unlike fingerprints (which could collide if truncated) or human-readable names (which require a mapping layer), the raw public key is the canonical, collision-resistant identifier.


Single-use semantics

MLS requires that each KeyPackage be used at most once to preserve the forward secrecy of the initial key exchange. The Authentication Service enforces this by atomically removing the KeyPackage on fetch.

Consequences for clients:

  • Clients should pre-upload multiple KeyPackages after generating their identity, so that several peers can add them to groups concurrently without exhausting the supply.
  • Clients should monitor their KeyPackage count on the server (via a future monitoring endpoint or periodic re-upload) and replenish when the supply runs low.
  • If a client has zero KeyPackages stored, it is effectively unreachable for new group invitations until it uploads more.

For the design rationale behind single-use KeyPackages, see ADR-005: Single-Use KeyPackages.


Relationship to NodeService

In the current unified architecture, the Authentication Service methods are exposed as part of the NodeService interface:

AuthenticationService Method NodeService Method Additional Parameters
uploadKeyPackage @0 uploadKeyPackage @0 auth :Auth
fetchKeyPackage @1 fetchKeyPackage @1 auth :Auth

The standalone AuthenticationService interface remains in the schema for documentation purposes and for use in contexts where the full NodeService is not needed.


Further reading