The Messaging Layer Security (MLS) Protocol
Extracted elements (32)
MLS derives a resumption PSK from each epoch to allow entropy from one epoch to be injected into a future epoch, enabling group reinitialization and subgroup branching. This cryptographically proves that members of the new group were also members during the epoch from which the PSK was extracted.
MLS uses a ratchet tree structure to achieve O(log N) cost for group key updates, as opposed to sender-key schemes that require O(N) or O(N^2) operations. This enables efficient post-compromise security for large groups by encrypting new entropy to only the necessary subtree of the group.
The filtered direct path removes intermediate nodes whose copath child has an empty resolution, reducing unnecessary key pairs. Encrypting to such a node would be equivalent to encrypting to its non-copath child, so omitting the key pair has no security impact while reducing tree size.
External joins allow a new member to join via an external Commit without a pre-published KeyPackage, using a GroupInfo object that includes the GroupContext and an external_pub key. This enables open-group scenarios where new members can join without prior coordination with existing members.
MLS uses GREASE (Generate Random Extensions And Sustain Extensibility) by having senders insert random values into extensible fields. Receivers are required to ignore unknown values in capabilities, extension types, proposal types, and credential types. GREASE values are registered in the appropriate IANA registries.
Applications MUST NOT rely on data in an application_id extension as if it were authenticated by the Authentication Service, and SHOULD gracefully handle cases where the identifier is not unique.
Applications MUST use PrivateMessage to encrypt application messages, and SHOULD use PrivateMessage for handshake messages. PublicMessage MAY be used for handshake messages only when the Delivery Service needs to examine them.
Each modification of LeafNode content MUST be reflected by a change in its signature, allowing other members to verify the validity of the LeafNode at any time.
For an X.509 credential, the public key encoded in the subjectPublicKeyInfo of the end-entity certificate MUST be identical to the signature_key in the LeafNode containing the credential.
The padding field in PrivateMessageContent MUST be filled with all zero bytes. A receiver MUST verify that there are no non-zero bytes in the padding field; if this check fails, the PrivateMessage MUST be rejected as malformed.
The sender of a PrivateMessage MUST generate a fresh random 4-byte reuse guard and XOR it with the first four bytes of the key-schedule nonce before encryption. The reuse guard MUST be included in the SenderData so recipients can reconstruct the nonce.
The signature algorithm specified in the group's cipher suite MUST be the same as the signature algorithm in the credentials stored in leaf nodes of the ratchet tree, including KeyPackages used to add new members.
Update messages SHOULD be sent at regular intervals as long as the group is active, and members that do not update SHOULD eventually be removed. The appropriate frequency is typically hours or days, not milliseconds, since the purpose is proactively constraining a compromise window.
Variable-length integer values MUST use the smallest number of bits required to represent the value. When decoding, values using more bits than necessary MUST be treated as malformed. Vectors starting with prefix '11' are invalid and MUST be rejected.
Whenever a new credential is introduced to the group (via KeyPackage, GroupInfo, Add, Update, or Commit with UpdatePath), it MUST be validated with the Authentication Service. When replacing a credential, the AS MUST also verify that the new presented identifiers are valid successors to the old ones.
PrivateMessage hides content and sender identity from the Delivery Service, but GroupID, epoch number, and message frequency are visible in the PrivateMessage header. Group extensions in the GroupContext are distributed to all members and may be visible to the DS if sent as PublicMessage. Group membership can be inferred by observing who processes Welcome messages.
A KeyPackage is a signed object published by a client prior to joining a group, containing an HPKE public key, signing key, credential, capabilities, and lifetime. Other members use it to add the client to a group and construct a Welcome message for them.
An MLSMessage is the top-level container for all MLS protocol messages, carrying a ProtocolVersion, WireFormat selector, and one of: PublicMessage, PrivateMessage, Welcome, GroupInfo, or KeyPackage. All messages are versioned with 'mls10(1)'.
EncryptWithLabel and DecryptWithLabel include a label and context in all HPKE encryption operations via an EncryptContext structure, preventing ciphertexts intended for one purpose from being used in another context. An IANA registry tracks label values.
SignWithLabel and VerifyWithLabel prefix all signed content with a label of the form 'MLS 1.0 ' + Label in a SignContent structure, binding signatures to their specific purpose and preventing cross-protocol confusion. An IANA registry tracks label values.
The key schedule derives a chain of secrets from the ratchet tree's commit_secret and the prior epoch's init_secret, producing the epoch_secret from which encryption_secret, exporter_secret, resumption_psk, and epoch_authenticator are further derived.
The ratchet tree is a perfect binary tree whose leaves represent group members and whose internal nodes hold HPKE public keys. It enforces the tree invariant: the private key for a node is known only to members whose leaves are descendants of that node.
MLS defines eight IANA registries: MLS Cipher Suites, MLS Wire Formats, MLS Extension Types, MLS Proposal Types, MLS Credential Types, MLS Signature Labels, MLS Public Key Encryption Labels, and MLS Exporter Labels. All use Specification Required or Standards Action policies, and a designated expert pool is established.
A compromised Authentication Service can cause members to accept credentials for identities they do not control, enabling impersonation. MLS does not provide protection against AS compromise; applications must rely on AS security and may use transparency mechanisms to detect misbehavior.
A compromised Delivery Service can withhold, reorder, or replay messages, but cannot forge messages or learn group secrets. However, DS compromise can cause group fragmentation by selectively delivering Commits, and can observe group metadata such as GroupID and message frequency.
KeyPackage reuse allows an adversary to add the same client to multiple groups without that client's knowledge. Each KeyPackage MUST be used only once; implementations should ensure that a KeyPackage is deleted from the distribution point after it has been consumed.
MLS provides forward secrecy and post-compromise security (PCS). FS is achieved because epoch secrets are deleted after use. PCS is achieved because each Commit provides fresh entropy derived from an updated ratchet tree, ensuring that compromise of an old epoch's keys does not compromise future epochs.
A group advances through a linear sequence of epochs, each initiated by a Commit message. States are: active epoch (members hold epoch_secret), transitioning (Commit sent/received, proposals applied, tree updated), and new epoch (fresh entropy derived, removed members excluded). Epochs are irreversible.
LeafNode contains HPKEPublicKey (encryption_key), SignaturePublicKey (signature_key), Credential, Capabilities, LeafNodeSource, optional Lifetime or parent_hash, Extensions, and a signature over LeafNodeTBS. When used in Update or Commit contexts, the group_id and leaf_index are included in the signed content.
PrivateMessage carries group_id (variable), epoch (uint64), content_type, authenticated_data (variable), encrypted_sender_data (variable), and ciphertext (variable). Both ciphertext and encrypted_sender_data are AEAD-protected using keys derived from the secret tree and sender_data_secret respectively.
SenderData contains leaf_index (uint32), generation (uint32), and reuse_guard (4 bytes). It is encrypted with a key and nonce derived from sender_data_secret and the first KDF.Nh bytes of the message ciphertext.
Variable-length integer encoding uses the two most significant bits of the first byte as a length prefix (00=1 byte, 01=2 bytes, 10=4 bytes, 11=invalid). The encoded value MUST use the minimum number of bits; over-long encodings MUST be rejected as malformed. Vectors may range from 0 to 2^30 bytes.