Device Enrollment
DraftEach device holds a DSK + DEK cross-signed into the user’s device directory. Two ceremonies put a device there; recovery after losing every device is cross-device recovery, not enrollment.
Trust split: account-creation auth (Authentication) establishes who owns the account and confers no data access. Data authority is cryptographic: the master key and device keys verified against the directory.
First-Device Enrollment
Section titled “First-Device Enrollment”- Master key from the OS CSPRNG (shape); wrapped under the recovery secret and uploaded as the master-key escrow.
- User IK (composition); private halves wrapped under the master key, public halves into the directory.
- Device keys (composition), signed by the IK. The classical half MUST be non-exportable in the secure element where one exists; secure elements offer only P-256, so the hardware path is the planned P-256 hybrid with the PQ half software-sealed under hardware-protected material. Until then both halves are software.
- Publish the IK-signed directory.
- Default album: a new MLS group at the master-key-derived
album_id(Key Chain), this device sole admin/writer; setdefault_album_id(Filesystem — Server). - Show the recovery secret behind a type-back gate (not advisory). It is never persisted.
A second device right after signup uses ordinary cross-device add.
Cross-Device Add
Section titled “Cross-Device Add”Precondition: device A is signed in and holds the master key.
- Initiate on A. Requires a fresh local authorization (biometric/passcode); a session token alone MUST NOT suffice. Server-side, the account must have proved a credential within 5 minutes of the session’s
authenticated_at, which a token refresh does not reset; a stale session re-proves viaPOST /v1/auth/reauthenticate. - Enrollment code. Single-use, 10-minute expiry, deleted on redeem or expiry, rate-limited at redemption. QR carries ≥64 bits; an 8–10-digit text fallback trades entropy for transcribability and is safe only because of the rate limit (argument in
capsule-server/src/counter/budgets.rs) and because channel integrity never rests on the code. - Channel. Ephemeral X25519 between A and B, LAN-direct (mDNS) when available, else server relay; authenticated by the code plus the DH.
- Verify. Both devices show a transcript-derived safety code in the same chunked fixed-length format with each device’s model and key fingerprint; the user MUST explicitly confirm match and identity on both devices. Mismatch aborts. This defeats a relay MITM or device swap.
- Transfer. A wraps the master key under the channel key; B unwraps, generates its own DSK + DEK, and returns their public halves.
- Cross-sign. A signs B’s keys with the IK (unwrapped via the master key — any fully enrolled device can authorize an add) and publishes the directory.
- Join MLS via Add new device.
Shipped: the server surface and the CLI path. Native add UI (QR, safety-code screens) is post-v1.
Cross-device recovery reuses the channel and key-transfer steps but is substitutive (devices lost) rather than additive.
Failure Modes
Section titled “Failure Modes”| Failure | Outcome |
|---|---|
| Abandoned mid-flow | Code expires; nothing persisted |
| Safety codes differ | Abort |
| Stolen session token | Cannot initiate (step 1) |
| Secure element refuses keygen | Fail with actionable error; no partial state |
| Server unreachable at publish | Device keys valid locally; retry with backoff, “finishing setup” shown |
| Default-album creation fails | Account still valid; the album is re-derived and created lazily before first import |
Validation
Section titled “Validation”- First-device round-trip: escrow stored, directory has one entry, recovery secret unwraps escrow.
- Mismatched safety codes and a key-swapping relay both abort.
- Code expiry and single-use: redeem fails after expiry or reuse; server deletes the code either way.
- Session token without fresh local authorization cannot initiate.
- Mocked secure-element refusal surfaces an error, never partial completion.