feat: add protocol test vectors generated from the reference implementation
Known-answer tests for every part of the protocol that produces bytes: key derivation, sealed envelopes with their intermediate values, accept tokens, session and registration frames, rotation certificates, frontmatter parsing, and the inputs a conformant implementation must refuse. vectors.py derives every value by calling smolmail.py, so the vectors cannot drift from the code, and verifies each one from the opposite side before emitting it. --check regenerates and diffs against the committed files. Verified independently: a checker written against SPEC.md and libsodium alone, without importing the reference, reproduces all 81 values. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
43e4be2b8a
commit
9d5908104e
4 changed files with 2216 additions and 1 deletions
817
VECTORS.md
Normal file
817
VECTORS.md
Normal file
|
|
@ -0,0 +1,817 @@
|
|||
<!-- SPDX-License-Identifier: CC-BY-SA-4.0 -->
|
||||
|
||||
# smolmail Test Vectors, version 1.2
|
||||
|
||||
Known-answer tests for [SPEC.md](SPEC.md), generated from the reference implementation by [vectors.py](vectors.py). [vectors.json](vectors.json) carries the same values in a form a test harness can load; this file is for reading alongside the specification.
|
||||
|
||||
Work through them in order. Derivation first (§2), because every later vector depends on it, then an envelope you can seal and unseal (§5), then the wire frames (§4, §6.1, §7). Finish with the rejections: they are the ones that catch an implementation which decrypts without verifying.
|
||||
|
||||
Hex throughout, unless a field name says otherwise. The two masters are test data and the private keys here are public. Never use them for anything.
|
||||
|
||||
## Labels (§11)
|
||||
|
||||
Every hash, signature and MAC is domain-separated by one of these, prefixed to the input as raw bytes with no separator or length:
|
||||
|
||||
- `LABEL_IDENTITY` = `smolmail/1 identity`
|
||||
- `LABEL_ACCEPT` = `smolmail/1 accept`
|
||||
- `LABEL_SEAL` = `smolmail/1 seal`
|
||||
- `LABEL_MSG` = `smolmail/1 msg`
|
||||
- `LABEL_ID` = `smolmail/1 id`
|
||||
- `LABEL_MAC` = `smolmail/1 mac`
|
||||
- `LABEL_AUTH` = `smolmail/1 auth`
|
||||
- `LABEL_ROTATE` = `smolmail/1 rotate`
|
||||
- `LABEL_REGISTER` = `smolmail/1 register`
|
||||
- `PROLOGUE` = `smolmail/1`
|
||||
|
||||
## §2 Identity
|
||||
|
||||
`seed_n = HKDF-SHA256(master, salt = "", info = "smolmail/1 identity" || n)`, with `n` a big-endian u32. The Ed25519 public key of that seed *is* the identity. The X25519 keypair comes from the same key via libsodium's conversions, and the accept key is derived without the index so it survives rotation.
|
||||
|
||||
### alice, rotation index 0
|
||||
|
||||
- `master`: `000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f`
|
||||
- `rotation_index`: `0`
|
||||
- `seed`: `f2fd61c1fba591a06eadf25ab3252caa1885b615f35fe9eab89dbf64ed233788`
|
||||
- `identity_key`: `da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292`
|
||||
- `x25519_private`: `205ef2abb8830bfaf41c910fe2fa2a67f3b7b5c7f87c74001bacbedea0be3a7a`
|
||||
- `x25519_public`: `0c2dfdd8a679c9ca05c908651396b36dd4da1cf6ac3fc5b0037bde8d3feb506b`
|
||||
- `base32`: `3jxsxqtdvxwobge7uxefpbordkulv6bc6ao3h4iusqlov4kgkkja`
|
||||
- `fingerprint`: `3jxs xqtd vxwo bge7 uxef`
|
||||
- `uri`: `smol://alice@example.org/3jxsxqtdvxwobge7uxefpbordkulv6bc6ao3h4iusqlov4kgkkja`
|
||||
|
||||
### alice, rotation index 1
|
||||
|
||||
- `master`: `000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f`
|
||||
- `rotation_index`: `1`
|
||||
- `seed`: `01bcae47fc0b45b9cfd8f6b6cc7ec094970e517715d9c037354646f37fd82dea`
|
||||
- `identity_key`: `cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e466`
|
||||
- `x25519_private`: `884e39cd42c09e5817059634c94c3855b93ebda61f864cc951c4d6e89389ea6b`
|
||||
- `x25519_public`: `d9c834e4238b16e5f92bcf3fcb78fd163dec6b1c6b6ba4867f5526bed5bd6e3c`
|
||||
- `base32`: `zoieneun2k7n5b65yxfeen4pxvxzq7sclm2kfaa7os3wrwrz4rta`
|
||||
- `fingerprint`: `zoie neun 2k7n 5b65 yxfe`
|
||||
- `uri`: `smol://alice@example.org/zoieneun2k7n5b65yxfeen4pxvxzq7sclm2kfaa7os3wrwrz4rta`
|
||||
|
||||
### bob, rotation index 0
|
||||
|
||||
- `master`: `202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f`
|
||||
- `rotation_index`: `0`
|
||||
- `seed`: `469fdf277869a739339c3c8d0877ca7d8bbd27170238aa61681787e5feafba8c`
|
||||
- `identity_key`: `37b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c`
|
||||
- `x25519_private`: `e0d577fb7fe95cf8f8e3a7d500e060155e484f89ef46c4f208fce77ccd485e48`
|
||||
- `x25519_public`: `0814610bf746f1e6f33eb9275c5a8e3b43ecf92fa442f144444779d62fe1144e`
|
||||
- `base32`: `g6zze6hqrpvn53gfsyleb23wgs6wmtys5vamhvuuqicfmb6ji4oa`
|
||||
- `fingerprint`: `g6zz e6hq rpvn 53gf syle`
|
||||
- `uri`: `smol://bob@example.org/g6zze6hqrpvn53gfsyleb23wgs6wmtys5vamhvuuqicfmb6ji4oa`
|
||||
|
||||
### Accept keys and tokens (§5.8)
|
||||
|
||||
alice's accept key, and the token she issues to bob. The accept key is derived without the rotation index, so it and every token from it survive rotation.
|
||||
|
||||
- `alice_accept_key`: `2c18d0eeaa9b2333f3ecd41391131ea13f10aa35903389d860c25265545026ae`
|
||||
- `bob_accept_key`: `eff6fd323304674053b55a8b6a804b6a9fdbd111faad802763c1feced48259ee`
|
||||
- `alice_token_for_bob`: `084e74a6dec8ed8101672225450265e5fa3dcbe3a69455569ce1ffc254df1885`
|
||||
- `alice_token_for_bob_base32`: `bbhhjjw6zdwycalheisukatf4x5d3s7du2kfkvu44h74evg7dccq`
|
||||
- `bob_token_for_alice_0`: `411bccb54d51808fcf329ca609e8d8dac866e556b2a90bb4374979cb0d8689b7`
|
||||
- `alice_token_for_bob_rotated`: `96ddeaeabc81dadf328898de5adec032eef7d98d799fed54b8b737282090831b`
|
||||
|
||||
`alice_token_for_bob_rotated` is the token alice would issue to bob's index-1 key. It differs from the one bob already holds, which is why §5.8 says a token is derived from the correspondent's identity *as it stood when they were accepted*: bob's rotation does not invalidate the token he was given.
|
||||
|
||||
## §3 Addressing
|
||||
|
||||
The short form is resolved by the server; the smol:// form carries the key and needs no server to be trusted. 1961 is the default port and is omitted from the short form.
|
||||
|
||||
### Usernames
|
||||
|
||||
| username | valid |
|
||||
| --- | --- |
|
||||
| `a` | yes |
|
||||
| `a0` | yes |
|
||||
| `alice` | yes |
|
||||
| `al-ice` | yes |
|
||||
| `a.b-c_d` | yes |
|
||||
| `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` | yes |
|
||||
| `(empty)` | no |
|
||||
| `-alice` | no |
|
||||
| `alice-` | no |
|
||||
| `.alice` | no |
|
||||
| `al..ice` | no |
|
||||
| `a._b` | no |
|
||||
| `a-_b` | no |
|
||||
| `Alice` | no |
|
||||
| `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` | no |
|
||||
| `al ice` | no |
|
||||
| `alice@` | no |
|
||||
| `ali/ce` | no |
|
||||
|
||||
### Addresses
|
||||
|
||||
| input | user | host | port | identity |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `alice@example.org` | `alice` | `example.org` | 1961 | resolved |
|
||||
| `alice@example.org:1961` | `alice` | `example.org` | 1961 | resolved |
|
||||
| `alice@example.org:2000` | `alice` | `example.org` | 2000 | resolved |
|
||||
| `smol://alice@example.org/3jxsxqtdvxwobge7uxefpbordkulv6bc6ao3h4iusqlov4kgkkja` | `alice` | `example.org` | 1961 | `da6f2bc263adece0…` |
|
||||
|
||||
Refused:
|
||||
|
||||
- `smol://alice@example.org` — SmolError: smol://alice@example.org: smol:// address carries no key
|
||||
- `smol://alice@example.org/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` — SmolError: smol://alice@example.org/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: key is 31 bytes, expected 32
|
||||
- `smol://alice@example.org/not-base32!` — SmolError: smol://alice@example.org/not-base32!: undecodable key: Non-base32 digit found
|
||||
- `-alice@example.org` — SmolError: '-alice' must begin and end with a letter or digit and may not contain two separators in a row
|
||||
|
||||
### Fingerprint
|
||||
|
||||
- `identity`: `da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292`
|
||||
- `encoded`: `3jxsxqtdvxwobge7uxefpbordkulv6bc6ao3h4iusqlov4kgkkja`
|
||||
- `fingerprint`: `3jxs xqtd vxwo bge7 uxef`
|
||||
- `fingerprint_note`: `the first 20 base32 characters in groups of four: 100 bits, so a collision costs ~2^100`
|
||||
|
||||
## §5 Messages
|
||||
|
||||
Each vector pins the ephemeral `esk` that §5.2 would draw at random and the `time` that §5.3 would take from the clock. Nothing else in the protocol is randomised, so with those two fixed an envelope reproduces byte for byte.
|
||||
|
||||
Build one in this order: agree on `x25519_shared`, derive `seal_key`, assemble `payload_header`, sign `signed_preimage`, concatenate the payload, then encrypt it under `aad` with an all-zero nonce. If your `seal_key` matches and your envelope does not, the fault is in the payload layout; if `x25519_shared` already differs, it is in §2's map.
|
||||
|
||||
`accept_mac` is what a sender holding the recipient's token attaches to `SEND` (§5.8); `message_id` is what the server returns. The full payload plaintext and the whole `SEND` request body are in vectors.json as `payload` and `send_body`.
|
||||
|
||||
### empty-body
|
||||
|
||||
body_len 0. The payload is 109 bytes and the envelope 194.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[0]`
|
||||
- `body`: (empty)
|
||||
- `body_len`: `0`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4040404040404040404040404040404040404040404040404040404040404040`
|
||||
- `epk`: `d7b5e81d336e578b13b8d706e82d061e3038c96bce66cdcf50d566b96ddbba10`
|
||||
- `x25519_shared`: `383fc0e605a085e558481bcf53dfc0247a6f2c1ad46fe659953cf36874000469`
|
||||
- `seal_key`: `d035954d97b00442b87ce8025cafe438c7791079d407dc11b75915ace169609c`
|
||||
- `aad`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292d7b5e81d336e578b13b8d706e82d061e3038c96bce66cdcf50d566b96ddbba10`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b90000000000`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1
|
||||
149416eaf1465292d7b5e81d336e578b13b8d706e82d061e3038c96bce66cdcf50d566b96ddb
|
||||
ba100137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b90000000000
|
||||
```
|
||||
- `signature`: `e41a00f14ce5dd28ca4242be7f1d4e92c4ddc5256a9071982462da20644cb136629e0c6dd817db8b0d5dcd2d23239f0b807586193acea67a3abfb339804e3501`
|
||||
- `payload_len`: `109`
|
||||
- `envelope_len`: `194`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292d7
|
||||
b5e81d336e578b13b8d706e82d061e3038c96bce66cdcf50d566b96ddbba10786f5f9e9e91dd
|
||||
4e29fc0a8e9516fcde856e9f6dcf5010ba87e7878bf99db9030cca7b73d61fef8a4e23e24628
|
||||
f0e75b993c647361e41bd53d6ddd3a565b2ba334afaeb191f13dc801d9e7d9eeffad7eae12b0
|
||||
e2e59243c7a523db3fcdb9c21e3b83508f4905624e4ae5234ba51cb5633813ffff93b60de3f1
|
||||
ca8cd8a8
|
||||
```
|
||||
- `envelope_sha256`: `1a37555e369665f562b6a492de97a8c9cf024764b2fae32bf7bce33ebc9bc88f`
|
||||
- `message_id`: `289dd78f0fb9ec8e27b1b648b1fc4cd36e388cad63e5320e8f331315998fc451`
|
||||
- `accept_mac`: `1ce7f575843fa08ca8976213efbb951c8e13f119ff578da8c3f4091a15c284e5`
|
||||
|
||||
### unpadded
|
||||
|
||||
The minimal form: 69 + 45 + 11 + 64 + 16 bytes. Start here.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[0]`
|
||||
- `body`: `68656c6c6f20616c696365`
|
||||
- `body_len`: `11`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4141414141414141414141414141414141414141414141414141414141414141`
|
||||
- `epk`: `7a1a4e709bf085ac494aba0469b9b1eda0ab1f78b16aabb79ffeda90623e8522`
|
||||
- `x25519_shared`: `012b8e969fb857162e7d00cef9e68b60ebc30a858439bf0c0e256b8807f70769`
|
||||
- `seal_key`: `c4c72488dc2b6582952cb297d5d54b05b43ec7540cfdc173e55010f38d6444ed`
|
||||
- `aad`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf14652927a1a4e709bf085ac494aba0469b9b1eda0ab1f78b16aabb79ffeda90623e8522`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b9000000000b`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1
|
||||
149416eaf14652927a1a4e709bf085ac494aba0469b9b1eda0ab1f78b16aabb79ffeda90623e
|
||||
85220137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b9000000000b68656c6c6f20616c696365
|
||||
```
|
||||
- `signature`: `f4b5f898318a0c7da2f779a24972f1b51041bce5723d54e340f9887199c2f299b40b76ca3097562928cff3c2d8e02e7e78492f7f80ed6b0f784e1015b3f3b20c`
|
||||
- `payload_len`: `120`
|
||||
- `envelope_len`: `205`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf14652927a
|
||||
1a4e709bf085ac494aba0469b9b1eda0ab1f78b16aabb79ffeda90623e85223f096c1be498f7
|
||||
9a436bb6e96b7d425fc1173bd34c39f824e44c886a0291c1ce88d5956af3ee9d13b4c002eb50
|
||||
63388392b4777356a96d32e8940477577337b48af677c773482b47c49e558e7f0dd5b93396e5
|
||||
f38e3b7b01d4e2784bf4bd3df0aa84efabe12925c7522c8ca9ab867bd64aa38f1488bf2cac84
|
||||
f2d6fd1f6657a67991393a5607e721
|
||||
```
|
||||
- `envelope_sha256`: `8594cdb21ec3373f1516253e7db829e18471c066d8a891f71e9c75d547a696c5`
|
||||
- `message_id`: `75f74029f5e6a60dae846767622c09177ec75ea8de171b1b4314e44faac26d35`
|
||||
- `accept_mac`: `5cb318c5db75b0f37f8b3b8bf31a5899e5f673416c0c442a3d01abc8019b01b4`
|
||||
|
||||
### padded
|
||||
|
||||
The same message with §5.3 padding to a 1024-byte multiple. A receiver must ignore the trailing zeros and trust body_len.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[0]`
|
||||
- `body`: `68656c6c6f20616c696365`
|
||||
- `body_len`: `11`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `true`
|
||||
- `esk`: `4242424242424242424242424242424242424242424242424242424242424242`
|
||||
- `epk`: `132c442be010fbd57e72603328aa76e71fccc1503aae219327d14d9c9993f472`
|
||||
- `x25519_shared`: `2957671c03ec2f21c2d1a1c9e743564016a3107618f53077f02aff745c90ef02`
|
||||
- `seal_key`: `db77b3dc494a2b299eadbbbdd3c3c0cd5e44a6b8c7ad7490729a63905668fbf4`
|
||||
- `aad`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292132c442be010fbd57e72603328aa76e71fccc1503aae219327d14d9c9993f472`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b9000000000b`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1
|
||||
149416eaf1465292132c442be010fbd57e72603328aa76e71fccc1503aae219327d14d9c9993
|
||||
f4720137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b9000000000b68656c6c6f20616c696365
|
||||
```
|
||||
- `signature`: `000e182ed5e1e10fc9ab0d1e358d54fb6ffb8fe9ea097fb795b900dfe3b9914734a11cfb0ddff7a5ce47d9b1f66fc48022b7402e2fbae0f32762632db59e7507`
|
||||
- `payload_len`: `1024`
|
||||
- `envelope_len`: `1109`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf146529213
|
||||
2c442be010fbd57e72603328aa76e71fccc1503aae219327d14d9c9993f47269e94cda066826
|
||||
23d97aed6f33fdd2ff38d48811450881350eb826904757f1e3e30ceeb0989c56e4638131f409
|
||||
68350f507f2d61d2320abb5cc3bc433340094c37bcc350abf0e7910a672879527c99e7a9f77c
|
||||
bff5e9d99138c56f75e9a98bf4128107a83176666c5db76298e338ce4be914cbecaca5ea11f1
|
||||
4555cb7028ac1ccf41d0b330beada77c61eb42cab21097b005d1cf1ad60b5bfcd137a02ecd9a
|
||||
af65a4692882d75e73e52d6ebcfe47bfead71ac9e54d7b1ac275aaf28a192666930324091049
|
||||
3ffdd92e396387dbfff545f4d8d6b598fcb4a79f48d681f03c70e7ee378bb2cef91c9f744793
|
||||
4d19aaaf36fd38434eef7dfcb2572b51ab49182278426cfb11f72614130a01907e1104ad5e27
|
||||
10072041085179eac48281396bbcc5de0f2f60d89934a70b4583dda1b45188609b7d0f959559
|
||||
38fb49aa2d61ad0c63d69a7f8da875b957bfff6f9b7d83a7ebb1e05f4099033e81cdaae5b0ab
|
||||
83960871f3da11ceabcdd710d589948e7cd7a0e3eedee7941ad250b224d8869e657b0af53d22
|
||||
ab8502919e40959acd69e303879d2ed2a4487e0d7d5a2203f886e2dd95c41655a3c4c09bcbb6
|
||||
b5fbff92f1694d5e1ad5c470bbe33eaa3254e416f72d32be96d46ecaf6fc12bd891f8d3a0dc8
|
||||
c36403b23f7875fa0afc518a307dcd3d7cb8846bbfdf40fedf49e3ea87a5f378050fa2f6ea8e
|
||||
a86a422c58f8e7c9a077cd3fbc69c4837d748a0d32678cc7f8b482d09e3c2c9eb5037cdf2082
|
||||
4be0f0c1fe26893d7e3b04a4a16ed8c7910fbf1a106a12d4c145dae793b46e36176f3c621c30
|
||||
75adec0e445c033dc6d4fbe0f3c7f9419604361435e2af332cc428b038ab0e339c07248f8ac9
|
||||
fc520f722558ff015b372a5d9f90a867f606b63329b21dcd05587f13e3abe40be2f5c9177048
|
||||
c69168f087e071aecccff1eb3f04f95d9557dd6a40c37338765bff6de1861ca04e28a92d372e
|
||||
fb92103a982d760aa89301b60c8d9a591c39492dad4467053f3c85ca226777a591434b814bdf
|
||||
86d4d7557665bdf118da32e2396eba2ca3dc24731690eee9bae9398f6b9ca81f449a486ef14f
|
||||
7db9c2c8e330c4b56569b24bdf1d53961d0338fd38e7ac345a1bccbd2ead3a2a133b798762bb
|
||||
ddaf60f7e743b2ab0bc9f9b14b7755b02f9068ab9b4a8f154d6e9d6f61013281a6a7a69ebaa2
|
||||
80f0fd7a7bc1734ddc37ef0af2d0628d5d6f7a62d345648e03b6aa84d2470a0883e79e962faa
|
||||
65b3547d2b4eac386cdcdcc2afa8ebf525183854d8baafbd09691edaa73c193ad54f99bea34e
|
||||
f8a2fd03ef6f869bd28bafb8377affdab5867cec7609eff5834d4cb7c9820a07fb17aebc6827
|
||||
ee1c7505f820d9be04973c0b264bb3be34d54cb2e1ac4edf437a3a065a85c4158af88952721c
|
||||
3d83195f898e514ba9e751060be46d2a6067e99c99a61d2959cb0d1b7ca6e76c207d26a50509
|
||||
0fa3007a406471
|
||||
```
|
||||
- `envelope_sha256`: `41a93d239e7da918e1e6480b724b8e23eeb39ddd454b889f6a55934658c143b2`
|
||||
- `message_id`: `ff849aa8b573dfc10dc5ac731b862ba1205f42c81a014744f2812d3bf1d62a2e`
|
||||
- `accept_mac`: `2b0a0b0804a78a32f47e461b8ed06e6c1a21ed750b2b33290cc91f884fb86ca0`
|
||||
|
||||
### utf8
|
||||
|
||||
body_len counts bytes, not characters: 29 bytes, 22 characters.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[0]`
|
||||
- `body`: `4772c3bcc39f65206175732064656d204d65736820e2809420f09f9bb00a`
|
||||
- `body_len`: `30`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4343434343434343434343434343434343434343434343434343434343434343`
|
||||
- `epk`: `cdefd8783a91b446640e2e1f95599db35e484a0071bd2182b3b60d0812c10c70`
|
||||
- `x25519_shared`: `40ff868360e1f61dd53a383f4e8d96205ac1eab3dea7f1c69f9a8d44f853da79`
|
||||
- `seal_key`: `3bab319a2a1e80a93c2639891f9dce11c35e8cbc558fea02f3c3ef494276b54b`
|
||||
- `aad`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292cdefd8783a91b446640e2e1f95599db35e484a0071bd2182b3b60d0812c10c70`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b9000000001e`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1
|
||||
149416eaf1465292cdefd8783a91b446640e2e1f95599db35e484a0071bd2182b3b60d0812c1
|
||||
0c700137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b9000000001e4772c3bcc39f65206175732064656d204d65736820e2809420f09f9bb0
|
||||
0a
|
||||
```
|
||||
- `signature`: `86372500958b7808f6fb1878d40ccc9a2b090fbb042f834b6e131ee1c7d55ef3be7ecb44db86c59bee9dc4f2268fce878e0d6e79e046969f3667bbb8b6fd110e`
|
||||
- `payload_len`: `139`
|
||||
- `envelope_len`: `224`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292cd
|
||||
efd8783a91b446640e2e1f95599db35e484a0071bd2182b3b60d0812c10c70315b93e0580e4c
|
||||
e845678e9aa71eeb8bf2f8c3155a8c1fd58dc43c91095e0a19032a91231f3f7ef11167dac73e
|
||||
296e98c921c15c8d02e24747df1ffa600818abfb6858aa82184277da1d1fd02d1d59ada01941
|
||||
8a2c708a7521e6a0f1e8e55f24f46d0bfa7d9c1ad761580f320f5c3248c18aac5158c0296992
|
||||
6f427d921fee8ba4ccf2bff233733e64d5e3b50757f8f5b880d1f869651c9a186608
|
||||
```
|
||||
- `envelope_sha256`: `fcf78b183a0c2fad26f36b15e6cd222d1e864f48c7eea616f66aa65a14872b7c`
|
||||
- `message_id`: `82c6d8c341ea821e4558dc6bb35f533e399a89646d9023437802b1d2499f2b88`
|
||||
- `accept_mac`: `b221784d76eb2d52517d142912139ab0f6e61900ff35eed45998cb459683cf68`
|
||||
|
||||
### frontmatter
|
||||
|
||||
§5.5 frontmatter carrying the reserved Reply-To (§5.7) and Accept (§5.8) fields. Both are only meaningful because the signature covers them.
|
||||
|
||||
- `sender`: `alice[0]`
|
||||
- `recipient`: `bob[0]`
|
||||
|
||||
`body`
|
||||
|
||||
```
|
||||
2d2d2d0a5375626a6563743a20746865207468696e670a5265706c792d546f3a20736d6f6c3a
|
||||
2f2f616c696365406578616d706c652e6f72672f336a7873787174647678776f626765377578
|
||||
656670626f72646b756c7636626336616f336834697573716c6f76346b676b6b6a610a416363
|
||||
6570743a20626268686a6a77367a64777963616c68656973756b617466347835643373376475
|
||||
326b666b7675343468373465766737646363710a2d2d2d0a48657265206973206120746f6b65
|
||||
6e20736f20796f7572206d61696c20736b697073206d7920726571756573747320746965722e
|
||||
0a
|
||||
```
|
||||
- `body_len`: `229`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4444444444444444444444444444444444444444444444444444444444444444`
|
||||
- `epk`: `ff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b`
|
||||
- `x25519_shared`: `07c5ae79c7568952aa78668c613389e4ecdd2f61f207618532fb3c8c8a26f213`
|
||||
- `seal_key`: `4dd79e54e611ac322ac0ace7e7a64b2c2139d422097f939c603ee6dd9843f7cc`
|
||||
- `aad`: `534d4f4c0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471cff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b`
|
||||
- `payload_header`: `01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292000000006955b900000000e5`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d736737b39278f08beadeecc5961640eb7634bd664f12ed40c3d6
|
||||
9482045607c9471cff2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff
|
||||
3e6b01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292000000
|
||||
006955b900000000e52d2d2d0a5375626a6563743a20746865207468696e670a5265706c792d
|
||||
546f3a20736d6f6c3a2f2f616c696365406578616d706c652e6f72672f336a78737871746476
|
||||
78776f626765377578656670626f72646b756c7636626336616f336834697573716c6f76346b
|
||||
676b6b6a610a4163636570743a20626268686a6a77367a64777963616c68656973756b617466
|
||||
347835643373376475326b666b7675343468373465766737646363710a2d2d2d0a4865726520
|
||||
6973206120746f6b656e20736f20796f7572206d61696c20736b697073206d79207265717565
|
||||
73747320746965722e0a
|
||||
```
|
||||
- `signature`: `23e0b6bd5660ab109144e07b24affb7298041dafe908a469ab28c120f812b91dbcc7cee0763d058df4357d74ef4dee85f42da50dffdc66fb8604288a3c3d0000`
|
||||
- `payload_len`: `338`
|
||||
- `envelope_len`: `423`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471cff
|
||||
2ee45601ec1b67310c7790404585ae697331eee1c1f8cf2419731c1fff3e6b7d16509bc2c568
|
||||
3501cacd195740772232cdb04f5375e55dac3d49e258524c0eca1819d6911503a76d1b80e2e2
|
||||
048947659c9925faa4e2710420d0be9110cd216f651808f4132dc13d6a91c55d9ac653b161ad
|
||||
63cc70b7c9eac3b89d4994b04e791b195ca148845649a3a473f7dc26bfd0326e1f65b7559d12
|
||||
824920c136e502d1c29c3211a3ca7d0782df4655e31123de9d61ebb35fe9fcfd0ecdf0c7e406
|
||||
854ab7bfddbc818dd839e02ea450fd94124228a8bae41bf020962919de514525304a8f2c512b
|
||||
8335bbef48af719c340d63a7e38cd6ab40c004601edf67a572062182a15328825f017d10b841
|
||||
9edf162610ece5884539e8408bd6893a47b5d99d02bd944e98194424333ee1a99aabf600ec83
|
||||
ae4cabc38c12c0044bc16536d54a65d78df62428b4ba290296986b19d8e143cad25ee6c20351
|
||||
5c3dcb3907f3adab87ec4dd4d5cdbfe24621beb2d4901939a02df296b67c996fef0b84fc591c
|
||||
87b9dc35be
|
||||
```
|
||||
- `envelope_sha256`: `4cd667f09da015acc5c6c1f57e57181334b89a11c2d7d543e4dcb2bf012bd698`
|
||||
- `message_id`: `e6a52f744a8c0eab0c0a72c56ef51af96b83d9721d38dc669be38ca2c272f498`
|
||||
- `accept_mac`: `8589379776f7d005c016593b5e04f624d7530f405213639361ab2a127004cd40`
|
||||
|
||||
### superseded-key
|
||||
|
||||
Sealed to alice's index-0 key while she is at index 1 (§7). She opens it with the retained key, which is re-derivable from the master alone.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[0]`
|
||||
- `body`: `73656e74206265666f726520796f7520726f74617465640a`
|
||||
- `body_len`: `24`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4545454545454545454545454545454545454545454545454545454545454545`
|
||||
- `epk`: `3286894cd2845a6db6a28fbf0677605f80e5a62385bf4e10a790ae5fde36736b`
|
||||
- `x25519_shared`: `bf14188f69b809b1c944f8d46c1d4a91f641b741537b88d98622d7f2ac310434`
|
||||
- `seal_key`: `7367d84d99359d719fdb9fceb49b29c19b14636dd4fc2896774061d110973cc8`
|
||||
- `aad`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf14652923286894cd2845a6db6a28fbf0677605f80e5a62385bf4e10a790ae5fde36736b`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b90000000018`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1
|
||||
149416eaf14652923286894cd2845a6db6a28fbf0677605f80e5a62385bf4e10a790ae5fde36
|
||||
736b0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b9000000001873656e74206265666f726520796f7520726f74617465640a
|
||||
```
|
||||
- `signature`: `4eb267c60e58d0f6acc2a9f0c39e384e16324ddb7bf8c23e14659682af1cfca526e5e72e39663c3d5207c929b0f65982f74ff7d3de4fce80d76bc8a39bbeac04`
|
||||
- `payload_len`: `133`
|
||||
- `envelope_len`: `218`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf146529232
|
||||
86894cd2845a6db6a28fbf0677605f80e5a62385bf4e10a790ae5fde36736b4272b58c6b941f
|
||||
f140f69144dc10f1d49a0f9603e7a5a97718edc2e0617631d2fed71776274b6d7d2653c1fa88
|
||||
9af93c9d57fbfd0d0b0ced3f8efdf59adaa23e3101c671d55850adbbb7d776c5f1a1296b6b46
|
||||
68041c0575d317b2e7bc796894091313cbf1c6be2382fe26229ba9bcfcee3281fd6b55731e06
|
||||
bf72bdd73efef8b4c32c6a269a2036fc272885f0f6551f9322f727ab
|
||||
```
|
||||
- `envelope_sha256`: `57c33559dc31934cae4d41e99954911422178b4a54a7c7cf5a8b3174485dee37`
|
||||
- `message_id`: `292854907f2bc92223edabf57ceead7276402ee3569b18d2d0d40b0e2c50886b`
|
||||
- `accept_mac`: `f417c61474e4c15bbecf8586a8b1adf37a03106aea0ef818a4b970b4e8d429e9`
|
||||
|
||||
### rotated-key
|
||||
|
||||
The same correspondents after alice's rotation. Only `to` changes; her accept token does not.
|
||||
|
||||
- `sender`: `bob[0]`
|
||||
- `recipient`: `alice[1]`
|
||||
- `body`: `73656e7420616674657220796f7520726f74617465640a`
|
||||
- `body_len`: `23`
|
||||
- `time`: `1767225600`
|
||||
- `padded`: `false`
|
||||
- `esk`: `4646464646464646464646464646464646464646464646464646464646464646`
|
||||
- `epk`: `a28a7c44ede257d664fbf156affa7da8abb3ae74b9fee8d7a2078543504e1a75`
|
||||
- `x25519_shared`: `e8265154d3d8063d89c7b591427fab6ae3b3207bc8ba87d287c2c10bcbfb5b4a`
|
||||
- `seal_key`: `b4e8a0876228c50744d1f3cde417d6299be612b485554300e44434e2f9446106`
|
||||
- `aad`: `534d4f4c01cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e466a28a7c44ede257d664fbf156affa7da8abb3ae74b9fee8d7a2078543504e1a75`
|
||||
- `payload_header`: `0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000006955b90000000017`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31206d7367cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a280
|
||||
1f74b768da39e466a28a7c44ede257d664fbf156affa7da8abb3ae74b9fee8d7a2078543504e
|
||||
1a750137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471c000000
|
||||
006955b9000000001773656e7420616674657220796f7520726f74617465640a
|
||||
```
|
||||
- `signature`: `857ef01e8bd0d7aee6650a86d189c9cb384c1bf6d1cc47c8666e67d88270d0d1b10a2b53388c8a9aca1c6fc0645a40cd8cb4f8af58cdc2e06801918e4e475203`
|
||||
- `payload_len`: `132`
|
||||
- `envelope_len`: `217`
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e466a2
|
||||
8a7c44ede257d664fbf156affa7da8abb3ae74b9fee8d7a2078543504e1a75559e854a04d51f
|
||||
d20336516fa2471e8b13784f6597813601f15c8f3d9aa95c049f9671ab843e1d40dc0eccf227
|
||||
942b48240590da1e753e443129d8ffdaf032d7f5d2298eb7b426bd937faf52af2c0303c33e25
|
||||
78574c37c0492a2b80a793d539c3ecd13a50dcd6d9ed86510749ae97e0f256d45ad8a4ea0bed
|
||||
15e50a125933d17e11fc3615f288c5aeeaf706f7dbf279db165e53
|
||||
```
|
||||
- `envelope_sha256`: `b8fbe91f24f6f8969a7a6e2aefaf03a0f8e8e8947d8521baa9fa641c002344c4`
|
||||
- `message_id`: `72c054747b8edd9c710df7ab295ed832ef791e6db4a585821968d8dff9ae3b02`
|
||||
- `accept_mac`: `e7d594c129757cdbf628b354c592cf566f6b40d95fa7f6a7c6be6ca2696917cb`
|
||||
|
||||
## §4 and §6.1 Session frames
|
||||
|
||||
The AUTH signature covers the Noise handshake hash, so it cannot be replayed to another session or server. The REGISTER signature covers the server's static key for the same reason: without it, any party could bind any public key to any username.
|
||||
|
||||
- `handshake_hash`: `808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f`
|
||||
- `server_static`: `606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f`
|
||||
- `auth_signed_preimage`: `736d6f6c6d61696c2f312061757468808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f`
|
||||
- `auth_signature`: `26936929ab0ead5f407d69a6516f32d2b871f41d73345b9b7d076d85eea9b6736ea0f522bcff8511c2aea1f8cf0e7a7d3f1f81f3d6d5654a27c5b81e462fa903`
|
||||
|
||||
`auth_frame`
|
||||
|
||||
```
|
||||
05616c696365da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292
|
||||
26936929ab0ead5f407d69a6516f32d2b871f41d73345b9b7d076d85eea9b6736ea0f522bcff
|
||||
8511c2aea1f8cf0e7a7d3f1f81f3d6d5654a27c5b81e462fa903010001084e74a6dec8ed8101
|
||||
672225450265e5fa3dcbe3a69455569ce1ffc254df1885
|
||||
```
|
||||
|
||||
username_len=5 || 'alice' || identity || signature || sync=1 || count=1 || alice's token for bob
|
||||
|
||||
`register_signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f31207265676973746572606162636465666768696a6b6c6d6e6f707172
|
||||
737475767778797a7b7c7d7e7f616c696365da6f2bc263adece0989fa5c85785d11aa8baf822
|
||||
f01db3f1149416eaf1465292
|
||||
```
|
||||
- `register_signature`: `78364170da13b57566df066c66756c29ba4f080e8b75e3503ac7614534cff3486b888455fd5e6ad756edb4ed28567aab8ccc3820b0289d15c48720066818220f`
|
||||
|
||||
`register_frame`
|
||||
|
||||
```
|
||||
05616c696365da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292
|
||||
78364170da13b57566df066c66756c29ba4f080e8b75e3503ac7614534cff3486b888455fd5e
|
||||
6ad756edb4ed28567aab8ccc3820b0289d15c48720066818220f0000
|
||||
```
|
||||
|
||||
token_len=0 and cert_len=0: a first registration, no invite token and no rotation certificate
|
||||
|
||||
## §7 Key rotation
|
||||
|
||||
A certificate is 200 bytes and carries no username: the name is covered by both signatures but not transported, so a certificate cannot be replayed against another username bound to the same key.
|
||||
|
||||
- `username`: `alice`
|
||||
- `old_key`: `da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292`
|
||||
- `new_key`: `cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e466`
|
||||
- `time`: `1767225600`
|
||||
|
||||
`signed_preimage`
|
||||
|
||||
```
|
||||
736d6f6c6d61696c2f3120726f74617465616c696365da6f2bc263adece0989fa5c85785d11a
|
||||
a8baf822f01db3f1149416eaf1465292cb9046928dd2bede87ddc5ca42378fbd6f987e425b34
|
||||
a2801f74b768da39e466000000006955b900
|
||||
```
|
||||
- `sig_old`: `ba3bd58ab28a0bb6758bfda39b95c2e391ef922a60a010e74543c255b6689f5e81bef8ee3f84e88e61959a523429ea2d4d47622df470743caf298a19e43b9b03`
|
||||
- `sig_new`: `58a928e912485548a74c2d8e9d14553a5f90c34411848a8d612fb55600539f762849102530f0ab411914e48879a62b33b1297a18ad774a614283c2268b958a0e`
|
||||
|
||||
`certificate`
|
||||
|
||||
```
|
||||
da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292cb9046928dd2
|
||||
bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e466000000006955b900ba3bd58a
|
||||
b28a0bb6758bfda39b95c2e391ef922a60a010e74543c255b6689f5e81bef8ee3f84e88e6195
|
||||
9a523429ea2d4d47622df470743caf298a19e43b9b0358a928e912485548a74c2d8e9d14553a
|
||||
5f90c34411848a8d612fb55600539f762849102530f0ab411914e48879a62b33b1297a18ad77
|
||||
4a614283c2268b958a0e
|
||||
```
|
||||
|
||||
`resolve_body`
|
||||
|
||||
```
|
||||
cb9046928dd2bede87ddc5ca42378fbd6f987e425b34a2801f74b768da39e46601da6f2bc263
|
||||
adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292cb9046928dd2bede87ddc5
|
||||
ca42378fbd6f987e425b34a2801f74b768da39e466000000006955b900ba3bd58ab28a0bb675
|
||||
8bfda39b95c2e391ef922a60a010e74543c255b6689f5e81bef8ee3f84e88e61959a523429ea
|
||||
2d4d47622df470743caf298a19e43b9b0358a928e912485548a74c2d8e9d14553a5f90c34411
|
||||
848a8d612fb55600539f762849102530f0ab411914e48879a62b33b1297a18ad774a614283c2
|
||||
268b958a0e
|
||||
```
|
||||
|
||||
Chain walking:
|
||||
|
||||
- pinned=old, offered=new, chain=[cert], username=alice → **accept**
|
||||
- same certificate checked as username=mallory → **refuse** (both signatures cover the username)
|
||||
- pinned=old, offered=new, empty chain → **refuse** (a key change needs a chain; absent means ask the user)
|
||||
- sig_new zeroed → **refuse** (the new key must sign too, or the old key alone could hand the username to a key nobody controls)
|
||||
|
||||
## §5.5 Frontmatter
|
||||
|
||||
A flat `Key: value` block, not YAML. A malformed line invalidates the whole block, which is then shown as ordinary body text: frontmatter fails closed toward display, never toward silent discard.
|
||||
|
||||
| case | input | fields | text | note |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `no-block` | `'hello\n'` | `{}` | `'hello\n'` | no leading '---\n', so the whole body is text |
|
||||
| `simple` | `'---\nSubject: hi\n---\nbody\n'` | `{'subject': 'hi'}` | `'body\n'` | one field, then the text |
|
||||
| `empty-block` | `'---\n---\n---\nliteral dashes\n'` | `{}` | `'---\nliteral dashes\n'` | an empty block escapes a body that genuinely starts with '---' |
|
||||
| `case-and-duplicates` | `'---\nSubject: first\nsubject: second\nX-Mood: calm\n'…` | `{'subject': 'first', 'x-mood': 'calm'}` | `'b'` | keys are lowercased for comparison and the first occurrence wins |
|
||||
| `value-trimmed` | `'---\nSubject: spaced out \n---\n'` | `{'subject': 'spaced out'}` | `''` | the value is the rest of the line, trimmed |
|
||||
| `colon-in-value` | `'---\nSubject: re: the thing\n---\n'` | `{'subject': 're: the thing'}` | `''` | only the first colon separates |
|
||||
| `no-colon` | `'---\nSubject hi\n---\nbody\n'` | `{}` | `'---\nSubject hi\n---\nbody\n'` | a malformed line invalidates the whole block, which becomes text |
|
||||
| `bad-key` | `'---\nSub ject: hi\n---\nbody\n'` | `{}` | `'---\nSub ject: hi\n---\nbody\n'` | key charset is [A-Za-z0-9-] |
|
||||
| `unterminated` | `'---\nSubject: hi\nbody\n'` | `{}` | `'---\nSubject: hi\nbody\n'` | no closing '---' |
|
||||
| `too-many-keys` | `'---\nK0: v\nK1: v\nK2: v\nK3: v\nK4: v\nK5: v\nK6: v\nK7'…` | `{}` | `'---\nK0: v\nK1: v\nK2: v\nK3: v\nK4: v\nK5: v\nK6: v\nK7'…` | over 64 keys |
|
||||
| `too-large` | `'---\nK: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv'…` | `{}` | `'---\nK: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv'…` | over 4 KiB |
|
||||
| `injected-field` | `'---\nSubject: hi\nAccept: aaaaaaaa\n---\nb'` | `{'subject': 'hi', 'accept': 'aaaaaaaa'}` | `'b'` | what a line break in a sender-supplied value produces: a second field, signed and indistinguishable from an intended one. A client building frontmatter MUST refuse a value containing a line break. |
|
||||
|
||||
Long inputs are clipped here; vectors.json has them whole.
|
||||
|
||||
## Rejections
|
||||
|
||||
Inputs a conformant implementation refuses. The envelope cases are mutations of one valid message, listed with the reference's own error, so a client can be tested against its own failure path.
|
||||
|
||||
Each envelope is a mutation of this valid one:
|
||||
|
||||
`valid_baseline`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
|
||||
### bad-magic
|
||||
|
||||
magic is not 'SMOL' (§5.1)
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
584d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
- `rejected_with`: `SmolError: not a smolmail envelope`
|
||||
|
||||
### bad-envelope-version
|
||||
|
||||
unknown envelope version; the sealed-box construction may differ
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c02da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
- `rejected_with`: `SmolError: unsupported envelope version 2`
|
||||
|
||||
### truncated
|
||||
|
||||
shorter than the 69-byte header plus a 16-byte tag
|
||||
|
||||
- `envelope`: `534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c306fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d36558252`
|
||||
- `rejected_with`: `SmolError: envelope too short`
|
||||
|
||||
### tag-flipped
|
||||
|
||||
the Poly1305 tag no longer authenticates
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2be
|
||||
```
|
||||
- `rejected_with`: `SmolError: decryption failed: wrong key or corrupt envelope`
|
||||
|
||||
### aad-tampered
|
||||
|
||||
epk is covered by the AAD, so altering it breaks the tag rather than silently re-addressing the message
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ff2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
- `rejected_with`: `SmolError: decryption failed: wrong key or corrupt envelope`
|
||||
|
||||
### not-for-us
|
||||
|
||||
`to` names a key we do not hold; a client MUST check it against its own
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c0137b39278f08beadeecc5961640eb7634bd664f12ed40c3d69482045607c9471cc3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
- `rejected_with`: `SmolError: addressed to g6zze6hqrpvn53gf…, not one of our keys`
|
||||
|
||||
### bad-signature
|
||||
|
||||
decrypts cleanly and the signature is zeroed. An implementation that skips §5.3 verification will accept forged mail here.
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3daf229b9065119b10570cbeec2967e78dc7d26906bda10ec4702b50a7d0f93418
|
||||
a97ab7aa5b6d10455d6ba65081e74824e96e1d637a4dc26845810958fe11269209adcd49b5e7
|
||||
6471b2c4df881338ba42
|
||||
```
|
||||
- `rejected_with`: `SmolError: signature does not verify`
|
||||
|
||||
### signature-bound-to-other-recipient
|
||||
|
||||
a payload signed for bob, resealed to alice. The signature covers `to`, so re-addressing a recorded message must not verify.
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3db7459221085c65f94569e41f2a7f00d84dc2045e491c300ebdfa3f8ea2af2560
|
||||
1ad057d0013ef1fad9564dc1f24b034f4ebff12458d979f593fe9fa4d5a70595bf0215f69abc
|
||||
1e1197d0b5979071727f
|
||||
```
|
||||
- `rejected_with`: `SmolError: signature does not verify`
|
||||
|
||||
### body-len-overflows
|
||||
|
||||
body_len exceeds the payload (§5.3)
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2bbdfc2
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd977b2479cfcb4d
|
||||
3883cf888582df8b22f0
|
||||
```
|
||||
- `rejected_with`: `SmolError: payload body length exceeds the payload`
|
||||
|
||||
### payload-version
|
||||
|
||||
unknown payload version
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825290a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97372cf15fd0d6
|
||||
c068a477ac4c35c10862
|
||||
```
|
||||
- `rejected_with`: `SmolError: unsupported payload version`
|
||||
|
||||
### dated-in-the-future
|
||||
|
||||
time is 4102444800, more than 86400s ahead of any clock before 2100 (§5.3)
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292c3
|
||||
06fb0ef2bf8b7f93bad98155fa37daec74db0c4cbeda6c6f1dba9d3655825293a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd8b19bf25e2abdfc4
|
||||
c605dfcb7d3da3c142dc7b0dbabf90b361744b6247bb8e9fc9407d51b383f018556d9fbfd999
|
||||
beaeb49bec2d719ce3c62785f850ce261eb68784050fd68f1e7655fcae4a659fe7353abcadb4
|
||||
da68e9b733c5704cbb51
|
||||
```
|
||||
- `rejected_with`: `SmolError: payload is dated in the future`
|
||||
|
||||
### low-order-epk
|
||||
|
||||
a low-order ephemeral key, which §2 requires be refused
|
||||
|
||||
`envelope`
|
||||
|
||||
```
|
||||
534d4f4c01da6f2bc263adece0989fa5c85785d11aa8baf822f01db3f1149416eaf1465292e0
|
||||
eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b80093a846f5413d3a
|
||||
945f8aa55bdc4f0fffd51e4f59624b753b1691571500e2db82aa003ffedd16ca5125e2abdfc4
|
||||
dc05c7c76b3d13e7aaee7c7d9eb6702bb90b0cbce8e59b7542200107e1fcda8f2f5462671898
|
||||
30879a2d6d9493eec48c918ec35e855eb7381ee060a09b38e429c221d489cd97c23c37031b96
|
||||
ad8d633e2c6b0d95f2bf
|
||||
```
|
||||
- `rejected_with`: `SmolError: rejected key agreement: Unexpected library error`
|
||||
|
||||
### Low-order X25519 keys
|
||||
|
||||
§2 and §4: a received ephemeral public key that is a low-order point MUST be refused, and an all-zero X25519 output MUST be refused. libsodium reports the first as the second, since the agreement output is zero.
|
||||
|
||||
- `0000000000000000000000000000000000000000000000000000000000000000`
|
||||
- `0100000000000000000000000000000000000000000000000000000000000000`
|
||||
- `e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800`
|
||||
- `5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157`
|
||||
- `ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f`
|
||||
- `edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f`
|
||||
- `eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f`
|
||||
|
||||
### Invalid identity keys
|
||||
|
||||
Keys that do not decode as Ed25519 points, or are of small order, so §2's map to X25519 has no valid result.
|
||||
|
||||
- `0000000000000000000000000000000000000000000000000000000000000000` — SmolError: not a valid Ed25519 public key: Unexpected library error
|
||||
- `ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff` — SmolError: not a valid Ed25519 public key: Unexpected library error
|
||||
- `0100000000000000000000000000000000000000000000000000000000000000` — SmolError: not a valid Ed25519 public key: Unexpected library error
|
||||
|
||||
## License
|
||||
|
||||
These vectors are licensed under [CC BY-SA 4.0](LICENSES/CC-BY-SA-4.0.txt), with the specification.
|
||||
Loading…
Add table
Add a link
Reference in a new issue