summaryrefslogtreecommitdiff
path: root/doc/rfc/rfc9420.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/rfc/rfc9420.txt')
-rw-r--r--doc/rfc/rfc9420.txt7040
1 files changed, 7040 insertions, 0 deletions
diff --git a/doc/rfc/rfc9420.txt b/doc/rfc/rfc9420.txt
new file mode 100644
index 0000000..6c4fdf6
--- /dev/null
+++ b/doc/rfc/rfc9420.txt
@@ -0,0 +1,7040 @@
+
+
+
+
+Internet Engineering Task Force (IETF) R. Barnes
+Request for Comments: 9420 Cisco
+Category: Standards Track B. Beurdouche
+ISSN: 2070-1721 Inria & Mozilla
+ R. Robert
+ Phoenix R&D
+ J. Millican
+ Meta Platforms
+ E. Omara
+
+ K. Cohn-Gordon
+ University of Oxford
+ July 2023
+
+
+ The Messaging Layer Security (MLS) Protocol
+
+Abstract
+
+ Messaging applications are increasingly making use of end-to-end
+ security mechanisms to ensure that messages are only accessible to
+ the communicating endpoints, and not to any servers involved in
+ delivering messages. Establishing keys to provide such protections
+ is challenging for group chat settings, in which more than two
+ clients need to agree on a key but may not be online at the same
+ time. In this document, we specify a key establishment protocol that
+ provides efficient asynchronous group key establishment with forward
+ secrecy (FS) and post-compromise security (PCS) for groups in size
+ ranging from two to thousands.
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 7841.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ https://www.rfc-editor.org/info/rfc9420.
+
+Copyright Notice
+
+ Copyright (c) 2023 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (https://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Revised BSD License text as described in Section 4.e of the
+ Trust Legal Provisions and are provided without warranty as described
+ in the Revised BSD License.
+
+Table of Contents
+
+ 1. Introduction
+ 2. Terminology
+ 2.1. Presentation Language
+ 2.1.1. Optional Value
+ 2.1.2. Variable-Size Vector Length Headers
+ 3. Protocol Overview
+ 3.1. Cryptographic State and Evolution
+ 3.2. Example Protocol Execution
+ 3.3. External Joins
+ 3.4. Relationships between Epochs
+ 4. Ratchet Tree Concepts
+ 4.1. Ratchet Tree Terminology
+ 4.1.1. Ratchet Tree Nodes
+ 4.1.2. Paths through a Ratchet Tree
+ 4.2. Views of a Ratchet Tree
+ 5. Cryptographic Objects
+ 5.1. Cipher Suites
+ 5.1.1. Public Keys
+ 5.1.2. Signing
+ 5.1.3. Public Key Encryption
+ 5.2. Hash-Based Identifiers
+ 5.3. Credentials
+ 5.3.1. Credential Validation
+ 5.3.2. Credential Expiry and Revocation
+ 5.3.3. Uniquely Identifying Clients
+ 6. Message Framing
+ 6.1. Content Authentication
+ 6.2. Encoding and Decoding a Public Message
+ 6.3. Encoding and Decoding a Private Message
+ 6.3.1. Content Encryption
+ 6.3.2. Sender Data Encryption
+ 7. Ratchet Tree Operations
+ 7.1. Parent Node Contents
+ 7.2. Leaf Node Contents
+ 7.3. Leaf Node Validation
+ 7.4. Ratchet Tree Evolution
+ 7.5. Synchronizing Views of the Tree
+ 7.6. Update Paths
+ 7.7. Adding and Removing Leaves
+ 7.8. Tree Hashes
+ 7.9. Parent Hashes
+ 7.9.1. Using Parent Hashes
+ 7.9.2. Verifying Parent Hashes
+ 8. Key Schedule
+ 8.1. Group Context
+ 8.2. Transcript Hashes
+ 8.3. External Initialization
+ 8.4. Pre-Shared Keys
+ 8.5. Exporters
+ 8.6. Resumption PSK
+ 8.7. Epoch Authenticators
+ 9. Secret Tree
+ 9.1. Encryption Keys
+ 9.2. Deletion Schedule
+ 10. Key Packages
+ 10.1. KeyPackage Validation
+ 11. Group Creation
+ 11.1. Required Capabilities
+ 11.2. Reinitialization
+ 11.3. Subgroup Branching
+ 12. Group Evolution
+ 12.1. Proposals
+ 12.1.1. Add
+ 12.1.2. Update
+ 12.1.3. Remove
+ 12.1.4. PreSharedKey
+ 12.1.5. ReInit
+ 12.1.6. ExternalInit
+ 12.1.7. GroupContextExtensions
+ 12.1.8. External Proposals
+ 12.2. Proposal List Validation
+ 12.3. Applying a Proposal List
+ 12.4. Commit
+ 12.4.1. Creating a Commit
+ 12.4.2. Processing a Commit
+ 12.4.3. Adding Members to the Group
+ 13. Extensibility
+ 13.1. Additional Cipher Suites
+ 13.2. Proposals
+ 13.3. Credential Extensibility
+ 13.4. Extensions
+ 13.5. GREASE
+ 14. Sequencing of State Changes
+ 15. Application Messages
+ 15.1. Padding
+ 15.2. Restrictions
+ 15.3. Delayed and Reordered Application Messages
+ 16. Security Considerations
+ 16.1. Transport Security
+ 16.2. Confidentiality of Group Secrets
+ 16.3. Confidentiality of Sender Data
+ 16.4. Confidentiality of Group Metadata
+ 16.4.1. GroupID, Epoch, and Message Frequency
+ 16.4.2. Group Extensions
+ 16.4.3. Group Membership
+ 16.5. Authentication
+ 16.6. Forward Secrecy and Post-Compromise Security
+ 16.7. Uniqueness of Ratchet Tree Key Pairs
+ 16.8. KeyPackage Reuse
+ 16.9. Delivery Service Compromise
+ 16.10. Authentication Service Compromise
+ 16.11. Additional Policy Enforcement
+ 16.12. Group Fragmentation by Malicious Insiders
+ 17. IANA Considerations
+ 17.1. MLS Cipher Suites
+ 17.2. MLS Wire Formats
+ 17.3. MLS Extension Types
+ 17.4. MLS Proposal Types
+ 17.5. MLS Credential Types
+ 17.6. MLS Signature Labels
+ 17.7. MLS Public Key Encryption Labels
+ 17.8. MLS Exporter Labels
+ 17.9. MLS Designated Expert Pool
+ 17.10. The "message/mls" Media Type
+ 18. References
+ 18.1. Normative References
+ 18.2. Informative References
+ Appendix A. Protocol Origins of Example Trees
+ Appendix B. Evolution of Parent Hashes
+ Appendix C. Array-Based Trees
+ Appendix D. Link-Based Trees
+ Contributors
+ Authors' Addresses
+
+1. Introduction
+
+ A group of users who want to send each other encrypted messages needs
+ a way to derive shared symmetric encryption keys. For two parties,
+ this problem has been studied thoroughly, with the Double Ratchet
+ emerging as a common solution [DoubleRatchet] [Signal]. Channels
+ implementing the Double Ratchet enjoy fine-grained forward secrecy as
+ well as post-compromise security, but are nonetheless efficient
+ enough for heavy use over low-bandwidth networks.
+
+ For a group of size greater than two, a common strategy is to
+ distribute symmetric "sender keys" over existing 1:1 secure channels,
+ and then for each member to send messages to the group encrypted with
+ their own sender key. On the one hand, using sender keys improves
+ efficiency relative to pairwise transmission of individual messages,
+ and it provides forward secrecy (with the addition of a hash
+ ratchet). On the other hand, it is difficult to achieve post-
+ compromise security with sender keys, requiring a number of key
+ update messages that scales as the square of the group size. An
+ adversary who learns a sender key can often indefinitely and
+ passively eavesdrop on that member's messages. Generating and
+ distributing a new sender key provides a form of post-compromise
+ security with regard to that sender. However, it requires
+ computation and communications resources that scale linearly with the
+ size of the group.
+
+ In this document, we describe a protocol based on tree structures
+ that enables asynchronous group keying with forward secrecy and post-
+ compromise security. Based on earlier work on "asynchronous
+ ratcheting trees" [ART], the protocol presented here uses an
+ asynchronous key-encapsulation mechanism for tree structures. This
+ mechanism allows the members of the group to derive and update shared
+ keys with costs that scale as the log of the group size.
+
+2. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in BCP
+ 14 [RFC2119] [RFC8174] when, and only when, they appear in all
+ capitals, as shown here.
+
+ Client: An agent that uses this protocol to establish shared
+ cryptographic state with other clients. A client is defined by
+ the cryptographic keys it holds.
+
+ Group: A group represents a logical collection of clients that share
+ a common secret value at any given time. Its state is represented
+ as a linear sequence of epochs in which each epoch depends on its
+ predecessor.
+
+ Epoch: A state of a group in which a specific set of authenticated
+ clients hold shared cryptographic state.
+
+ Member: A client that is included in the shared state of a group and
+ hence has access to the group's secrets.
+
+ Key Package: A signed object describing a client's identity and
+ capabilities, including a hybrid public key encryption (HPKE)
+ [RFC9180] public key that can be used to encrypt to that client.
+ Other clients can use a client's KeyPackage to introduce the
+ client to a new group.
+
+ Group Context: An object that summarizes the shared, public state of
+ the group. The group context is typically distributed in a signed
+ GroupInfo message, which is provided to new members to help them
+ join a group.
+
+ Signature Key: A signing key pair used to authenticate the sender of
+ a message.
+
+ Proposal: A message that proposes a change to the group, e.g.,
+ adding or removing a member.
+
+ Commit: A message that implements the changes to the group proposed
+ in a set of Proposals.
+
+ PublicMessage: An MLS protocol message that is signed by its sender
+ and authenticated as coming from a member of the group in a
+ particular epoch, but not encrypted.
+
+ PrivateMessage: An MLS protocol message that is signed by its
+ sender, authenticated as coming from a member of the group in a
+ particular epoch, and encrypted so that it is confidential to the
+ members of the group in that epoch.
+
+ Handshake Message: A PublicMessage or PrivateMessage carrying an MLS
+ Proposal or Commit object, as opposed to application data.
+
+ Application Message: A PrivateMessage carrying application data.
+
+ Terminology specific to tree computations is described in
+ Section 4.1.
+
+ In general, symmetric values are referred to as "keys" or "secrets"
+ interchangeably. Either term denotes a value that MUST be kept
+ confidential to a client. When labeling individual values, we
+ typically use "secret" to refer to a value that is used to derive
+ further secret values and "key" to refer to a value that is used with
+ an algorithm such as Hashed Message Authentication Code (HMAC) or an
+ Authenticated Encryption with Associated Data (AEAD) algorithm.
+
+ The PublicMessage and PrivateMessage formats are defined in
+ Section 6. Security notions such as forward secrecy and post-
+ compromise security are defined in Section 16.
+
+ As detailed in Section 13.5, MLS uses the "Generate Random Extensions
+ And Sustain Extensibility" (GREASE) approach to maintaining
+ extensibility, where senders insert random values into fields in
+ which receivers are required to ignore unknown values. Specific
+ "GREASE values" for this purpose are registered in the appropriate
+ IANA registries.
+
+2.1. Presentation Language
+
+ We use the TLS presentation language [RFC8446] to describe the
+ structure of protocol messages. In addition to the base syntax, we
+ add two additional features: the ability for fields to be optional
+ and the ability for vectors to have variable-size length headers.
+
+2.1.1. Optional Value
+
+ An optional value is encoded with a presence-signaling octet,
+ followed by the value itself if present. When decoding, a presence
+ octet with a value other than 0 or 1 MUST be rejected as malformed.
+
+ struct {
+ uint8 present;
+ select (present) {
+ case 0: struct{};
+ case 1: T value;
+ };
+ } optional<T>;
+
+2.1.2. Variable-Size Vector Length Headers
+
+ In the TLS presentation language, vectors are encoded as a sequence
+ of encoded elements prefixed with a length. The length field has a
+ fixed size set by specifying the minimum and maximum lengths of the
+ encoded sequence of elements.
+
+ In MLS, there are several vectors whose sizes vary over significant
+ ranges. So instead of using a fixed-size length field, we use a
+ variable-size length using a variable-length integer encoding based
+ on the one described in Section 16 of [RFC9000]. They differ only in
+ that the one here requires a minimum-size encoding. Instead of
+ presenting min and max values, the vector description simply includes
+ a V. For example:
+
+ struct {
+ uint32 fixed<0..255>;
+ opaque variable<V>;
+ } StructWithVectors;
+
+ Such a vector can represent values with length from 0 bytes to 2^30
+ bytes. The variable-length integer encoding reserves the two most
+ significant bits of the first byte to encode the base 2 logarithm of
+ the integer encoding length in bytes. The integer value is encoded
+ on the remaining bits, so that the overall value is in network byte
+ order. The encoded value 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.
+
+ This means that integers are encoded in 1, 2, or 4 bytes and can
+ encode 6-, 14-, or 30-bit values, respectively.
+
+ +========+=========+=============+=======+============+
+ | Prefix | Length | Usable Bits | Min | Max |
+ +========+=========+=============+=======+============+
+ | 00 | 1 | 6 | 0 | 63 |
+ +--------+---------+-------------+-------+------------+
+ | 01 | 2 | 14 | 64 | 16383 |
+ +--------+---------+-------------+-------+------------+
+ | 10 | 4 | 30 | 16384 | 1073741823 |
+ +--------+---------+-------------+-------+------------+
+ | 11 | invalid | - | - | - |
+ +--------+---------+-------------+-------+------------+
+
+ Table 1: Summary of Integer Encodings
+
+ Vectors that start with the prefix "11" are invalid and MUST be
+ rejected.
+
+ For example:
+
+ * The four-byte length value 0x9d7f3e7d decodes to 494878333.
+
+ * The two-byte length value 0x7bbd decodes to 15293.
+
+ * The single-byte length value 0x25 decodes to 37.
+
+ The following figure adapts the pseudocode provided in [RFC9000] to
+ add a check for minimum-length encoding:
+
+ ReadVarint(data):
+ // The length of variable-length integers is encoded in the
+ // first two bits of the first byte.
+ v = data.next_byte()
+ prefix = v >> 6
+ if prefix == 3:
+ raise Exception('invalid variable length integer prefix')
+
+ length = 1 << prefix
+
+ // Once the length is known, remove these bits and read any
+ // remaining bytes.
+ v = v & 0x3f
+ repeat length-1 times:
+ v = (v << 8) + data.next_byte()
+
+ // Check if the value would fit in half the provided length.
+ if prefix >= 1 && v < (1 << (8*(length/2) - 2)):
+ raise Exception('minimum encoding was not used')
+
+ return v
+
+ The use of variable-size integers for vector lengths allows vectors
+ to grow very large, up to 2^30 bytes. Implementations should take
+ care not to allow vectors to overflow available storage. To
+ facilitate debugging of potential interoperability problems,
+ implementations SHOULD provide a clear error when such an overflow
+ condition occurs.
+
+3. Protocol Overview
+
+ MLS is designed to operate in the context described in [MLS-ARCH].
+ In particular, we assume that the following services are provided:
+
+ * An Authentication Service (AS) that enables group members to
+ authenticate the credentials presented by other group members.
+
+ * A Delivery Service (DS) that routes MLS messages among the
+ participants in the protocol.
+
+ MLS assumes a trusted AS but a largely untrusted DS. Section 16.10
+ describes the impact of compromise or misbehavior of an AS. MLS is
+ designed to protect the confidentiality and integrity of the group
+ data even in the face of a compromised DS; in general, the DS is only
+ expected to reliably deliver messages. Section 16.9 describes the
+ impact of compromise or misbehavior of a DS.
+
+ The core functionality of MLS is continuous group authenticated key
+ exchange (AKE). As with other authenticated key exchange protocols
+ (such as TLS), the participants in the protocol agree on a common
+ secret value, and each participant can verify the identity of the
+ other participants. That secret can then be used to protect messages
+ sent from one participant in the group to the other participants
+ using the MLS framing layer or can be exported for use with other
+ protocols. MLS provides group AKE in the sense that there can be
+ more than two participants in the protocol, and continuous group AKE
+ in the sense that the set of participants in the protocol can change
+ over time.
+
+ The core organizing principles of MLS are _groups_ and _epochs_. A
+ group represents a logical collection of clients that share a common
+ secret value at any given time. The history of a group is divided
+ into a linear sequence of epochs. In each epoch, a set of
+ authenticated _members_ agree on an _epoch secret_ that is known only
+ to the members of the group in that epoch. The set of members
+ involved in the group can change from one epoch to the next, and MLS
+ ensures that only the members in the current epoch have access to the
+ epoch secret. From the epoch secret, members derive further shared
+ secrets for message encryption, group membership authentication, and
+ so on.
+
+ The creator of an MLS group creates the group's first epoch
+ unilaterally, with no protocol interactions. Thereafter, the members
+ of the group advance their shared cryptographic state from one epoch
+ to another by exchanging MLS messages.
+
+ * A _KeyPackage_ object describes a client's capabilities and
+ provides keys that can be used to add the client to a group.
+
+ * A _Proposal_ message proposes a change to be made in the next
+ epoch, such as adding or removing a member.
+
+ * A _Commit_ message initiates a new epoch by instructing members of
+ the group to implement a collection of proposals.
+
+ * A _Welcome_ message provides a new member to the group with the
+ information to initialize their state for the epoch in which they
+ were added or in which they want to add themselves to the group.
+
+ KeyPackage and Welcome messages are used to initiate a group or
+ introduce new members, so they are exchanged between group members
+ and clients not yet in the group. A client publishes a KeyPackage
+ via the DS, thus enabling other clients to add it to groups. When a
+ group member wants to add a new member to a group, it uses the new
+ member's KeyPackage to add them and constructs a Welcome message with
+ which the new member can initialize their local state.
+
+ Proposal and Commit messages are sent from one member of a group to
+ the others. MLS provides a common framing layer for sending messages
+ within a group: A _PublicMessage_ provides sender authentication for
+ unencrypted Proposal and Commit messages. A _PrivateMessage_
+ provides encryption and authentication for both Proposal/Commit
+ messages as well as any application data.
+
+3.1. Cryptographic State and Evolution
+
+ The cryptographic state at the core of MLS is divided into three
+ areas of responsibility:
+
+ .- ... -.
+ | |
+ | | |
+ | | | Key Schedule
+ | V |
+ | epoch_secret |
+. | | | .
+|\ Ratchet | | | Secret /|
+| \ Tree | | | Tree / |
+| \ | | | / |
+| \ | V | / |
+| +--> commit_secret --> epoch_secret --> encryption_secret -->+ |
+| / | | | \ |
+| / | | | \ |
+| / | | | \ |
+|/ | | | \|
+' | V | '
+ | epoch_secret |
+ | | |
+ | | |
+ | V |
+ | |
+ '- ... -'
+
+ Figure 1: Overview of MLS Group Evolution
+
+ * A _ratchet tree_ that represents the membership of the group,
+ providing group members a way to authenticate each other and
+ efficiently encrypt messages to subsets of the group. Each epoch
+ has a distinct ratchet tree. It seeds the _key schedule_.
+
+ * A _key schedule_ that describes the chain of key derivations used
+ to progress from epoch to epoch (mainly using the _init_secret_
+ and _epoch_secret_), as well as the derivation of a variety of
+ other secrets (see Table 4). For example:
+
+ - An _encryption secret_ that is used to initialize the secret
+ tree for the epoch.
+
+ - An _exporter secret_ that allows other protocols to leverage
+ MLS as a generic authenticated group key exchange.
+
+ - A _resumption secret_ that members can use to prove their
+ membership in the group, e.g., when creating a subgroup or a
+ successor group.
+
+ * A _secret tree_ derived from the key schedule that represents
+ shared secrets used by the members of the group for encrypting and
+ authenticating messages. Each epoch has a distinct secret tree.
+
+ Each member of the group maintains a partial view of these components
+ of the group's state. MLS messages are used to initialize these
+ views and keep them in sync as the group transitions between epochs.
+
+ Each new epoch is initiated with a Commit message. The Commit
+ instructs existing members of the group to update their views of the
+ ratchet tree by applying a set of Proposals, and uses the updated
+ ratchet tree to distribute fresh entropy to the group. This fresh
+ entropy is provided only to members in the new epoch and not to
+ members who have been removed. Commits thus maintain the property
+ that the epoch secret is confidential to the members in the current
+ epoch.
+
+ For each Commit that adds one or more members to the group, there are
+ one or more corresponding Welcome messages. Each Welcome message
+ provides new members with the information they need to initialize
+ their views of the key schedule and ratchet tree, so that these views
+ align with the views held by other members of the group in this
+ epoch.
+
+3.2. Example Protocol Execution
+
+ There are three major operations in the life of a group:
+
+ * Adding a member, initiated by a current member;
+
+ * Updating the keys that represent a member in the tree; and
+
+ * Removing a member.
+
+ Each of these operations is "proposed" by sending a message of the
+ corresponding type (Add / Update / Remove). The state of the group
+ is not changed, however, until a Commit message is sent to provide
+ the group with fresh entropy. In this section, we show each proposal
+ being committed immediately, but in more advanced deployment cases,
+ an application might gather several proposals before committing them
+ all at once. In the illustrations below, we show the Proposal and
+ Commit messages directly, while in reality they would be sent
+ encapsulated in PublicMessage or PrivateMessage objects.
+
+ Before the initialization of a group, clients publish KeyPackages to
+ a directory provided by the DS (see Figure 2).
+
+ Delivery Service
+ |
+ .--------' '--------.
+ | |
+ Group
+ A B C Directory Channel
+ | | | | |
+ | KeyPackageA | | | |
+ +------------------------------------------------->| |
+ | | | | |
+ | | KeyPackageB | | |
+ | +-------------------------------->| |
+ | | | | |
+ | | | KeyPackageC | |
+ | | +--------------->| |
+ | | | | |
+
+ Figure 2: Clients A, B, and C publish KeyPackages to the directory
+
+ Figure 3 shows how these pre-published KeyPackages are used to create
+ a group. When client A wants to establish a group with clients B and
+ C, it first initializes a group state containing only itself and
+ downloads KeyPackages for B and C. For each member, A generates an
+ Add proposal and a Commit message to add that member and then
+ broadcasts the two messages to the group. Client A also generates a
+ Welcome message and sends it directly to the new member (there's no
+ need to send it to the group). Only after A has received its Commit
+ message back from the Delivery Service does it update its state to
+ reflect the new member's addition.
+
+ Once A has updated its state, the new member has processed the
+ Welcome, and any other group members have processed the Commit, they
+ will all have consistent representations of the group state,
+ including a group secret that is known only to the members the group.
+ The new member will be able to read and send new messages to the
+ group, but messages sent before they were added to the group will not
+ be accessible.
+
+ Group
+ A B C Directory Channel
+ | | | | |
+ | KeyPackageB, KeyPackageC | |
+ |<-------------------------------------------+ |
+ | | | | |
+ | | | | Add(A->AB) |
+ | | | | Commit(Add) |
+ +--------------------------------------------------------------->|
+ | | | | |
+ | Welcome(B) | | | |
+ +------------->| | | |
+ | | | | |
+ | | | | Add(A->AB) |
+ | | | | Commit(Add) |
+ |<---------------------------------------------------------------+
+ | | | | |
+ | | | | |
+ | | | | Add(AB->ABC) |
+ | | | | Commit(Add) |
+ +--------------------------------------------------------------->|
+ | | | | |
+ | | Welcome(C) | | |
+ +---------------------------->| | |
+ | | | | |
+ | | | | Add(AB->ABC) |
+ | | | | Commit(Add) |
+ |<---------------------------------------------------------------+
+ | |<------------------------------------------------+
+ | | | | |
+
+ Figure 3: Client A creates a group with clients B and C
+
+ Subsequent additions of group members proceed in the same way. Any
+ member of the group can download a KeyPackage for a new client,
+ broadcast Add and Commit messages that the current group will use to
+ update their state, and send a Welcome message that the new client
+ can use to initialize its state and join the group.
+
+ To enforce the forward secrecy and post-compromise security of
+ messages, each member periodically updates the keys that represent
+ them to the group. A member does this by sending a Commit (possibly
+ with no proposals) or by sending an Update message that is committed
+ by another member (see Figure 4). Once the other members of the
+ group have processed these messages, the group's secrets will be
+ unknown to an attacker that had compromised the secrets corresponding
+ to the sender's leaf in the tree. At the end of the scenario shown
+ in Figure 4, the group has post-compromise security with respect to
+ both A and B.
+
+ Update messages SHOULD be sent at regular intervals of time as long
+ as the group is active, and members that don't update SHOULD
+ eventually be removed from the group. It's left to the application
+ to determine an appropriate amount of time between Updates. Since
+ the purpose of sending an Update is to proactively constrain a
+ compromise window, the right frequency is usually on the order of
+ hours or days, not milliseconds. For example, an application might
+ send an Update each time a member sends an application message after
+ receiving any message from another member, or daily if no application
+ messages are sent.
+
+ The MLS architecture recommends that MLS be operated over a secure
+ transport (see Section 7.1 of [MLS-ARCH]). Such transport protocols
+ will typically provide functions such as congestion control that
+ manage the impact of an MLS-using application on other applications
+ sharing the same network. Applications should take care that they do
+ not send MLS messages at a rate that will cause problems such as
+ network congestion, especially if they are not following the above
+ recommendation (e.g., sending MLS directly over UDP instead).
+
+ Group
+ A B ... Z Directory Channel
+ | | | | |
+ | | Update(B) | | |
+ | +------------------------------------------->|
+ | | | | Update(B) |
+ |<----------------------------------------------------------+
+ | |<-------------------------------------------+
+ | | |<----------------------------+
+ | | | | |
+ | Commit(Upd) | | | |
+ +---------------------------------------------------------->|
+ | | | | Commit(Upd) |
+ |<----------------------------------------------------------+
+ | |<-------------------------------------------+
+ | | |<----------------------------+
+ | | | | |
+
+ Figure 4: Client B proposes to update its key, and client A
+ commits the proposal
+
+ Members are removed from the group in a similar way, as shown in
+ Figure 5. Any member of the group can send a Remove proposal
+ followed by a Commit message. The Commit message provides new
+ entropy to all members of the group except the removed member. This
+ new entropy is added to the epoch secret for the new epoch so that it
+ is not known to the removed member. Note that this does not
+ necessarily imply that any member is actually allowed to evict other
+ members; groups can enforce access control policies on top of these
+ basic mechanisms.
+
+ Group
+ A B ... Z Directory Channel
+ | | | | |
+ | | | Remove(B) | |
+ | | | Commit(Rem) | |
+ | | +---------------------------->|
+ | | | | |
+ | | | | Remove(B) |
+ | | | | Commit(Rem) |
+ |<----------------------------------------------------------+
+ | |<-------------------------------------------+
+ | | |<----------------------------+
+ | | | | |
+
+ Figure 5: Client Z removes client B from the group
+
+ Note that the flows in this section are examples; applications can
+ arrange message flows in other ways. For example:
+
+ * Welcome messages don't necessarily need to be sent directly to new
+ joiners. Since they are encrypted to new joiners, they could be
+ distributed more broadly, say if the application only had access
+ to a broadcast channel for the group.
+
+ * Proposal messages don't need to be immediately sent to all group
+ members. They need to be available to the committer before
+ generating a Commit, and to other members before processing the
+ Commit.
+
+ * The sender of a Commit doesn't necessarily have to wait to receive
+ its own Commit back before advancing its state. It only needs to
+ know that its Commit will be the next one applied by the group,
+ say based on a promise from an orchestration server.
+
+3.3. External Joins
+
+ In addition to the Welcome-based flow for adding a new member to the
+ group, it is also possible for a new member to join by means of an
+ "external Commit". This mechanism can be used when the existing
+ members don't have a KeyPackage for the new member, for example, in
+ the case of an "open" group that can be joined by new members without
+ asking permission from existing members.
+
+ Figure 6 shows a typical message flow for an external join. To
+ enable a new member to join the group in this way, a member of the
+ group (A, B) publishes a GroupInfo object that includes the
+ GroupContext for the group as well as a public key that can be used
+ to encrypt a secret to the existing members of the group. When the
+ new member Z wishes to join, they download the GroupInfo object and
+ use it to form a Commit of a special form that adds Z to the group
+ (as detailed in Section 12.4.3.2). The existing members of the group
+ process this external Commit in a similar way to a normal Commit,
+ advancing to a new epoch in which Z is now a member of the group.
+
+ Group
+ A B Z Directory Channel
+ | | | | |
+ | GroupInfo | | | |
+ +------------------------------------------->| |
+ | | | GroupInfo | |
+ | | |<-------------+ |
+ | | | | |
+ | | | Commit(ExtZ) | |
+ | | +---------------------------->|
+ | | | | Commit(ExtZ) |
+ |<----------------------------------------------------------+
+ | |<-------------------------------------------+
+ | | |<----------------------------+
+ | | | | |
+
+ Figure 6: Client A publishes a GroupInfo object, and Client Z
+ uses it to join the group
+
+3.4. Relationships between Epochs
+
+ A group has a single linear sequence of epochs. Groups and epochs
+ are generally independent of one another. However, it can sometimes
+ be useful to link epochs cryptographically, either within a group or
+ across groups. MLS derives a resumption pre-shared key (PSK) from
+ each epoch to allow entropy extracted from one epoch to be injected
+ into a future epoch. A group member that wishes to inject a PSK
+ issues a PreSharedKey proposal (Section 12.1.4) describing the PSK to
+ be injected. When this proposal is committed, the corresponding PSK
+ will be incorporated into the key schedule as described in
+ Section 8.4.
+
+ Linking epochs in this way guarantees that members entering the new
+ epoch agree on a key if and only if they were members of the group
+ during the epoch from which the resumption key was extracted.
+
+ MLS supports two ways to tie a new group to an existing group, which
+ are illustrated in Figures 7 and 8. Reinitialization closes one
+ group and creates a new group comprising the same members with
+ different parameters. Branching starts a new group with a subset of
+ the original group's participants (with no effect on the original
+ group). In both cases, the new group is linked to the old group via
+ a resumption PSK.
+
+ epoch_A_[n-1]
+ |
+ |
+ |<-- ReInit
+ |
+ V
+ epoch_A_[n] epoch_B_[0]
+ . |
+ . PSK(usage=reinit) |
+ .....................>|
+ |
+ V
+ epoch_B_[1]
+
+ Figure 7: Reinitializing a Group
+
+ epoch_A_[n] epoch_B_[0]
+ | |
+ | PSK(usage=branch) |
+ |....................>|
+ | |
+ V V
+ epoch_A_[n+1] epoch_B_[1]
+
+ Figure 8: Branching a Group
+
+ Applications may also choose to use resumption PSKs to link epochs in
+ other ways. For example, Figure 9 shows a case where a resumption
+ PSK from epoch n is injected into epoch n+k. This demonstrates that
+ the members of the group at epoch n+k were also members at epoch n,
+ irrespective of any changes to these members' keys due to Updates or
+ Commits.
+
+ epoch_A_[n]
+ |
+ | PSK(usage=application)
+ |.....................
+ | .
+ | .
+ ... ...
+ | .
+ | .
+ V .
+ epoch_A_[n+k-1] .
+ | .
+ | .
+ |<....................
+ |
+ V
+ epoch_A_[n+k]
+
+ Figure 9: Reinjecting Entropy from an Earlier Epoch
+
+4. Ratchet Tree Concepts
+
+ The protocol uses "ratchet trees" for deriving shared secrets among a
+ group of clients. A ratchet tree is an arrangement of secrets and
+ key pairs among the members of a group in a way that allows for
+ secrets to be efficiently updated to reflect changes in the group.
+
+ Ratchet trees allow a group to efficiently remove any member by
+ encrypting new entropy to a subset of the group. A ratchet tree
+ assigns shared keys to subgroups of the overall group, so that, for
+ example, encrypting to all but one member of the group requires only
+ log(N) encryptions to subtrees, instead of the N-1 encryptions that
+ would be needed to encrypt to each participant individually (where N
+ is the number of members in the group).
+
+ This remove operation allows MLS to efficiently achieve post-
+ compromise security. In an Update proposal or a full Commit message,
+ an old (possibly compromised) representation of a member is
+ efficiently removed from the group and replaced with a freshly
+ generated instance.
+
+4.1. Ratchet Tree Terminology
+
+ Trees consist of _nodes_. A node is a _leaf_ if it has no children;
+ otherwise, it is a _parent_. All parents in our trees have precisely
+ two children, a _left_ child and a _right_ child. A node is the
+ _root_ of a tree if it has no parent, and _intermediate_ if it has
+ both children and a parent. The _descendants_ of a node are that
+ node's children, and the descendants of its children. We say a tree
+ _contains_ a node if that node is a descendant of the root of the
+ tree, or if the node itself is the root of the tree. Nodes are
+ _siblings_ if they share the same parent.
+
+ A _subtree_ of a tree is the tree given by any node (the _head_ of
+ the subtree) and its descendants. The _size_ of a tree or subtree is
+ the number of leaf nodes it contains. For a given parent node, its
+ _left subtree_ is the subtree with its left child as head and its
+ _right subtree_ is the subtree with its right child as head.
+
+ Every tree used in this protocol is a perfect binary tree, that is, a
+ complete balanced binary tree with 2^d leaves all at the same depth
+ d. This structure is unique for a given depth d.
+
+ There are multiple ways that an implementation might represent a
+ ratchet tree in memory. A convenient property of left-balanced
+ binary trees (including the complete trees used here) is that they
+ can be represented as an array of nodes, with node relationships
+ computed based on the nodes' indices in the array. A more
+ traditional representation based on linked node objects may also be
+ used. Appendices C and D provide some details on how to implement
+ the tree operations required for MLS in these representations. MLS
+ places no requirements on implementations' internal representations
+ of ratchet trees. An implementation may use any tree representation
+ and associated algorithms, as long as they produce correct protocol
+ messages.
+
+4.1.1. Ratchet Tree Nodes
+
+ Each leaf node in a ratchet tree is given an _index_ (or _leaf
+ index_), starting at 0 from the left to 2^d - 1 at the right (for a
+ tree with 2^d leaves). A tree with 2^d leaves has 2^(d+1) - 1 nodes,
+ including parent nodes.
+
+ Each node in a ratchet tree is either _blank_ (containing no value)
+ or it holds an HPKE public key with some associated data:
+
+ * A public key (for the HPKE scheme in use; see Section 5.1)
+
+ * A credential (only for leaf nodes; see Section 5.3)
+
+ * An ordered list of "unmerged" leaves (see Section 4.2)
+
+ * A hash of certain information about the node's parent, as of the
+ last time the node was changed (see Section 7.9).
+
+ As described in Section 4.2, different members know different subsets
+ of the set of private keys corresponding to the public keys in nodes
+ in the tree. The private key corresponding to a parent node is known
+ only to members at leaf nodes that are descendants of that node. The
+ private key corresponding to a leaf node is known only to the member
+ at that leaf node. A leaf node is _unmerged_ relative to one of its
+ ancestor nodes if the member at the leaf node does not know the
+ private key corresponding to the ancestor node.
+
+ Every node, regardless of whether the node is blank or populated, has
+ a corresponding _hash_ that summarizes the contents of the subtree
+ below that node. The rules for computing these hashes are described
+ in Section 7.8.
+
+ The _resolution_ of a node is an ordered list of non-blank nodes that
+ collectively cover all non-blank descendants of the node. The
+ resolution of the root contains the set of keys that are collectively
+ necessary to encrypt to every node in the group. The resolution of a
+ node is effectively a depth-first, left-first enumeration of the
+ nearest non-blank nodes below the node:
+
+ * The resolution of a non-blank node comprises the node itself,
+ followed by its list of unmerged leaves, if any.
+
+ * The resolution of a blank leaf node is the empty list.
+
+ * The resolution of a blank intermediate node is the result of
+ concatenating the resolution of its left child with the resolution
+ of its right child, in that order.
+
+ For example, consider the following subtree, where the _ character
+ represents a blank node and unmerged leaves are indicated in square
+ brackets:
+
+ ...
+ /
+ _
+ ______|______
+ / \
+ X[B] _
+ __|__ __|__
+ / \ / \
+ _ _ Y _
+ / \ / \ / \ / \
+ A B _ D E F _ H
+
+ 0 1 2 3 4 5 6 7
+
+ Figure 10: A Tree with Blanks and Unmerged Leaves
+
+ In this tree, we can see all of the above rules in play:
+
+ * The resolution of node X is the list [X, B].
+
+ * The resolution of leaf 2 or leaf 6 is the empty list [].
+
+ * The resolution of top node is the list [X, B, Y, H].
+
+4.1.2. Paths through a Ratchet Tree
+
+ The _direct path_ of a root is the empty list. The direct path of
+ any other node is the concatenation of that node's parent along with
+ the parent's direct path.
+
+ The _copath_ of a node is the node's sibling concatenated with the
+ list of siblings of all the nodes in its direct path, excluding the
+ root.
+
+ The _filtered direct path_ of a leaf node L is the node's direct
+ path, with any node removed whose child on the copath of L has an
+ empty resolution (keeping in mind that any unmerged leaves of the
+ copath child count toward its resolution). The removed nodes do not
+ need their own key pairs because encrypting to the node's key pair
+ would be equivalent to encrypting to its non-copath child.
+
+ For example, consider the following tree (where blank nodes are
+ indicated with _, but also assigned a label for reference):
+
+ W = root
+ |
+ .-----+-----.
+ / \
+ _=U Y
+ | |
+ .-+-. .-+-.
+ / \ / \
+ T _=V X _=Z
+ / \ / \ / \ / \
+ A B _ _ E F G _=H
+
+ 0 1 2 3 4 5 6 7
+
+ Figure 11: A Complete Tree with Five Members, with Labels for
+ Blank Parent Nodes
+
+ In this tree, the direct paths, copaths, and filtered direct paths
+ for the leaf nodes are as follows:
+
+ +======+=============+=========+======================+
+ | Node | Direct path | Copath | Filtered Direct Path |
+ +======+=============+=========+======================+
+ | A | T, U, W | B, V, Y | T, W |
+ +------+-------------+---------+----------------------+
+ | B | T, U, W | A, V, Y | T, W |
+ +------+-------------+---------+----------------------+
+ | E | X, Y, W | F, Z, U | X, Y, W |
+ +------+-------------+---------+----------------------+
+ | F | X, Y, W | E, Z, U | X, Y, W |
+ +------+-------------+---------+----------------------+
+ | G | Z, Y, W | H, X, U | Y, W |
+ +------+-------------+---------+----------------------+
+
+ Table 2
+
+4.2. Views of a Ratchet Tree
+
+ We generally assume that each participant maintains a complete and
+ up-to-date view of the public state of the group's ratchet tree,
+ including the public keys for all nodes and the credentials
+ associated with the leaf nodes.
+
+ No participant in an MLS group knows the private key associated with
+ every node in the tree. Instead, each member is assigned to a leaf
+ of the tree, which determines the subset of private keys it knows.
+ The credential stored at that leaf is one provided by the member.
+
+ In particular, MLS maintains the members' views of the tree in such a
+ way as to maintain the _tree invariant_:
+
+ | The private key for a node in the tree is known to a member of the
+ | group only if the node's subtree contains that member's leaf.
+
+ In other words, if a node is not blank, then it holds a public key.
+ The corresponding private key is known only to members occupying
+ leaves below that node.
+
+ The reverse implication is not true: A member may not know the
+ private key of an intermediate node above them. Such a member has an
+ _unmerged_ leaf at the intermediate node. Encrypting to an
+ intermediate node requires encrypting to the node's public key, as
+ well as the public keys of all the unmerged leaves below it. A leaf
+ is unmerged with regard to all of its ancestors when it is first
+ added, because the process of adding the leaf does not give it access
+ to the private keys for all of the nodes above it in the tree.
+ Leaves are "merged" as they receive the private keys for nodes, as
+ described in Section 7.4.
+
+ For example, consider a four-member group (A, B, C, D) where the node
+ above the right two members is blank. (This is what it would look
+ like if A created a group with B, C, and D.) Then the public state
+ of the tree and the views of the private keys of the tree held by
+ each participant would be as follows, where _ represents a blank
+ node, ? represents an unknown private key, and pk(X) represents the
+ public key corresponding to the private key X:
+
+ Public Tree
+ ============================
+ pk(ABCD)
+ / \
+ pk(AB) _
+ / \ / \
+ pk(A) pk(B) pk(C) pk(D)
+
+
+ Private @ A Private @ B Private @ C Private @ D
+ ============= ============= ============= =============
+ ABCD ABCD ABCD ABCD
+ / \ / \ / \ / \
+ AB _ AB _ ? _ ? _
+ / \ / \ / \ / \ / \ / \ / \ / \
+ A ? ? ? ? B ? ? ? ? C ? ? ? ? D
+
+ Note how the tree invariant applies: Each member knows only their own
+ leaf, the private key AB is known only to A and B, and the private
+ key ABCD is known to all four members. This also illustrates another
+ important point: it is possible for there to be "holes" on the path
+ from a member's leaf to the root in which the member knows the key
+ both above and below a given node, but not for that node, as in the
+ case with D.
+
+5. Cryptographic Objects
+
+5.1. Cipher Suites
+
+ Each MLS session uses a single cipher suite that specifies the
+ following primitives to be used in group key computations:
+
+ * HPKE parameters:
+
+ - A Key Encapsulation Mechanism (KEM)
+
+ - A Key Derivation Function (KDF)
+
+ - An Authenticated Encryption with Associated Data (AEAD)
+ encryption algorithm
+
+ * A hash algorithm
+
+ * A Message Authentication Code (MAC) algorithm
+
+ * A signature algorithm
+
+ MLS uses HPKE for public key encryption [RFC9180]. The DeriveKeyPair
+ function associated to the KEM for the cipher suite maps octet
+ strings to HPKE key pairs. As in HPKE, MLS assumes that an AEAD
+ algorithm produces a single ciphertext output from AEAD encryption
+ (aligning with [RFC5116]), as opposed to a separate ciphertext and
+ tag.
+
+ Cipher suites are represented with the CipherSuite type. The cipher
+ suites are defined in Section 17.1.
+
+5.1.1. Public Keys
+
+ HPKE public keys are opaque values in a format defined by the
+ underlying protocol (see Section 4 of [RFC9180] for more
+ information).
+
+ opaque HPKEPublicKey<V>;
+
+ Signature public keys are likewise represented as opaque values in a
+ format defined by the cipher suite's signature scheme.
+
+ opaque SignaturePublicKey<V>;
+
+ For cipher suites using the Edwards-curve Digital Signature Algorithm
+ (EdDSA) signature schemes (Ed25519 or Ed448), the public key is in
+ the format specified in [RFC8032].
+
+ For cipher suites using the Elliptic Curve Digital Signature
+ Algorithm (ECDSA) with the NIST curves (P-256, P-384, or P-521), the
+ public key is represented as an encoded
+ UncompressedPointRepresentation struct, as defined in [RFC8446].
+
+5.1.2. Signing
+
+ The signature algorithm specified in a group's cipher suite is the
+ mandatory algorithm to be used for signing messages within the group.
+ It MUST be the same as the signature algorithm specified in the
+ credentials in the leaves of the tree (including the leaf node
+ information in KeyPackages used to add new members).
+
+ The signatures used in this document are encoded as specified in
+ [RFC8446]. In particular, ECDSA signatures are DER encoded, and
+ EdDSA signatures are defined as the concatenation of R and S, as
+ specified in [RFC8032].
+
+ To disambiguate different signatures used in MLS, each signed value
+ is prefixed by a label as shown below:
+
+ SignWithLabel(SignatureKey, Label, Content) =
+ Signature.Sign(SignatureKey, SignContent)
+
+ VerifyWithLabel(VerificationKey, Label, Content, SignatureValue) =
+ Signature.Verify(VerificationKey, SignContent, SignatureValue)
+
+ Where SignContent is specified as:
+
+ struct {
+ opaque label<V>;
+ opaque content<V>;
+ } SignContent;
+
+ And its fields are set to:
+
+ label = "MLS 1.0 " + Label;
+ content = Content;
+
+ The functions Signature.Sign and Signature.Verify are defined by the
+ signature algorithm. If MLS extensions require signatures by group
+ members, they should reuse the SignWithLabel construction, using a
+ distinct label. To avoid collisions in these labels, an IANA
+ registry is defined in Section 17.6.
+
+5.1.3. Public Key Encryption
+
+ As with signing, MLS includes a label and context in encryption
+ operations to avoid confusion between ciphertexts produced for
+ different purposes. Encryption and decryption including this label
+ and context are done as follows:
+
+ EncryptWithLabel(PublicKey, Label, Context, Plaintext) =
+ SealBase(PublicKey, EncryptContext, "", Plaintext)
+
+ DecryptWithLabel(PrivateKey, Label, Context, KEMOutput, Ciphertext) =
+ OpenBase(KEMOutput, PrivateKey, EncryptContext, "", Ciphertext)
+
+ Where EncryptContext is specified as:
+
+ struct {
+ opaque label<V>;
+ opaque context<V>;
+ } EncryptContext;
+
+ And its fields are set to:
+
+ label = "MLS 1.0 " + Label;
+ context = Context;
+
+ The functions SealBase and OpenBase are defined in Section 6.1 of
+ [RFC9180] (with "Base" as the MODE), using the HPKE algorithms
+ specified by the group's cipher suite. If MLS extensions require
+ HPKE encryption operations, they should reuse the EncryptWithLabel
+ construction, using a distinct label. To avoid collisions in these
+ labels, an IANA registry is defined in Section 17.7.
+
+5.2. Hash-Based Identifiers
+
+ Some MLS messages refer to other MLS objects by hash. For example,
+ Welcome messages refer to KeyPackages for the members being welcomed,
+ and Commits refer to Proposals they cover. These identifiers are
+ computed as follows:
+
+ opaque HashReference<V>;
+
+ HashReference KeyPackageRef;
+ HashReference ProposalRef;
+
+ MakeKeyPackageRef(value)
+ = RefHash("MLS 1.0 KeyPackage Reference", value)
+
+ MakeProposalRef(value)
+ = RefHash("MLS 1.0 Proposal Reference", value)
+
+ RefHash(label, value) = Hash(RefHashInput)
+
+ Where RefHashInput is defined as:
+
+ struct {
+ opaque label<V>;
+ opaque value<V>;
+ } RefHashInput;
+
+ And its fields are set to:
+
+ label = label;
+ value = value;
+
+ For a KeyPackageRef, the value input is the encoded KeyPackage, and
+ the cipher suite specified in the KeyPackage determines the KDF used.
+ For a ProposalRef, the value input is the AuthenticatedContent
+ carrying the Proposal. In the latter two cases, the KDF is
+ determined by the group's cipher suite.
+
+5.3. Credentials
+
+ Each member of a group presents a credential that provides one or
+ more identities for the member and associates them with the member's
+ signing key. The identities and signing key are verified by the
+ Authentication Service in use for a group.
+
+ It is up to the application to decide which identifiers to use at the
+ application level. For example, a certificate in an X509Credential
+ may attest to several domain names or email addresses in its
+ subjectAltName extension. An application may decide to present all
+ of these to a user, or if it knows a "desired" domain name or email
+ address, it can check that the desired identifier is among those
+ attested. Using the terminology from [RFC6125], a credential
+ provides "presented identifiers", and it is up to the application to
+ supply a "reference identifier" for the authenticated client, if any.
+
+ // See the "MLS Credential Types" IANA registry for values
+ uint16 CredentialType;
+
+ struct {
+ opaque cert_data<V>;
+ } Certificate;
+
+ struct {
+ CredentialType credential_type;
+ select (Credential.credential_type) {
+ case basic:
+ opaque identity<V>;
+
+ case x509:
+ Certificate certificates<V>;
+ };
+ } Credential;
+
+ A "basic" credential is a bare assertion of an identity, without any
+ additional information. The format of the encoded identity is
+ defined by the application.
+
+ For an X.509 credential, each entry in the certificates field
+ represents a single DER-encoded X.509 certificate. The chain is
+ ordered such that the first entry (certificates[0]) is the end-entity
+ certificate. The public key encoded in the subjectPublicKeyInfo of
+ the end-entity certificate MUST be identical to the signature_key in
+ the LeafNode containing this credential. A chain MAY omit any non-
+ leaf certificates that supported peers are known to already possess.
+
+5.3.1. Credential Validation
+
+ The application using MLS is responsible for specifying which
+ identifiers it finds acceptable for each member in a group. In other
+ words, following the model that [RFC6125] describes for TLS, the
+ application maintains a list of "reference identifiers" for the
+ members of a group, and the credentials provide "presented
+ identifiers". A member of a group is authenticated by first
+ validating that the member's credential legitimately represents some
+ presented identifiers, and then ensuring that the reference
+ identifiers for the member are authenticated by those presented
+ identifiers.
+
+ The parts of the system that perform these functions are collectively
+ referred to as the Authentication Service (AS) [MLS-ARCH]. A
+ member's credential is said to be _validated with the AS_ when the AS
+ verifies that the credential's presented identifiers are correctly
+ associated with the signature_key field in the member's LeafNode, and
+ that those identifiers match the reference identifiers for the
+ member.
+
+ Whenever a new credential is introduced in the group, it MUST be
+ validated with the AS. In particular, at the following events in the
+ protocol:
+
+ * When a member receives a KeyPackage that it will use in an Add
+ proposal to add a new member to the group
+
+ * When a member receives a GroupInfo object that it will use to join
+ a group, either via a Welcome or via an external Commit
+
+ * When a member receives an Add proposal adding a member to the
+ group
+
+ * When a member receives an Update proposal whose LeafNode has a new
+ credential for the member
+
+ * When a member receives a Commit with an UpdatePath whose LeafNode
+ has a new credential for the committer
+
+ * When an external_senders extension is added to the group
+
+ * When an existing external_senders extension is updated
+
+ In cases where a member's credential is being replaced, such as the
+ Update and Commit cases above, the AS MUST also verify that the set
+ of presented identifiers in the new credential is valid as a
+ successor to the set of presented identifiers in the old credential,
+ according to the application's policy.
+
+5.3.2. Credential Expiry and Revocation
+
+ In some credential schemes, a valid credential can "expire" or become
+ invalid after a certain point in time. For example, each X.509
+ certificate has a notAfter field, expressing a time after which the
+ certificate is not valid.
+
+ Expired credentials can cause operational problems in light of the
+ validation requirements of Section 5.3.1. Applications can apply
+ some operational practices and adaptations to Authentication Service
+ policies to moderate these impacts.
+
+ In general, to avoid operational problems such as new joiners
+ rejecting expired credentials in a group, applications that use such
+ credentials should ensure to the extent practical that all of the
+ credentials in use in a group are valid at all times.
+
+ If a member finds that its credential has expired (or will soon), it
+ should issue an Update or Commit that replaces it with a valid
+ credential. For this reason, members SHOULD accept Update proposals
+ and Commits issued by members with expired credentials, if the
+ credential in the Update or Commit is valid.
+
+ Similarly, when a client is processing messages sent some time in the
+ past (e.g., syncing up with a group after being offline), the client
+ SHOULD accept signatures from members with expired credentials, since
+ the credential may have been valid at the time the message was sent.
+
+ If a member finds that another member's credential has expired, they
+ may issue a Remove that removes that member. For example, an
+ application could require a member preparing to issue a Commit to
+ check the tree for expired credentials and include Remove proposals
+ for those members in its Commit. In situations where the group tree
+ is known to the DS, the DS could also monitor the tree for expired
+ credentials and issue external Remove proposals.
+
+ Some credential schemes also allow credentials to be revoked.
+ Revocation is similar to expiry in that a previously valid credential
+ becomes invalid. As such, most of the considerations above also
+ apply to revoked credentials. However, applications may want to
+ treat revoked credentials differently, e.g., by removing members with
+ revoked credentials while allowing members with expired credentials
+ time to update.
+
+5.3.3. Uniquely Identifying Clients
+
+ MLS implementations will presumably provide applications with a way
+ to request protocol operations with regard to other clients (e.g.,
+ removing clients). Such functions will need to refer to the other
+ clients using some identifier. MLS clients have a few types of
+ identifiers, with different operational properties.
+
+ Internally to the protocol, group members are uniquely identified by
+ their leaf index. However, a leaf index is only valid for referring
+ to members in a given epoch. The same leaf index may represent a
+ different member, or no member at all, in a subsequent epoch.
+
+ The Credentials presented by the clients in a group authenticate
+ application-level identifiers for the clients. However, these
+ identifiers may not uniquely identify clients. For example, if a
+ user has multiple devices that are all present in an MLS group, then
+ those devices' clients could all present the user's application-layer
+ identifiers.
+
+ If needed, applications may add application-specific identifiers to
+ the extensions field of a LeafNode object with the application_id
+ extension.
+
+ opaque application_id<V>;
+
+ However, applications MUST NOT rely on the data in an application_id
+ extension as if it were authenticated by the Authentication Service,
+ and SHOULD gracefully handle cases where the identifier presented is
+ not unique.
+
+6. Message Framing
+
+ Handshake and application messages use a common framing structure.
+ This framing provides encryption to ensure confidentiality within the
+ group, as well as signing to authenticate the sender.
+
+ In most of the protocol, messages are handled in the form of
+ AuthenticatedContent objects. These structures contain the content
+ of the message itself as well as information to authenticate the
+ sender (see Section 6.1). The additional protections required to
+ transmit these messages over an untrusted channel (group membership
+ authentication or AEAD encryption) are added by encoding the
+ AuthenticatedContent as a PublicMessage or PrivateMessage message,
+ which can then be sent as an MLSMessage. Likewise, these protections
+ are enforced (via membership verification or AEAD decryption) when
+ decoding a PublicMessage or PrivateMessage into an
+ AuthenticatedContent object.
+
+ PrivateMessage represents a signed and encrypted message, with
+ protections for both the content of the message and related metadata.
+ PublicMessage represents a message that is only signed, and not
+ encrypted. Applications MUST use PrivateMessage to encrypt
+ application messages and SHOULD use PrivateMessage to encode
+ handshake messages, but they MAY transmit handshake messages encoded
+ as PublicMessage objects in cases where it is necessary for the
+ Delivery Service to examine such messages.
+
+ enum {
+ reserved(0),
+ mls10(1),
+ (65535)
+ } ProtocolVersion;
+
+ enum {
+ reserved(0),
+ application(1),
+ proposal(2),
+ commit(3),
+ (255)
+ } ContentType;
+
+ enum {
+ reserved(0),
+ member(1),
+ external(2),
+ new_member_proposal(3),
+ new_member_commit(4),
+ (255)
+ } SenderType;
+
+ struct {
+ SenderType sender_type;
+ select (Sender.sender_type) {
+ case member:
+ uint32 leaf_index;
+ case external:
+ uint32 sender_index;
+ case new_member_commit:
+ case new_member_proposal:
+ struct{};
+ };
+ } Sender;
+
+ // See the "MLS Wire Formats" IANA registry for values
+ uint16 WireFormat;
+
+ struct {
+ opaque group_id<V>;
+ uint64 epoch;
+ Sender sender;
+ opaque authenticated_data<V>;
+
+ ContentType content_type;
+ select (FramedContent.content_type) {
+ case application:
+ opaque application_data<V>;
+ case proposal:
+ Proposal proposal;
+ case commit:
+ Commit commit;
+ };
+ } FramedContent;
+
+ struct {
+ ProtocolVersion version = mls10;
+ WireFormat wire_format;
+ select (MLSMessage.wire_format) {
+ case mls_public_message:
+ PublicMessage public_message;
+ case mls_private_message:
+ PrivateMessage private_message;
+ case mls_welcome:
+ Welcome welcome;
+ case mls_group_info:
+ GroupInfo group_info;
+ case mls_key_package:
+ KeyPackage key_package;
+ };
+ } MLSMessage;
+
+ Messages from senders that aren't in the group are sent as
+ PublicMessage. See Sections 12.1.8 and 12.4.3.2 for more details.
+
+ The following structure is used to fully describe the data
+ transmitted in plaintexts or ciphertexts.
+
+ struct {
+ WireFormat wire_format;
+ FramedContent content;
+ FramedContentAuthData auth;
+ } AuthenticatedContent;
+
+ The following figure illustrates how the various structures described
+ in this section relate to each other, and the high-level operations
+ used to produce and consume them:
+
+ Proposal Commit Application Data
+ | | |
+ +--------------+--------------+
+ |
+ V
+ FramedContent
+ | | -.
+ +--------+ | |
+ | | |
+ V | +-- Asymmetric
+ FramedContentAuthData | | Sign / Verify
+ | | |
+ +--------+ | |
+ | | |
+ V V -'
+ AuthenticatedContent
+ | -.
+ +--------+--------+ |
+ | | +-- Symmetric
+ V V | Protect / Unprotect
+ PublicMessage PrivateMessage -'
+ | |
+ | | Welcome KeyPackage GroupInfo
+ | | | | |
+ +-----------------+-----+----------+----------+
+ |
+ V
+ MLSMessage
+
+ Figure 12: Relationships among MLS Objects
+
+6.1. Content Authentication
+
+ FramedContent is authenticated using the FramedContentAuthData
+ structure.
+
+ struct {
+ ProtocolVersion version = mls10;
+ WireFormat wire_format;
+ FramedContent content;
+ select (FramedContentTBS.content.sender.sender_type) {
+ case member:
+ case new_member_commit:
+ GroupContext context;
+ case external:
+ case new_member_proposal:
+ struct{};
+ };
+ } FramedContentTBS;
+
+ opaque MAC<V>;
+
+ struct {
+ /* SignWithLabel(., "FramedContentTBS", FramedContentTBS) */
+ opaque signature<V>;
+ select (FramedContent.content_type) {
+ case commit:
+ /*
+ MAC(confirmation_key,
+ GroupContext.confirmed_transcript_hash)
+ */
+ MAC confirmation_tag;
+ case application:
+ case proposal:
+ struct{};
+ };
+ } FramedContentAuthData;
+
+ The signature is computed using SignWithLabel with label
+ "FramedContentTBS" and with a content that covers the message content
+ and the wire format that will be used for this message. If the
+ sender's sender_type is member, the content also covers the
+ GroupContext for the current epoch so that signatures are specific to
+ a given group and epoch.
+
+ The sender MUST use the private key corresponding to the following
+ signature key depending on the sender's sender_type:
+
+ * member: The signature key contained in the LeafNode at the index
+ indicated by leaf_index in the ratchet tree.
+
+ * external: The signature key at the index indicated by sender_index
+ in the external_senders group context extension (see
+ Section 12.1.8.1). The content_type of the message MUST be
+ proposal and the proposal_type MUST be a value that is allowed for
+ external senders.
+
+ * new_member_commit: The signature key in the LeafNode in the
+ Commit's path (see Section 12.4.3.2). The content_type of the
+ message MUST be commit.
+
+ * new_member_proposal: The signature key in the LeafNode in the
+ KeyPackage embedded in an external Add proposal. The content_type
+ of the message MUST be proposal and the proposal_type of the
+ Proposal MUST be add.
+
+ Recipients of an MLSMessage MUST verify the signature with the key
+ depending on the sender_type of the sender as described above.
+
+ The confirmation tag value confirms that the members of the group
+ have arrived at the same state of the group. A FramedContentAuthData
+ is said to be valid when both the signature and confirmation_tag
+ fields are valid.
+
+6.2. Encoding and Decoding a Public Message
+
+ Messages that are authenticated but not encrypted are encoded using
+ the PublicMessage structure.
+
+ struct {
+ FramedContent content;
+ FramedContentAuthData auth;
+ select (PublicMessage.content.sender.sender_type) {
+ case member:
+ MAC membership_tag;
+ case external:
+ case new_member_commit:
+ case new_member_proposal:
+ struct{};
+ };
+ } PublicMessage;
+
+ The membership_tag field in the PublicMessage object authenticates
+ the sender's membership in the group. For messages sent by members,
+ it MUST be set to the following value:
+
+ struct {
+ FramedContentTBS content_tbs;
+ FramedContentAuthData auth;
+ } AuthenticatedContentTBM;
+
+ membership_tag = MAC(membership_key, AuthenticatedContentTBM)
+
+ When decoding a PublicMessage into an AuthenticatedContent, the
+ application MUST check membership_tag and MUST check that the
+ FramedContentAuthData is valid.
+
+6.3. Encoding and Decoding a Private Message
+
+ Authenticated and encrypted messages are encoded using the
+ PrivateMessage structure.
+
+ struct {
+ opaque group_id<V>;
+ uint64 epoch;
+ ContentType content_type;
+ opaque authenticated_data<V>;
+ opaque encrypted_sender_data<V>;
+ opaque ciphertext<V>;
+ } PrivateMessage;
+
+ encrypted_sender_data and ciphertext are encrypted using the AEAD
+ function specified by the cipher suite in use, using the SenderData
+ and PrivateMessageContent structures as input.
+
+6.3.1. Content Encryption
+
+ Content to be encrypted is encoded in a PrivateMessageContent
+ structure.
+
+ struct {
+ select (PrivateMessage.content_type) {
+ case application:
+ opaque application_data<V>;
+
+ case proposal:
+ Proposal proposal;
+
+ case commit:
+ Commit commit;
+ };
+
+ FramedContentAuthData auth;
+ opaque padding[length_of_padding];
+ } PrivateMessageContent;
+
+ The padding field is set by the sender, by first encoding the content
+ (via the select) and the auth field, and then appending the chosen
+ number of zero bytes. A receiver identifies the padding field in a
+ plaintext decoded from PrivateMessage.ciphertext by first decoding
+ the content and the auth field; then the padding field comprises any
+ remaining octets of plaintext. The padding field MUST be filled with
+ all zero bytes. A receiver MUST verify that there are no non-zero
+ bytes in the padding field, and if this check fails, the enclosing
+ PrivateMessage MUST be rejected as malformed. This check ensures
+ that the padding process is deterministic, so that, for example,
+ padding cannot be used as a covert channel.
+
+ In the MLS key schedule, the sender creates two distinct key ratchets
+ for handshake and application messages for each member of the group.
+ When encrypting a message, the sender looks at the ratchets it
+ derived for its own member and chooses an unused generation from
+ either the handshake ratchet or the application ratchet, depending on
+ the content type of the message. This generation of the ratchet is
+ used to derive a provisional nonce and key.
+
+ Before use in the encryption operation, the nonce is XORed with a
+ fresh random value to guard against reuse. Because the key schedule
+ generates nonces deterministically, a client MUST keep persistent
+ state as to where in the key schedule it is; if this persistent state
+ is lost or corrupted, a client might reuse a generation that has
+ already been used, causing reuse of a key/nonce pair.
+
+ To avoid this situation, the sender of a message MUST generate a
+ fresh random four-byte "reuse guard" value and XOR it with the first
+ four bytes of the nonce from the key schedule before using the nonce
+ for encryption. The sender MUST include the reuse guard in the
+ reuse_guard field of the sender data object, so that the recipient of
+ the message can use it to compute the nonce to be used for
+ decryption.
+
+ +-+-+-+-+---------...---+
+ | Key Schedule Nonce |
+ +-+-+-+-+---------...---+
+ XOR
+ +-+-+-+-+---------...---+
+ | Guard | 0 |
+ +-+-+-+-+---------...---+
+ ===
+ +-+-+-+-+---------...---+
+ | Encrypt/Decrypt Nonce |
+ +-+-+-+-+---------...---+
+
+ The Additional Authenticated Data (AAD) input to the encryption
+ contains an object of the following form, with the values used to
+ identify the key and nonce:
+
+ struct {
+ opaque group_id<V>;
+ uint64 epoch;
+ ContentType content_type;
+ opaque authenticated_data<V>;
+ } PrivateContentAAD;
+
+ When decoding a PrivateMessageContent, the application MUST check
+ that the FramedContentAuthData is valid.
+
+ It is up to the application to decide what authenticated_data to
+ provide and how much padding to add to a given message (if any). The
+ overall size of the AAD and ciphertext MUST fit within the limits
+ established for the group's AEAD algorithm in [CFRG-AEAD-LIMITS].
+
+6.3.2. Sender Data Encryption
+
+ The "sender data" used to look up the key for content encryption is
+ encrypted with the cipher suite's AEAD with a key and nonce derived
+ from both the sender_data_secret and a sample of the encrypted
+ content. Before being encrypted, the sender data is encoded as an
+ object of the following form:
+
+ struct {
+ uint32 leaf_index;
+ uint32 generation;
+ opaque reuse_guard[4];
+ } SenderData;
+
+ When constructing a SenderData object from a Sender object, the
+ sender MUST verify Sender.sender_type is member and use
+ Sender.leaf_index for SenderData.leaf_index.
+
+ The reuse_guard field contains a fresh random value used to avoid
+ nonce reuse in the case of state loss or corruption, as described in
+ Section 6.3.1.
+
+ The key and nonce provided to the AEAD are computed as the KDF of the
+ first KDF.Nh bytes of the ciphertext generated in the previous
+ section. If the length of the ciphertext is less than KDF.Nh, the
+ whole ciphertext is used. In pseudocode, the key and nonce are
+ derived as:
+
+ ciphertext_sample = ciphertext[0..KDF.Nh-1]
+
+ sender_data_key = ExpandWithLabel(sender_data_secret, "key",
+ ciphertext_sample, AEAD.Nk)
+ sender_data_nonce = ExpandWithLabel(sender_data_secret, "nonce",
+ ciphertext_sample, AEAD.Nn)
+
+ The AAD for the SenderData ciphertext is the first three fields of
+ PrivateMessage:
+
+ struct {
+ opaque group_id<V>;
+ uint64 epoch;
+ ContentType content_type;
+ } SenderDataAAD;
+
+ When parsing a SenderData struct as part of message decryption, the
+ recipient MUST verify that the leaf index indicated in the leaf_index
+ field identifies a non-blank node.
+
+7. Ratchet Tree Operations
+
+ The ratchet tree for an epoch describes the membership of a group in
+ that epoch, providing public key encryption (HPKE) keys that can be
+ used to encrypt to subsets of the group as well as information to
+ authenticate the members. In order to reflect changes to the
+ membership of the group from one epoch to the next, corresponding
+ changes are made to the ratchet tree. In this section, we describe
+ the content of the tree and the required operations.
+
+7.1. Parent Node Contents
+
+ As discussed in Section 4.1.1, the nodes of a ratchet tree contain
+ several types of data describing individual members (for leaf nodes)
+ or subgroups of the group (for parent nodes). Parent nodes are
+ simpler:
+
+ struct {
+ HPKEPublicKey encryption_key;
+ opaque parent_hash<V>;
+ uint32 unmerged_leaves<V>;
+ } ParentNode;
+
+ The encryption_key field contains an HPKE public key whose private
+ key is held only by the members at the leaves among its descendants.
+ The parent_hash field contains a hash of this node's parent node, as
+ described in Section 7.9. The unmerged_leaves field lists the leaves
+ under this parent node that are unmerged, according to their indices
+ among all the leaves in the tree. The entries in the unmerged_leaves
+ vector MUST be sorted in increasing order.
+
+7.2. Leaf Node Contents
+
+ A leaf node in the tree describes all the details of an individual
+ client's appearance in the group, signed by that client. It is also
+ used in client KeyPackage objects to store the information that will
+ be needed to add a client to a group.
+
+ enum {
+ reserved(0),
+ key_package(1),
+ update(2),
+ commit(3),
+ (255)
+ } LeafNodeSource;
+
+ struct {
+ ProtocolVersion versions<V>;
+ CipherSuite cipher_suites<V>;
+ ExtensionType extensions<V>;
+ ProposalType proposals<V>;
+ CredentialType credentials<V>;
+ } Capabilities;
+
+ struct {
+ uint64 not_before;
+ uint64 not_after;
+ } Lifetime;
+
+ // See the "MLS Extension Types" IANA registry for values
+ uint16 ExtensionType;
+
+ struct {
+ ExtensionType extension_type;
+ opaque extension_data<V>;
+ } Extension;
+
+ struct {
+ HPKEPublicKey encryption_key;
+ SignaturePublicKey signature_key;
+ Credential credential;
+ Capabilities capabilities;
+
+ LeafNodeSource leaf_node_source;
+ select (LeafNode.leaf_node_source) {
+ case key_package:
+ Lifetime lifetime;
+
+ case update:
+ struct{};
+
+ case commit:
+ opaque parent_hash<V>;
+ };
+
+ Extension extensions<V>;
+ /* SignWithLabel(., "LeafNodeTBS", LeafNodeTBS) */
+ opaque signature<V>;
+ } LeafNode;
+
+ struct {
+ HPKEPublicKey encryption_key;
+ SignaturePublicKey signature_key;
+ Credential credential;
+ Capabilities capabilities;
+
+ LeafNodeSource leaf_node_source;
+ select (LeafNodeTBS.leaf_node_source) {
+ case key_package:
+ Lifetime lifetime;
+
+ case update:
+ struct{};
+
+ case commit:
+ opaque parent_hash<V>;
+ };
+
+ Extension extensions<V>;
+
+ select (LeafNodeTBS.leaf_node_source) {
+ case key_package:
+ struct{};
+
+ case update:
+ opaque group_id<V>;
+ uint32 leaf_index;
+
+ case commit:
+ opaque group_id<V>;
+ uint32 leaf_index;
+ };
+ } LeafNodeTBS;
+
+ The encryption_key field contains an HPKE public key whose private
+ key is held only by the member occupying this leaf (or in the case of
+ a LeafNode in a KeyPackage object, the issuer of the KeyPackage).
+ The signature_key field contains the member's public signing key.
+ The credential field contains information authenticating both the
+ member's identity and the provided signing key, as described in
+ Section 5.3.
+
+ The capabilities field indicates the protocol features that the
+ client supports, including protocol versions, cipher suites,
+ credential types, non-default proposal types, and non-default
+ extension types. The following proposal and extension types are
+ considered "default" and MUST NOT be listed:
+
+ * Proposal types:
+
+ - 0x0001 - add
+
+ - 0x0002 - update
+
+ - 0x0003 - remove
+
+ - 0x0004 - psk
+
+ - 0x0005 - reinit
+
+ - 0x0006 - external_init
+
+ - 0x0007 - group_context_extensions
+
+ * Extension types:
+
+ - 0x0001 - application_id
+
+ - 0x0002 - ratchet_tree
+
+ - 0x0003 - required_capabilities
+
+ - 0x0004 - external_pub
+
+ - 0x0005 - external_senders
+
+ There are no default values for the other fields of a capabilities
+ object. The client MUST list all values for the respective
+ parameters that it supports.
+
+ The types of any non-default extensions that appear in the extensions
+ field of a LeafNode MUST be included in the extensions field of the
+ capabilities field, and the credential type used in the LeafNode MUST
+ be included in the credentials field of the capabilities field.
+
+ As discussed in Section 13, unknown values in capabilities MUST be
+ ignored, and the creator of a capabilities field SHOULD include some
+ random GREASE values to help ensure that other clients correctly
+ ignore unknown values.
+
+ The leaf_node_source field indicates how this LeafNode came to be
+ added to the tree. This signal tells other members of the group
+ whether the leaf node is required to have a lifetime or parent_hash,
+ and whether the group_id is added as context to the signature. These
+ fields are included selectively because the client creating a
+ LeafNode is not always able to compute all of them. For example, a
+ KeyPackage is created before the client knows which group it will be
+ used with, so its signature can't bind to a group_id.
+
+ In the case where the leaf was added to the tree based on a pre-
+ published KeyPackage, the lifetime field represents the times between
+ which clients will consider a LeafNode valid. These times are
+ represented as absolute times, measured in seconds since the Unix
+ epoch (1970-01-01T00:00:00Z). Applications MUST define a maximum
+ total lifetime that is acceptable for a LeafNode, and reject any
+ LeafNode where the total lifetime is longer than this duration. In
+ order to avoid disagreements about whether a LeafNode has a valid
+ lifetime, the clients in a group SHOULD maintain time synchronization
+ (e.g., using the Network Time Protocol [RFC5905]).
+
+ In the case where the leaf node was inserted into the tree via a
+ Commit message, the parent_hash field contains the parent hash for
+ this leaf node (see Section 7.9).
+
+ The LeafNodeTBS structure covers the fields above the signature in
+ the LeafNode. In addition, when the leaf node was created in the
+ context of a group (the update and commit cases), the group ID of the
+ group is added as context to the signature.
+
+ LeafNode objects stored in the group's ratchet tree are updated
+ according to the evolution of the tree. Each modification of
+ LeafNode content MUST be reflected by a change in its signature.
+ This allows other members to verify the validity of the LeafNode at
+ any time, particularly in the case of a newcomer joining the group.
+
+7.3. Leaf Node Validation
+
+ The validity of a LeafNode needs to be verified at the following
+ stages:
+
+ * When a LeafNode is downloaded in a KeyPackage, before it is used
+ to add the client to the group
+
+ * When a LeafNode is received by a group member in an Add, Update,
+ or Commit message
+
+ * When a client validates a ratchet tree, e.g., when joining a group
+ or after processing a Commit
+
+ The client verifies the validity of a LeafNode using the following
+ steps:
+
+ * Verify that the credential in the LeafNode is valid, as described
+ in Section 5.3.1.
+
+ * Verify that the signature on the LeafNode is valid using
+ signature_key.
+
+ * Verify that the LeafNode is compatible with the group's
+ parameters. If the GroupContext has a required_capabilities
+ extension, then the required extensions, proposals, and credential
+ types MUST be listed in the LeafNode's capabilities field.
+
+ * Verify that the credential type is supported by all members of the
+ group, as specified by the capabilities field of each member's
+ LeafNode, and that the capabilities field of this LeafNode
+ indicates support for all the credential types currently in use by
+ other members.
+
+ * Verify the lifetime field:
+
+ - If the LeafNode appears in a message being sent by the client,
+ e.g., a Proposal or a Commit, then the client MUST verify that
+ the current time is within the range of the lifetime field.
+
+ - If instead the LeafNode appears in a message being received by
+ the client, e.g., a Proposal, a Commit, or a ratchet tree of
+ the group the client is joining, it is RECOMMENDED that the
+ client verifies that the current time is within the range of
+ the lifetime field. (This check is not mandatory because the
+ LeafNode might have expired in the time between when the
+ message was sent and when it was received.)
+
+ * Verify that the extensions in the LeafNode are supported by
+ checking that the ID for each extension in the extensions field is
+ listed in the capabilities.extensions field of the LeafNode.
+
+ * Verify the leaf_node_source field:
+
+ - If the LeafNode appears in a KeyPackage, verify that
+ leaf_node_source is set to key_package.
+
+ - If the LeafNode appears in an Update proposal, verify that
+ leaf_node_source is set to update and that encryption_key
+ represents a different public key than the encryption_key in
+ the leaf node being replaced by the Update proposal.
+
+ - If the LeafNode appears in the leaf_node value of the
+ UpdatePath in a Commit, verify that leaf_node_source is set to
+ commit.
+
+ * Verify that the following fields are unique among the members of
+ the group:
+
+ - signature_key
+
+ - encryption_key
+
+7.4. Ratchet Tree Evolution
+
+ Whenever a member initiates an epoch change (i.e., commits; see
+ Section 12.4), they may need to refresh the key pairs of their leaf
+ and of the nodes on their leaf's direct path in order to maintain
+ forward secrecy and post-compromise security.
+
+ The member initiating the epoch change generates the fresh key pairs
+ using the following procedure. The procedure is designed in a way
+ that allows group members to efficiently communicate the fresh secret
+ keys to other group members, as described in Section 7.6.
+
+ A member updates the nodes along its direct path as follows:
+
+ * Blank all the nodes on the direct path from the leaf to the root.
+
+ * Generate a fresh HPKE key pair for the leaf.
+
+ * Generate a sequence of path secrets, one for each node on the
+ leaf's filtered direct path, as follows. In this setting,
+ path_secret[0] refers to the first parent node in the filtered
+ direct path, path_secret[1] to the second parent node, and so on.
+
+ path_secret[0] is sampled at random
+ path_secret[n] = DeriveSecret(path_secret[n-1], "path")
+
+ * Compute the sequence of HPKE key pairs (node_priv,node_pub), one
+ for each node on the leaf's direct path, as follows.
+
+ node_secret[n] = DeriveSecret(path_secret[n], "node")
+ node_priv[n], node_pub[n] = KEM.DeriveKeyPair(node_secret[n])
+
+ The node secret is derived as a temporary intermediate secret so that
+ each secret is only used with one algorithm: The path secret is used
+ as an input to DeriveSecret, and the node secret is used as an input
+ to DeriveKeyPair.
+
+ For example, suppose there is a group with four members, with C an
+ unmerged leaf at Z:
+
+ Y
+ |
+ .-+-.
+ / \
+ X Z[C]
+ / \ / \
+ A B C D
+
+ 0 1 2 3
+
+ Figure 13: A Full Tree with One Unmerged Leaf
+
+ If member B subsequently generates an UpdatePath based on a secret
+ "leaf_secret", then it would generate the following sequence of path
+ secrets:
+
+ path_secret[1] ---> node_secret[1] -------> node_priv[1], node_pub[1]
+
+ ^
+ |
+ |
+ path_secret[0] ---> node_secret[0] -------> node_priv[0], node_pub[0]
+
+ ^
+ |
+ |
+ leaf_secret ------> leaf_node_secret --+--> leaf_priv, leaf_pub
+ | |
+ '-------. .-------'
+ |
+ leaf_node
+
+ Figure 14: Derivation of Ratchet Tree Keys along a Direct Path
+
+ After applying the UpdatePath, the tree will have the following
+ structure:
+
+ node_priv[1] --------> Y'
+ |
+ .-+-.
+ / \
+ node_priv[0] ----> X' Z[C]
+ / \ / \
+ A B C D
+ ^
+ leaf_priv -----------+
+ 0 1 2 3
+
+ Figure 15: Placement of Keys in a Ratchet Tree
+
+7.5. Synchronizing Views of the Tree
+
+ After generating fresh key material and applying it to update their
+ local tree state as described in Section 7.4, the generator
+ broadcasts this update to other members of the group in a Commit
+ message, who apply it to keep their local views of the tree in sync
+ with the sender's. More specifically, when a member commits a change
+ to the tree (e.g., to add or remove a member), it transmits an
+ UpdatePath containing a set of public keys and encrypted path secrets
+ for intermediate nodes in the filtered direct path of its leaf. The
+ other members of the group use these values to update their view of
+ the tree, aligning their copy of the tree to the sender's.
+
+ An UpdatePath contains the following information for each node in the
+ filtered direct path of the sender's leaf, including the root:
+
+ * The public key for the node
+
+ * One or more encrypted copies of the path secret corresponding to
+ the node
+
+ The path secret value for a given node is encrypted to the subtree
+ rooted at the parent's non-updated child, i.e., the child on the
+ copath of the sender's leaf node. There is one encryption of the
+ path secret to each public key in the resolution of the non-updated
+ child.
+
+ A member of the group _updates their direct path_ by computing new
+ values for their leaf node and the nodes along their filtered direct
+ path as follows:
+
+ 1. Blank all nodes along the direct path of the sender's leaf.
+
+ 2. Compute updated path secrets and public keys for the nodes on the
+ sender's filtered direct path.
+
+ * Generate a sequence of path secrets of the same length as the
+ filtered direct path, as defined in Section 7.4.
+
+ * For each node in the filtered direct path, replace the node's
+ public key with the node_pub[n] value derived from the
+ corresponding path secret path_secret[n].
+
+ 3. Compute the new parent hashes for the nodes along the filtered
+ direct path and the sender's leaf node.
+
+ 4. Update the leaf node for the sender.
+
+ * Set the leaf_node_source to commit.
+
+ * Set the encryption_key to the public key of a freshly sampled
+ key pair.
+
+ * Set the parent hash to the parent hash for the leaf.
+
+ * Re-sign the leaf node with its new contents.
+
+ Since the new leaf node effectively updates an existing leaf node in
+ the group, it MUST adhere to the same restrictions as LeafNodes used
+ in Update proposals (aside from leaf_node_source). The application
+ MAY specify other changes to the leaf node, e.g., providing a new
+ signature key, updated capabilities, or different extensions.
+
+ The member then _encrypts path secrets to the group_. For each node
+ in the member's filtered direct path, the member takes the following
+ steps:
+
+ 1. Compute the resolution of the node's child that is on the copath
+ of the sender (the child that is not in the direct path of the
+ sender). Any new member (from an Add proposal) added in the same
+ Commit MUST be excluded from this resolution.
+
+ 2. For each node in the resolution, encrypt the path secret for the
+ direct path node using the public key of the resolution node, as
+ defined in Section 7.6.
+
+ The recipient of an UpdatePath performs the corresponding steps.
+ First, the recipient _merges UpdatePath into the tree_:
+
+ 1. Blank all nodes on the direct path of the sender's leaf.
+
+ 2. For all nodes on the filtered direct path of the sender's leaf,
+
+ * Set the public key to the public key in the UpdatePath.
+
+ * Set the list of unmerged leaves to the empty list.
+
+ 3. Compute parent hashes for the nodes in the sender's filtered
+ direct path, and verify that the parent_hash field of the leaf
+ node matches the parent hash for the first node in its filtered
+ direct path.
+
+ * Note that these hashes are computed from root to leaf, so that
+ each hash incorporates all the non-blank nodes above it. The
+ root node always has a zero-length hash for its parent hash.
+
+ Second, the recipient _decrypts the path secrets_:
+
+ 1. Identify a node in the filtered direct path for which the
+ recipient is in the subtree of the non-updated child.
+
+ 2. Identify a node in the resolution of the copath node for which
+ the recipient has a private key.
+
+ 3. Decrypt the path secret for the parent of the copath node using
+ the private key from the resolution node.
+
+ 4. Derive path secrets for ancestors of that node in the sender's
+ filtered direct path using the algorithm described above.
+
+ 5. Derive the node secrets and node key pairs from the path secrets.
+
+ 6. Verify that the derived public keys are the same as the
+ corresponding public keys sent in the UpdatePath.
+
+ 7. Store the derived private keys in the corresponding ratchet tree
+ nodes.
+
+ For example, in order to communicate the example update described in
+ Section 7.4, the member at node B would transmit the following
+ values:
+
+ +=============+====================================================+
+ | Public Key | Ciphertext(s) |
+ +=============+====================================================+
+ | node_pub[1] | E(pk(Z), path_secret[1]), E(pk(C), path_secret[1]) |
+ +-------------+----------------------------------------------------+
+ | node_pub[0] | E(pk(A), path_secret[0]) |
+ +-------------+----------------------------------------------------+
+
+ Table 3
+
+ In this table, the value node_pub[i] represents the public key
+ derived from node_secret[i], pk(X) represents the current public key
+ of node X, and E(K, S) represents the public key encryption of the
+ path secret S to the public key K (using HPKE).
+
+ A recipient at node A would decrypt E(pk(A), path_secret\[0\]) to
+ obtain path_secret\[0\], then use it to derive path_secret[1] and the
+ resulting node secrets and key pairs. Thus, A would have the private
+ keys to nodes X' and Y', in accordance with the tree invariant.
+
+ Similarly, a recipient at node D would decrypt E(pk(Z),
+ path_secret[1]) to obtain path_secret[1], then use it to derive the
+ node secret and key pair for the node Y'. As required to maintain
+ the tree invariant, node D does not receive the private key for the
+ node X', since X' is not an ancestor of D.
+
+ After processing the update, each recipient MUST delete outdated key
+ material, specifically:
+
+ * The path secrets and node secrets used to derive each updated node
+ key pair.
+
+ * Each outdated node key pair that was replaced by the update.
+
+7.6. Update Paths
+
+ As described in Section 12.4, each Commit message may optionally
+ contain an UpdatePath, with a new LeafNode and set of parent nodes
+ for the sender's filtered direct path. For each parent node, the
+ UpdatePath contains a new public key and encrypted path secret. The
+ parent nodes are kept in the same order as the filtered direct path.
+
+ struct {
+ opaque kem_output<V>;
+ opaque ciphertext<V>;
+ } HPKECiphertext;
+
+ struct {
+ HPKEPublicKey encryption_key;
+ HPKECiphertext encrypted_path_secret<V>;
+ } UpdatePathNode;
+
+ struct {
+ LeafNode leaf_node;
+ UpdatePathNode nodes<V>;
+ } UpdatePath;
+
+ For each UpdatePathNode, the resolution of the corresponding copath
+ node MUST exclude all new leaf nodes added as part of the current
+ Commit. The length of the encrypted_path_secret vector MUST be equal
+ to the length of the resolution of the copath node (excluding new
+ leaf nodes), with each ciphertext being the encryption to the
+ respective resolution node.
+
+ The HPKECiphertext values are encrypted and decrypted as follows:
+
+ (kem_output, ciphertext) =
+ EncryptWithLabel(node_public_key, "UpdatePathNode",
+ group_context, path_secret)
+
+ path_secret =
+ DecryptWithLabel(node_private_key, "UpdatePathNode",
+ group_context, kem_output, ciphertext)
+
+ Here node_public_key is the public key of the node for which the path
+ secret is encrypted, group_context is the provisional GroupContext
+ object for the group, and the EncryptWithLabel function is as defined
+ in Section 5.1.3.
+
+7.7. Adding and Removing Leaves
+
+ In addition to the path-based updates to the tree described above, it
+ is also necessary to add and remove leaves of the tree in order to
+ reflect changes to the membership of the group (see Sections 12.1.1
+ and 12.1.3). Since the tree is always full, adding or removing
+ leaves corresponds to increasing or decreasing the depth of the tree,
+ resulting in the number of leaves being doubled or halved. These
+ operations are also known as _extending_ and _truncating_ the tree.
+
+ Leaves are always added and removed at the right edge of the tree.
+ When the size of the tree needs to be increased, a new blank root
+ node is added, whose left subtree is the existing tree and right
+ subtree is a new all-blank subtree. This operation is typically done
+ when adding a member to the group.
+
+ _ <-- new blank root _
+ __|__ __|__
+ / \ / \
+ X ===> X _ <-- new blank subtree ===> X _
+ / \ / \ / \ / \ / \
+ A B A B _ _ A B C _
+ ^
+ |
+ new member --+
+
+ Figure 16: Extending the Tree to Make Room for a Third Member
+
+ When the right subtree of the tree no longer has any non-blank nodes,
+ it can be safely removed. The root of the tree and the right subtree
+ are discarded (whether or not the root node is blank). The left
+ child of the root becomes the new root node, and the left subtree
+ becomes the new tree. This operation is typically done after
+ removing a member from the group.
+
+ Y Y
+ __|__ __|__
+ / \ / \
+ X _ ===> X _ ==> X <-- new root
+ / \ / \ / \ / \ / \
+ A B C _ A B _ _ A B
+ ^
+ |
+ removed member --+
+
+ Figure 17: Cleaning Up after Removing Member C
+
+ Concrete algorithms for these operations on array-based and link-
+ based trees are provided in Appendices C and D. The concrete
+ algorithms are non-normative. An implementation may use any
+ algorithm that produces the correct tree in its internal
+ representation.
+
+7.8. Tree Hashes
+
+ MLS hashes the contents of the tree in two ways to authenticate
+ different properties of the tree. _Tree hashes_ are defined in this
+ section, and _parent hashes_ are defined in Section 7.9.
+
+ Each node in a ratchet tree has a tree hash that summarizes the
+ subtree below that node. The tree hash of the root is used in the
+ GroupContext to confirm that the group agrees on the whole tree.
+ Tree hashes are computed recursively from the leaves up to the root.
+
+ P --> th(P)
+ ^ ^
+ / \
+ / \
+ th(L) th(R)
+
+ Figure 18: Composition of the Tree Hash
+
+ The tree hash of an individual node is the hash of the node's
+ TreeHashInput object, which may contain either a LeafNodeHashInput or
+ a ParentNodeHashInput depending on the type of node.
+ LeafNodeHashInput objects contain the leaf_index and the LeafNode (if
+ any). ParentNodeHashInput objects contain the ParentNode (if any)
+ and the tree hash of the node's left and right children. For both
+ parent and leaf nodes, the optional node value MUST be absent if the
+ node is blank and present if the node contains a value.
+
+ enum {
+ reserved(0),
+ leaf(1),
+ parent(2),
+ (255)
+ } NodeType;
+
+ struct {
+ NodeType node_type;
+ select (TreeHashInput.node_type) {
+ case leaf: LeafNodeHashInput leaf_node;
+ case parent: ParentNodeHashInput parent_node;
+ };
+ } TreeHashInput;
+
+ struct {
+ uint32 leaf_index;
+ optional<LeafNode> leaf_node;
+ } LeafNodeHashInput;
+
+ struct {
+ optional<ParentNode> parent_node;
+ opaque left_hash<V>;
+ opaque right_hash<V>;
+ } ParentNodeHashInput;
+
+ The tree hash of an entire tree corresponds to the tree hash of the
+ root node, which is computed recursively by starting at the leaf
+ nodes and building up.
+
+7.9. Parent Hashes
+
+ While tree hashes summarize the state of a tree at point in time,
+ parent hashes capture information about how keys in the tree were
+ populated.
+
+ When a client sends a Commit to change a group, it can include an
+ UpdatePath to assign new keys to the nodes along its filtered direct
+ path. When a client computes an UpdatePath (as defined in
+ Section 7.5), it computes and signs a parent hash that summarizes the
+ state of the tree after the UpdatePath has been applied. These
+ summaries are constructed in a chain from the root to the member's
+ leaf so that the part of the chain closer to the root can be
+ overwritten as nodes set in one UpdatePath are reset by a later
+ UpdatePath.
+
+ ph(Q)
+ /
+ /
+ V
+ P.public_key --> ph(P)
+ / ^
+ / \
+ V \
+ N.parent_hash th(S)
+
+ Figure 19: Inputs to a Parent Hash
+
+ As a result, the signature over the parent hash in each member's leaf
+ effectively signs the subtree of the tree that hasn't been changed
+ since that leaf was last changed in an UpdatePath. A new member
+ joining the group uses these parent hashes to verify that the parent
+ nodes in the tree were set by members of the group, not chosen by an
+ external attacker. For an example of how this works, see Appendix B.
+
+ Consider a ratchet tree with a non-blank parent node P and children D
+ and S (for "parent", "direct path", and "sibling"), with D and P in
+ the direct path of a leaf node L (for "leaf"):
+
+ ...
+ /
+ P
+ __|__
+ / \
+ D S
+ / \ / \
+ ... ... ... ...
+ /
+ L
+
+ Figure 20: Nodes Involved in a Parent Hash Computation
+
+ The parent hash of P changes whenever an UpdatePath object is applied
+ to the ratchet tree along a path from a leaf L traversing node D (and
+ hence also P). The new "Parent hash of P (with copath child S)" is
+ obtained by hashing P's ParentHashInput struct.
+
+ struct {
+ HPKEPublicKey encryption_key;
+ opaque parent_hash<V>;
+ opaque original_sibling_tree_hash<V>;
+ } ParentHashInput;
+
+ The field encryption_key contains the HPKE public key of P. If P is
+ the root, then the parent_hash field is set to a zero-length octet
+ string. Otherwise, parent_hash is the parent hash of the next node
+ after P on the filtered direct path of the leaf L. This way, P's
+ parent hash fixes the new HPKE public key of each non-blank node on
+ the path from P to the root. Note that the path from P to the root
+ may contain some blank nodes that are not fixed by P's parent hash.
+ However, for each node that has an HPKE key, this key is fixed by P's
+ parent hash.
+
+ Finally, original_sibling_tree_hash is the tree hash of S in the
+ ratchet tree modified as follows: For each leaf L in
+ P.unmerged_leaves, blank L and remove it from the unmerged_leaves
+ sets of all parent nodes.
+
+ Observe that original_sibling_tree_hash does not change between
+ updates of P. This property is crucial for the correctness of the
+ protocol.
+
+ Note that original_sibling_tree_hash is the tree hash of S, not the
+ parent hash. The parent_hash field in ParentHashInput captures
+ information about the nodes above P. the original_sibling_tree_hash
+ captures information about the subtree under S that is not being
+ updated (and thus the subtree to which a path secret for P would be
+ encrypted according to Section 7.5).
+
+ For example, in the following tree:
+
+ W [F]
+ ______|_____
+ / \
+ U Y [F]
+ __|__ __|__
+ / \ / \
+ T _ _ _
+ / \ / \ / \ / \
+ A B C D E F G _
+
+ Figure 21: A Tree Illustrating Parent Hash Computations
+
+ With P = W and S = Y, original_sibling_tree_hash is the tree hash of
+ the following tree:
+
+ Y
+ __|__
+ / \
+ _ _
+ / \ / \
+ E _ G _
+
+ Because W.unmerged_leaves includes F, F is blanked and removed from
+ Y.unmerged_leaves.
+
+ Note that no recomputation is needed if the tree hash of S is
+ unchanged since the last time P was updated. This is the case for
+ computing or processing a Commit whose UpdatePath traverses P, since
+ the Commit itself resets P. (In other words, it is only necessary to
+ recompute the original sibling tree hash when validating a group's
+ tree on joining.) More generally, if none of the entries in
+ P.unmerged_leaves are in the subtree under S (and thus no leaves were
+ blanked), then the original tree hash at S is the tree hash of S in
+ the current tree.
+
+ If it is necessary to recompute the original tree hash of a node, the
+ efficiency of recomputation can be improved by caching intermediate
+ tree hashes, to avoid recomputing over the subtree when the subtree
+ is included in multiple parent hashes. A subtree hash can be reused
+ as long as the intersection of the parent's unmerged leaves with the
+ subtree is the same as in the earlier computation.
+
+7.9.1. Using Parent Hashes
+
+ In ParentNode objects and LeafNode objects with leaf_node_source set
+ to commit, the value of the parent_hash field is the parent hash of
+ the next non-blank parent node above the node in question (the next
+ node in the filtered direct path). Using the node labels in
+ Figure 20, the parent_hash field of D is equal to the parent hash of
+ P with copath child S. This is the case even when the node D is a
+ leaf node.
+
+ The parent_hash field of a LeafNode is signed by the member. The
+ signature of such a LeafNode thus attests to which keys the group
+ member introduced into the ratchet tree and to whom the corresponding
+ secret keys were sent, in addition to the other contents of the
+ LeafNode. This prevents malicious insiders from constructing
+ artificial ratchet trees with a node D whose HPKE secret key is known
+ to the insider, yet where the insider isn't assigned a leaf in the
+ subtree rooted at D. Indeed, such a ratchet tree would violate the
+ tree invariant.
+
+7.9.2. Verifying Parent Hashes
+
+ Parent hashes are verified at two points in the protocol: When
+ joining a group and when processing a Commit.
+
+ The parent hash in a node D is valid with respect to a parent node P
+ if the following criteria hold. Here C and S are the children of P
+ (for "child" and "sibling"), with C being the child that is on the
+ direct path of D (possibly D itself) and S being the other child:
+
+ * D is a descendant of P in the tree.
+
+ * The parent_hash field of D is equal to the parent hash of P with
+ copath child S.
+
+ * D is in the resolution of C, and the intersection of P's
+ unmerged_leaves with the subtree under C is equal to the
+ resolution of C with D removed.
+
+ These checks verify that D and P were updated at the same time (in
+ the same UpdatePath), and that they were neighbors in the UpdatePath
+ because the nodes in between them would have omitted from the
+ filtered direct path.
+
+ A parent node P is "parent-hash valid" if it can be chained back to a
+ leaf node in this way. That is, if there is leaf node L and a
+ sequence of parent nodes P_1, ..., P_N such that P_N = P and each
+ step in the chain is authenticated by a parent hash, then L's parent
+ hash is valid with respect to P_1, P_1's parent hash is valid with
+ respect to P_2, and so on.
+
+ When joining a group, the new member MUST authenticate that each non-
+ blank parent node P is parent-hash valid. This can be done "bottom
+ up" by building chains up from leaves and verifying that all non-
+ blank parent nodes are covered by exactly one such chain, or "top
+ down" by verifying that there is exactly one descendant of each non-
+ blank parent node for which the parent node is parent-hash valid.
+
+ When processing a Commit message that includes an UpdatePath, clients
+ MUST recompute the expected value of parent_hash for the committer's
+ new leaf and verify that it matches the parent_hash value in the
+ supplied leaf_node. After being merged into the tree, the nodes in
+ the UpdatePath form a parent-hash chain from the committer's leaf to
+ the root.
+
+8. Key Schedule
+
+ Group keys are derived using the Extract and Expand functions from
+ the KDF for the group's cipher suite, as well as the functions
+ defined below:
+
+ ExpandWithLabel(Secret, Label, Context, Length) =
+ KDF.Expand(Secret, KDFLabel, Length)
+
+ DeriveSecret(Secret, Label) =
+ ExpandWithLabel(Secret, Label, "", KDF.Nh)
+
+ Where KDFLabel is specified as:
+
+ struct {
+ uint16 length;
+ opaque label<V>;
+ opaque context<V>;
+ } KDFLabel;
+
+ And its fields are set to:
+
+ length = Length;
+ label = "MLS 1.0 " + Label;
+ context = Context;
+
+ The value KDF.Nh is the size of an output from KDF.Extract, in bytes.
+ In the below diagram:
+
+ * KDF.Extract takes its salt argument from the top and its Input
+ Keying Material (IKM) argument from the left.
+
+ * DeriveSecret takes its Secret argument from the incoming arrow.
+
+ * 0 represents an all-zero byte string of length KDF.Nh.
+
+ When processing a handshake message, a client combines the following
+ information to derive new epoch secrets:
+
+ * The init secret from the previous epoch
+
+ * The commit secret for the current epoch
+
+ * The GroupContext object for current epoch
+
+ Given these inputs, the derivation of secrets for an epoch proceeds
+ as shown in the following diagram:
+
+ init_secret_[n-1]
+ |
+ |
+ V
+ commit_secret --> KDF.Extract
+ |
+ |
+ V
+ ExpandWithLabel(., "joiner", GroupContext_[n], KDF.Nh)
+ |
+ |
+ V
+ joiner_secret
+ |
+ |
+ V
+psk_secret (or 0) --> KDF.Extract
+ |
+ |
+ +--> DeriveSecret(., "welcome")
+ | = welcome_secret
+ |
+ V
+ ExpandWithLabel(., "epoch", GroupContext_[n], KDF.Nh)
+ |
+ |
+ V
+ epoch_secret
+ |
+ |
+ +--> DeriveSecret(., <label>)
+ | = <secret>
+ |
+ V
+ DeriveSecret(., "init")
+ |
+ |
+ V
+ init_secret_[n]
+
+ Figure 22: The MLS Key Schedule
+
+ A number of values are derived from the epoch secret for different
+ purposes:
+
+ +==================+=====================+=======================+
+ | Label | Secret | Purpose |
+ +==================+=====================+=======================+
+ | "sender data" | sender_data_secret | Deriving keys to |
+ | | | encrypt sender data |
+ +------------------+---------------------+-----------------------+
+ | "encryption" | encryption_secret | Deriving message |
+ | | | encryption keys (via |
+ | | | the secret tree) |
+ +------------------+---------------------+-----------------------+
+ | "exporter" | exporter_secret | Deriving exported |
+ | | | secrets |
+ +------------------+---------------------+-----------------------+
+ | "external" | external_secret | Deriving the external |
+ | | | init key |
+ +------------------+---------------------+-----------------------+
+ | "confirm" | confirmation_key | Computing the |
+ | | | confirmation MAC for |
+ | | | an epoch |
+ +------------------+---------------------+-----------------------+
+ | "membership" | membership_key | Computing the |
+ | | | membership MAC for a |
+ | | | PublicMessage |
+ +------------------+---------------------+-----------------------+
+ | "resumption" | resumption_psk | Proving membership in |
+ | | | this epoch (via a PSK |
+ | | | injected later) |
+ +------------------+---------------------+-----------------------+
+ | "authentication" | epoch_authenticator | Confirming that two |
+ | | | clients have the same |
+ | | | view of the group |
+ +------------------+---------------------+-----------------------+
+
+ Table 4: Epoch-Derived Secrets
+
+ The external_secret is used to derive an HPKE key pair whose private
+ key is held by the entire group:
+
+ external_priv, external_pub = KEM.DeriveKeyPair(external_secret)
+
+ The public key external_pub can be published as part of the GroupInfo
+ struct in order to allow non-members to join the group using an
+ external Commit.
+
+8.1. Group Context
+
+ Each member of the group maintains a GroupContext object that
+ summarizes the state of the group:
+
+ struct {
+ ProtocolVersion version = mls10;
+ CipherSuite cipher_suite;
+ opaque group_id<V>;
+ uint64 epoch;
+ opaque tree_hash<V>;
+ opaque confirmed_transcript_hash<V>;
+ Extension extensions<V>;
+ } GroupContext;
+
+ The fields in this state have the following semantics:
+
+ * The cipher_suite is the cipher suite used by the group.
+
+ * The group_id field is an application-defined identifier for the
+ group.
+
+ * The epoch field represents the current version of the group.
+
+ * The tree_hash field contains a commitment to the contents of the
+ group's ratchet tree and the credentials for the members of the
+ group, as described in Section 7.8.
+
+ * The confirmed_transcript_hash field contains a running hash over
+ the messages that led to this state.
+
+ * The extensions field contains the details of any protocol
+ extensions that apply to the group.
+
+ When a new member is added to the group, an existing member of the
+ group provides the new member with a Welcome message. The Welcome
+ message provides the information the new member needs to initialize
+ its GroupContext.
+
+ Different changes to the group will have different effects on the
+ group state. These effects are described in their respective
+ subsections of Section 12.1. The following general rules apply:
+
+ * The group_id field is constant.
+
+ * The epoch field increments by one for each Commit message that is
+ processed.
+
+ * The tree_hash is updated to represent the current tree and
+ credentials.
+
+ * The confirmed_transcript_hash field is updated with the data for
+ an AuthenticatedContent encoding a Commit message, as described
+ below.
+
+ * The extensions field changes when a GroupContextExtensions
+ proposal is committed.
+
+8.2. Transcript Hashes
+
+ The transcript hashes computed in MLS represent a running hash over
+ all Proposal and Commit messages that have ever been sent in a group.
+ Commit messages are included directly. Proposal messages are
+ indirectly included via the Commit that applied them. Messages of
+ both types are included by hashing the AuthenticatedContent object in
+ which they were sent.
+
+ The transcript hash comprises two individual hashes:
+
+ * A confirmed_transcript_hash that represents a transcript over the
+ whole history of Commit messages, up to and including the
+ signature of the most recent Commit.
+
+ * An interim_transcript_hash that covers the confirmed transcript
+ hash plus the confirmation_tag of the most recent Commit.
+
+ New members compute the interim transcript hash using the
+ confirmation_tag field of the GroupInfo struct, while existing
+ members can compute it directly.
+
+ Each Commit message updates these hashes by way of its enclosing
+ AuthenticatedContent. The AuthenticatedContent struct is split into
+ ConfirmedTranscriptHashInput and InterimTranscriptHashInput. The
+ former is used to update the confirmed transcript hash and the latter
+ is used to update the interim transcript hash.
+
+ struct {
+ WireFormat wire_format;
+ FramedContent content; /* with content_type == commit */
+ opaque signature<V>;
+ } ConfirmedTranscriptHashInput;
+
+ struct {
+ MAC confirmation_tag;
+ } InterimTranscriptHashInput;
+
+ confirmed_transcript_hash_[0] = ""; /* zero-length octet string */
+ interim_transcript_hash_[0] = ""; /* zero-length octet string */
+
+ confirmed_transcript_hash_[epoch] =
+ Hash(interim_transcript_hash_[epoch - 1] ||
+ ConfirmedTranscriptHashInput_[epoch]);
+
+ interim_transcript_hash_[epoch] =
+ Hash(confirmed_transcript_hash_[epoch] ||
+ InterimTranscriptHashInput_[epoch]);
+
+ In this notation, ConfirmedTranscriptHashInput_[epoch] and
+ InterimTranscriptHashInput_[epoch] are based on the Commit that
+ initiated the epoch with epoch number epoch. (Note that
+ theepochfield in this Commit will be set toepoch - 1`, since it is
+ sent within the previous epoch.)
+
+ The transcript hash ConfirmedTranscriptHashInput_[epoch] is used as
+ the confirmed_transcript_hash input to the confirmation_tag field for
+ this Commit. Each Commit thus confirms the whole transcript of
+ Commits up to that point, except for the latest Commit's confirmation
+ tag.
+
+ ...
+
+ |
+ |
+ V
+ +-----------------+
+ | interim_[N-1] |
+ +--------+--------+
+ |
+ .--------------. +------------------+ |
+ | Ratchet Tree | | wire_format | |
+ | Key Schedule |<-------+ content | |
+ '-------+------' | epoch = N-1 +------------+
+ | | commit | |
+ V | signature | V
+ +------------------------+ +------------------+ +-----------------+
+ | confirmation_key_[N] +-->| confirmation_tag |<--+ confirmed_[N] |
+ +------------------------+ +--------+---------+ +--------+--------+
+ | |
+ | V
+ | +-----------------+
+ +------------>| interim_[N] |
+ +--------+--------+
+ |
+ .--------------. +------------------+ |
+ | Ratchet Tree | | wire_format | |
+ | Key Schedule |<-------+ content | |
+ '-------+------' | epoch = N +------------+
+ | | commit | |
+ V | signature | V
+ +------------------------+ +------------------+ +-----------------+
+ | confirmation_key_[N+1] +-->| confirmation_tag |<--+ confirmed_[N+1] |
+ +------------------------+ +--------+---------+ +--------+--------+
+ | |
+ | V
+ | +-----------------+
+ +------------>| interim_[N+1] |
+ +--------+--------+
+ |
+ V
+
+ ...
+
+ Figure 23: Evolution of the Transcript Hashes through Two Epoch
+ Changes
+
+8.3. External Initialization
+
+ In addition to initializing a new epoch via KDF invocations as
+ described above, an MLS group can also initialize a new epoch via an
+ asymmetric interaction using the external key pair for the previous
+ epoch. This is done when a new member is joining via an external
+ commit.
+
+ In this process, the joiner sends a new init_secret value to the
+ group using the HPKE export method. The joiner then uses that
+ init_secret with information provided in the GroupInfo and an
+ external Commit to initialize their copy of the key schedule for the
+ new epoch.
+
+ kem_output, context = SetupBaseS(external_pub, "")
+ init_secret = context.export("MLS 1.0 external init secret", KDF.Nh)
+
+ Members of the group receive the kem_output in an ExternalInit
+ proposal and perform the corresponding calculation to retrieve the
+ init_secret value.
+
+ context = SetupBaseR(kem_output, external_priv, "")
+ init_secret = context.export("MLS 1.0 external init secret", KDF.Nh)
+
+8.4. Pre-Shared Keys
+
+ Groups that already have an out-of-band mechanism to generate shared
+ group secrets can inject them into the MLS key schedule to
+ incorporate this external entropy in the computation of MLS group
+ secrets.
+
+ Injecting an external PSK can improve security in the case where
+ having a full run of Updates across members is too expensive, or if
+ the external group key establishment mechanism provides stronger
+ security against classical or quantum adversaries.
+
+ Note that, as a PSK may have a different lifetime than an Update, it
+ does not necessarily provide the same forward secrecy or post-
+ compromise security guarantees as a Commit message. Unlike the key
+ pairs populated in the tree by an Update or Commit, which are always
+ freshly generated, PSKs may be pre-distributed and stored. This
+ creates the risk that a PSK may be compromised in the process of
+ distribution and storage. The security that the group gets from
+ injecting a PSK thus depends on both the entropy of the PSK and the
+ risk of compromise. These factors are outside of the scope of this
+ document, but they should be considered by application designers
+ relying on PSKs.
+
+ Each PSK in MLS has a type that designates how it was provisioned.
+ External PSKs are provided by the application, while resumption PSKs
+ are derived from the MLS key schedule and used in cases where it is
+ necessary to authenticate a member's participation in a prior epoch.
+
+ The injection of one or more PSKs into the key schedule is signaled
+ in two ways: Existing members are informed via PreSharedKey proposals
+ covered by a Commit, and new members added in the Commit are informed
+ by the GroupSecrets object in the Welcome message corresponding to
+ the Commit. To ensure that existing and new members compute the same
+ PSK input to the key schedule, the Commit and GroupSecrets objects
+ MUST indicate the same set of PSKs, in the same order.
+
+ enum {
+ reserved(0),
+ external(1),
+ resumption(2),
+ (255)
+ } PSKType;
+
+ enum {
+ reserved(0),
+ application(1),
+ reinit(2),
+ branch(3),
+ (255)
+ } ResumptionPSKUsage;
+
+ struct {
+ PSKType psktype;
+ select (PreSharedKeyID.psktype) {
+ case external:
+ opaque psk_id<V>;
+
+ case resumption:
+ ResumptionPSKUsage usage;
+ opaque psk_group_id<V>;
+ uint64 psk_epoch;
+ };
+ opaque psk_nonce<V>;
+ } PreSharedKeyID;
+
+ Each time a client injects a PSK into a group, the psk_nonce of its
+ PreSharedKeyID MUST be set to a fresh random value of length KDF.Nh,
+ where KDF is the KDF for the cipher suite of the group into which the
+ PSK is being injected. This ensures that even when a PSK is used
+ multiple times, the value used as an input into the key schedule is
+ different each time.
+
+ Upon receiving a Commit with a PreSharedKey proposal or a
+ GroupSecrets object with the psks field set, the receiving client
+ includes them in the key schedule in the order listed in the Commit,
+ or in the psks field, respectively. For resumption PSKs, the PSK is
+ defined as the resumption_psk of the group and epoch specified in the
+ PreSharedKeyID object. Specifically, psk_secret is computed as
+ follows:
+
+ struct {
+ PreSharedKeyID id;
+ uint16 index;
+ uint16 count;
+ } PSKLabel;
+
+ psk_extracted_[i] = KDF.Extract(0, psk_[i])
+ psk_input_[i] = ExpandWithLabel(psk_extracted_[i], "derived psk",
+ PSKLabel, KDF.Nh)
+
+ psk_secret_[0] = 0
+ psk_secret_[i] = KDF.Extract(psk_input_[i-1], psk_secret_[i-1])
+ psk_secret = psk_secret_[n]
+
+ Here 0 represents the all-zero vector of length KDF.Nh. The index
+ field in PSKLabel corresponds to the index of the PSK in the psk
+ array, while the count field contains the total number of PSKs. In
+ other words, the PSKs are chained together with KDF.Extract
+ invocations (labeled "Extract" for brevity in the diagram), as
+ follows:
+
+ 0 0 = psk_secret_[0]
+ | |
+ V V
+ psk_[0] --> Extract --> ExpandWithLabel --> Extract = psk_secret_[1]
+ |
+ 0 |
+ | |
+ V V
+ psk_[1] --> Extract --> ExpandWithLabel --> Extract = psk_secret_[2]
+ |
+ 0 ...
+ | |
+ V V
+ psk_[n-1] --> Extract --> ExpandWithLabel --> Extract = psk_secret_[n]
+
+ Figure 24: Computation of a PSK Secret from a Set of PSKs
+
+ In particular, if there are no PreSharedKey proposals in a given
+ Commit, then the resulting psk_secret is psk_secret_[0], the all-zero
+ vector.
+
+8.5. Exporters
+
+ The main MLS key schedule provides an exporter_secret that can be
+ used by an application to derive new secrets for use outside of MLS.
+
+ MLS-Exporter(Label, Context, Length) =
+ ExpandWithLabel(DeriveSecret(exporter_secret, Label),
+ "exported", Hash(Context), Length)
+
+ Applications SHOULD provide a unique label to MLS-Exporter that
+ identifies the secret's intended purpose. This is to help prevent
+ the same secret from being generated and used in two different
+ places. To help avoid the same label being used in different
+ applications, an IANA registry for these labels has been defined in
+ Section 17.8.
+
+ The exported values are bound to the group epoch from which the
+ exporter_secret is derived, and hence reflect a particular state of
+ the group.
+
+ It is RECOMMENDED for the application generating exported values to
+ refresh those values after a Commit is processed.
+
+8.6. Resumption PSK
+
+ The main MLS key schedule provides a resumption_psk that is used as a
+ PSK to inject entropy from one epoch into another. This
+ functionality is used in the reinitialization and branching processes
+ described in Sections 11.2 and 11.3, but it may be used by
+ applications for other purposes.
+
+ Some uses of resumption PSKs might call for the use of PSKs from
+ historical epochs. The application SHOULD specify an upper limit on
+ the number of past epochs for which the resumption_psk may be stored.
+
+8.7. Epoch Authenticators
+
+ The main MLS key schedule provides a per-epoch epoch_authenticator.
+ If one member of the group is being impersonated by an active
+ attacker, the epoch_authenticator computed by their client will
+ differ from those computed by the other group members.
+
+ This property can be used to construct defenses against impersonation
+ attacks that are effective even if members' signature keys are
+ compromised. As a trivial example, if the users of the clients in an
+ MLS group were to meet in person and reliably confirm that their
+ epoch authenticator values were equal (using some suitable user
+ interface), then each user would be assured that the others were not
+ being impersonated in the current epoch. As soon as the epoch
+ changed, though, they would need to redo this confirmation. The
+ state of the group would have changed, possibly introducing an
+ attacker.
+
+ More generally, in order for the members of an MLS group to obtain
+ concrete authentication protections using the epoch_authenticator,
+ they will need to use it in some secondary protocol (such as the
+ face-to-face protocol above). The details of that protocol will then
+ determine the specific authentication protections provided to the MLS
+ group.
+
+9. Secret Tree
+
+ For the generation of encryption keys and nonces, the key schedule
+ begins with the encryption_secret at the root and derives a tree of
+ secrets with the same structure as the group's ratchet tree. Each
+ leaf in the secret tree is associated with the same group member as
+ the corresponding leaf in the ratchet tree.
+
+ If N is a parent node in the secret tree, then the secrets of the
+ children of N are defined as follows (where left(N) and right(N)
+ denote the children of N):
+
+ tree_node_[N]_secret
+ |
+ |
+ +--> ExpandWithLabel(., "tree", "left", KDF.Nh)
+ | = tree_node_[left(N)]_secret
+ |
+ +--> ExpandWithLabel(., "tree", "right", KDF.Nh)
+ = tree_node_[right(N)]_secret
+
+ Figure 25: Derivation of Secrets from Parent to Children within a
+ Secret Tree
+
+ The secret in the leaf of the secret tree is used to initiate two
+ symmetric hash ratchets, from which a sequence of single-use keys and
+ nonces are derived, as described in Section 9.1. The root of each
+ ratchet is computed as:
+
+ tree_node_[N]_secret
+ |
+ |
+ +--> ExpandWithLabel(., "handshake", "", KDF.Nh)
+ | = handshake_ratchet_secret_[N]_[0]
+ |
+ +--> ExpandWithLabel(., "application", "", KDF.Nh)
+ = application_ratchet_secret_[N]_[0]
+
+ Figure 26: Initialization of the Hash Ratchets from the Leaves of
+ a Secret Tree
+
+9.1. Encryption Keys
+
+ As described in Section 6, MLS encrypts three different types of
+ information:
+
+ * Metadata (sender information)
+
+ * Handshake messages (Proposal and Commit)
+
+ * Application messages
+
+ The sender information used to look up the key for content encryption
+ is encrypted with an AEAD where the key and nonce are derived from
+ both sender_data_secret and a sample of the encrypted message
+ content.
+
+ For handshake and application messages, a sequence of keys is derived
+ via a "sender ratchet". Each sender has their own sender ratchet,
+ and each step along the ratchet is called a "generation".
+
+ The following figure shows a secret tree for a four-member group,
+ with the handshake and application ratchets that member D will use
+ for sending and the first two application keys and nonces.
+
+ G
+ |
+ .-+-.
+ / \
+ E F
+ / \ / \
+ A B C D
+ / \
+ HR0 AR0--+--K0
+ | |
+ | +--N0
+ |
+ AR1--+--K1
+ | |
+ | +--N1
+ |
+ AR2
+
+ Figure 27: Secret Tree for a Four-Member Group
+
+ A sender ratchet starts from a per-sender base secret derived from a
+ Secret Tree, as described in Section 9. The base secret initiates a
+ symmetric hash ratchet, which generates a sequence of keys and
+ nonces. The sender uses the j-th key/nonce pair in the sequence to
+ encrypt (using the AEAD) the j-th message they send during that
+ epoch. Each key/nonce pair MUST NOT be used to encrypt more than one
+ message.
+
+ Keys, nonces, and the secrets in ratchets are derived using
+ DeriveTreeSecret. The context in a given call consists of the
+ current position in the ratchet.
+
+ DeriveTreeSecret(Secret, Label, Generation, Length) =
+ ExpandWithLabel(Secret, Label, Generation, Length)
+
+ Where Generation is encoded as a big endian uint32.
+
+ ratchet_secret_[N]_[j]
+ |
+ +--> DeriveTreeSecret(., "nonce", j, AEAD.Nn)
+ | = ratchet_nonce_[N]_[j]
+ |
+ +--> DeriveTreeSecret(., "key", j, AEAD.Nk)
+ | = ratchet_key_[N]_[j]
+ |
+ V
+ DeriveTreeSecret(., "secret", j, KDF.Nh)
+ = ratchet_secret_[N]_[j+1]
+
+ Here AEAD.Nn and AEAD.Nk denote the lengths in bytes of the nonce and
+ key for the AEAD scheme defined by the cipher suite.
+
+9.2. Deletion Schedule
+
+ It is important to delete all security-sensitive values as soon as
+ they are _consumed_. A sensitive value S is said to be _consumed_ if:
+
+ * S was used to encrypt or (successfully) decrypt a message, or
+
+ * a key, nonce, or secret derived from S has been consumed. (This
+ goes for values derived via DeriveSecret as well as
+ ExpandWithLabel.)
+
+ Here S may be the init_secret, commit_secret, epoch_secret, or
+ encryption_secret as well as any secret in a secret tree or one of
+ the ratchets.
+
+ As soon as a group member consumes a value, they MUST immediately
+ delete (all representations of) that value. This is crucial to
+ ensuring forward secrecy for past messages. Members MAY keep
+ unconsumed values around for some reasonable amount of time to handle
+ out-of-order message delivery.
+
+ For example, suppose a group member encrypts or (successfully)
+ decrypts an application message using the j-th key and nonce in the
+ ratchet of leaf node L in some epoch n. Then, for that member, at
+ least the following values have been consumed and MUST be deleted:
+
+ * the commit_secret, joiner_secret, epoch_secret, and
+ encryption_secret of that epoch n as well as the init_secret of
+ the previous epoch n-1,
+
+ * all node secrets in the secret tree on the path from the root to
+ the leaf with node L,
+
+ * the first j secrets in the application data ratchet of node L, and
+
+ * application_ratchet_nonce_[L]_[j] and
+ application_ratchet_key_[L]_[j].
+
+ Concretely, consider the secret tree shown in Figure 27. Client A,
+ B, or C would generate the illustrated values on receiving a message
+ from D with generation equal to 1, having not received a message with
+ generation 0 (e.g., due to out-of-order delivery). In such a case,
+ the following values would be consumed:
+
+ * The key K1 and nonce N1 used to decrypt the message
+
+ * The application ratchet secrets AR1 and AR0
+
+ * The tree secrets D, F, and G (recall that G is the
+ encryption_secret for the epoch)
+
+ * The epoch_secret, commit_secret, psk_secret, and joiner_secret for
+ the current epoch
+
+ Other values may be retained (not consumed):
+
+ * K0 and N0 for decryption of an out-of-order message with
+ generation 0
+
+ * AR2 for derivation of further message decryption keys and nonces
+
+ * HR0 for protection of handshake messages from D
+
+ * E and C for deriving secrets used by senders A, B, and C
+
+10. Key Packages
+
+ In order to facilitate the asynchronous addition of clients to a
+ group, clients can pre-publish KeyPackage objects that provide some
+ public information about a user. A KeyPackage object specifies:
+
+ 1. a protocol version and cipher suite that the client supports,
+
+ 2. a public key that others can use to encrypt a Welcome message to
+ this client (an "init key"), and
+
+ 3. the content of the leaf node that should be added to the tree to
+ represent this client.
+
+ KeyPackages are intended to be used only once and SHOULD NOT be
+ reused except in the case of a "last resort" KeyPackage (see
+ Section 16.8). Clients MAY generate and publish multiple KeyPackages
+ to support multiple cipher suites.
+
+ The value for init_key MUST be a public key for the asymmetric
+ encryption scheme defined by cipher_suite, and it MUST be unique
+ among the set of KeyPackages created by this client. Likewise, the
+ leaf_node field MUST be valid for the cipher suite, including both
+ the encryption_key and signature_key fields. The whole structure is
+ signed using the client's signature key. A KeyPackage object with an
+ invalid signature field MUST be considered malformed.
+
+ The signature is computed by the function SignWithLabel with a label
+ "KeyPackageTBS" and a Content input comprising all of the fields
+ except for the signature field.
+
+ struct {
+ ProtocolVersion version;
+ CipherSuite cipher_suite;
+ HPKEPublicKey init_key;
+ LeafNode leaf_node;
+ Extension extensions<V>;
+ /* SignWithLabel(., "KeyPackageTBS", KeyPackageTBS) */
+ opaque signature<V>;
+ } KeyPackage;
+
+ struct {
+ ProtocolVersion version;
+ CipherSuite cipher_suite;
+ HPKEPublicKey init_key;
+ LeafNode leaf_node;
+ Extension extensions<V>;
+ } KeyPackageTBS;
+
+ If a client receives a KeyPackage carried within an MLSMessage
+ object, then it MUST verify that the version field of the KeyPackage
+ has the same value as the version field of the MLSMessage. The
+ version field in the KeyPackage provides an explicit signal of the
+ intended version to the other members of group when they receive the
+ KeyPackage in an Add proposal.
+
+ The field leaf_node.capabilities indicates what protocol versions,
+ cipher suites, credential types, and non-default proposal/extension
+ types are supported by the client. (As discussed in Section 7.2,
+ some proposal and extension types defined in this document are
+ considered "default" and thus are not listed.) This information
+ allows MLS session establishment to be safe from downgrade attacks on
+ the parameters described (as discussed in Section 11), while still
+ only advertising one version and one cipher suite per KeyPackage.
+
+ The field leaf_node.leaf_node_source of the LeafNode in a KeyPackage
+ MUST be set to key_package.
+
+ Extensions included in the extensions or leaf_node.extensions fields
+ MUST be included in the leaf_node.capabilities field. As discussed
+ in Section 13, unknown extensions in KeyPackage.extensions MUST be
+ ignored, and the creator of a KeyPackage object SHOULD include some
+ random GREASE extensions to help ensure that other clients correctly
+ ignore unknown extensions.
+
+10.1. KeyPackage Validation
+
+ The validity of a KeyPackage needs to be verified at a few stages:
+
+ * When a KeyPackage is downloaded by a group member, before it is
+ used to add the client to the group
+
+ * When a KeyPackage is received by a group member in an Add message
+
+ The client verifies the validity of a KeyPackage using the following
+ steps:
+
+ * Verify that the cipher suite and protocol version of the
+ KeyPackage match those in the GroupContext.
+
+ * Verify that the leaf_node of the KeyPackage is valid for a
+ KeyPackage according to Section 7.3.
+
+ * Verify that the signature on the KeyPackage is valid using the
+ public key in leaf_node.credential.
+
+ * Verify that the value of leaf_node.encryption_key is different
+ from the value of the init_key field.
+
+11. Group Creation
+
+ A group is always created with a single member, the "creator". Other
+ members are then added to the group using the usual Add/Commit
+ mechanism.
+
+ The creator of a group is responsible for setting the group ID,
+ cipher suite, and initial extensions for the group. If the creator
+ intends to add other members at the time of creation, then it SHOULD
+ fetch KeyPackages for the members to be added, and select a cipher
+ suite and extensions according to the capabilities of the members.
+ To protect against downgrade attacks, the creator MUST use the
+ capabilities information in these KeyPackages to verify that the
+ chosen version and cipher suite is the best option supported by all
+ members.
+
+ Group IDs SHOULD be constructed in such a way that there is an
+ overwhelmingly low probability of honest group creators generating
+ the same group ID, even without assistance from the Delivery Service.
+ This can be done, for example, by making the group ID a freshly
+ generated random value of size KDF.Nh. The Delivery Service MAY
+ attempt to ensure that group IDs are globally unique by rejecting the
+ creation of new groups with a previously used ID.
+
+ To initialize a group, the creator of the group MUST take the
+ following steps:
+
+ * Initialize a one-member group with the following initial values:
+
+ - Ratchet tree: A tree with a single node, a leaf node containing
+ an HPKE public key and credential for the creator
+
+ - Group ID: A value set by the creator
+
+ - Epoch: 0
+
+ - Tree hash: The root hash of the above ratchet tree
+
+ - Confirmed transcript hash: The zero-length octet string
+
+ - Epoch secret: A fresh random value of size KDF.Nh
+
+ - Extensions: Any values of the creator's choosing
+
+ * Calculate the interim transcript hash:
+
+ - Derive the confirmation_key for the epoch as described in
+ Section 8.
+
+ - Compute a confirmation_tag over the empty
+ confirmed_transcript_hash using the confirmation_key as
+ described in Section 6.1.
+
+ - Compute the updated interim_transcript_hash from the
+ confirmed_transcript_hash and the confirmation_tag as described
+ in Section 8.2.
+
+ At this point, the creator's state represents a one-member group with
+ a fully initialized key schedule, transcript hashes, etc. Proposals
+ and Commits can be generated for this group state just like any other
+ state of the group, such as Add proposals and Commits to add other
+ members to the group. A GroupInfo object for this group state can
+ also be published to facilitate external joins.
+
+ Members other than the creator join either by being sent a Welcome
+ message (as described in Section 12.4.3.1) or by sending an external
+ Commit (see Section 12.4.3.2).
+
+ In principle, the above process could be streamlined by having the
+ creator directly create a tree and choose a random value for first
+ epoch's epoch secret. We follow the steps above because it removes
+ unnecessary choices, by which, for example, bad randomness could be
+ introduced. The only choices the creator makes here are its own
+ KeyPackage and the leaf secret from which the Commit is built.
+
+11.1. Required Capabilities
+
+ The configuration of a group imposes certain requirements on clients
+ in the group. At a minimum, all members of the group need to support
+ the cipher suite and protocol version in use. Additional
+ requirements can be imposed by including a required_capabilities
+ extension in the GroupContext.
+
+ struct {
+ ExtensionType extension_types<V>;
+ ProposalType proposal_types<V>;
+ CredentialType credential_types<V>;
+ } RequiredCapabilities;
+
+ This extension lists the extensions, proposals, and credential types
+ that must be supported by all members of the group. The "default"
+ proposal and extension types defined in this document are assumed to
+ be implemented by all clients, and need not be listed in
+ RequiredCapabilities in order to be safely used. Note that this is
+ not true for credential types.
+
+ For new members, support for required capabilities is enforced by
+ existing members during the application of Add commits. Existing
+ members should of course be in compliance already. In order to
+ ensure this continues to be the case even as the group's extensions
+ are updated, a GroupContextExtensions proposal is deemed invalid if
+ it contains a required_capabilities extension that requires non-
+ default capabilities not supported by all current members.
+
+11.2. Reinitialization
+
+ A group may be reinitialized by creating a new group with the same
+ membership and different parameters, and linking it to the old group
+ via a resumption PSK. The members of a group reinitialize it using
+ the following steps:
+
+ 1. A member of the old group sends a ReInit proposal (see
+ Section 12.1.5).
+
+ 2. A member of the old group sends a Commit covering the ReInit
+ proposal.
+
+ 3. A member of the old group creates an initial Commit that sets up
+ a new group that matches the ReInit and sends a Welcome message:
+
+ * The version, cipher_suite, group_id, and extensions fields of
+ the GroupContext object in the Welcome message MUST be the
+ same as the corresponding fields in the ReInit proposal. The
+ epoch in the Welcome message MUST be 1.
+
+ * The Welcome message MUST specify a PreSharedKeyID of type
+ resumption with usage reinit, where the group_id field matches
+ the old group and the epoch field indicates the epoch after
+ the Commit covering the ReInit.
+
+ Note that these three steps may be done by the same group member or
+ different members. For example, if a group member sends a Commit
+ with an inline ReInit proposal (steps 1 and 2) but then goes offline,
+ another group member may recreate the group instead. This
+ flexibility avoids situations where a group gets stuck between steps
+ 2 and 3.
+
+ Resumption PSKs with usage reinit MUST NOT be used in other contexts.
+ A PreSharedKey proposal with type resumption and usage reinit MUST be
+ considered invalid.
+
+11.3. Subgroup Branching
+
+ A new group can be formed from a subset of an existing group's
+ members, using the same parameters as the old group.
+
+ A member can create a subgroup by performing the following steps:
+
+ 1. Fetch a new KeyPackage for each group member that should be
+ included in the subgroup.
+
+ 2. Create an initial Commit message that sets up the new group and
+ contains a PreSharedKey proposal of type resumption with usage
+ branch. To avoid key reuse, the psk_nonce included in the
+ PreSharedKeyID object MUST be a randomly sampled nonce of length
+ KDF.Nh.
+
+ 3. Send the corresponding Welcome message to the subgroup members.
+
+ A client receiving a Welcome message including a PreSharedKey of type
+ resumption with usage branch MUST verify that the new group reflects
+ a subgroup branched from the referenced group by checking that:
+
+ * The version and cipher_suite values in the Welcome message are the
+ same as those used by the old group.
+
+ * The epoch in the Welcome message MUST be 1.
+
+ * Each LeafNode in a new subgroup MUST match some LeafNode in the
+ original group. In this context, a pair of LeafNodes is said to
+ "match" if the identifiers presented by their respective
+ credentials are considered equivalent by the application.
+
+ Resumption PSKs with usage branch MUST NOT be used in other contexts.
+ A PreSharedKey proposal with type resumption and usage branch MUST be
+ considered invalid.
+
+12. Group Evolution
+
+ Over the lifetime of a group, its membership can change, and existing
+ members might want to change their keys in order to achieve post-
+ compromise security. In MLS, each such change is accomplished by a
+ two-step process:
+
+ 1. A proposal to make the change is broadcast to the group in a
+ Proposal message.
+
+ 2. A member of the group or a new member broadcasts a Commit message
+ that causes one or more proposed changes to enter into effect.
+
+ In cases where the Proposal and Commit are sent by the same member,
+ these two steps can be combined by sending the proposals in the
+ commit.
+
+ The group thus evolves from one cryptographic state to another each
+ time a Commit message is sent and processed. These states are
+ referred to as "epochs" and are uniquely identified among states of
+ the group by eight-octet epoch values. When a new group is
+ initialized, its initial state epoch is 0x0000000000000000. Each
+ time a state transition occurs, the epoch number is incremented by
+ one.
+
+12.1. Proposals
+
+ Proposals are included in a FramedContent by way of a Proposal
+ structure that indicates their type:
+
+ // See the "MLS Proposal Types" IANA registry for values
+ uint16 ProposalType;
+
+ struct {
+ ProposalType proposal_type;
+ select (Proposal.proposal_type) {
+ case add: Add;
+ case update: Update;
+ case remove: Remove;
+ case psk: PreSharedKey;
+ case reinit: ReInit;
+ case external_init: ExternalInit;
+ case group_context_extensions: GroupContextExtensions;
+ };
+ } Proposal;
+
+ On receiving a FramedContent containing a Proposal, a client MUST
+ verify the signature inside FramedContentAuthData and that the epoch
+ field of the enclosing FramedContent is equal to the epoch field of
+ the current GroupContext object. If the verification is successful,
+ then the Proposal should be cached in such a way that it can be
+ retrieved by hash (as a ProposalOrRef object) in a later Commit
+ message.
+
+12.1.1. Add
+
+ An Add proposal requests that a client with a specified KeyPackage be
+ added to the group.
+
+ struct {
+ KeyPackage key_package;
+ } Add;
+
+ An Add proposal is invalid if the KeyPackage is invalid according to
+ Section 10.1.
+
+ An Add is applied after being included in a Commit message. The
+ position of the Add in the list of proposals determines the leaf node
+ where the new member will be added. For the first Add in the Commit,
+ the corresponding new member will be placed in the leftmost empty
+ leaf in the tree, for the second Add, the next empty leaf to the
+ right, etc. If no empty leaf exists, the tree is extended to the
+ right.
+
+ * Identify the leaf L for the new member: if there are empty leaves
+ in the tree, L is the leftmost empty leaf. Otherwise, the tree is
+ extended to the right as described in Section 7.7, and L is
+ assigned the leftmost new blank leaf.
+
+ * For each non-blank intermediate node along the path from the leaf
+ L to the root, add L's leaf index to the unmerged_leaves list for
+ the node.
+
+ * Set the leaf node L to a new node containing the LeafNode object
+ carried in the leaf_node field of the KeyPackage in the Add.
+
+12.1.2. Update
+
+ An Update proposal is a similar mechanism to Add with the distinction
+ that it replaces the sender's LeafNode in the tree instead of adding
+ a new leaf to the tree.
+
+ struct {
+ LeafNode leaf_node;
+ } Update;
+
+ An Update proposal is invalid if the LeafNode is invalid for an
+ Update proposal according to Section 7.3.
+
+ A member of the group applies an Update message by taking the
+ following steps:
+
+ * Replace the sender's LeafNode with the one contained in the Update
+ proposal.
+
+ * Blank the intermediate nodes along the path from the sender's leaf
+ to the root.
+
+12.1.3. Remove
+
+ A Remove proposal requests that the member with the leaf index
+ removed be removed from the group.
+
+ struct {
+ uint32 removed;
+ } Remove;
+
+ A Remove proposal is invalid if the removed field does not identify a
+ non-blank leaf node.
+
+ A member of the group applies a Remove message by taking the
+ following steps:
+
+ * Identify the leaf node matching removed. Let L be this leaf node.
+
+ * Replace the leaf node L with a blank node.
+
+ * Blank the intermediate nodes along the path from L to the root.
+
+ * Truncate the tree by removing the right subtree until there is at
+ least one non-blank leaf node in the right subtree. If the
+ rightmost non-blank leaf has index L, then this will result in the
+ tree having 2^d leaves, where d is the smallest value such that
+ 2^d > L.
+
+12.1.4. PreSharedKey
+
+ A PreSharedKey proposal can be used to request that a pre-shared key
+ be injected into the key schedule in the process of advancing the
+ epoch.
+
+ struct {
+ PreSharedKeyID psk;
+ } PreSharedKey;
+
+ A PreSharedKey proposal is invalid if any of the following is true:
+
+ * The PreSharedKey proposal is not being processed as part of a
+ reinitialization of the group (see Section 11.2), and the
+ PreSharedKeyID has psktype set to resumption and usage set to
+ reinit.
+
+ * The PreSharedKey proposal is not being processed as part of a
+ subgroup branching operation (see Section 11.3), and the
+ PreSharedKeyID has psktype set to resumption and usage set to
+ branch.
+
+ * The psk_nonce is not of length KDF.Nh.
+
+ The psk_nonce MUST be randomly sampled. When processing a Commit
+ message that includes one or more PreSharedKey proposals, group
+ members derive psk_secret as described in Section 8.4, where the
+ order of the PSKs corresponds to the order of the PreSharedKey
+ proposals in the Commit.
+
+12.1.5. ReInit
+
+ A ReInit proposal represents a request to reinitialize the group with
+ different parameters, for example, to increase the version number or
+ to change the cipher suite. The reinitialization is done by creating
+ a completely new group and shutting down the old one.
+
+ struct {
+ opaque group_id<V>;
+ ProtocolVersion version;
+ CipherSuite cipher_suite;
+ Extension extensions<V>;
+ } ReInit;
+
+ A ReInit proposal is invalid if the version field is less than the
+ version for the current group.
+
+ A member of the group applies a ReInit proposal by waiting for the
+ committer to send the Welcome message that matches the ReInit,
+ according to the criteria in Section 11.2.
+
+12.1.6. ExternalInit
+
+ An ExternalInit proposal is used by new members that want to join a
+ group by using an external commit. This proposal can only be used in
+ that context.
+
+ struct {
+ opaque kem_output<V>;
+ } ExternalInit;
+
+ A member of the group applies an ExternalInit message by initializing
+ the next epoch using an init secret computed as described in
+ Section 8.3. The kem_output field contains the required KEM output.
+
+12.1.7. GroupContextExtensions
+
+ A GroupContextExtensions proposal is used to update the list of
+ extensions in the GroupContext for the group.
+
+ struct {
+ Extension extensions<V>;
+ } GroupContextExtensions;
+
+ A GroupContextExtensions proposal is invalid if it includes a
+ required_capabilities extension and some members of the group do not
+ support some of the required capabilities (including those added in
+ the same Commit, and excluding those removed).
+
+ A member of the group applies a GroupContextExtensions proposal with
+ the following steps:
+
+ * Remove all of the existing extensions from the GroupContext object
+ for the group and replace them with the list of extensions in the
+ proposal. (This is a wholesale replacement, not a merge. An
+ extension is only carried over if the sender of the proposal
+ includes it in the new list.)
+
+ Note that once the GroupContext is updated, its inclusion in the
+ confirmation_tag by way of the key schedule will confirm that all
+ members of the group agree on the extensions in use.
+
+12.1.8. External Proposals
+
+ Proposals can be constructed and sent to the group by a party that is
+ outside the group in two cases. One case, indicated by the external
+ SenderType, allows an entity outside the group to submit proposals to
+ the group. For example, an automated service might propose removing
+ a member of a group who has been inactive for a long time, or propose
+ adding a newly hired staff member to a group representing a real-
+ world team. An external sender might send a ReInit proposal to
+ enforce a changed policy regarding MLS versions or cipher suites.
+
+ The external SenderType requires that signers are pre-provisioned to
+ the clients within a group and can only be used if the
+ external_senders extension is present in the group's GroupContext.
+
+ The other case, indicated by the new_member_proposal SenderType, is
+ useful when existing members of the group can independently verify
+ that an Add proposal sent by the new joiner itself (not an existing
+ member) is authorized. External proposals that are not authorized
+ are considered invalid.
+
+ An external proposal MUST be sent as a PublicMessage object, since
+ the sender will not have the keys necessary to construct a
+ PrivateMessage object.
+
+ Proposals of some types cannot be sent by an external sender. Among
+ the proposal types defined in this document, only the following types
+ may be sent by an external sender:
+
+ * add
+
+ * remove
+
+ * psk
+
+ * reinit
+
+ * group_context_extensions
+
+ Messages from external senders containing proposal types other than
+ the above MUST be rejected as malformed. New proposal types defined
+ in the future MUST define whether they may be sent by external
+ senders. The "Ext" column in the "MLS Proposal Types" registry
+ (Section 17.4) reflects this property.
+
+12.1.8.1. External Senders Extension
+
+ The external_senders extension is a group context extension that
+ contains the credentials and signature keys of senders that are
+ permitted to send external proposals to the group.
+
+ struct {
+ SignaturePublicKey signature_key;
+ Credential credential;
+ } ExternalSender;
+
+ ExternalSender external_senders<V>;
+
+12.2. Proposal List Validation
+
+ A group member creating a Commit and a group member processing a
+ Commit MUST verify that the list of committed proposals is valid
+ using one of the following procedures, depending on whether the
+ Commit is external or not. If the list of proposals is invalid, then
+ the Commit message MUST be rejected as invalid.
+
+ For a regular, i.e., not external, Commit, the list is invalid if any
+ of the following occurs:
+
+ * It contains an individual proposal that is invalid as specified in
+ Section 12.1.
+
+ * It contains an Update proposal generated by the committer.
+
+ * It contains a Remove proposal that removes the committer.
+
+ * It contains multiple Update and/or Remove proposals that apply to
+ the same leaf. If the committer has received multiple such
+ proposals they SHOULD prefer any Remove received, or the most
+ recent Update if there are no Removes.
+
+ * It contains multiple Add proposals that contain KeyPackages that
+ represent the same client according to the application (for
+ example, identical signature keys).
+
+ * It contains an Add proposal with a KeyPackage that represents a
+ client already in the group according to the application, unless
+ there is a Remove proposal in the list removing the matching
+ client from the group.
+
+ * It contains multiple PreSharedKey proposals that reference the
+ same PreSharedKeyID.
+
+ * It contains multiple GroupContextExtensions proposals.
+
+ * It contains a ReInit proposal together with any other proposal.
+ If the committer has received other proposals during the epoch,
+ they SHOULD prefer them over the ReInit proposal, allowing the
+ ReInit to be resent and applied in a subsequent epoch.
+
+ * It contains an ExternalInit proposal.
+
+ * It contains a Proposal with a non-default proposal type that is
+ not supported by some members of the group that will process the
+ Commit (i.e., members being added or removed by the Commit do not
+ need to support the proposal type).
+
+ * After processing the Commit the ratchet tree is invalid, in
+ particular, if it contains any leaf node that is invalid according
+ to Section 7.3.
+
+ An application may extend the above procedure by additional rules,
+ for example, requiring application-level permissions to add members,
+ or rules concerning non-default proposal types.
+
+ For an external Commit, the list is valid if it contains only the
+ following proposals (not necessarily in this order):
+
+ * Exactly one ExternalInit
+
+ * At most one Remove proposal, with which the joiner removes an old
+ version of themselves. If a Remove proposal is present, then the
+ LeafNode in the path field of the external Commit MUST meet the
+ same criteria as would the LeafNode in an Update for the removed
+ leaf (see Section 12.1.2). In particular, the credential in the
+ LeafNode MUST present a set of identifiers that is acceptable to
+ the application for the removed participant.
+
+ * Zero or more PreSharedKey proposals
+
+ * No other proposals
+
+ Proposal types defined in the future may make updates to the above
+ validation logic to incorporate considerations related to proposals
+ of the new type.
+
+12.3. Applying a Proposal List
+
+ The sections above defining each proposal type describe how each
+ individual proposal is applied. When creating or processing a
+ Commit, a client applies a list of proposals to the ratchet tree and
+ GroupContext. The client MUST apply the proposals in the list in the
+ following order:
+
+ * If there is a GroupContextExtensions proposal, replace the
+ extensions field of the GroupContext for the group with the
+ contents of the proposal. The new extensions MUST be used when
+ evaluating other proposals in this list. For example, if a
+ GroupContextExtensions proposal adds a required_capabilities
+ extension, then any Add proposals need to indicate support for
+ those capabilities.
+
+ * Apply any Update proposals to the ratchet tree, in any order.
+
+ * Apply any Remove proposals to the ratchet tree, in any order.
+
+ * Apply any Add proposals to the ratchet tree, in the order they
+ appear in the list.
+
+ * Look up the PSK secrets for any PreSharedKey proposals, in the
+ order they appear in the list. These secrets are then used to
+ advance the key schedule later in Commit processing.
+
+ * If there is an ExternalInit proposal, use it to derive the
+ init_secret for use later in Commit processing.
+
+ * If there is a ReInit proposal, note its parameters for application
+ later in Commit processing.
+
+ Proposal types defined in the future MUST specify how the above steps
+ are to be adjusted to accommodate the application of proposals of the
+ new type.
+
+12.4. Commit
+
+ A Commit message initiates a new epoch for the group, based on a
+ collection of Proposals. It instructs group members to update their
+ representation of the state of the group by applying the proposals
+ and advancing the key schedule.
+
+ Each proposal covered by the Commit is included by a ProposalOrRef
+ value, which identifies the proposal to be applied by value or by
+ reference. Commits that refer to new Proposals from the committer
+ can be included by value. Commits for previously sent proposals from
+ anyone (including the committer) can be sent by reference. Proposals
+ sent by reference are specified by including the hash of the
+ AuthenticatedContent object in which the proposal was sent (see
+ Section 5.2).
+
+ enum {
+ reserved(0),
+ proposal(1),
+ reference(2),
+ (255)
+ } ProposalOrRefType;
+
+ struct {
+ ProposalOrRefType type;
+ select (ProposalOrRef.type) {
+ case proposal: Proposal proposal;
+ case reference: ProposalRef reference;
+ };
+ } ProposalOrRef;
+
+ struct {
+ ProposalOrRef proposals<V>;
+ optional<UpdatePath> path;
+ } Commit;
+
+ A group member that has observed one or more valid proposals within
+ an epoch MUST send a Commit message before sending application data.
+ This ensures, for example, that any members whose removal was
+ proposed during the epoch are actually removed before any application
+ data is transmitted.
+
+ A sender and a receiver of a Commit MUST verify that the committed
+ list of proposals is valid as specified in Section 12.2. A list is
+ invalid if, for example, it includes an Update and a Remove for the
+ same member, or an Add when the sender does not have the application-
+ level permission to add new users.
+
+ The sender of a Commit SHOULD include all proposals that it has
+ received during the current epoch that are valid according to the
+ rules for their proposal types and according to application policy,
+ as long as this results in a valid proposal list.
+
+ Due to the asynchronous nature of proposals, receivers of a Commit
+ SHOULD NOT enforce that all valid proposals sent within the current
+ epoch are referenced by the next Commit. In the event that a valid
+ proposal is omitted from the next Commit, and that proposal is still
+ valid in the current epoch, the sender of the proposal MAY resend it
+ after updating it to reflect the current epoch.
+
+ A member of the group MAY send a Commit that references no proposals
+ at all, which would thus have an empty proposals vector. Such a
+ Commit resets the sender's leaf and the nodes along its direct path,
+ and provides forward secrecy and post-compromise security with regard
+ to the sender of the Commit. An Update proposal can be regarded as a
+ "lazy" version of this operation, where only the leaf changes and
+ intermediate nodes are blanked out.
+
+ By default, the path field of a Commit MUST be populated. The path
+ field MAY be omitted if (a) it covers at least one proposal and (b)
+ none of the proposals covered by the Commit are of "path required"
+ types. A proposal type requires a path if it cannot change the group
+ membership in a way that requires the forward secrecy and post-
+ compromise security guarantees that an UpdatePath provides. The only
+ proposal types defined in this document that do not require a path
+ are:
+
+ * add
+
+ * psk
+
+ * reinit
+
+ New proposal types MUST state whether they require a path. If any
+ instance of a proposal type requires a path, then the proposal type
+ requires a path. This attribute of a proposal type is reflected in
+ the "Path Required" field of the "MLS Proposal Types" registry
+ defined in Section 17.4.
+
+ Update and Remove proposals are the clearest examples of proposals
+ that require a path. An UpdatePath is required to evict the removed
+ member or the old appearance of the updated member.
+
+ In pseudocode, the logic for validating the path field of a Commit is
+ as follows:
+
+ pathRequiredTypes = [
+ update,
+ remove,
+ external_init,
+ group_context_extensions
+ ]
+
+ pathRequired = false
+
+ for proposal in commit.proposals:
+ pathRequired = pathRequired ||
+ (proposal.msg_type in pathRequiredTypes)
+
+ if len(commit.proposals) == 0 || pathRequired:
+ assert(commit.path != null)
+
+ To summarize, a Commit can have three different configurations, with
+ different uses:
+
+ 1. An "empty" Commit that references no proposals, which updates the
+ committer's contribution to the group and provides PCS with
+ regard to the committer.
+
+ 2. A "partial" Commit that references proposals that do not require
+ a path, and where the path is empty. Such a Commit doesn't
+ provide PCS with regard to the committer.
+
+ 3. A "full" Commit that references proposals of any type, which
+ provides FS with regard to any removed members and PCS for the
+ committer and any updated members.
+
+12.4.1. Creating a Commit
+
+ When creating or processing a Commit, a client updates the ratchet
+ tree and GroupContext for the group. These values advance from an
+ "old" state reflecting the current epoch to a "new" state reflecting
+ the new epoch initiated by the Commit. When the Commit includes an
+ UpdatePath, a "provisional" group context is constructed that
+ reflects changes due to the proposals and UpdatePath, but with the
+ old confirmed transcript hash.
+
+ A member of the group creates a Commit message and the corresponding
+ Welcome message at the same time, by taking the following steps:
+
+ * Verify that the list of proposals to be committed is valid as
+ specified in Section 12.2.
+
+ * Construct an initial Commit object with the proposals field
+ populated from Proposals received during the current epoch, and
+ with the path field empty.
+
+ * Create the new ratchet tree and GroupContext by applying the list
+ of proposals to the old ratchet tree and GroupContext, as defined
+ in Section 12.3.
+
+ * Decide whether to populate the path field: If the path field is
+ required based on the proposals that are in the Commit (see
+ above), then it MUST be populated. Otherwise, the sender MAY omit
+ the path field at its discretion.
+
+ * If populating the path field:
+
+ - If this is an external Commit, assign the sender the leftmost
+ blank leaf node in the new ratchet tree. If there are no blank
+ leaf nodes in the new ratchet tree, expand the tree to the
+ right as defined in Section 7.7 and assign the leftmost new
+ blank leaf to the sender.
+
+ - Update the sender's direct path in the ratchet tree as
+ described in Section 7.5. Define commit_secret as the value
+ path_secret[n+1] derived from the last path secret value
+ (path_secret[n]) derived for the UpdatePath.
+
+ - Construct a provisional GroupContext object containing the
+ following values:
+
+ o group_id: Same as the old GroupContext
+
+ o epoch: The epoch number for the new epoch
+
+ o tree_hash: The tree hash of the new ratchet tree
+
+ o confirmed_transcript_hash: Same as the old GroupContext
+
+ o extensions: The new GroupContext extensions (possibly
+ updated by a GroupContextExtensions proposal)
+
+ - Encrypt the path secrets resulting from the tree update to the
+ group as described in Section 7.5, using the provisional group
+ context as the context for HPKE encryption.
+
+ - Create an UpdatePath containing the sender's new leaf node and
+ the new public keys and encrypted path secrets along the
+ sender's filtered direct path. Assign this UpdatePath to the
+ path field in the Commit.
+
+ * If not populating the path field: Set the path field in the Commit
+ to the null optional. Define commit_secret as the all-zero vector
+ of length KDF.Nh (the same length as a path_secret value would
+ be).
+
+ * Derive the psk_secret as specified in Section 8.4, where the order
+ of PSKs in the derivation corresponds to the order of PreSharedKey
+ proposals in the proposals vector.
+
+ * Construct a FramedContent object containing the Commit object.
+ Sign the FramedContent using the old GroupContext as context.
+
+ - Use the FramedContent to update the confirmed transcript hash
+ and update the new GroupContext.
+
+ - Use the init_secret from the previous epoch, the commit_secret
+ and psk_secret defined in the previous steps, and the new
+ GroupContext to compute the new joiner_secret, welcome_secret,
+ epoch_secret, and derived secrets for the new epoch.
+
+ - Use the confirmation_key for the new epoch to compute the
+ confirmation_tag value.
+
+ - Calculate the interim transcript hash using the new confirmed
+ transcript hash and the confirmation_tag from the
+ FramedContentAuthData.
+
+ * Protect the AuthenticatedContent object using keys from the old
+ epoch:
+
+ - If encoding as PublicMessage, compute the membership_tag value
+ using the membership_key.
+
+ - If encoding as a PrivateMessage, encrypt the message using the
+ sender_data_secret and the next (key, nonce) pair from the
+ sender's handshake ratchet.
+
+ * Construct a GroupInfo reflecting the new state:
+
+ - Set the group_id, epoch, tree, confirmed_transcript_hash,
+ interim_transcript_hash, and group_context_extensions fields to
+ reflect the new state.
+
+ - Set the confirmation_tag field to the value of the
+ corresponding field in the FramedContentAuthData object.
+
+ - Add any other extensions as defined by the application.
+
+ - Optionally derive an external key pair as described in
+ Section 8. (required for external Commits, see
+ Section 12.4.3.2).
+
+ - Sign the GroupInfo using the member's private signing key.
+
+ - Encrypt the GroupInfo using the key and nonce derived from the
+ joiner_secret. for the new epoch (see Section 12.4.3.1).
+
+ * For each new member in the group:
+
+ - Identify the lowest common ancestor in the tree of the new
+ member's leaf node and the member sending the Commit.
+
+ - If the path field was populated above: Compute the path secret
+ corresponding to the common ancestor node.
+
+ - Compute an EncryptedGroupSecrets object that encapsulates the
+ init_secret for the current epoch and the path secret (if
+ present).
+
+ * Construct one or more Welcome messages from the encrypted
+ GroupInfo object, the encrypted key packages, and any PSKs for
+ which a proposal was included in the Commit. The order of the
+ psks MUST be the same as the order of PreSharedKey proposals in
+ the proposals vector. As discussed in Section 12.4.3.1, the
+ committer is free to choose how many Welcome messages to
+ construct. However, the set of Welcome messages produced in this
+ step MUST cover every new member added in the Commit.
+
+ * If a ReInit proposal was part of the Commit, the committer MUST
+ create a new group with the parameters specified in the ReInit
+ proposal, and with the same members as the original group. The
+ Welcome message MUST include a PreSharedKeyID with the following
+ parameters:
+
+ - psktype: resumption
+
+ - usage: reinit
+
+ - group_id: The group ID for the current group
+
+ - epoch: The epoch that the group will be in after this Commit
+
+12.4.2. Processing a Commit
+
+ A member of the group applies a Commit message by taking the
+ following steps:
+
+ * Verify that the epoch field of the enclosing FramedContent is
+ equal to the epoch field of the current GroupContext object.
+
+ * Unprotect the Commit using the keys from the current epoch:
+
+ - If the message is encoded as PublicMessage, verify the
+ membership MAC using the membership_key.
+
+ - If the message is encoded as PrivateMessage, decrypt the
+ message using the sender_data_secret and the (key, nonce) pair
+ from the step on the sender's hash ratchet indicated by the
+ generation field.
+
+ * Verify the signature on the FramedContent message as described in
+ Section 6.1.
+
+ * Verify that the proposals vector is valid according to the rules
+ in Section 12.2.
+
+ * Verify that all PreSharedKey proposals in the proposals vector are
+ available.
+
+ * Create the new ratchet tree and GroupContext by applying the list
+ of proposals to the old ratchet tree and GroupContext, as defined
+ in Section 12.3.
+
+ * Verify that the path value is populated if the proposals vector
+ contains any Update or Remove proposals, or if it's empty.
+ Otherwise, the path value MAY be omitted.
+
+ * If the path value is populated, validate it and apply it to the
+ tree:
+
+ - If this is an external Commit, assign the sender the leftmost
+ blank leaf node in the new ratchet tree. If there are no blank
+ leaf nodes in the new ratchet tree, add a blank leaf to the
+ right side of the new ratchet tree and assign it to the sender.
+
+ - Validate the LeafNode as specified in Section 7.3. The
+ leaf_node_source field MUST be set to commit.
+
+ - Verify that the encryption_key value in the LeafNode is
+ different from the committer's current leaf node.
+
+ - Verify that none of the public keys in the UpdatePath appear in
+ any node of the new ratchet tree.
+
+ - Merge the UpdatePath into the new ratchet tree, as described in
+ Section 7.5.
+
+ - Construct a provisional GroupContext object containing the
+ following values:
+
+ o group_id: Same as the old GroupContext
+
+ o epoch: The epoch number for the new epoch
+
+ o tree_hash: The tree hash of the new ratchet tree
+
+ o confirmed_transcript_hash: Same as the old GroupContext
+
+ o extensions: The new GroupContext extensions (possibly
+ updated by a GroupContextExtensions proposal)
+
+ - Decrypt the path secrets for UpdatePath as described in
+ Section 7.5, using the provisional GroupContext as the context
+ for HPKE decryption.
+
+ - Define commit_secret as the value path_secret[n+1] derived from
+ the last path secret value (path_secret[n]) derived for the
+ UpdatePath.
+
+ * If the path value is not populated, define commit_secret as the
+ all-zero vector of length KDF.Nh (the same length as a path_secret
+ value would be).
+
+ * Update the confirmed and interim transcript hashes using the new
+ Commit, and generate the new GroupContext.
+
+ * Derive the psk_secret as specified in Section 8.4, where the order
+ of PSKs in the derivation corresponds to the order of PreSharedKey
+ proposals in the proposals vector.
+
+ * Use the init_secret from the previous epoch, the commit_secret and
+ psk_secret defined in the previous steps, and the new GroupContext
+ to compute the new joiner_secret, welcome_secret, epoch_secret,
+ and derived secrets for the new epoch.
+
+ * Use the confirmation_key for the new epoch to compute the
+ confirmation tag for this message, as described below, and verify
+ that it is the same as the confirmation_tag field in the
+ FramedContentAuthData object.
+
+ * If the above checks are successful, consider the new GroupContext
+ object as the current state of the group.
+
+ * If the Commit included a ReInit proposal, the client MUST NOT use
+ the group to send messages anymore. Instead, it MUST wait for a
+ Welcome message from the committer meeting the requirements of
+ Section 11.2.
+
+ Note that clients need to be prepared to receive a valid Commit
+ message that removes them from the group. In this case, the client
+ cannot send any more messages in the group and SHOULD promptly delete
+ its group state and secret tree. (A client might keep the secret
+ tree for a short time to decrypt late messages in the previous
+ epoch.)
+
+12.4.3. Adding Members to the Group
+
+ New members can join the group in two ways: by being added by a group
+ member or by adding themselves through an external Commit. In both
+ cases, the new members need information to bootstrap their local
+ group state.
+
+ struct {
+ GroupContext group_context;
+ Extension extensions<V>;
+ MAC confirmation_tag;
+ uint32 signer;
+ /* SignWithLabel(., "GroupInfoTBS", GroupInfoTBS) */
+ opaque signature<V>;
+ } GroupInfo;
+
+ The group_context field represents the current state of the group.
+ The extensions field allows the sender to provide additional data
+ that might be useful to new joiners. The confirmation_tag represents
+ the confirmation tag from the Commit that initiated the current
+ epoch, or for epoch 0, the confirmation tag computed in the creation
+ of the group (see Section 11). (In either case, the creator of a
+ GroupInfo may recompute the confirmation tag as MAC(confirmation_key,
+ confirmed_transcript_hash).)
+
+ As discussed in Section 13, unknown extensions in
+ GroupInfo.extensions MUST be ignored, and the creator of a GroupInfo
+ object SHOULD include some random GREASE extensions to help ensure
+ that other clients correctly ignore unknown extensions. Extensions
+ in GroupInfo.group_context.extensions, however, MUST be supported by
+ the new joiner.
+
+ New members MUST verify that group_id is unique among the groups they
+ are currently participating in.
+
+ New members also MUST verify the signature using the public key taken
+ from the leaf node of the ratchet tree with leaf index signer. The
+ signature covers the following structure, comprising all the fields
+ in the GroupInfo above signature:
+
+ struct {
+ GroupContext group_context;
+ Extension extensions<V>;
+ MAC confirmation_tag;
+ uint32 signer;
+ } GroupInfoTBS;
+
+12.4.3.1. Joining via Welcome Message
+
+ The sender of a Commit message is responsible for sending a Welcome
+ message to each new member added via Add proposals. The format of
+ the Welcome message allows a single Welcome message to be encrypted
+ for multiple new members. It is up to the committer to decide how
+ many Welcome messages to create for a given Commit. The committer
+ could create one Welcome that is encrypted for all new members, a
+ different Welcome for each new member, or Welcome messages for
+ batches of new members (according to some batching scheme that works
+ well for the application). The processes for creating and processing
+ the Welcome are the same in all cases, aside from the set of new
+ members for whom a given Welcome is encrypted.
+
+ The Welcome message provides the new members with the current state
+ of the group after the application of the Commit message. The new
+ members will not be able to decrypt or verify the Commit message, but
+ they will have the secrets they need to participate in the epoch
+ initiated by the Commit message.
+
+ In order to allow the same Welcome message to be sent to multiple new
+ members, information describing the group is encrypted with a
+ symmetric key and nonce derived from the joiner_secret for the new
+ epoch. The joiner_secret is then encrypted to each new member using
+ HPKE. In the same encrypted package, the committer transmits the
+ path secret for the lowest (closest to the leaf) node that is
+ contained in the direct paths of both the committer and the new
+ member. This allows the new member to compute private keys for nodes
+ in its direct path that are being reset by the corresponding Commit.
+
+ If the sender of the Welcome message wants the receiving member to
+ include a PSK in the derivation of the epoch_secret, they can
+ populate the psks field indicating which PSK to use.
+
+ struct {
+ opaque path_secret<V>;
+ } PathSecret;
+
+ struct {
+ opaque joiner_secret<V>;
+ optional<PathSecret> path_secret;
+ PreSharedKeyID psks<V>;
+ } GroupSecrets;
+
+ struct {
+ KeyPackageRef new_member;
+ HPKECiphertext encrypted_group_secrets;
+ } EncryptedGroupSecrets;
+
+ struct {
+ CipherSuite cipher_suite;
+ EncryptedGroupSecrets secrets<V>;
+ opaque encrypted_group_info<V>;
+ } Welcome;
+
+ The client processing a Welcome message will need to have a copy of
+ the group's ratchet tree. The tree can be provided in the Welcome
+ message, in an extension of type ratchet_tree. If it is sent
+ otherwise (e.g., provided by a caching service on the Delivery
+ Service), then the client MUST download the tree before processing
+ the Welcome.
+
+ On receiving a Welcome message, a client processes it using the
+ following steps:
+
+ * Identify an entry in the secrets array where the new_member value
+ corresponds to one of this client's KeyPackages, using the hash
+ indicated by the cipher_suite field. If no such field exists, or
+ if the cipher suite indicated in the KeyPackage does not match the
+ one in the Welcome message, return an error.
+
+ * Decrypt the encrypted_group_secrets value with the algorithms
+ indicated by the cipher suite and the private key init_key_priv
+ corresponding to init_key in the referenced KeyPackage.
+
+ encrypted_group_secrets =
+ EncryptWithLabel(init_key, "Welcome",
+ encrypted_group_info, group_secrets)
+
+ group_secrets =
+ DecryptWithLabel(init_key_priv, "Welcome",
+ encrypted_group_info, kem_output, ciphertext)
+
+ * If a PreSharedKeyID is part of the GroupSecrets and the client is
+ not in possession of the corresponding PSK, return an error.
+ Additionally, if a PreSharedKeyID has type resumption with usage
+ reinit or branch, verify that it is the only such PSK.
+
+ * From the joiner_secret in the decrypted GroupSecrets object and
+ the PSKs specified in the GroupSecrets, derive the welcome_secret
+ and then the welcome_key and welcome_nonce. Use the key and nonce
+ to decrypt the encrypted_group_info field.
+
+ welcome_nonce = ExpandWithLabel(welcome_secret, "nonce", "", AEAD.Nn)
+ welcome_key = ExpandWithLabel(welcome_secret, "key", "", AEAD.Nk)
+
+ * Verify the signature on the GroupInfo object. The signature input
+ comprises all of the fields in the GroupInfo object except the
+ signature field. The public key is taken from the LeafNode of the
+ ratchet tree with leaf index signer. If the node is blank or if
+ signature verification fails, return an error.
+
+ * Verify that the group_id is unique among the groups that the
+ client is currently participating in.
+
+ * Verify that the cipher_suite in the GroupInfo matches the
+ cipher_suite in the KeyPackage.
+
+ * Verify the integrity of the ratchet tree.
+
+ - Verify that the tree hash of the ratchet tree matches the
+ tree_hash field in GroupInfo.
+
+ - For each non-empty parent node, verify that it is "parent-hash
+ valid", as described in Section 7.9.2.
+
+ - For each non-empty leaf node, validate the LeafNode as
+ described in Section 7.3.
+
+ - For each non-empty parent node and each entry in the node's
+ unmerged_leaves field:
+
+ o Verify that the entry represents a non-blank leaf node that
+ is a descendant of the parent node.
+
+ o Verify that every non-blank intermediate node between the
+ leaf node and the parent node also has an entry for the leaf
+ node in its unmerged_leaves.
+
+ o Verify that the encryption key in the parent node does not
+ appear in any other node of the tree.
+
+ * Identify a leaf whose LeafNode is identical to the one in the
+ KeyPackage. If no such field exists, return an error. Let
+ my_leaf represent this leaf in the tree.
+
+ * Construct a new group state using the information in the GroupInfo
+ object.
+
+ - Initialize the GroupContext for the group from the
+ group_context field from the GroupInfo object.
+
+ - Update the leaf my_leaf with the private key corresponding to
+ the public key in the node, where my_leaf is the new member's
+ leaf node in the ratchet tree, as defined above.
+
+ - If the path_secret value is set in the GroupSecrets object:
+ Identify the lowest common ancestor of the leaf node my_leaf
+ and of the node of the member with leaf index GroupInfo.signer.
+ Set the private key for this node to the private key derived
+ from the path_secret.
+
+ - For each parent of the common ancestor, up to the root of the
+ tree, derive a new path secret, and set the private key for the
+ node to the private key derived from the path secret. The
+ private key MUST be the private key that corresponds to the
+ public key in the node.
+
+ * Use the joiner_secret from the GroupSecrets object to generate the
+ epoch secret and other derived secrets for the current epoch.
+
+ * Set the confirmed transcript hash in the new state to the value of
+ the confirmed_transcript_hash in the GroupInfo.
+
+ * Verify the confirmation tag in the GroupInfo using the derived
+ confirmation key and the confirmed_transcript_hash from the
+ GroupInfo.
+
+ * Use the confirmed transcript hash and confirmation tag to compute
+ the interim transcript hash in the new state.
+
+ * If a PreSharedKeyID was used that has type resumption with usage
+ reinit or branch, verify that the epoch field in the GroupInfo is
+ equal to 1.
+
+ - For usage reinit, verify that the last Commit to the referenced
+ group contains a ReInit proposal and that the group_id,
+ version, cipher_suite, and group_context.extensions fields of
+ the GroupInfo match the ReInit proposal. Additionally, verify
+ that all the members of the old group are also members of the
+ new group, according to the application.
+
+ - For usage branch, verify that the version and cipher_suite of
+ the new group match those of the old group, and that the
+ members of the new group compose a subset of the members of the
+ old group, according to the application.
+
+12.4.3.2. Joining via External Commits
+
+ External Commits are a mechanism for new members (external parties
+ that want to become members of the group) to add themselves to a
+ group, without requiring that an existing member has to come online
+ to issue a Commit that references an Add proposal.
+
+ Whether existing members of the group will accept or reject an
+ external Commit follows the same rules that are applied to other
+ handshake messages.
+
+ New members can create and issue an external Commit if they have
+ access to the following information for the group's current epoch:
+
+ * group ID
+
+ * epoch ID
+
+ * cipher suite
+
+ * public tree hash
+
+ * confirmed transcript hash
+
+ * confirmation tag of the most recent Commit
+
+ * group extensions
+
+ * external public key
+
+ In other words, to join a group via an external Commit, a new member
+ needs a GroupInfo with an external_pub extension present in its
+ extensions field.
+
+ struct {
+ HPKEPublicKey external_pub;
+ } ExternalPub;
+
+ Thus, a member of the group can enable new clients to join by making
+ a GroupInfo object available to them. Note that because a GroupInfo
+ object is specific to an epoch, it will need to be updated as the
+ group advances. In particular, each GroupInfo object can be used for
+ one external join, since that external join will cause the epoch to
+ change.
+
+ Note that the tree_hash field is used the same way as in the Welcome
+ message. The full tree can be included via the ratchet_tree
+ extension (see Section 12.4.3.3).
+
+ The information in a GroupInfo is not generally public information,
+ but applications can choose to make it available to new members in
+ order to allow External Commits.
+
+ In principle, external Commits work like regular Commits. However,
+ their content has to meet a specific set of requirements:
+
+ * External Commits MUST contain a path field (and is therefore a
+ "full" Commit). The joiner is added at the leftmost free leaf
+ node (just as if they were added with an Add proposal), and the
+ path is calculated relative to that leaf node.
+
+ * The Commit MUST NOT include any proposals by reference, since an
+ external joiner cannot determine the validity of proposals sent
+ within the group.
+
+ * External Commits MUST be signed by the new member. In particular,
+ the signature on the enclosing AuthenticatedContent MUST verify
+ using the public key for the credential in the leaf_node of the
+ path field.
+
+ * When processing a Commit, both existing and new members MUST use
+ the external init secret as described in Section 8.3.
+
+ * The sender type for the AuthenticatedContent encapsulating the
+ external Commit MUST be new_member_commit.
+
+ External Commits come in two "flavors" -- a "join" Commit that adds
+ the sender to the group or a "resync" Commit that replaces a member's
+ prior appearance with a new one.
+
+ Note that the "resync" operation allows an attacker that has
+ compromised a member's signature private key to introduce themselves
+ into the group and remove the prior, legitimate member in a single
+ Commit. Without resync, this can still be done, but it requires two
+ operations: the external Commit to join and a second Commit to remove
+ the old appearance. Applications for whom this distinction is
+ salient can choose to disallow external commits that contain a
+ Remove, or to allow such resync commits only if they contain a
+ "reinit" PSK proposal that demonstrates the joining member's presence
+ in a prior epoch of the group. With the latter approach, the
+ attacker would need to compromise the PSK as well as the signing key,
+ but the application will need to ensure that continuing, non-
+ resynchronizing members have the required PSK.
+
+12.4.3.3. Ratchet Tree Extension
+
+ By default, a GroupInfo message only provides the joiner with a hash
+ of the group's ratchet tree. In order to process or generate
+ handshake messages, the joiner will need to get a copy of the ratchet
+ tree from some other source. (For example, the DS might provide a
+ cached copy.) The inclusion of the tree hash in the GroupInfo
+ message means that the source of the ratchet tree need not be trusted
+ to maintain the integrity of the tree.
+
+ In cases where the application does not wish to provide such an
+ external source, the whole public state of the ratchet tree can be
+ provided in an extension of type ratchet_tree, containing a
+ ratchet_tree object of the following form:
+
+ struct {
+ NodeType node_type;
+ select (Node.node_type) {
+ case leaf: LeafNode leaf_node;
+ case parent: ParentNode parent_node;
+ };
+ } Node;
+
+ optional<Node> ratchet_tree<V>;
+
+ Each entry in the ratchet_tree vector provides the value for a node
+ in the tree, or the null optional for a blank node.
+
+ The nodes are listed in the order specified by a left-to-right in-
+ order traversal of the ratchet tree. Each node is listed between its
+ left subtree and its right subtree. (This is the same ordering as
+ specified for the array-based trees outlined in Appendix C.)
+
+ If the tree has 2^d leaves, then it has 2^(d+1) - 1 nodes. The
+ ratchet_tree vector logically has this number of entries, but the
+ sender MUST NOT include blank nodes after the last non-blank node.
+ The receiver MUST check that the last node in ratchet_tree is non-
+ blank, and then extend the tree to the right until it has a length of
+ the form 2^(d+1) - 1, adding the minimum number of blank values
+ possible. (Obviously, this may be done "virtually", by synthesizing
+ blank nodes when required, as opposed to actually changing the
+ structure in memory.)
+
+ The leaves of the tree are stored in even-numbered entries in the
+ array (the leaf with index L in array position 2*L). The root node
+ of the tree is at position 2^d - 1 of the array. Intermediate parent
+ nodes can be identified by performing the same calculation to the
+ subarrays to the left and right of the root, following something like
+ the following algorithm:
+
+ # Assuming a class Node that has left and right members
+ def subtree_root(nodes):
+ # If there is only one node in the array, return it
+ if len(nodes) == 1:
+ return Node(nodes[0])
+
+ # Otherwise, the length of the array MUST be odd
+ if len(nodes) % 2 == 0:
+ raise Exception("Malformed node array {}", len(nodes))
+
+ # Identify the root of the subtree
+ d = 0
+ while (2**(d+1)) < len(nodes):
+ d += 1
+ R = 2**d - 1
+ root = Node(nodes[R])
+ root.left = subtree_root(nodes[:R])
+ root.right = subtree_root(nodes[(R+1):])
+ return root
+
+ (Note that this is the same ordering of nodes as in the array-based
+ tree representation described in Appendix C. The algorithms in that
+ section may be used to simplify decoding this extension into other
+ representations.)
+
+ For example, the following tree with six non-blank leaves would be
+ represented as an array of eleven elements, [A, W, B, X, C, _, D, Y,
+ E, Z, F]. The above decoding procedure would identify the subtree
+ roots as follows (using R to represent a subtree root):
+
+ Y
+ |
+ .-----+-----.
+ / \
+ X _
+ | |
+ .-+-. .-+-.
+ / \ / \
+ W _ Z _
+ / \ / \ / \ / \
+ A B C D E F _ _
+
+ 1
+ 0 1 2 3 4 5 6 7 8 9 0
+ <-----------> R <----------->
+ <---> R <---> <---> R <--->
+ - R - - R - - R - - R -
+
+ Figure 28: Left-to-Right In-Order Traversal of a Six-Member Tree
+
+ The presence of a ratchet_tree extension in a GroupInfo message does
+ not result in any changes to the GroupContext extensions for the
+ group. The ratchet tree provided is simply stored by the client and
+ used for MLS operations.
+
+ If this extension is not provided in a Welcome message, then the
+ client will need to fetch the ratchet tree over some other channel
+ before it can generate or process Commit messages. Applications
+ should ensure that this out-of-band channel is provided with security
+ protections equivalent to the protections that are afforded to
+ Proposal and Commit messages. For example, an application that
+ encrypts Proposal and Commit messages might distribute ratchet trees
+ encrypted using a key exchanged over the MLS channel.
+
+ Regardless of how the client obtains the tree, the client MUST verify
+ that the root hash of the ratchet tree matches the tree_hash of the
+ GroupContext before using the tree for MLS operations.
+
+13. Extensibility
+
+ The base MLS protocol can be extended in a few ways. New cipher
+ suites can be added to enable the use of new cryptographic
+ algorithms. New types of proposals can be used to perform new
+ actions within an epoch. Extension fields can be used to add
+ additional information to the protocol. In this section, we discuss
+ some constraints on these extensibility mechanisms that are necessary
+ to ensure broad interoperability.
+
+13.1. Additional Cipher Suites
+
+ As discussed in Section 5.1, MLS allows the participants in a group
+ to negotiate the cryptographic algorithms used within the group.
+ This extensibility is important for maintaining the security of the
+ protocol over time [RFC7696]. It also creates a risk of
+ interoperability failure due to clients not supporting a common
+ cipher suite.
+
+ The cipher suite registry defined in Section 17.1 attempts to strike
+ a balance on this point. On the one hand, the base policy for the
+ registry is Specification Required, a fairly low bar designed to
+ avoid the need for standards work in cases where different ciphers
+ are needed for niche applications. On the other hand, there is a
+ higher bar (Standards Action) for ciphers to set the Recommended
+ field in the registry. This higher bar is there in part to ensure
+ that the interoperability implications of new cipher suites are
+ considered.
+
+ MLS cipher suites are defined independent of MLS versions, so that in
+ principle, the same cipher suite can be used across versions.
+ Standards work defining new versions of MLS should consider whether
+ it is desirable for the new version to be compatible with existing
+ cipher suites, or whether the new version should rule out some cipher
+ suites. For example, a new version could follow the example of
+ HTTP/2, which restricted the set of allowed TLS ciphers (see
+ Section 9.2.2 of [RFC9113]).
+
+13.2. Proposals
+
+ Commit messages do not have an extension field because the set of
+ proposals is extensible. As discussed in Section 12.4, Proposals
+ with a non-default proposal type MUST NOT be included in a commit
+ unless the proposal type is supported by all the members of the group
+ that will process the Commit.
+
+13.3. Credential Extensibility
+
+ In order to ensure that MLS provides meaningful authentication, it is
+ important that each member is able to authenticate some identity
+ information for each other member. Identity information is encoded
+ in Credentials, so this property is provided by ensuring that members
+ use compatible credential types.
+
+ The only types of credential that may be used in a group are those
+ that all members of the group support, as specified by the
+ capabilities field of each LeafNode in the ratchet tree. An
+ application can introduce new credential types by choosing an
+ unallocated identifier from the registry in Section 17.5 and
+ indicating support for the credential type in published LeafNodes,
+ whether in Update proposals to existing groups or KeyPackages that
+ are added to new groups. Once all members in a group indicate
+ support for the credential type, members can start using LeafNodes
+ with the new credential. Application may enforce that certain
+ credential types always remain supported by adding a
+ required_capabilities extension to the group's GroupContext, which
+ would prevent any member from being added to the group that doesn't
+ support them.
+
+ In future extensions to MLS, it may be useful to allow a member to
+ present more than one credential. For example, such credentials
+ might present different attributes attested by different authorities.
+ To be consistent with the general principle stated at the beginning
+ of this section, such an extension would need to ensure that each
+ member can authenticate some identity for each other member. For
+ each pair of members (Alice, Bob), Alice would need to present at
+ least one credential of a type that Bob supports.
+
+13.4. Extensions
+
+ This protocol includes a mechanism for negotiating extension
+ parameters similar to the one in TLS [RFC8446]. In TLS, extension
+ negotiation is one-to-one: The client offers extensions in its
+ ClientHello message, and the server expresses its choices for the
+ session with extensions in its ServerHello and EncryptedExtensions
+ messages. In MLS, extensions appear in the following places:
+
+ * In KeyPackages, to describe additional information related to the
+ client
+
+ * In LeafNodes, to describe additional information about the client
+ or its participation in the group (once in the ratchet tree)
+
+ * In the GroupInfo, to tell new members of a group what parameters
+ are being used by the group, and to provide any additional details
+ required to join the group
+
+ * In the GroupContext object, to ensure that all members of the
+ group have the same view of the parameters in use
+
+ In other words, an application can use GroupContext extensions to
+ ensure that all members of the group agree on a set of parameters.
+ Clients indicate their support for parameters in the capabilities
+ field of their LeafNode. New members of a group are informed of the
+ group's GroupContext extensions via the extensions field in the
+ group_context field of the GroupInfo object. The extensions field in
+ a GroupInfo object (outside of the group_context field) can be used
+ to provide additional parameters to new joiners that are used to join
+ the group.
+
+ This extension mechanism is designed to allow for the secure and
+ forward-compatible negotiation of extensions. For this to work,
+ implementations MUST correctly handle extensible fields:
+
+ * A client that posts a KeyPackage MUST support all parameters
+ advertised in it. Otherwise, another client might fail to
+ interoperate by selecting one of those parameters.
+
+ * A client processing a KeyPackage object MUST ignore all
+ unrecognized values in the capabilities field of the LeafNode and
+ all unknown extensions in the extensions and leaf_node.extensions
+ fields. Otherwise, it could fail to interoperate with newer
+ clients.
+
+ * A client processing a GroupInfo object MUST ignore all
+ unrecognized extensions in the extensions field.
+
+ * Any field containing a list of extensions MUST NOT have more than
+ one extension of any given type.
+
+ * A client adding a new member to a group MUST verify that the
+ LeafNode for the new member is compatible with the group's
+ extensions. The capabilities field MUST indicate support for each
+ extension in the GroupContext.
+
+ * A client joining a group MUST verify that it supports every
+ extension in the GroupContext for the group. Otherwise, it MUST
+ treat the enclosing GroupInfo message as invalid and not join the
+ group.
+
+ Note that the latter two requirements mean that all MLS GroupContext
+ extensions are mandatory, in the sense that an extension in use by
+ the group MUST be supported by all members of the group.
+
+ The parameters of a group may be changed by sending a
+ GroupContextExtensions proposal to enable additional extensions
+ (Section 12.1.7), or by reinitializing the group (Section 11.2).
+
+13.5. GREASE
+
+ As described in Section 13.4, clients are required to ignore unknown
+ values for certain parameters. To help ensure that other clients
+ implement this behavior, a client can follow the "Generate Random
+ Extensions And Sustain Extensibility" or GREASE approach described in
+ [RFC8701]. In the context of MLS, this means that a client
+ generating a KeyPackage, LeafNode, or GroupInfo object includes
+ random values in certain fields which would be ignored by a correctly
+ implemented client processing the message. A client that incorrectly
+ rejects unknown code points will fail to process such a message,
+ providing a signal to its implementer that the client needs to be
+ fixed.
+
+ When generating the following fields, an MLS client SHOULD include a
+ random selection of values chosen from these GREASE values:
+
+ * LeafNode.capabilities.cipher_suites
+
+ * LeafNode.capabilities.extensions
+
+ * LeafNode.capabilities.proposals
+
+ * LeafNode.capabilities.credentials
+
+ * LeafNode.extensions
+
+ * KeyPackage.extensions
+
+ * GroupInfo.extensions
+
+ For the KeyPackage and GroupInfo extensions, the extension_data for
+ GREASE extensions MAY have any contents selected by the sender, since
+ they will be ignored by a correctly implemented receiver. For
+ example, a sender might populate these extensions with a randomly
+ sized amount of random data.
+
+ Note that any GREASE values added to LeafNode.extensions need to be
+ reflected in LeafNode.capabilities.extensions, since the LeafNode
+ validation process described in Section 7.3 requires that these two
+ fields be consistent.
+
+ GREASE values MUST NOT be sent in the following fields, because an
+ unsupported value in one these fields (including a GREASE value) will
+ cause the enclosing message to be rejected:
+
+ * Proposal.proposal_type
+
+ * Credential.credential_type
+
+ * GroupContext.extensions
+
+ * GroupContextExtensions.extensions
+
+ Values reserved for GREASE have been registered in the various
+ registries in Section 17. This prevents conflict between GREASE and
+ real future values. The following values are reserved in each
+ registry: 0x0A0A, 0x1A1A, 0x2A2A, 0x3A3A, 0x4A4A, 0x5A5A, 0x6A6A,
+ 0x7A7A, 0x8A8A, 0x9A9A, 0xAAAA, 0xBABA, 0xCACA, 0xDADA, and 0xEAEA.
+ (The value 0xFAFA falls within the private use range.) These values
+ MUST only appear in the fields listed above, and not, for example, in
+ the proposal_type field of a Proposal. Clients MUST NOT implement
+ any special processing rules for how to handle these values when
+ receiving them, since this negates their utility for detecting
+ extensibility failures.
+
+ GREASE values MUST be handled using normal logic for processing
+ unsupported values. When comparing lists of capabilities to identify
+ mutually supported capabilities, clients MUST represent their own
+ capabilities with a list containing only the capabilities actually
+ supported, without any GREASE values. In other words, lists
+ including GREASE values are only sent to other clients;
+ representations of a client's own capabilities MUST NOT contain
+ GREASE values.
+
+14. Sequencing of State Changes
+
+ Each Commit message is premised on a given starting state, indicated
+ by the epoch field of the enclosing FramedContent. If the changes
+ implied by a Commit message are made starting from a different state,
+ the results will be incorrect.
+
+ This need for sequencing is not a problem as long as each time a
+ group member sends a Commit message, it is based on the most current
+ state of the group. In practice, however, there is a risk that two
+ members will generate Commit messages simultaneously based on the
+ same state.
+
+ Applications MUST have an established way to resolve conflicting
+ Commit messages for the same epoch. They can do this either by
+ preventing conflicting messages from occurring in the first place, or
+ by developing rules for deciding which Commit out of several sent in
+ an epoch will be canonical. The approach chosen MUST minimize the
+ amount of time that forked or previous group states are kept in
+ memory, and promptly delete them once they're no longer necessary to
+ ensure forward secrecy.
+
+ The generation of Commit messages MUST NOT modify a client's state,
+ since the client doesn't know at that time whether the changes
+ implied by the Commit message will conflict with another Commit or
+ not. Similarly, the Welcome message corresponding to a Commit MUST
+ NOT be delivered to a new joiner until it's clear that the Commit has
+ been accepted.
+
+ Regardless of how messages are kept in sequence, there is a risk that
+ in a sufficiently busy group, a given member may never be able to
+ send a Commit message because they always lose to other members. The
+ degree to which this is a practical problem will depend on the
+ dynamics of the application.
+
+15. Application Messages
+
+ The primary purpose of handshake messages is to provide an
+ authenticated group key exchange to clients. In order to protect
+ application messages sent among the members of a group, the
+ encryption_secret provided by the key schedule is used to derive a
+ sequence of nonces and keys for message encryption. Every epoch
+ moves the key schedule forward, which triggers the creation of a new
+ secret tree, as described in Section 9, along with a new set of
+ symmetric ratchets of nonces and keys for each member.
+
+ Each client maintains their own local copy of the key schedule for
+ each epoch during which they are a group member. They derive new
+ keys, nonces, and secrets as needed while deleting old ones as soon
+ as they have been used.
+
+ The group identifier and epoch allow a recipient to know which group
+ secrets should be used and from which epoch_secret to start computing
+ other secrets. The sender identifier and content type are used to
+ identify which symmetric ratchet to use from the secret tree. The
+ generation counter determines how far into the ratchet to iterate in
+ order to produce the required nonce and key for encryption or
+ decryption.
+
+15.1. Padding
+
+ Application messages MAY be padded to provide some resistance against
+ traffic analysis techniques over encrypted traffic [CLINIC] [HCJ16].
+ While MLS might deliver the same payload less frequently across a lot
+ of ciphertexts than traditional web servers, it might still provide
+ the attacker enough information to mount an attack. If Alice asks
+ Bob "When are we going to the movie?", then the answer "Wednesday"
+ could be leaked to an adversary solely by the ciphertext length.
+
+ The length of the padding field in PrivateMessageContent can be
+ chosen by the sender at the time of message encryption. Senders may
+ use padding to reduce the ability of attackers outside the group to
+ infer the size of the encrypted content. Note, however, that the
+ transports used to carry MLS messages may have maximum message sizes,
+ so padding schemes SHOULD avoid increasing message size beyond any
+ such limits that exist in a given deployment scenario.
+
+15.2. Restrictions
+
+ During each epoch, senders MUST NOT encrypt more data than permitted
+ by the security bounds of the AEAD scheme used [CFRG-AEAD-LIMITS].
+
+ Note that each change to the group through a handshake message will
+ also set a new encryption_secret. Hence this change MUST be applied
+ before encrypting any new application message. This is required both
+ to ensure that any users removed from the group can no longer receive
+ messages and to (potentially) recover confidentiality and
+ authenticity for future messages despite a past state compromise.
+
+15.3. Delayed and Reordered Application Messages
+
+ Since each application message contains the group identifier, the
+ epoch, and a generation counter, a client can receive messages out of
+ order. When messages are received out of order, the client moves the
+ sender ratchet forward to match the received generation counter. Any
+ unused nonce and key pairs from the ratchet are potentially stored so
+ that they can be used to decrypt the messages that were delayed or
+ reordered.
+
+ Applications SHOULD define a policy on how long to keep unused nonce
+ and key pairs for a sender, and the maximum number to keep. This is
+ in addition to ensuring that these secrets are deleted according to
+ the deletion schedule defined in Section 9.2. Applications SHOULD
+ also define a policy limiting the maximum number of steps that
+ clients will move the ratchet forward in response to a new message.
+ Messages received with a generation counter that is too much higher
+ than the last message received would then be rejected. This avoids
+ causing a denial-of-service attack by requiring the recipient to
+ perform an excessive number of key derivations. For example, a
+ malicious group member could send a message with generation =
+ 0xffffffff at the beginning of a new epoch, forcing recipients to
+ perform billions of key derivations unless they apply limits of the
+ type discussed above.
+
+16. Security Considerations
+
+ The security goals of MLS are described in [MLS-ARCH]. We describe
+ here how the protocol achieves its goals at a high level, though a
+ complete security analysis is outside of the scope of this document.
+ The Security Considerations section of [MLS-ARCH] provides some
+ citations to detailed security analyses.
+
+16.1. Transport Security
+
+ Because MLS messages are protected at the message level, the
+ confidentiality and integrity of the group state do not depend on
+ those messages being protected in transit. However, an attacker who
+ can observe those messages in transit will be able to learn about the
+ group state, including potentially the group membership (see
+ Section 16.4.3 below). Such an attacker might also be able to mount
+ denial-of-service attacks on the group or exclude new members by
+ selectively removing messages in transit. In order to prevent this
+ form of attack, it is RECOMMENDED that all MLS messages be carried
+ over a secure transport such as TLS [RFC8446] or QUIC [RFC9000].
+
+16.2. Confidentiality of Group Secrets
+
+ Group secrets are partly derived from the output of a ratchet tree.
+ Ratchet trees work by assigning each member of the group to a leaf in
+ the tree and maintaining the following property: the private key of a
+ node in the tree is known only to members of the group that are
+ assigned a leaf in the node's subtree. This is called the _tree
+ invariant_, and it makes it possible to encrypt to all group members
+ except one, with a number of ciphertexts that is logarithmic in the
+ number of group members.
+
+ The ability to efficiently encrypt to all members except one allows
+ members to be securely removed from a group. It also allows a member
+ to rotate their key pair such that the old private key can no longer
+ be used to decrypt new messages.
+
+16.3. Confidentiality of Sender Data
+
+ The PrivateMessage framing encrypts "sender data" that identifies
+ which group member sent an encrypted message, as described in
+ Section 6.3.2. As with the QUIC header protection scheme [RFC9001],
+ Section 5.4, this scheme is a variant of the HN1 construction
+ analyzed in [NAN]. A sample of the ciphertext is combined with a
+ sender_data_secret to derive a key and nonce that are used for AEAD
+ encryption of the sender data.
+
+ (key, nonce) = PRF(sender_data_secret, sample)
+ encrypted_sender_data =
+ AEAD.Seal(key, nonce, sender_data_aad, sender_data)
+
+ The only differences between this construction and HN1 as described
+ in [NAN] are that it (1) uses authenticated encryption instead of
+ unauthenticated encryption and (2) protects information used to
+ derive a nonce instead of the nonce itself.
+
+ Since the sender_data_secret is distinct from the content encryption
+ key, it follows that the sender data encryption scheme achieves AE2
+ security as defined in [NAN], and therefore guarantees the
+ confidentiality of the sender data.
+
+ Use of the same sender_data_secret and ciphertext sample more than
+ once risks compromising sender data protection by reusing an AEAD
+ (key, nonce) pair. For example, in many AEAD schemes, reusing a key
+ and nonce reveals the exclusive OR of the two plaintexts. Assuming
+ the ciphertext output of the AEAD algorithm is indistinguishable from
+ random data (i.e., the AEAD is AE1-secure in the phrasing of [NAN]),
+ the odds of two ciphertext samples being identical is roughly
+ 2^(-L/2), i.e., the birthday bound.
+
+ The AEAD algorithms for cipher suites defined in this document all
+ provide this property. The size of the sample depends on the cipher
+ suite's hash function, but in all cases, the probability of collision
+ is no more than 2^-128. Any future cipher suite MUST use an
+ AE1-secure AEAD algorithm.
+
+16.4. Confidentiality of Group Metadata
+
+ MLS does not provide confidentiality protection to some messages and
+ fields within messages:
+
+ * KeyPackage messages
+
+ * GroupInfo messages
+
+ * The unencrypted portion of a Welcome message
+
+ * Any Proposal or Commit messages sent as PublicMessage messages
+
+ * The unencrypted header fields in PrivateMessage messages
+
+ * The lengths of encrypted Welcome and PrivateMessage messages
+
+ The only mechanism MLS provides for confidentially distributing a
+ group's ratchet tree to new members is to send it in a Welcome
+ message as a ratchet_tree extension. If an application distributes
+ the tree in some other way, its security will depend on that
+ application mechanism.
+
+ A party observing these fields might be able to infer certain
+ properties of the group:
+
+ * Group ID
+
+ * Current epoch and frequency of epoch changes
+
+ * Frequency of messages within an epoch
+
+ * Group extensions
+
+ * Group membership
+
+ The amount of metadata exposed to parties outside the group, and thus
+ the ability of these parties to infer the group's properties, depends
+ on several aspects of the DS design, such as:
+
+ * How KeyPackages are distributed
+
+ * How the ratchet tree is distributed
+
+ * How prospective external joiners get a GroupInfo object for the
+ group
+
+ * Whether Proposal and Commit messages are sent as PublicMessage or
+ PrivateMessage
+
+ In the remainder of this section, we note the ways that the above
+ properties of the group are reflected in unprotected group messages,
+ as a guide to understanding how they might be exposed or protected in
+ a given application.
+
+16.4.1. GroupID, Epoch, and Message Frequency
+
+ MLS provides no mechanism to protect the group ID and epoch of a
+ message from the DS, so the group ID and the frequency of messages
+ and epoch changes are not protected against inspection by the DS.
+ However, any modifications to these will cause decryption failure.
+
+16.4.2. Group Extensions
+
+ A group's extensions are first set by the group's creator and then
+ updated by GroupContextExtensions proposals. A
+ GroupContextExtensions proposal sent as a PublicMessage leaks the
+ group's extensions.
+
+ A new member learns the group's extensions via a GroupInfo object.
+ When the new member joins via a Welcome message, the Welcome
+ message's encryption protects the GroupInfo message. When the new
+ member joins via an external join, they must be provided with a
+ GroupInfo object. Protection of this GroupInfo object is up to the
+ application -- if it is transmitted over a channel that is not
+ confidential to the group and the new joiner, then it will leak the
+ group's extensions.
+
+16.4.3. Group Membership
+
+ The group's membership is represented directly by its ratchet tree,
+ since each member's LeafNode contains members' cryptographic keys, a
+ credential that contains information about the member's identity, and
+ possibly other identifiers. Applications that expose the group's
+ ratchet tree outside the group also leak the group's membership.
+
+ Changes to the group's membership are made by means of Add and Remove
+ proposals. If these proposals are sent as PublicMessage, then
+ information will be leaked about the corresponding changes to the
+ group's membership. A party that sees all of these changes can
+ reconstruct the group membership.
+
+ Welcome messages contain a hash of each KeyPackage for which the
+ Welcome message is encrypted. If a party has access to a pool of
+ KeyPackages and observes a Welcome message, then they can identify
+ the KeyPackage representing the new member. If the party can also
+ associate the Welcome with a group, then the party can infer that the
+ identified new member was added to that group.
+
+ Note that these information leaks reveal the group's membership only
+ to the degree that membership is revealed by the contents of a
+ member's LeafNode in the ratchet tree. In some cases, this may be
+ quite direct, e.g., due to credentials attesting to identifiers such
+ as email addresses. An application could construct a member's leaf
+ node to be less identifying, e.g., by using a pseudonymous credential
+ and frequently rotating encryption and signature keys.
+
+16.5. Authentication
+
+ The first form of authentication we provide is that group members can
+ verify a message originated from one of the members of the group.
+ For encrypted messages, this is guaranteed because messages are
+ encrypted with an AEAD under a key derived from the group secrets.
+ For plaintext messages, this is guaranteed by the use of a
+ membership_tag, which constitutes a MAC over the message, under a key
+ derived from the group secrets.
+
+ The second form of authentication is that group members can verify a
+ message originated from a particular member of the group. This is
+ guaranteed by a digital signature on each message from the sender's
+ signature key.
+
+ The signature keys held by group members are critical to the security
+ of MLS against active attacks. If a member's signature key is
+ compromised, then an attacker can create LeafNodes and KeyPackages
+ impersonating the member; depending on the application, this can then
+ allow the attacker to join the group with the compromised member's
+ identity. For example, if a group has enabled external parties to
+ join via external commits, then an attacker that has compromised a
+ member's signature key could use an external Commit to insert
+ themselves into the group -- even using a "resync"-style external
+ Commit to replace the compromised member in the group.
+
+ Applications can mitigate the risks of signature key compromise using
+ pre-shared keys. If a group requires joiners to know a PSK in
+ addition to authenticating with a credential, then in order to mount
+ an impersonation attack, the attacker would need to compromise the
+ relevant PSK as well as the victim's signature key. The cost of this
+ mitigation is that the application needs some external arrangement
+ that ensures that the legitimate members of the group have the
+ required PSKs.
+
+16.6. Forward Secrecy and Post-Compromise Security
+
+ Forward secrecy and post-compromise security are important security
+ notions for long-lived MLS groups. Forward secrecy means that
+ messages sent at a certain point in time are secure in the face of
+ later compromise of a group member. Post-compromise security means
+ that messages are secure even if a group member was compromised at
+ some point in the past.
+
+ Compromise
+ |
+ |
+ | V |
+ ------------------|---------|------------------------->
+ | | Time
+ <-----------------| |---------------->
+ Forward Secrecy | | Post-Compromise
+ | | Security
+
+ Figure 29: Forward Secrecy and Post-Compromise Security
+
+ Post-compromise security is provided between epochs by members
+ regularly updating their leaf key in the ratchet tree. Updating
+ their leaf key prevents group secrets from continuing to be encrypted
+ to public keys whose private keys had previously been compromised.
+ Note that sending an Update proposal does not achieve PCS until
+ another member includes it in a Commit. Members can achieve
+ immediate PCS by sending their own Commit and populating the path
+ field, as described in Section 12.4. To be clear, in all these
+ cases, the PCS guarantees come into effect when the members of the
+ group process the relevant Commit, not when the sender creates it.
+
+ Forward secrecy between epochs is provided by deleting private keys
+ from past versions of the ratchet tree, as this prevents old group
+ secrets from being re-derived. Forward secrecy _within_ an epoch is
+ provided by deleting message encryption keys once they've been used
+ to encrypt or decrypt a message. Note that group secrets and message
+ encryption keys are shared by the group. There is thus a risk to
+ forward secrecy as long as any member has not deleted these keys.
+ This is a particular risk if a member is offline for a long period of
+ time. Applications SHOULD have mechanisms for evicting group members
+ that are offline for too long (i.e., have not changed their key
+ within some period).
+
+ New groups are also at risk of using previously compromised keys (as
+ with post-compromise security) if a member is added to a new group
+ via an old KeyPackage whose corresponding private key has been
+ compromised. This risk can be mitigated by having clients regularly
+ generate new KeyPackages and upload them to the Delivery Service.
+ This way, the key material used to add a member to a new group is
+ more likely to be fresh and less likely to be compromised.
+
+16.7. Uniqueness of Ratchet Tree Key Pairs
+
+ The encryption and signature keys stored in the encryption_key and
+ signature_key fields of ratchet tree nodes MUST be distinct from one
+ another. If two members' leaf nodes have the same signature key, for
+ example, then the data origin authentication properties afforded by
+ signatures within the group are degraded.
+
+ Uniqueness of keys in leaf nodes is assured by explicitly checking
+ each leaf node as it is added to the tree, whether in an Add
+ proposal, in an Update proposal, or in the path field of a Commit.
+ Details can be found in Sections 7.3, 12.2, and 12.4.2. Uniqueness
+ of encryption keys in parent nodes is assured by checking that the
+ keys in an UpdatePath are not found elsewhere in the tree (see
+ Section 12.4.2).
+
+16.8. KeyPackage Reuse
+
+ KeyPackages are intended to be used only once. That is, once a
+ KeyPackage has been used to introduce the corresponding client to a
+ group, it SHOULD be deleted from the KeyPackage publication system.
+ Reuse of KeyPackages can lead to replay attacks.
+
+ An application MAY allow for reuse of a "last resort" KeyPackage in
+ order to prevent denial-of-service attacks. Since a KeyPackage is
+ needed to add a client to a new group, an attacker could prevent a
+ client from being added to new groups by exhausting all available
+ KeyPackages. To prevent such a denial-of-service attack, the
+ KeyPackage publication system SHOULD rate-limit KeyPackage requests,
+ especially if not authenticated.
+
+16.9. Delivery Service Compromise
+
+ MLS is designed to protect the confidentiality and integrity of the
+ group data even in the face of a compromised DS. However, a
+ compromised DS can still mount some attacks. While it cannot forge
+ messages, it can selectively delay or remove them. In some cases,
+ this can be observed by detecting gaps in the per-sender generation
+ counter, though it may not always be possible to distinguish an
+ attack from message loss. In addition, the DS can permanently block
+ messages to and from a group member. This will not always be
+ detectable by other members. If an application uses the DS to
+ resolve conflicts between simultaneous Commits (see Section 14), it
+ is also possible for the DS to influence which Commit is applied,
+ even to the point of preventing a member from ever having its Commits
+ applied.
+
+ When put together, these abilities potentially allow a DS to collude
+ with an attacker who has compromised a member's state to defeat PCS
+ by suppressing the valid Update and Commit messages from the member
+ that would lock out the attacker and update the member's leaf to a
+ new, uncompromised state. Aside from the SenderData.generation
+ value, MLS leaves loss detection up to the application.
+
+16.10. Authentication Service Compromise
+
+ Authentication Service compromise is much more serious than
+ compromise of the Delivery Service. A compromised AS can assert a
+ binding for a signature key and identity pair of its choice, thus
+ allowing impersonation of a given user. This ability is sufficient
+ to allow the AS to join new groups as if it were that user.
+ Depending on the application architecture, it may also be sufficient
+ to allow the compromised AS to join the group as an existing user,
+ for instance, as if it were a new device associated with the same
+ user. If the application uses a transparency mechanism such as
+ CONIKS [CONIKS] or Key Transparency [KT], then it may be possible for
+ end users to detect this kind of misbehavior by the AS. It is also
+ possible to construct schemes in which the various clients owned by a
+ user vouch for each other, e.g., by signing each others' keys.
+
+16.11. Additional Policy Enforcement
+
+ The DS and AS may also apply additional policies to MLS operations to
+ obtain additional security properties. For example, MLS enables any
+ participant to add or remove members of a group; a DS could enforce a
+ policy that only certain members are allowed to perform these
+ operations. MLS authenticates all members of a group; a DS could
+ help ensure that only clients with certain types of credentials are
+ admitted. MLS provides no inherent protection against denial of
+ service; a DS could also enforce rate limits in order to mitigate
+ these risks.
+
+16.12. Group Fragmentation by Malicious Insiders
+
+ It is possible for a malicious member of a group to "fragment" the
+ group by crafting an invalid UpdatePath. Recall that an UpdatePath
+ encrypts a sequence of path secrets to different subtrees of the
+ group's ratchet trees. These path secrets should be derived in a
+ sequence as described in Section 7.4, but the UpdatePath syntax
+ allows the sender to encrypt arbitrary, unrelated secrets. The
+ syntax also does not guarantee that the encrypted path secret for a
+ given node corresponds to the public key provided for that node.
+
+ Both of these types of corruption will cause processing of a Commit
+ to fail for some members of the group. If the public key for a node
+ does not match the path secret, then the members that decrypt that
+ path secret will reject the Commit based on this mismatch. If the
+ path secret sequence is incorrect at some point, then members that
+ can decrypt nodes before that point will compute a different public
+ key for the mismatched node than the one in the UpdatePath, which
+ also causes the Commit to fail. Applications SHOULD provide
+ mechanisms for failed commits to be reported, so that group members
+ who were not able to recognize the error themselves can reinitialize
+ the group if necessary.
+
+ Even with such an error reporting mechanism in place, however, it is
+ still possible for members to get locked out of the group by a
+ malformed Commit. Since malformed Commits can only be recognized by
+ certain members of the group, in an asynchronous application, it may
+ be the case that all members that could detect a fault in a Commit
+ are offline. In such a case, the Commit will be accepted by the
+ group, and the resulting state will possibly be used as the basis for
+ further Commits. When the affected members come back online, they
+ will reject the first Commit, and thus be unable to catch up with the
+ group. These members will need to either add themselves back with an
+ external Commit or reinitialize the group from scratch.
+
+ Applications can address this risk by requiring certain members of
+ the group to acknowledge successful processing of a Commit before the
+ group regards the Commit as accepted. The minimum set of
+ acknowledgements necessary to verify that a Commit is well-formed
+ comprises an acknowledgement from one member per node in the
+ UpdatePath, that is, one member from each subtree rooted in the
+ copath node corresponding to the node in the UpdatePath. MLS does
+ not provide a built-in mechanism for such acknowledgements, but they
+ can be added at the application layer.
+
+17. IANA Considerations
+
+ IANA has created the following registries:
+
+ * MLS Cipher Suites (Section 17.1)
+
+ * MLS Wire Formats (Section 17.2)
+
+ * MLS Extension Types (Section 17.3)
+
+ * MLS Proposal Types (Section 17.4)
+
+ * MLS Credential Types (Section 17.5)
+
+ * MLS Signature Labels (Section 17.6)
+
+ * MLS Public Key Encryption Labels (Section 17.7)
+
+ * MLS Exporter Labels (Section 17.8)
+
+ All of these registries are under the "Messaging Layer Security"
+ group registry heading, and assignments are made via the
+ Specification Required policy [RFC8126]. See Section 17.9 for
+ additional information about the MLS Designated Experts (DEs).
+
+17.1. MLS Cipher Suites
+
+ A cipher suite is a combination of a protocol version and the set of
+ cryptographic algorithms that should be used.
+
+ Cipher suite names follow the naming convention:
+
+ CipherSuite MLS_LVL_KEM_AEAD_HASH_SIG = VALUE;
+
+ Where VALUE is represented as a 16-bit integer:
+
+ uint16 CipherSuite;
+
+ +===========+==================================+
+ | Component | Contents |
+ +===========+==================================+
+ | LVL | The security level (in bits) |
+ +-----------+----------------------------------+
+ | KEM | The KEM algorithm used for HPKE |
+ | | in ratchet tree operations |
+ +-----------+----------------------------------+
+ | AEAD | The AEAD algorithm used for HPKE |
+ | | and message protection |
+ +-----------+----------------------------------+
+ | HASH | The hash algorithm used for HPKE |
+ | | and the MLS transcript hash |
+ +-----------+----------------------------------+
+ | SIG | The signature algorithm used for |
+ | | message authentication |
+ +-----------+----------------------------------+
+
+ Table 5
+
+ The columns in the registry are as follows:
+
+ * Value: The numeric value of the cipher suite
+
+ * Name: The name of the cipher suite
+
+ * Recommended: Whether support for this cipher suite is recommended
+ by the IETF. Valid values are "Y", "N", and "D", as described
+ below. The default value of the "Recommended" column is "N".
+ Setting the Recommended item to "Y" or "D", or changing an item
+ whose current value is "Y" or "D", requires Standards Action
+ [RFC8126].
+
+ - Y: Indicates that the IETF has consensus that the item is
+ RECOMMENDED. This only means that the associated mechanism is
+ fit for the purpose for which it was defined. Careful reading
+ of the documentation for the mechanism is necessary to
+ understand the applicability of that mechanism. The IETF could
+ recommend mechanisms that have limited applicability, but it
+ will provide applicability statements that describe any
+ limitations of the mechanism or necessary constraints on its
+ use.
+
+ - N: Indicates that the item has not been evaluated by the IETF
+ and that the IETF has made no statement about the suitability
+ of the associated mechanism. This does not necessarily mean
+ that the mechanism is flawed, only that no consensus exists.
+ The IETF might have consensus to leave an item marked as "N" on
+ the basis of it having limited applicability or usage
+ constraints.
+
+ - D: Indicates that the item is discouraged and SHOULD NOT or
+ MUST NOT be used. This marking could be used to identify
+ mechanisms that might result in problems if they are used, such
+ as a weak cryptographic algorithm or a mechanism that might
+ cause interoperability problems in deployment.
+
+ * Reference: The document where this cipher suite is defined
+
+ Initial contents:
+
+ +========+===================================================+=+====+
+ | Value |Name |R|Ref |
+ +========+===================================================+=+====+
+ | 0x0000 |RESERVED |-|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0001 |MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0002 |MLS_128_DHKEMP256_AES128GCM_SHA256_P256 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0003 |MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519|Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0004 |MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0005 |MLS_256_DHKEMP521_AES256GCM_SHA512_P521 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0006 |MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0007 |MLS_256_DHKEMP384_AES256GCM_SHA384_P384 |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x0A0A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x1A1A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x2A2A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x3A3A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x4A4A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x5A5A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x6A6A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x7A7A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x8A8A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0x9A9A |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xAAAA |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xBABA |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xCACA |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xDADA |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xEAEA |GREASE |Y|RFC |
+ | | | |9420|
+ +--------+---------------------------------------------------+-+----+
+ | 0xF000 |Reserved for Private Use |-|RFC |
+ | - | | |9420|
+ | 0xFFFF | | | |
+ +--------+---------------------------------------------------+-+----+
+
+ Table 6: MLS Extension Types Registry
+
+ All of the non-GREASE cipher suites use HMAC [RFC2104] as their MAC
+ function, with different hashes per cipher suite. The mapping of
+ cipher suites to HPKE primitives [RFC9180], HMAC hash functions, and
+ TLS signature schemes [RFC8446] is as follows:
+
+ +======+======+========+========+========+========================+
+ |Value |KEM | KDF | AEAD | Hash | Signature |
+ +======+======+========+========+========+========================+
+ |0x0001|0x0020| 0x0001 | 0x0001 | SHA256 | ed25519 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0002|0x0010| 0x0001 | 0x0001 | SHA256 | ecdsa_secp256r1_sha256 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0003|0x0020| 0x0001 | 0x0003 | SHA256 | ed25519 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0004|0x0021| 0x0003 | 0x0002 | SHA512 | ed448 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0005|0x0012| 0x0003 | 0x0002 | SHA512 | ecdsa_secp521r1_sha512 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0006|0x0021| 0x0003 | 0x0003 | SHA512 | ed448 |
+ +------+------+--------+--------+--------+------------------------+
+ |0x0007|0x0011| 0x0002 | 0x0002 | SHA384 | ecdsa_secp384r1_sha384 |
+ +------+------+--------+--------+--------+------------------------+
+
+ Table 7
+
+ The hash used for the MLS transcript hash is the one referenced in
+ the cipher suite name. In the cipher suites defined above, "SHA256",
+ "SHA384", and "SHA512" refer, respectively, to the SHA-256, SHA-384,
+ and SHA-512 functions defined in [SHS].
+
+ In addition to the general requirements of Section 13.1, future
+ cipher suites MUST meet the requirements of Section 16.3.
+
+ It is advisable to keep the number of cipher suites low to increase
+ the likelihood that clients can interoperate in a federated
+ environment. The cipher suites therefore include only modern, yet
+ well-established algorithms. Depending on their requirements,
+ clients can choose between two security levels (roughly 128-bit and
+ 256-bit). Within the security levels, clients can choose between
+ faster X25519/X448 curves and curves compliant with FIPS 140-2 for
+ Diffie-Hellman key negotiations. Clients may also choose
+ ChaCha20Poly1305 or AES-GCM, e.g., for performance reasons. Since
+ ChaCha20Poly1305 is not listed by FIPS 140-2, it is not paired with
+ curves compliant with FIPS 140-2. The security level of symmetric
+ encryption algorithms and hash functions is paired with the security
+ level of the curves.
+
+ The mandatory-to-implement cipher suite for MLS 1.0 is
+ MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519, which uses Curve25519
+ for key exchange, AES-128-GCM for HPKE, HKDF over SHA2-256, and
+ Ed25519 for signatures. MLS clients MUST implement this cipher
+ suite.
+
+17.2. MLS Wire Formats
+
+ The "MLS Wire Formats" registry lists identifiers for the types of
+ messages that can be sent in MLS. The wire format field is two bytes
+ wide, so the valid wire format values are in the range 0x0000 to
+ 0xFFFF.
+
+ Template:
+
+ * Value: The numeric value of the wire format
+
+ * Name: The name of the wire format
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this wire format is defined
+
+ Initial contents:
+
+ +=================+==========================+===+==========+
+ | Value | Name | R | Ref |
+ +=================+==========================+===+==========+
+ | 0x0000 | RESERVED | - | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0001 | mls_public_message | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0002 | mls_private_message | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0003 | mls_welcome | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0004 | mls_group_info | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0005 | mls_key_package | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xF000 - 0xFFFF | Reserved for Private Use | - | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+
+ Table 8: MLS Wire Formats Registry
+
+17.3. MLS Extension Types
+
+ The "MLS Extension Types" registry lists identifiers for extensions
+ to the MLS protocol. The extension type field is two bytes wide, so
+ valid extension type values are in the range 0x0000 to 0xFFFF.
+
+ Template:
+
+ * Value: The numeric value of the extension type
+
+ * Name: The name of the extension type
+
+ * Message(s): The messages in which the extension may appear, drawn
+ from the following list:
+
+ - KP: KeyPackage objects
+
+ - LN: LeafNode objects
+
+ - GC: GroupContext objects
+
+ - GI: GroupInfo objects
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this extension is defined
+
+ Initial contents:
+
+ +==========+=======================+============+===+==========+
+ | Value | Name | Message(s) | R | Ref |
+ +==========+=======================+============+===+==========+
+ | 0x0000 | RESERVED | N/A | - | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0001 | application_id | LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0002 | ratchet_tree | GI | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0003 | required_capabilities | GC | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0004 | external_pub | GI | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0005 | external_senders | GC | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x0A0A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x1A1A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x2A2A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x3A3A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x4A4A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x5A5A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x6A6A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x7A7A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x8A8A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0x9A9A | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xAAAA | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xBABA | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xCACA | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xDADA | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xEAEA | GREASE | KP, GI, LN | Y | RFC 9420 |
+ +----------+-----------------------+------------+---+----------+
+ | 0xF000 - | Reserved for Private | N/A | - | RFC 9420 |
+ | 0xFFFF | Use | | | |
+ +----------+-----------------------+------------+---+----------+
+
+ Table 9: MLS Extension Types Registry
+
+17.4. MLS Proposal Types
+
+ The "MLS Proposal Types" registry lists identifiers for types of
+ proposals that can be made for changes to an MLS group. The
+ extension type field is two bytes wide, so valid extension type
+ values are in the range 0x0000 to 0xFFFF.
+
+ Template:
+
+ * Value: The numeric value of the proposal type
+
+ * Name: The name of the proposal type
+
+ * Recommended: Same as in Section 17.1
+
+ * External: Whether a proposal of this type may be sent by an
+ external sender (see Section 12.1.8)
+
+ * Path Required: Whether a Commit covering a proposal of this type
+ is required to have its path field populated (see Section 12.4)
+
+ * Reference: The document where this extension is defined
+
+ Initial contents:
+
+ +==========+==========================+===+=====+======+==========+
+ | Value | Name | R | Ext | Path | Ref |
+ +==========+==========================+===+=====+======+==========+
+ | 0x0000 | RESERVED | - | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0001 | add | Y | Y | N | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0002 | update | Y | N | Y | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0003 | remove | Y | Y | Y | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0004 | psk | Y | Y | N | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0005 | reinit | Y | Y | N | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0006 | external_init | Y | N | Y | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0007 | group_context_extensions | Y | Y | Y | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x0A0A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x1A1A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x2A2A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x3A3A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x4A4A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x5A5A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x6A6A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x7A7A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x8A8A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0x9A9A | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xAAAA | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xBABA | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xCACA | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xDADA | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xEAEA | GREASE | Y | - | - | RFC 9420 |
+ +----------+--------------------------+---+-----+------+----------+
+ | 0xF000 - | Reserved for Private Use | - | - | - | RFC 9420 |
+ | 0xFFFF | | | | | |
+ +----------+--------------------------+---+-----+------+----------+
+
+ Table 10: MLS Proposal Types Registry
+
+17.5. MLS Credential Types
+
+ The "MLS Credential Types" registry lists identifiers for types of
+ credentials that can be used for authentication in the MLS protocol.
+ The credential type field is two bytes wide, so valid credential type
+ values are in the range 0x0000 to 0xFFFF.
+
+ Template:
+
+ * Value: The numeric value of the credential type
+
+ * Name: The name of the credential type
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this credential is defined
+
+ Initial contents:
+
+ +=================+==========================+===+==========+
+ | Value | Name | R | Ref |
+ +=================+==========================+===+==========+
+ | 0x0000 | RESERVED | - | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0001 | basic | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0002 | x509 | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x0A0A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x1A1A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x2A2A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x3A3A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x4A4A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x5A5A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x6A6A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x7A7A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x8A8A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0x9A9A | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xAAAA | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xBABA | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xCACA | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xDADA | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xEAEA | GREASE | Y | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+ | 0xF000 - 0xFFFF | Reserved for Private Use | - | RFC 9420 |
+ +-----------------+--------------------------+---+----------+
+
+ Table 11: MLS Credential Types Registry
+
+17.6. MLS Signature Labels
+
+ The SignWithLabel function defined in Section 5.1.2 avoids the risk
+ of confusion between signatures in different contexts. Each context
+ is assigned a distinct label that is incorporated into the signature.
+ The "MLS Signature Labels" registry records the labels defined in
+ this document and allows additional labels to be registered in case
+ extensions add other types of signatures using the same signature
+ keys used elsewhere in MLS.
+
+ Template:
+
+ * Label: The string to be used as the Label parameter to
+ SignWithLabel
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this label is defined
+
+ Initial contents:
+
+ +====================+===+==========+
+ | Label | R | Ref |
+ +====================+===+==========+
+ | "FramedContentTBS" | Y | RFC 9420 |
+ +--------------------+---+----------+
+ | "LeafNodeTBS" | Y | RFC 9420 |
+ +--------------------+---+----------+
+ | "KeyPackageTBS" | Y | RFC 9420 |
+ +--------------------+---+----------+
+ | "GroupInfoTBS" | Y | RFC 9420 |
+ +--------------------+---+----------+
+
+ Table 12: MLS Signature Labels
+ Registry
+
+17.7. MLS Public Key Encryption Labels
+
+ The EncryptWithLabel function defined in Section 5.1.3 avoids the
+ risk of confusion between ciphertexts produced for different purposes
+ in different contexts. Each context is assigned a distinct label
+ that is incorporated into the signature. The "MLS Public Key
+ Encryption Labels" registry records the labels defined in this
+ document and allows additional labels to be registered in case
+ extensions add other types of public key encryption using the same
+ HPKE keys used elsewhere in MLS.
+
+ Template:
+
+ * Label: The string to be used as the Label parameter to
+ EncryptWithLabel
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this label is defined
+
+ Initial contents:
+
+ +==================+===+==========+
+ | Label | R | Ref |
+ +==================+===+==========+
+ | "UpdatePathNode" | Y | RFC 9420 |
+ +------------------+---+----------+
+ | "Welcome" | Y | RFC 9420 |
+ +------------------+---+----------+
+
+ Table 13: MLS Public Key
+ Encryption Labels Registry
+
+17.8. MLS Exporter Labels
+
+ The exporter function defined in Section 8.5 allows applications to
+ derive key material from the MLS key schedule. Like the TLS exporter
+ [RFC8446], the MLS exporter uses a label to distinguish between
+ different applications' use of the exporter. The "MLS Exporter
+ Labels" registry allows applications to register their usage to avoid
+ collisions.
+
+ Template:
+
+ * Label: The string to be used as the Label parameter to MLS-
+ Exporter
+
+ * Recommended: Same as in Section 17.1
+
+ * Reference: The document where this label is defined
+
+ The registry has no initial contents, since it is intended to be used
+ by applications, not the core protocol. The table below is intended
+ only to show the column layout of the registry.
+
+ +=======+=============+===========+
+ | Label | Recommended | Reference |
+ +=======+=============+===========+
+ | (N/A) | (N/A) | (N/A) |
+ +-------+-------------+-----------+
+
+ Table 14: MLS Exporter Labels
+ Registry
+
+17.9. MLS Designated Expert Pool
+
+ Specification Required [RFC8126] registry requests are registered
+ after a three-week review period on the MLS Designated Expert (DE)
+ mailing list <mailto:mls-reg-review@ietf.org> on the advice of one or
+ more of the MLS DEs. However, to allow for the allocation of values
+ prior to publication, the MLS DEs may approve registration once they
+ are satisfied that such a specification will be published.
+
+ Registration requests sent to the MLS DEs' mailing list for review
+ SHOULD use an appropriate subject (e.g., "Request to register value
+ in MLS Bar registry").
+
+ Within the review period, the MLS DEs will either approve or deny the
+ registration request, communicating this decision to the MLS DEs'
+ mailing list and IANA. Denials SHOULD include an explanation and, if
+ applicable, suggestions as to how to make the request successful.
+ Registration requests that are undetermined for a period longer than
+ 21 days can be brought to the IESG's attention for resolution using
+ the <mailto:iesg@ietf.org> mailing list.
+
+ Criteria that SHOULD be applied by the MLS DEs includes determining
+ whether the proposed registration duplicates existing functionality,
+ whether it is likely to be of general applicability or useful only
+ for a single application, and whether the registration description is
+ clear. For example, for cipher suite registrations, the MLS DEs will
+ apply the advisory found in Section 17.1.
+
+ IANA MUST only accept registry updates from the MLS DEs and SHOULD
+ direct all requests for registration to the MLS DEs' mailing list.
+
+ It is suggested that multiple MLS DEs who are able to represent the
+ perspectives of different applications using this specification be
+ appointed, in order to enable a broadly informed review of
+ registration decisions. In cases where a registration decision could
+ be perceived as creating a conflict of interest for a particular MLS
+ DE, that MLS DE SHOULD defer to the judgment of the other MLS DEs.
+
+17.10. The "message/mls" Media Type
+
+ This document registers the "message/mls" media type in the "message"
+ registry in order to allow other protocols (e.g., HTTP [RFC9113]) to
+ convey MLS messages.
+
+ Type name: message
+
+ Subtype name: mls
+
+ Required parameters: none
+
+ Optional parameters: version
+
+ version: The MLS protocol version expressed as
+ a string <major>.<minor>. If omitted, the version is "1.0",
+ which corresponds to MLS ProtocolVersion mls10. If for some
+ reason the version number in the media type parameter differs
+ from the ProtocolVersion embedded in the protocol, the protocol
+ takes precedence.
+
+ Encoding considerations: MLS messages are represented using the TLS
+ presentation language [RFC8446]. Therefore, MLS messages need to
+ be treated as binary data.
+
+ Security considerations: MLS is an encrypted messaging layer
+ designed to be transmitted over arbitrary lower-layer protocols.
+ The security considerations in this document (RFC 9420) also
+ apply.
+
+ Interoperability considerations: N/A
+
+ Published specification: RFC 9420
+
+ Applications that use this media type: MLS-based messaging
+ applications
+
+ Fragment identifier considerations: N/A
+
+ Additional information:
+
+ Deprecated alias names for this type: N/A
+ Magic number(s): N/A
+ File extension(s): N/A
+ Macintosh file type code(s): N/A
+
+ Person & email address to contact for further information: IETF MLS
+ Working Group <mailto:mls@ietf.org>
+
+ Intended usage: COMMON
+
+ Restrictions on usage: N/A
+
+ Author: IETF MLS Working Group
+
+ Change controller: IETF
+
+18. References
+
+18.1. Normative References
+
+ [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
+ Hashing for Message Authentication", RFC 2104,
+ DOI 10.17487/RFC2104, February 1997,
+ <https://www.rfc-editor.org/info/rfc2104>.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119,
+ DOI 10.17487/RFC2119, March 1997,
+ <https://www.rfc-editor.org/info/rfc2119>.
+
+ [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
+ Writing an IANA Considerations Section in RFCs", BCP 26,
+ RFC 8126, DOI 10.17487/RFC8126, June 2017,
+ <https://www.rfc-editor.org/info/rfc8126>.
+
+ [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
+ 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
+ May 2017, <https://www.rfc-editor.org/info/rfc8174>.
+
+ [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
+ Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
+ <https://www.rfc-editor.org/info/rfc8446>.
+
+ [RFC9180] Barnes, R., Bhargavan, K., Lipp, B., and C. Wood, "Hybrid
+ Public Key Encryption", RFC 9180, DOI 10.17487/RFC9180,
+ February 2022, <https://www.rfc-editor.org/info/rfc9180>.
+
+18.2. Informative References
+
+ [ART] Cohn-Gordon, K., Cremers, C., Garratt, L., Millican, J.,
+ and K. Milner, "On Ends-to-Ends Encryption: Asynchronous
+ Group Messaging with Strong Security Guarantees", Version
+ 2.3, DOI 10.1145/3243734.3243747, March 2020,
+ <https://eprint.iacr.org/2017/666.pdf>.
+
+ [CFRG-AEAD-LIMITS]
+ Günther, F., Thomson, M., and C. A. Wood, "Usage Limits on
+ AEAD Algorithms", Work in Progress, Internet-Draft, draft-
+ irtf-cfrg-aead-limits-07, 31 May 2023,
+ <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-
+ aead-limits-07>.
+
+ [CLINIC] Miller, B., Huang, L., Joseph, A., and J. Tygar, "I Know
+ Why You Went to the Clinic: Risks and Realization of HTTPS
+ Traffic Analysis", Privacy Enhancing Technologies, pp.
+ 143-163, DOI 10.1007/978-3-319-08506-7_8, 2014,
+ <https://doi.org/10.1007/978-3-319-08506-7_8>.
+
+ [CONIKS] Melara, M. S., Blankstein, A., Bonneau, J., Felten, E. W.,
+ and M. J. Freedman, "CONIKS: Bringing Key Transparency to
+ End Users", Proceedings of the 24th USENIX Security
+ Symposium, ISBN 978-1-939133-11-3, August 2015,
+ <https://www.usenix.org/system/files/conference/
+ usenixsecurity15/sec15-paper-melara.pdf>.
+
+ [DoubleRatchet]
+ Cohn-Gordon, K., Cremers, C., Dowling, B., Garratt, L.,
+ and D. Stebila, "A Formal Security Analysis of the Signal
+ Messaging Protocol", 2017 IEEE European Symposium on
+ Security and Privacy (EuroS&P),
+ DOI 10.1109/eurosp.2017.27, April 2017,
+ <https://doi.org/10.1109/eurosp.2017.27>.
+
+ [HCJ16] Husák, M., Čermák, M., Jirsík, T., and P. Čeleda, "HTTPS
+ traffic analysis and client identification using passive
+ SSL/TLS fingerprinting", EURASIP Journal on Information
+ Security, Vol. 2016, Issue 1,
+ DOI 10.1186/s13635-016-0030-7, February 2016,
+ <https://doi.org/10.1186/s13635-016-0030-7>.
+
+ [KT] "Key Transparency Design Doc", commit fb0f87f, June 2020,
+ <https://github.com/google/keytransparency/blob/master/
+ docs/design.md>.
+
+ [MLS-ARCH] Beurdouche, B., Rescorla, E., Omara, E., Inguva, S., and
+ A. Duric, "The Messaging Layer Security (MLS)
+ Architecture", Work in Progress, Internet-Draft, draft-
+ ietf-mls-architecture-10, 16 December 2022,
+ <https://datatracker.ietf.org/doc/html/draft-ietf-mls-
+ architecture-10>.
+
+ [NAN] Bellare, M., Ng, R., and B. Tackmann, "Nonces Are Noticed:
+ AEAD Revisited", Advances in Cryptology - CRYPTO 2019, pp.
+ 235-265, DOI 10.1007/978-3-030-26948-7_9, August 2019,
+ <https://doi.org/10.1007/978-3-030-26948-7_9>.
+
+ [RFC5116] McGrew, D., "An Interface and Algorithms for Authenticated
+ Encryption", RFC 5116, DOI 10.17487/RFC5116, January 2008,
+ <https://www.rfc-editor.org/info/rfc5116>.
+
+ [RFC5905] Mills, D., Martin, J., Ed., Burbank, J., and W. Kasch,
+ "Network Time Protocol Version 4: Protocol and Algorithms
+ Specification", RFC 5905, DOI 10.17487/RFC5905, June 2010,
+ <https://www.rfc-editor.org/info/rfc5905>.
+
+ [RFC6125] Saint-Andre, P. and J. Hodges, "Representation and
+ Verification of Domain-Based Application Service Identity
+ within Internet Public Key Infrastructure Using X.509
+ (PKIX) Certificates in the Context of Transport Layer
+ Security (TLS)", RFC 6125, DOI 10.17487/RFC6125, March
+ 2011, <https://www.rfc-editor.org/info/rfc6125>.
+
+ [RFC7696] Housley, R., "Guidelines for Cryptographic Algorithm
+ Agility and Selecting Mandatory-to-Implement Algorithms",
+ BCP 201, RFC 7696, DOI 10.17487/RFC7696, November 2015,
+ <https://www.rfc-editor.org/info/rfc7696>.
+
+ [RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
+ Signature Algorithm (EdDSA)", RFC 8032,
+ DOI 10.17487/RFC8032, January 2017,
+ <https://www.rfc-editor.org/info/rfc8032>.
+
+ [RFC8701] Benjamin, D., "Applying Generate Random Extensions And
+ Sustain Extensibility (GREASE) to TLS Extensibility",
+ RFC 8701, DOI 10.17487/RFC8701, January 2020,
+ <https://www.rfc-editor.org/info/rfc8701>.
+
+ [RFC9000] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based
+ Multiplexed and Secure Transport", RFC 9000,
+ DOI 10.17487/RFC9000, May 2021,
+ <https://www.rfc-editor.org/info/rfc9000>.
+
+ [RFC9001] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure
+ QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021,
+ <https://www.rfc-editor.org/info/rfc9001>.
+
+ [RFC9113] Thomson, M., Ed. and C. Benfield, Ed., "HTTP/2", RFC 9113,
+ DOI 10.17487/RFC9113, June 2022,
+ <https://www.rfc-editor.org/info/rfc9113>.
+
+ [SHS] National Institute of Standards and Technology (NIST),
+ "Secure Hash Standard (SHS)", FIPS PUB 180-4,
+ DOI 10.6028/NIST.FIPS.180-4, August 2015,
+ <https://doi.org/10.6028/NIST.FIPS.180-4>.
+
+ [Signal] Perrin(ed), T. and M. Marlinspike, "The Double Ratchet
+ Algorithm", Revision 1, November 2016,
+ <https://www.signal.org/docs/specifications/
+ doubleratchet/>.
+
+Appendix A. Protocol Origins of Example Trees
+
+ Protocol operations in MLS give rise to specific forms of ratchet
+ tree, typically affecting a whole direct path at once. In this
+ section, we describe the protocol operations that could have given
+ rise to the various example trees in this document.
+
+ To construct the tree in Figure 11:
+
+ * A creates a group with B, ..., G
+
+ * F sends an empty Commit, setting X, Y, and W
+
+ * G removes C and D, blanking V, U, and setting Y and W
+
+ * B sends an empty Commit, setting T and W
+
+ To construct the tree in Figure 10:
+
+ * A creates a group with B, ..., H, as well as some members outside
+ this subtree
+
+ * F sends an empty Commit, setting Y and its ancestors
+
+ * D removes B and C, with the following effects:
+
+ - Blank the direct paths of B and C
+
+ - Set X, the top node, and any further nodes in the direct path
+ of D
+
+ * Someone outside this subtree removes G, blanking the direct path
+ of G
+
+ * A adds a new member at B with a partial Commit, adding B as
+ unmerged at X
+
+ To construct the tree in Figure 13:
+
+ * A creates a group with B, C, and D
+
+ * B sends a full Commit, setting X and Y
+
+ * D removes C, setting Z and Y
+
+ * B adds a new member at C with a full Commit
+
+ - The Add proposal adds C as unmerged at Z and Y
+
+ - The path in the Commit resets X and Y, clearing Y's unmerged
+ leaves
+
+ To construct the tree in Figure 21:
+
+ * A creates a group with B, ..., G
+
+ * A removes F in a full Commit, setting T, U, and W
+
+ * E sends an empty Commit, setting Y and W
+
+ * A adds a new member at F in a partial Commit, adding F as unmerged
+ at Y and W
+
+Appendix B. Evolution of Parent Hashes
+
+ To better understand how parent hashes are maintained, let's look in
+ detail at how they evolve in a small group. Consider the following
+ sequence of operations:
+
+ 1. A initializes a new group
+
+ 2. A adds B to the group with a full Commit
+
+ 3. B adds C and D to the group with a full Commit
+
+ 4. C sends an empty Commit
+
+ Y Y'
+ | |
+ .-+-. .-+-.
+ ==> ==> / \ ==> / \
+ X X' _=Z X' Z'
+ / \ / \ / \ / \ / \
+ A A B A B C D A B C D
+
+ Figure 30: Building a Four-Member Tree to Illustrate Parent Hashes
+
+ Then the parent hashes associated to the nodes will be updated as
+ follows (where we use the shorthand ph for parent hash, th for tree
+ hash, and osth for original sibling tree hash):
+
+ 1. A adds B: set X
+
+ * A.parent_hash = ph(X) = H(X, ph="", osth=th(B))
+
+ 2. B adds C, D: set B', X', and Y
+
+ * X'.parent_hash = ph(Y) = H(Y, ph="", osth=th(Z)), where th(Z)
+ covers (C, _, D)
+
+ * B'.parent_hash = ph(X') = H(X', ph=X'.parent_hash, osth=th(A))
+
+ 3. C sends empty Commit: set C', Z', Y'
+
+ * Z'.parent_hash = ph(Y') = H(Y', ph="", osth=th(X')), where
+ th(X') covers (A, X', B')
+
+ * C'.parent_hash = ph(Z') = H(Z', ph=Z'.parent_hash, osth=th(D))
+
+ When a new member joins, they will receive a tree that has the
+ following parent hash values and compute the indicated parent hash
+ validity relationships:
+
+ +======+======================================+=====================+
+ | Node | Parent Hash Value | Valid? |
+ +======+======================================+=====================+
+ | A | H(X, ph="", osth=th(B)) | No, B changed |
+ +------+--------------------------------------+---------------------+
+ | B' | H(X', ph=X'.parent_hash, osth=th(A)) | Yes |
+ +------+--------------------------------------+---------------------+
+ | C' | H(Z', ph=Z'.parent_hash, osth=th(D)) | Yes |
+ +------+--------------------------------------+---------------------+
+ | D | (none, never sent an UpdatePath) | N/A |
+ +------+--------------------------------------+---------------------+
+ | X' | H(Y, ph="", osth=th(Z)) | No, Y and Z |
+ | | | changed |
+ +------+--------------------------------------+---------------------+
+ | Z' | H(Y', ph="", osth=th(X')) | Yes |
+ +------+--------------------------------------+---------------------+
+
+ Table 15
+
+ In other words, the joiner will find the following path-hash links in
+ the tree:
+
+ Y'
+ |
+ +-.
+ \
+ X' Z'
+ \ /
+ A B' C' D
+
+ Figure 31: Parent-hash links connect all non-empty parent nodes
+ to leaves
+
+ Since these chains collectively cover all non-blank parent nodes in
+ the tree, the tree is parent-hash valid.
+
+ Note that this tree, though valid, contains invalid parent-hash
+ links. If a client were checking parent hashes top-down from Y', for
+ example, they would find that X' has an invalid parent hash relative
+ to Y', but that Z' has a valid parent hash. Likewise, if the client
+ were checking bottom-up, they would find that the chain from B' ends
+ in an invalid link from X' to Y'. These invalid links are the
+ natural result of multiple clients having committed.
+
+ Note also the way the tree hash and the parent hash interact. The
+ parent hash of node C' includes the tree hash of node D. The parent
+ hash of node Z' includes the tree hash of X', which covers nodes A
+ and B' (including the parent hash of B'). Although the tree hash and
+ the parent hash depend on each other, the dependency relationships
+ are structured so that there is never a circular dependency.
+
+ In the particular case where a new member first receives the tree for
+ a group (e.g., in a ratchet tree GroupInfo extension
+ Section 12.4.3.3), the parent hashes will be expressed in the tree
+ representation, but the tree hash need not be. Instead, the new
+ member will recompute the tree hashes for all the nodes in the tree,
+ verifying that this matches the tree hash in the GroupInfo object.
+ If the tree is valid, then the subtree hashes computed in this way
+ will align with the inputs needed for parent hash validation (except
+ where recomputation is needed to account for unmerged leaves).
+
+Appendix C. Array-Based Trees
+
+ One benefit of using complete balanced trees is that they admit a
+ simple flat array representation. In this representation, leaf nodes
+ are even-numbered nodes, with the n-th leaf at 2*n. Intermediate
+ nodes are held in odd-numbered nodes. For example, the tree with 8
+ leaves has the following structure:
+
+ X
+ |
+ .---------+---------.
+ / \
+ X X
+ | |
+ .---+---. .---+---.
+ / \ / \
+ X X X X
+ / \ / \ / \ / \
+ / \ / \ / \ / \
+ X X X X X X X X
+
+ Node: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+
+ Leaf: 0 1 2 3 4 5 6 7
+
+ Figure 32: An Eight-Member Tree Represented as an Array
+
+ This allows us to compute relationships between tree nodes simply by
+ manipulating indices, rather than having to maintain complicated
+ structures in memory. The basic rule is that the high-order bits of
+ parent and child nodes indices have the following relation (where x
+ is an arbitrary bit string):
+
+ parent=01x => left=00x, right=10x
+
+ Since node relationships are implicit, the algorithms for adding and
+ removing nodes at the right edge of the tree are quite simple. If
+ there are N nodes in the array:
+
+ * Add: Append N + 1 blank values to the end of the array.
+
+ * Remove: Truncate the array to its first (N-1) / 2 entries.
+
+ The following python code demonstrates the tree computations
+ necessary to use an array-based tree for MLS.
+
+ # The exponent of the largest power of 2 less than x. Equivalent to:
+ # int(math.floor(math.log(x, 2)))
+ def log2(x):
+ if x == 0:
+ return 0
+
+ k = 0
+ while (x >> k) > 0:
+ k += 1
+ return k-1
+
+ # The level of a node in the tree. Leaves are level 0, their parents
+ # are level 1, etc. If a node's children are at different levels,
+ # then its level is the max level of its children plus one.
+ def level(x):
+ if x & 0x01 == 0:
+ return 0
+
+ k = 0
+ while ((x >> k) & 0x01) == 1:
+ k += 1
+ return k
+
+ # The number of nodes needed to represent a tree with n leaves.
+ def node_width(n):
+ if n == 0:
+ return 0
+ else:
+ return 2*(n - 1) + 1
+
+ # The index of the root node of a tree with n leaves.
+ def root(n):
+ w = node_width(n)
+ return (1 << log2(w)) - 1
+
+ # The left child of an intermediate node.
+ def left(x):
+ k = level(x)
+ if k == 0:
+ raise Exception('leaf node has no children')
+
+ return x ^ (0x01 << (k - 1))
+
+ # The right child of an intermediate node.
+ def right(x):
+ k = level(x)
+ if k == 0:
+ raise Exception('leaf node has no children')
+
+ return x ^ (0x03 << (k - 1))
+
+ # The parent of a node.
+ def parent(x, n):
+ if x == root(n):
+ raise Exception('root node has no parent')
+
+ k = level(x)
+ b = (x >> (k + 1)) & 0x01
+ return (x | (1 << k)) ^ (b << (k + 1))
+
+ # The other child of the node's parent.
+ def sibling(x, n):
+ p = parent(x, n)
+ if x < p:
+ return right(p)
+ else:
+ return left(p)
+
+ # The direct path of a node, ordered from leaf to root.
+ def direct_path(x, n):
+ r = root(n)
+ if x == r:
+ return []
+
+ d = []
+ while x != r:
+ x = parent(x, n)
+ d.append(x)
+ return d
+
+ # The copath of a node, ordered from leaf to root.
+ def copath(x, n):
+ if x == root(n):
+ return []
+
+ d = direct_path(x, n)
+ d.insert(0, x)
+ d.pop()
+ return [sibling(y, n) for y in d]
+
+ # The common ancestor of two nodes is the lowest node that is in the
+ # direct paths of both leaves.
+ def common_ancestor_semantic(x, y, n):
+ dx = set([x]) | set(direct_path(x, n))
+ dy = set([y]) | set(direct_path(y, n))
+ dxy = dx & dy
+ if len(dxy) == 0:
+ raise Exception('failed to find common ancestor')
+
+ return min(dxy, key=level)
+
+ # The common ancestor of two nodes is the lowest node that is in the
+ # direct paths of both leaves.
+ def common_ancestor_direct(x, y, _):
+ # Handle cases where one is an ancestor of the other
+ lx, ly = level(x)+1, level(y)+1
+ if (lx <= ly) and (x>>ly == y>>ly):
+ return y
+ elif (ly <= lx) and (x>>lx == y>>lx):
+ return x
+
+ # Handle other cases
+ xn, yn = x, y
+ k = 0
+ while xn != yn:
+ xn, yn = xn >> 1, yn >> 1
+ k += 1
+ return (xn << k) + (1 << (k-1)) - 1
+
+Appendix D. Link-Based Trees
+
+ An implementation may choose to store ratchet trees in a "link-based"
+ representation, where each node stores references to its parents and/
+ or children (as opposed to the array-based representation suggested
+ above, where these relationships are computed from relationships
+ between nodes' indices in the array). Such an implementation needs
+ to update these links to maintain the balanced structure of the tree
+ as the tree is extended to add new members or truncated when members
+ are removed.
+
+ The following code snippet shows how these algorithms could be
+ implemented in Python.
+
+ class Node:
+ def __init__(self, value, left=None, right=None):
+ self.value = value # Value of the node
+ self.left = left # Left child node
+ self.right = right # Right child node
+
+ @staticmethod
+ def blank_subtree(depth):
+ if depth == 1:
+ return Node(None)
+
+ L = Node.blank_subtree(depth-1)
+ R = Node.blank_subtree(depth-1)
+ return Node(None, left=L, right=R)
+
+ def empty(self):
+ L_empty = (self.left == None) or self.left.empty()
+ R_empty = (self.right == None) or self.right.empty()
+ return (self.value == None) and L_empty and R_empty
+
+ class Tree:
+ def __init__(self):
+ self.depth = 0 # Depth of the tree
+ self.root = None # Root node of the tree, initially empty
+
+ # Add a blank subtree to the right
+ def extend(self):
+ if self.depth == 0:
+ self.depth = 1
+ self.root = Node(None)
+
+ L = self.root
+ R = Node.blank_subtree(self.depth)
+ self.root = Node(None, left=L, right=R)
+ self.depth += 1
+
+ # Truncate the right subtree
+ def truncate(self):
+ if self.root == None:
+ return
+
+ if not self.root.right.empty():
+ raise Exception("Cannot truncate non-blank subtree")
+
+ self.depth -= 1
+ self.root = self.root.left
+
+Contributors
+
+ Joel Alwen
+ Amazon
+ Email: alwenjo@amazon.com
+
+
+ Karthikeyan Bhargavan
+ Inria
+ Email: karthikeyan.bhargavan@inria.fr
+
+
+ Cas Cremers
+ CISPA
+ Email: cremers@cispa.de
+
+
+ Alan Duric
+ Wire
+ Email: alan@wire.com
+
+
+ Britta Hale
+ Naval Postgraduate School
+ Email: britta.hale@nps.edu
+
+
+ Srinivas Inguva
+ Email: singuva@yahoo.com
+
+
+ Konrad Kohbrok
+ Phoenix R&D
+ Email: konrad.kohbrok@datashrine.de
+
+
+ Albert Kwon
+ MIT
+ Email: kwonal@mit.edu
+
+
+ Tom Leavy
+ Amazon
+ Email: tomleavy@amazon.com
+
+
+ Brendan McMillion
+ Email: brendanmcmillion@gmail.com
+
+
+ Marta Mularczyk
+ Amazon
+ Email: mulmarta@amazon.com
+
+
+ Eric Rescorla
+ Mozilla
+ Email: ekr@rtfm.com
+
+
+ Michael Rosenberg
+ Trail of Bits
+ Email: michael.rosenberg@trailofbits.com
+
+
+ Théophile Wallez
+ Inria
+ Email: theophile.wallez@inria.fr
+
+
+ Thyla van der Merwe
+ Royal Holloway, University of London
+ Email: tjvdmerwe@gmail.com
+
+
+Authors' Addresses
+
+ Richard Barnes
+ Cisco
+ Email: rlb@ipv.sx
+
+
+ Benjamin Beurdouche
+ Inria & Mozilla
+ Email: ietf@beurdouche.com
+
+
+ Raphael Robert
+ Phoenix R&D
+ Email: ietf@raphaelrobert.com
+
+
+ Jon Millican
+ Meta Platforms
+ Email: jmillican@meta.com
+
+
+ Emad Omara
+ Email: emad.omara@gmail.com
+
+
+ Katriel Cohn-Gordon
+ University of Oxford
+ Email: me@katriel.co.uk