mirror of
https://github.com/chatmail/core.git
synced 2026-10-02 11:10:25 +03:00
docs: revise keyupdate draft after link2xt review
review comment: https://github.com/chatmail/core/pull/8595#discussion_r3791274942 The intended recipient fingerprint subpacket is optional, so drop the contact-list-leak argument against per-recipient chunking and add a section on why keyupdates are signed even if they don't need to be.
This commit is contained in:
+57
-27
@@ -101,11 +101,8 @@ so the channel would let us drop the concept completely.
|
|||||||
|
|
||||||
We should be able to hand our current key to our contacts
|
We should be able to hand our current key to our contacts
|
||||||
without waiting for a conversation to happen.
|
without waiting for a conversation to happen.
|
||||||
One way to address such a message is per recipient,
|
The straightforward way is to address such a message per recipient,
|
||||||
in chunks of about twenty contacts, as sketched in [#8588].
|
in chunks of a few dozen contacts, as sketched in [#8588].
|
||||||
To name two problems: it reveals a slice of your contact list to each contact,
|
|
||||||
because the signature names every intended recipient in the chunk,
|
|
||||||
and it uploads the keyupdate message 10 times for 200 contacts.
|
|
||||||
This draft argues for a different way of sending key updates,
|
This draft argues for a different way of sending key updates,
|
||||||
starting with a simple observation:
|
starting with a simple observation:
|
||||||
|
|
||||||
@@ -127,17 +124,19 @@ What using automatically derived secrets and existing broadcast encryption buys:
|
|||||||
- No new header names, no new key distribution or bookkeeping protocol (phew!),
|
- No new header names, no new key distribution or bookkeeping protocol (phew!),
|
||||||
only a new `Chat-Content` value.
|
only a new `Chat-Content` value.
|
||||||
|
|
||||||
- Network cost is largely independent of contact count for senders.
|
- Network cost is largely independent of recipient count.
|
||||||
One message per relay change rather than one per chunk.
|
A keyupdate is a few KB, rendered once per relay change,
|
||||||
Relays by default currently allow 1000 recipients per submission,
|
and addresses only travel as `RCPT TO` commands in the SMTP transaction.
|
||||||
so a keyupdate (which is below 10Kbyte even with Autocrypt2),
|
Chatmail relays take 1000 addresses per submission,
|
||||||
would be uploaded once for anyone below 1K contacts,
|
so for most profiles today a keyupdate is a single upload,
|
||||||
which today is the vast majority by a wide margin.
|
and each upload stays well under 100KB on the wire.
|
||||||
|
|
||||||
- Recipients learn nothing about our contact list.
|
- Recipients learn nothing about our contact list
|
||||||
Every recipient gets the same encrypted message with no per-recipient framing,
|
because nothing in the message is recipient-specific:
|
||||||
and no chunk has to group contacts together.
|
one password-encrypted session key packet instead of one per recipient,
|
||||||
The submitting relay still sees the envelope, as it does today.
|
and a signature that names only its issuer,
|
||||||
|
with no `intended recipient fingerprint` subpackets.
|
||||||
|
The submitting relay still sees the envelope metadata, as it does today.
|
||||||
|
|
||||||
- Contacts acquired at any point in the past are reached.
|
- Contacts acquired at any point in the past are reached.
|
||||||
The secret comes from the key itself and not from a shared session,
|
The secret comes from the key itself and not from a shared session,
|
||||||
@@ -154,14 +153,14 @@ so "Remove" can mean actually removed, like users intend it.
|
|||||||
It would also unblock automatic relay management.
|
It would also unblock automatic relay management.
|
||||||
What ships under that name today is initial onboarding only
|
What ships under that name today is initial onboarding only
|
||||||
([#8444], still off by default): no rotation, no removal.
|
([#8444], still off by default): no rotation, no removal.
|
||||||
Designing those is hard while changing a relay is unsafe,
|
Designing those proved to be hard while changing a relay is unsafe,
|
||||||
because any automatic change would silently cut off
|
because any automatic change would silently cut off
|
||||||
the contacts who do not hear about it.
|
the contacts who do not hear about it.
|
||||||
Keyupdates would lift that constraint and could land in the next release,
|
Keyupdates would lift that constraint and could land in the next release,
|
||||||
well before automatic addition/removal mechanics are settled.
|
well before automatic addition/removal mechanics are settled.
|
||||||
|
|
||||||
|
|
||||||
## Keyupdates are decryptable forever, MUST only contain key updates
|
## Keyupdates are decryptable forever, so MUST only contain key updates
|
||||||
|
|
||||||
Anyone who ever obtained our "public" key could derive the secret
|
Anyone who ever obtained our "public" key could derive the secret
|
||||||
and decrypt these messages, forever.
|
and decrypt these messages, forever.
|
||||||
@@ -280,14 +279,13 @@ Properties that follow, and requirements they imply:
|
|||||||
- **Only update the key the secret was derived from.**
|
- **Only update the key the secret was derived from.**
|
||||||
A keyupdate must be signed by that key and carry an update to it,
|
A keyupdate must be signed by that key and carry an update to it,
|
||||||
and anything else is dropped.
|
and anything else is dropped.
|
||||||
The rule is needed because the AEAD tag only proves the writer knew the
|
Without the rule anyone holding a contact's key could send
|
||||||
secret, which every key holder does, so it authenticates nobody by itself.
|
|
||||||
Certificate merging already prevents a forged relay list,
|
|
||||||
but without the rule anyone holding a contact's key could send
|
|
||||||
a stream of messages carrying freshly generated keys in the Autocrypt
|
a stream of messages carrying freshly generated keys in the Autocrypt
|
||||||
header, each silently creating a contact and a stored key
|
header, each silently creating a contact the user never sees,
|
||||||
the user never sees, because keyupdates are trashed.
|
because keyupdates are trashed.
|
||||||
Note that keyupdates can only arrive for contacts whose key we already have.
|
The signature is not what makes the key credible, though,
|
||||||
|
and it is not what limits the audience either,
|
||||||
|
see *Keyupdates could come from anywhere but are signed anyway* below.
|
||||||
|
|
||||||
- **Domain-separated.**
|
- **Domain-separated.**
|
||||||
A v6 fingerprint is also a SHA-256 over the same key material,
|
A v6 fingerprint is also a SHA-256 over the same key material,
|
||||||
@@ -320,9 +318,8 @@ Properties that follow, and requirements they imply:
|
|||||||
which any sender could trigger with undecryptable garbage.
|
which any sender could trigger with undecryptable garbage.
|
||||||
Keyupdate secrets should therefore be tried last,
|
Keyupdate secrets should therefore be tried last,
|
||||||
after the securejoin and broadcast secrets.
|
after the securejoin and broadcast secrets.
|
||||||
Parsing and deriving on-demand in the try-decryption pipeline
|
Parsing and deriving on demand was measured at under a second
|
||||||
is probably fine even for thousands of contacts,
|
for a thousand contacts, so the secrets need no caching layer.
|
||||||
at tens of microseconds per certificate.
|
|
||||||
|
|
||||||
- **One body, many deliveries.**
|
- **One body, many deliveries.**
|
||||||
The body would be rendered once and independently from the contact count.
|
The body would be rendered once and independently from the contact count.
|
||||||
@@ -355,6 +352,39 @@ Properties that follow, and requirements they imply:
|
|||||||
and because we perform some merging on concurrent transport additions.
|
and because we perform some merging on concurrent transport additions.
|
||||||
|
|
||||||
|
|
||||||
|
### Keyupdates could come from anywhere but are signed anyway
|
||||||
|
|
||||||
|
The relay list in a keyupdate lives in a direct key self-signature,
|
||||||
|
and certificate merging verifies it and prefers the newest one,
|
||||||
|
so the resulting certificate is as trustworthy whether the keyupdate
|
||||||
|
arrived signed or unsigned, from the key owner or from a stranger.
|
||||||
|
Merging, not signing, is the cryptographic gate for every certificate we get,
|
||||||
|
so conceptually we could accept keyupdates from anyone.
|
||||||
|
However, the secret is derived from the key,
|
||||||
|
so we only ever ingest keyupdates from contacts whose certificate we store,
|
||||||
|
an audience fixed by construction rather than by policy.
|
||||||
|
|
||||||
|
Keyupdates should be signed
|
||||||
|
for implementation simplicity and a smaller attack surface:
|
||||||
|
every past holder of the key can derive the secret,
|
||||||
|
so the AEAD tag says only that the writer was one of them
|
||||||
|
while the signature narrows it to the key owner,
|
||||||
|
and core takes the sender contact from it,
|
||||||
|
treating a message without one as unencrypted and discarding it.
|
||||||
|
Unsigned keyupdates stay conceptually defensible,
|
||||||
|
but they would need an exception from the rule
|
||||||
|
that a contact-bound secret implies exactly one signature by that contact,
|
||||||
|
which broadcast channels and securejoin rest on too, and that is not worth it.
|
||||||
|
|
||||||
|
The same reasoning bounds a possible extension:
|
||||||
|
If we let our key-contacts gossip us other keys,
|
||||||
|
a keyupdate can carry `Autocrypt-Gossip` headers,
|
||||||
|
constrained to contacts we already share so no unknown one is added.
|
||||||
|
Conceptually that is fine but requires more implementation changes,
|
||||||
|
including the sender side of gossiping keyupdates,
|
||||||
|
so it is best considered separately from a first keyupdate release.
|
||||||
|
|
||||||
|
|
||||||
## Out of scope: envelope SMTP failures can terminate all sending
|
## Out of scope: envelope SMTP failures can terminate all sending
|
||||||
|
|
||||||
A permanently refused `RCPT TO` would fail the whole SMTP transaction,
|
A permanently refused `RCPT TO` would fail the whole SMTP transaction,
|
||||||
|
|||||||
Reference in New Issue
Block a user