Why MLS needs them
Adding someone to an encrypted group means giving them the group’s secrets in a form only they can read. That requires a public key of theirs. If the person is asleep, out of range or has their phone switched off, they cannot hand one over at the moment you need it.
MLS solves this the way a postbox does. RFC 9420 says clients can pre-publish KeyPackage objects to make it possible to add them to a group asynchronously. Each device uploads several in advance to a place others can reach, and anyone who wants to start a conversation or add that device fetches one later. The device itself does not need to be online when it is added.
What is inside
RFC 9420 Section 10 lists what a key package specifies:
- A protocol version and cipher suite the client supports. A client that supports several cipher suites can publish a separate package for each.
- An init key. A public key others use to encrypt the Welcome message to this client. It must be unique among the packages the client has created.
- A leaf node. The content that will represent the client in the group’s ratchet tree: its encryption key, its signature key, a credential that ties that signature key to an identity, the capabilities it supports, and a lifetime giving the times between which the leaf is valid.
- Extensions, and a signature over everything else, made with the client’s signature key.
A key package with an invalid signature must be treated as malformed. The RFC also requires the encryption key in the leaf to be different from the init key, so the key used to join and the key used inside the group are separate.
How a key package is used
RFC 9420 walks through the steps with three clients, A, B and C. A creates a group containing only itself, downloads key packages for B and C, and for each one sends an Add proposal and a Commit to the group. It also sends each new member a Welcome message directly.
Before using a package, the member adding someone checks it. RFC 9420 Section 10.1 says to verify that its version and cipher suite match the group’s, that its leaf node is valid, that the signature verifies against the public key in the credential, and that the leaf’s encryption key differs from the init key. The same checks run again when other members receive the package inside an Add.
RFC 9750 describes how the secrets travel. The information needed to join is encrypted with an ephemeral key, and that key is encrypted to the init key from the new member’s package. The new member decrypts the Welcome, sets up its state, and is expected to delete the private part of the init key afterwards. It can read new messages from then on, but not messages sent before it joined.
One use only
RFC 9420 says key packages are intended to be used only once, and that once a package has added its client to a group it should be deleted from wherever it was published. RFC 9750 gives the two reasons: reuse can allow replay attacks, and single use keeps forward secrecy for messages sent with the initial keying material.
Single use creates a weakness of its own. An attacker who fetches every package a client has published can stop that client being added to new groups. To limit this, the RFC allows a “last resort” key package that may be reused, and says the publication system should rate-limit requests, especially unauthenticated ones. RFC 9750 recommends provisioning enough ordinary packages that the last resort one is rarely needed, rotating it soon after it is used, and having a client added through it update its leaf keys as early as possible.
Keeping them fresh
A key package is a promise made in advance, so it can go stale. RFC 9420 warns that a member added to a new group through an old package whose private key has since been compromised starts that group exposed, the same risk that post-compromise security addresses inside a group. The fix it suggests is for clients to regularly generate new packages and upload them.
Other rules follow from the contents. Applications must set a maximum lifetime for leaf nodes and reject any that claim longer, and RFC 9750 notes that packages need to be replaced when a client’s signature keys change.
Where key packages are published
RFC 9750 assumes clients store key packages with the Delivery Service, which hands them out on request. It suggests the service return only the minimum needed, such as one per supported cipher suite, even when it holds more, so the client can be added to several groups before it has to upload fresh ones.
Without a central server, a deployment still needs some place where others can fetch packages, and choosing it is part of the design. In the Offline Protocol mesh SDK, the coldContactEnabled setting publishes and resolves key packages to support first contact over the Nostr path. It defaults to true, and the docs suggest disabling it if that publication pattern does not suit the deployment.