docs: specify response framing and superseded-key retention
This commit is contained in:
parent
6c76d1d6e9
commit
9a31607648
1 changed files with 28 additions and 2 deletions
30
SPEC.md
30
SPEC.md
|
|
@ -54,7 +54,7 @@ A client MUST NOT `REGISTER`, `FETCH` or `DELETE` against a server whose static
|
|||
|
||||
**Framing.** Each Noise message carries a 2-byte length prefix and is at most 65535 bytes. Application frames are `length (u32) || type (u8) || body`, split across Noise messages, with a default maximum of 1 MiB. Every field is length-prefixed; nothing on the wire requires text parsing or delimiter scanning.
|
||||
|
||||
**Session authentication.** `FETCH` and `DELETE` require one `AUTH` frame after the handshake:
|
||||
**Session authentication.** `FETCH` and `DELETE` require one `AUTH` frame — an application frame of type `0x00` — after the handshake:
|
||||
|
||||
```
|
||||
username_len u8 || username || identity 32 || signature 64
|
||||
|
|
@ -157,6 +157,30 @@ Because `esk` is wiped, a sender cannot decrypt what they sent. To keep a Sent f
|
|||
|
||||
`FETCH` has no cursors, flags or server-side read state; a client loops until it returns nothing. `REGISTER` without a certificate binds a free username, or returns code 9; with one, it rebinds an existing username when the chain validates against the currently bound key.
|
||||
|
||||
### 6.1 Request and response bodies
|
||||
|
||||
A request body is the operation's payload. A response body begins with `status (u8)` from §12; on `0` the operation's payload follows, on anything else an optional UTF-8 reason string. A response reuses the request's type byte. `AUTH` is type `0x00` and its response carries a status and no payload.
|
||||
|
||||
```
|
||||
RESOLVE → username_len u8 || username
|
||||
← identity 32 || chain_len u8 || cert 136 × chain_len
|
||||
|
||||
SEND → envelope
|
||||
← id 16
|
||||
|
||||
FETCH → (empty)
|
||||
← count u16 || ( id 16 || received_at i64 || env_len u32 || envelope ) × count
|
||||
|
||||
DELETE → count u16 || id 16 × count
|
||||
← removed u16
|
||||
|
||||
REGISTER → username_len u8 || username || identity 32
|
||||
|| token_len u8 || token || cert_len u8 || cert
|
||||
← (empty)
|
||||
```
|
||||
|
||||
A zero length means the field is absent. `FETCH` returns records oldest first, up to a server byte budget which MUST be smaller than the maximum application frame; 512 KiB against the default 1 MiB frame is a reasonable choice.
|
||||
|
||||
## 7. Key rotation
|
||||
|
||||
```
|
||||
|
|
@ -166,6 +190,8 @@ signature = Ed25519 by old_pub over "smolmail/1 rotate" || old_pub || new_pub ||
|
|||
|
||||
A server keeps each username's ordered chain of certificates and returns it with every `RESOLVE`. A client holding a stale pinned key walks the chain forward from that key, verifying each link, and accepts the new key silently if the chain terminates at the key `RESOLVE` returned. A broken, absent or over-long chain — maximum 16 links — requires explicit user confirmation. Senders SHOULD also push their certificate to contacts as an ordinary message, so rotation propagates without depending on the old server.
|
||||
|
||||
A server MUST retain every key ever bound to a username, MUST accept `SEND` addressed to any of them, and MUST return messages addressed to any of them on `FETCH`. Without this, mail from a contact who has not yet seen a rotation is addressed to a superseded key and becomes unreachable.
|
||||
|
||||
**Rotation is not revocation.** An attacker holding a stolen identity key can rotate to their own key and the chain will validate. Clients MUST surface rotations in the interface rather than applying them invisibly; out-of-band re-verification is the only defence against a compromised identity key. There is no revocation mechanism in version 1.
|
||||
|
||||
## 8. Trust model
|
||||
|
|
@ -213,7 +239,7 @@ A conforming server is a single binary over an embedded key-value store.
|
|||
2 bad version 5 auth failed 8 rate limited
|
||||
```
|
||||
|
||||
A response MAY carry a UTF-8 reason string. Clients MUST NOT parse it.
|
||||
A status is the first byte of every response body (§6.1), which MAY be followed by a UTF-8 reason string. Clients MUST NOT parse the reason.
|
||||
|
||||
## 13. Out of scope for version 1
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue