Network Working Group R. Barnes Internet-Draft Cisco Intended status: Informational B. Beurdouche Expires: 12 January 2023 Inria & Mozilla R. Robert J. Millican Facebook E. Omara Google K. Cohn-Gordon University of Oxford 11 July 2022 The Messaging Layer Security (MLS) Protocol draft-ietf-mls-protocol-16 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 and post-compromise security for groups in size ranging from two to thousands. Discussion Venues This note is to be removed before publishing as an RFC. Source for this draft and an issue tracker can be found at https://github.com/mlswg/mls-protocol (https://github.com/mlswg/mls- protocol). Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Barnes, et al. Expires 12 January 2023 [Page 1] Internet-Draft MLS July 2022 Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 12 January 2023. Copyright Notice Copyright (c) 2022 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 . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1. Change Log . . . . . . . . . . . . . . . . . . . . . . . 5 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.1. Presentation Language . . . . . . . . . . . . . . . . . . 14 2.1.1. Optional Value . . . . . . . . . . . . . . . . . . . 14 2.1.2. Variable-size Vector Headers . . . . . . . . . . . . 14 3. Operating Context . . . . . . . . . . . . . . . . . . . . . . 16 4. Protocol Overview . . . . . . . . . . . . . . . . . . . . . . 17 4.1. Cryptographic State and Evolution . . . . . . . . . . . . 18 4.2. Example Protocol Execution . . . . . . . . . . . . . . . 19 4.3. Relationships Between Epochs . . . . . . . . . . . . . . 23 5. Ratchet Tree Concepts . . . . . . . . . . . . . . . . . . . . 24 5.1. Ratchet Tree Terminology . . . . . . . . . . . . . . . . 25 5.1.1. Ratchet Tree Nodes . . . . . . . . . . . . . . . . . 26 5.1.2. Paths through a Ratchet Tree . . . . . . . . . . . . 27 5.2. Views of a Ratchet Tree . . . . . . . . . . . . . . . . . 28 6. Cryptographic Objects . . . . . . . . . . . . . . . . . . . . 30 6.1. Ciphersuites . . . . . . . . . . . . . . . . . . . . . . 30 6.2. Hash-Based Identifiers . . . . . . . . . . . . . . . . . 31 6.3. Credentials . . . . . . . . . . . . . . . . . . . . . . . 32 6.3.1. Credential Validation . . . . . . . . . . . . . . . . 33 6.3.2. Uniquely Identifying Clients . . . . . . . . . . . . 34 7. Message Framing . . . . . . . . . . . . . . . . . . . . . . . 35 7.1. Content Authentication . . . . . . . . . . . . . . . . . 38 7.2. Encoding and Decoding a Plaintext . . . . . . . . . . . . 40 Barnes, et al. Expires 12 January 2023 [Page 2] Internet-Draft MLS July 2022 7.3. Encoding and Decoding a Ciphertext . . . . . . . . . . . 41 7.3.1. Content Encryption . . . . . . . . . . . . . . . . . 41 7.3.2. Sender Data Encryption . . . . . . . . . . . . . . . 43 8. Ratchet Tree Operations . . . . . . . . . . . . . . . . . . . 44 8.1. Parent Node Contents . . . . . . . . . . . . . . . . . . 44 8.2. Leaf Node Contents . . . . . . . . . . . . . . . . . . . 44 8.3. Leaf Node Validation . . . . . . . . . . . . . . . . . . 47 8.4. Ratchet Tree Evolution . . . . . . . . . . . . . . . . . 49 8.5. Synchronizing Views of the Tree . . . . . . . . . . . . . 51 8.6. Update Paths . . . . . . . . . . . . . . . . . . . . . . 54 8.7. Adding and Removing Leaves . . . . . . . . . . . . . . . 55 8.8. Tree Hashes . . . . . . . . . . . . . . . . . . . . . . . 56 8.9. Parent Hashes . . . . . . . . . . . . . . . . . . . . . . 57 8.9.1. Using Parent Hashes . . . . . . . . . . . . . . . . . 60 8.9.2. Verifying Parent Hashes . . . . . . . . . . . . . . . 60 9. Key Schedule . . . . . . . . . . . . . . . . . . . . . . . . 61 9.1. Group Context . . . . . . . . . . . . . . . . . . . . . . 64 9.2. Transcript Hashes . . . . . . . . . . . . . . . . . . . . 66 9.3. External Initialization . . . . . . . . . . . . . . . . . 67 9.4. Pre-Shared Keys . . . . . . . . . . . . . . . . . . . . . 67 9.5. Exporters . . . . . . . . . . . . . . . . . . . . . . . . 70 9.6. Resumption PSK . . . . . . . . . . . . . . . . . . . . . 71 9.7. Epoch Authenticators . . . . . . . . . . . . . . . . . . 71 10. Secret Tree . . . . . . . . . . . . . . . . . . . . . . . . . 72 10.1. Encryption Keys . . . . . . . . . . . . . . . . . . . . 72 10.2. Deletion Schedule . . . . . . . . . . . . . . . . . . . 74 11. Key Packages . . . . . . . . . . . . . . . . . . . . . . . . 75 11.1. KeyPackage Validation . . . . . . . . . . . . . . . . . 77 12. Group Creation . . . . . . . . . . . . . . . . . . . . . . . 77 12.1. Required Capabilities . . . . . . . . . . . . . . . . . 79 12.2. Reinitialization . . . . . . . . . . . . . . . . . . . . 79 12.3. Subgroup Branching . . . . . . . . . . . . . . . . . . . 80 13. Group Evolution . . . . . . . . . . . . . . . . . . . . . . . 81 13.1. Proposals . . . . . . . . . . . . . . . . . . . . . . . 81 13.1.1. Add . . . . . . . . . . . . . . . . . . . . . . . . 82 13.1.2. Update . . . . . . . . . . . . . . . . . . . . . . . 83 13.1.3. Remove . . . . . . . . . . . . . . . . . . . . . . . 83 13.1.4. PreSharedKey . . . . . . . . . . . . . . . . . . . . 84 13.1.5. ReInit . . . . . . . . . . . . . . . . . . . . . . . 84 13.1.6. ExternalInit . . . . . . . . . . . . . . . . . . . . 85 13.1.7. GroupContextExtensions . . . . . . . . . . . . . . . 85 13.1.8. External Proposals . . . . . . . . . . . . . . . . . 86 13.2. Proposal List Validation . . . . . . . . . . . . . . . . 87 13.3. Applying a Proposal List . . . . . . . . . . . . . . . . 88 13.4. Commit . . . . . . . . . . . . . . . . . . . . . . . . . 89 13.4.1. Creating a Commit . . . . . . . . . . . . . . . . . 92 13.4.2. Processing a Commit . . . . . . . . . . . . . . . . 95 13.4.3. Adding Members to the Group . . . . . . . . . . . . 98 Barnes, et al. Expires 12 January 2023 [Page 3] Internet-Draft MLS July 2022 13.5. Ciphersuites . . . . . . . . . . . . . . . . . . . . . . 107 13.6. Proposals . . . . . . . . . . . . . . . . . . . . . . . 107 13.7. Credential Extensibility . . . . . . . . . . . . . . . . 107 13.8. Extensions . . . . . . . . . . . . . . . . . . . . . . . 108 14. Sequencing of State Changes . . . . . . . . . . . . . . . . . 110 15. Application Messages . . . . . . . . . . . . . . . . . . . . 110 15.1. Padding . . . . . . . . . . . . . . . . . . . . . . . . 111 15.2. Restrictions . . . . . . . . . . . . . . . . . . . . . . 111 15.3. Delayed and Reordered Application messages . . . . . . . 112 16. Security Considerations . . . . . . . . . . . . . . . . . . . 112 16.1. Confidentiality of the Group Secrets . . . . . . . . . . 112 16.2. Authentication . . . . . . . . . . . . . . . . . . . . . 113 16.3. Forward Secrecy and Post-Compromise Security . . . . . . 113 16.4. KeyPackage Reuse . . . . . . . . . . . . . . . . . . . . 114 16.5. Group Fragmentation by Malicious Insiders . . . . . . . 114 17. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 115 17.1. MLS Ciphersuites . . . . . . . . . . . . . . . . . . . . 115 17.2. MLS Extension Types . . . . . . . . . . . . . . . . . . 119 17.3. MLS Proposal Types . . . . . . . . . . . . . . . . . . . 120 17.4. MLS Credential Types . . . . . . . . . . . . . . . . . . 121 17.5. MLS Designated Expert Pool . . . . . . . . . . . . . . . 122 17.6. The "message/mls" MIME Type . . . . . . . . . . . . . . 123 18. References . . . . . . . . . . . . . . . . . . . . . . . . . 123 18.1. Normative References . . . . . . . . . . . . . . . . . . 123 18.2. Informative References . . . . . . . . . . . . . . . . . 124 Appendix A. Protocol Origins of Example Trees . . . . . . . . . 126 Appendix B. Evolution of Parent Hashes . . . . . . . . . . . . . 127 Appendix C. Array-Based Trees . . . . . . . . . . . . . . . . . 130 Appendix D. Link-Based Trees . . . . . . . . . . . . . . . . . . 133 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 136 1. Introduction DISCLAIMER: This is a work-in-progress draft of MLS and has not yet seen significant security analysis. It should not be used as a basis for building production systems. RFC EDITOR: PLEASE REMOVE THE FOLLOWING PARAGRAPH The source for this draft is maintained in GitHub. Suggested changes should be submitted as pull requests at https://github.com/mlswg/mls-protocol. Instructions are on that page as well. Editorial changes can be managed in GitHub, but any substantive change should be discussed on the MLS mailing list. 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 Barnes, et al. Expires 12 January 2023 [Page 4] Internet-Draft MLS July 2022 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 unilaterally broadcast symmetric "sender" keys over existing shared symmetric channels, and then for each member to send messages to the group encrypted with their own sender key. Unfortunately, while this improves efficiency over pairwise broadcast of individual messages and provides forward secrecy (with the addition of a hash ratchet), it is difficult to achieve post-compromise security with sender keys. 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 enable 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. 1.1. Change Log RFC EDITOR PLEASE DELETE THIS SECTION. draft-15 * Include ciphersuite in group context (*) * Add new new_proposal_member SenderType (*) * Always use a full tree (*) * Change KeyPackage identifier extension to be LeafNode identifier (*) * Use new tree for context in path secret encryption (*) * Use a hash function for hash identifiers (*) * Add a marker byte to tree hash input structs (*) Barnes, et al. Expires 12 January 2023 [Page 5] Internet-Draft MLS July 2022 * Recommend that group ids are generated randomly (*) * Update external senders extension to have SignaturePublicKey and Credential (*) * Replace LeafNodeRef with leaf index (*) * Remove AppAck proposal (*) * Make padding arbitrary-size and all-zero (*) * Require that unmerged_leaves be ordered * Derive the commit secret from the end of the UpdatePath, not the root * Specify the precise points in the protocol where credential validation must be done * Make PSK provisions more uniform, e.g., always generating a fresh random nonce * Improve parent hash guarantees with stricter checks on tree correctness * Streamline some structs, e.g., folding GroupContext into GroupInfo * Provide clearer rules for validating and applying commits * Clarify tree hash and parent hash, and correct examples * Clean up struct names and references to outdated structs * Cite AEAD limits draft draft-14 * Ensure that a signature public key is always intelligible (*) * Clean up terminology of derived secrets/keys * Fix parent hash (*) * Specify compatibility behavior around new credentials * Add Path Required to Proposal Type template * Sub-group branching requires fresh key packages for each member Barnes, et al. Expires 12 January 2023 [Page 6] Internet-Draft MLS July 2022 * Use aasvg and typed code blocks * Require init key and leaf key to be different * Preconfigured senders extension and removal of signature key indirection draft-13 * TLS syntax updates (including variable-header-length vectors) (*) * Stop generating redundant PKE key pairs. (*) * Move validation of identity change to the AS * Add message/mls MIME type registration * Split LeafNode from KeyPackage (*) * Remove endpoint_id (*) * Reorganize to make section layout more sane * Forbid proposals by reference in external commits (*) * Domain separation for KeyPackage and Proposal references (*) * Downgrade MUST to SHOULD for commit senders including all valid commits * Stronger parent hashes for authenticated identities (*) * Move wire_format to a separate tagged-union structure MLSMessage * Generalize tree extend/truncate algorithms * Add algorithms for link-based trees * Forbid self-Update entirely (*) * Consolidate resumption PSK cases (*) * 384 Ciphersuite Addition * Remove explicit version pin on HPKE (*) * Remove the requirement for Add in external commit (*) Barnes, et al. Expires 12 January 2023 [Page 7] Internet-Draft MLS July 2022 * Use smaller, fixed-size hash-based identifiers (*) * Be explicit that Credentials can attest to multiple identities (*) draft-12 * Use the GroupContext to derive the joiner_secret (*) * Make PreSharedKeys non optional in GroupSecrets (*) * Update name for this particular key (*) * Truncate tree size on removal (*) * Use HPKE draft-08 (*) * Clarify requirements around identity in MLS groups (*) * Signal the intended wire format for MLS messages (*) * Inject GroupContext as HPKE info instead of AAD (*) * Clarify extension handling and make extension updatable (*) * Improve extensibility of Proposals (*) * Constrain proposal in External Commit (*) * Remove the notion of a 'leaf index' (*) * Add group_context_extensions proposal ID (*) * Add RequiredCapabilities extension (*) * Use cascaded KDF instead of concatenation to consolidate PSKs (*) * Use key package hash to index clients in message structs (*) * Don't require PublicGroupState for external init (*) * Make ratchet tree section clearer. * Handle non-member sender cases in MLSPlaintextTBS * Clarify encoding of signatures with NIST curves * Remove OPEN ISSUEs and TODOs Barnes, et al. Expires 12 January 2023 [Page 8] Internet-Draft MLS July 2022 * Normalize the description of the zero vector draft-11 * Include subtree keys in parent hash (*) * Pin HPKE to draft-07 (*) * Move joiner secret to the end of the first key schedule epoch (*) * Add an AppAck proposal * Make initializations of transcript hashes consistent draft-10 * Allow new members to join via an external Commit (*) * Enable proposals to be sent inline in a Commit (*) * Re-enable constant-time Add (*) * Change expiration extension to lifetime extension (*) * Make the tree in the Welcome optional (*) * PSK injection, re-init, sub-group branching (*) * Require the initial init_secret to be a random value (*) * Remove explicit sender data nonce (*) * Do not encrypt to joiners in UpdatePath generation (*) * Move MLSPlaintext signature under the confirmation tag (*) * Explicitly authenticate group membership with MLSPLaintext (*) * Clarify X509Credential structure (*) * Remove unneeded interim transcript hash from GroupInfo (*) * IANA considerations * Derive an authentication secret * Use Extract/Expand from HPKE KDF Barnes, et al. Expires 12 January 2023 [Page 9] Internet-Draft MLS July 2022 * Clarify that application messages MUST be encrypted draft-09 * Remove blanking of nodes on Add (*) * Change epoch numbers to uint64 (*) * Add PSK inputs (*) * Add key schedule exporter (*) * Sign the updated direct path on Commit, using "parent hashes" and one signature per leaf (*) * Use structured types for external senders (*) * Redesign Welcome to include confirmation and use derived keys (*) * Remove ignored proposals (*) * Always include an Update with a Commit (*) * Add per-message entropy to guard against nonce reuse (*) * Use the same hash ratchet construct for both application and handshake keys (*) * Add more ciphersuites * Use HKDF to derive key pairs (*) * Mandate expiration of ClientInitKeys (*) * Add extensions to GroupContext and flesh out the extensibility story (*) * Rename ClientInitKey to KeyPackage draft-08 * Change ClientInitKeys so that they only refer to one ciphersuite (*) * Decompose group operations into Proposals and Commits (*) * Enable Add and Remove proposals from outside the group (*) Barnes, et al. Expires 12 January 2023 [Page 10] Internet-Draft MLS July 2022 * Replace Init messages with multi-recipient Welcome message (*) * Add extensions to ClientInitKeys for expiration and downgrade resistance (*) * Allow multiple Proposals and a single Commit in one MLSPlaintext (*) draft-07 * Initial version of the Tree based Application Key Schedule (*) * Initial definition of the Init message for group creation (*) * Fix issue with the transcript used for newcomers (*) * Clarifications on message framing and HPKE contexts (*) draft-06 * Reorder blanking and update in the Remove operation (*) * Rename the GroupState structure to GroupContext (*) * Rename UserInitKey to ClientInitKey * Resolve the circular dependency that draft-05 introduced in the confirmation MAC calculation (*) * Cover the entire MLSPlaintext in the transcript hash (*) draft-05 * Common framing for handshake and application messages (*) * Handshake message encryption (*) * Convert from literal state to a commitment via the "tree hash" (*) * Add credentials to the tree and remove the "roster" concept (*) * Remove the secret field from tree node values draft-04 * Updating the language to be similar to the Architecture document * ECIES is now renamed in favor of HPKE (*) Barnes, et al. Expires 12 January 2023 [Page 11] Internet-Draft MLS July 2022 * Using a KDF instead of a Hash in TreeKEM (*) draft-03 * Added ciphersuites and signature schemes (*) * Re-ordered fields in UserInitKey to make parsing easier (*) * Fixed inconsistencies between Welcome and GroupState (*) * Added encryption of the Welcome message (*) draft-02 * Removed ART (*) * Allowed partial trees to avoid double-joins (*) * Added explicit key confirmation (*) draft-01 * Initial description of the Message Protection mechanism. (*) * Initial specification proposal for the Application Key Schedule using the per-participant chaining of the Application Secret design. (*) * Initial specification proposal for an encryption mechanism to protect Application Messages using an AEAD scheme. (*) * Initial specification proposal for an authentication mechanism of Application Messages using signatures. (*) * Initial specification proposal for a padding mechanism to improving protection of Application Messages against traffic analysis. (*) * Inversion of the Group Init Add and Application Secret derivations in the Handshake Key Schedule to be ease chaining in case we switch design. (*) * Removal of the UserAdd construct and split of GroupAdd into Add and Welcome messages (*) * Initial proposal for authenticating handshake messages by signing over group state and including group state in the key schedule (*) Barnes, et al. Expires 12 January 2023 [Page 12] Internet-Draft MLS July 2022 * Added an appendix with example code for tree math * Changed the ECIES mechanism used by TreeKEM so that it uses nonces generated from the shared secret draft-00 * Initial adoption of draft-barnes-mls-protocol-01 as a WG item. 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, hence has access to the group's secrets. Key Package: A signed object describing a client's identity and capabilities, and including a hybrid public-key encryption (HPKE [RFC9180]) public key that can be used to encrypt to that client, and which other clients can use to introduce the client to a new group. Group Context: An object that summarizes the state of the group. The group context is signed to bind a message to a particular group, and also provided to new members to help them join a group. Signature Key: A signing key pair used to authenticate the sender of a message. Handshake Message: An MLSPlaintext or MLSCiphertext message carrying an MLS Proposal or Commit object, as opposed to application data. Barnes, et al. Expires 12 January 2023 [Page 13] Internet-Draft MLS July 2022 Application Message: An MLSCiphertext message carrying application data. Terminology specific to tree computations is described in Section 5.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 derive further secret values, and "key" to refer to a value that is used with an algorithm such as HMAC or an AEAD algorithm. 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; 2.1.2. Variable-size Vector 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 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: Barnes, et al. Expires 12 January 2023 [Page 14] Internet-Draft MLS July 2022 struct { uint32 fixed<0..255>; opaque variable; } 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, 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 on 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 "11" prefix are invalid and MUST be rejected. For example, the four byte sequence 0x9d7f3e7d decodes to 494878333; the two byte sequence 0x7bbd decodes to 15293; and the single byte 0x25 decodes to 37. The following figure adapts the pseudocode provided in [RFC9000] to add a check for minimum-length encoding: Barnes, et al. Expires 12 January 2023 [Page 15] Internet-Draft MLS July 2022 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 that the encoder used the minimum bits required if prefix >= 1 && v < (1 << (8*(1 << (prefix-1))-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. Operating Context MLS is designed to operate in the context described in [I-D.ietf-mls-architecture]. In particular, we assume that the following services are provided: * A Delivery Service that routes MLS messages among the participants in the protocol. The following types of delivery are typically required: - Pre-publication of KeyPackage objects for clients - Broadcast delivery of Proposal and Commit messages to members of a group - Unicast delivery of Welcome messages to new members of a group * An Authentication Service that enables group members to authenticate the credentials presented by other group members. Barnes, et al. Expires 12 January 2023 [Page 16] Internet-Draft MLS July 2022 4. Protocol Overview 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. 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. 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: An _MLSPlaintext_ message provides sender Barnes, et al. Expires 12 January 2023 [Page 17] Internet-Draft MLS July 2022 authentication for unencrypted Proposal and Commit messages. An _MLSCiphertext_ message provides encryption and authentication for both Proposal/Commit messages as well as any application data. 4.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. Barnes, et al. Expires 12 January 2023 [Page 18] Internet-Draft MLS July 2022 - 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., in the case of branching a subgroup. * 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 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 is a single corresponding Welcome message. The Welcome message provides all the 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. 4.2. Example Protocol Execution There are three major operations in the lifecycle of a group: * Adding a member, initiated by a current member; * Updating the leaf secret of a member; * Removing a member. Barnes, et al. Expires 12 January 2023 [Page 19] Internet-Draft MLS July 2022 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 MLSPlaintext or MLSCiphertext objects. Before the initialization of a group, clients publish KeyPackages to a directory provided by the Service Provider. Group A B C Directory Channel | | | | | | KeyPackageA | | | | +------------------------------------------------->| | | | | | | | | KeyPackageB | | | | +-------------------------------->| | | | | | | | | | KeyPackageC | | | | +--------------->| | | | | | | Figure 2: Clients A, B, and C publish KeyPackages to the directory When a client A wants to establish a group with 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 and Commit message adding that member, and broadcasts them to the group. It also generates a Welcome message and sends this 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 server does it update its state to reflect the new member's addition. Upon receiving the Welcome message, the new member will be able to read and send new messages to the group. However, messages sent before they were added to the group will not be accessible. Barnes, et al. Expires 12 January 2023 [Page 20] Internet-Draft MLS July 2022 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 and broadcast Add and Commit messages that the current group will use to update their state, and 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. 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 sender's prior leaf secret. Barnes, et al. Expires 12 January 2023 [Page 21] Internet-Draft MLS July 2022 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. 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. As a result, the keys for both B and A updated, so the group has post-compromise security with respect to both of them. Members are removed from the group in a similar way. 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 mechanism. Barnes, et al. Expires 12 January 2023 [Page 22] Internet-Draft MLS July 2022 Group A B ... Z Directory Channel | | | | | | | | Remove(B) | | | | | Commit(Rem) | | | | +---------------------------->| | | | | | | | | | Remove(B) | | | | | Commit(Rem) | |<----------------------------------------------------------+ | | |<----------------------------+ | | | | | Figure 5: Client Z removes client B from the group 4.3. 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. This link 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. 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 6: Reinitializing a group Barnes, et al. Expires 12 January 2023 [Page 23] Internet-Draft MLS July 2022 epoch_A_[n] epoch_B_[0] | | | PSK(usage=branch) | |....................>| | | V V epoch_A_[n+1] epoch_B_[1] Figure 7: Branching a group Applications may also choose to use resumption PSKs to link epochs in other ways. For example, the following figure 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 8: Reinjecting entropy from an earlier epoch 5. 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 Barnes, et al. Expires 12 January 2023 [Page 24] Internet-Draft MLS July 2022 log(N) encryptions, 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. 5.1. Ratchet Tree Terminology Trees consist of _nodes_. A node is a _leaf_ if it has no children, and a _parent_ otherwise; note that 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 parents, and _intermediate_ if it has both children and parents. The _descendants_ of a node are that node's children, and the descendants of its children, and 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 (respectively _right subtree_). 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. Appendix C and Appendix 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. Barnes, et al. Expires 12 January 2023 [Page 25] Internet-Draft MLS July 2022 5.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 asymmetric key pair with some associated data: * A public key (for the HPKE scheme in use, see Section 6.1) * A private key (only within the member's direct path, see Section 5.2) * A credential (only for leaf nodes) * An ordered list of "unmerged" leaves (see Section 5.2) * A hash of certain information about the node's parent, as of the last time the node was changed (see Section 8.9). 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 8.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 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: Barnes, et al. Expires 12 January 2023 [Page 26] Internet-Draft MLS July 2022 ... / _ ______|______ / \ X[B] _ __|__ __|__ / \ / \ _ _ Y _ / \ / \ / \ / \ A B _ D E F _ H 0 1 2 3 4 5 6 7 Figure 9: 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] 5.1.2. Paths through a Ratchet Tree The _direct path_ of a root is the empty list, and 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): Barnes, et al. Expires 12 January 2023 [Page 27] Internet-Draft MLS July 2022 W = root | .-----+-----. / \ _=U Y | | .-+-. .-+-. / \ / \ T _=V X _=Z / \ / \ / \ / \ A B _ _ E F G _=H 0 1 2 3 4 5 6 7 Figure 10: A complete tree with seven 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 5.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. Barnes, et al. Expires 12 January 2023 [Page 28] Internet-Draft MLS July 2022 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 keys of all the intermediate nodes they're below. Such a member has an _unmerged_ leaf. 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 when it is first added, because the process of adding the leaf does not give it access to all of the nodes above it in the tree. Leaves are "merged" as they receive the private keys for nodes, as described in Section 8.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, and the private key AB is known only to A and B. Barnes, et al. Expires 12 January 2023 [Page 29] Internet-Draft MLS July 2022 6. Cryptographic Objects 6.1. Ciphersuites Each MLS session uses a single ciphersuite 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 AEAD encryption algorithm * A hash algorithm * A MAC algorithm * A signature algorithm MLS uses HPKE for public-key encryption [RFC9180]. The DeriveKeyPair function associated to the KEM for the ciphersuite 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. Ciphersuites are represented with the CipherSuite type. HPKE public keys are opaque values in a format defined by the underlying protocol (see the Cryptographic Dependencies section of the HPKE specification for more information). opaque HPKEPublicKey; The signature algorithm specified in the ciphersuite is the mandatory algorithm to be used for signatures in MLSContentAuthData and the tree signatures. 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). Like HPKE public keys, signature public keys are represented as opaque values in a format defined by the ciphersuite's signature scheme. opaque SignaturePublicKey; Barnes, et al. Expires 12 January 2023 [Page 30] Internet-Draft MLS July 2022 For ciphersuites using Ed25519 or Ed448 signature schemes, the public key is in the format specified in [RFC8032]. For ciphersuites using ECDSA with the NIST curves (P-256, P-384, or P-521), the public key is the output of the uncompressed Elliptic-Curve-Point-to-Octet- String conversion according to [SECG]. 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 = "MLS 1.0 " + Label; opaque content = Content; } SignContent; Here, the functions Signature.Sign and Signature.Verify are defined by the signature algorithm. The ciphersuites are defined in section Section 17.1. 6.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; HashReference KeyPackageRef; HashReference ProposalRef; Barnes, et al. Expires 12 January 2023 [Page 31] Internet-Draft MLS July 2022 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 = label; opaque value = value; } RefHashInput; For a KeyPackageRef, the value input is the encoded KeyPackage, and the ciphersuite specified in the KeyPackage determines the KDF used. For a ProposalRef, the value input is the MLSAuthenticatedContent carrying the proposal. In the latter two cases, the KDF is determined by the group's ciphersuite. 6.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 identifier or 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. Barnes, et al. Expires 12 January 2023 [Page 32] Internet-Draft MLS July 2022 // See IANA registry for registered values uint16 CredentialType; struct { opaque cert_data; } Certificate; struct { CredentialType credential_type; select (Credential.credential_type) { case basic: opaque identity; case x509: Certificate chain; }; } Credential; A BasicCredential 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 chain represents a single DER-encoded X.509 certificate. The chain is ordered such that the first entry (chain[0]) is the end-entity certificate and each subsequent certificate in the chain MUST be the issuer of the previous 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. 6.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. Barnes, et al. Expires 12 January 2023 [Page 33] Internet-Draft MLS July 2022 The parts of the system that perform these functions are collectively referred to as the Authentication Service (AS) [I-D.ietf-mls-architecture]. A member's credential is said to be _validated with the AS_ when the AS verifies the credential's presented identifiers, and verifies 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, or an existing external_senders extension is updated. In cases where a member's credential is being replaced, such as 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. 6.3.2. 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. Barnes, et al. Expires 12 January 2023 [Page 34] Internet-Draft MLS July 2022 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; However, applications SHOULD 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. 7. 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 MLSAuthenticatedContent objects. These structures contain the content of the message itself as well as information to authenticate the sender (see Section 7.1). The additional protections required to transmit these messages over an untrusted channel (group membership authentication or AEAD encryption) are added by encoding the MLSAuthenticatedContent as an MLSPlaintext or MLSCiphertext message, which can then be sent as an MLSMessage. Likewise, these protections are enforced (via membership verification or AEAD decryption) when decoding an MLSPlaintext or MLSCiphertext into an MLSAuthenticatedContent object. MLSCiphertext represents a signed and encrypted message, with protections for both the content of the message and related metadata. MLSPlaintext represents a message that is only signed, and not encrypted. Applications MUST use MLSCiphertext to encrypt application messages and SHOULD use MLSCiphertext to encode handshake messages, but MAY transmit handshake messages encoded as MLSPlaintext objects in cases where it is necessary for the Delivery Service to examine such messages. Barnes, et al. Expires 12 January 2023 [Page 35] Internet-Draft MLS July 2022 enum { reserved(0), mls10(1), (255) } 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; enum { reserved(0), mls_plaintext(1), mls_ciphertext(2), mls_welcome(3), mls_group_info(4), mls_key_package(5), (255) } WireFormat; struct { opaque group_id; Barnes, et al. Expires 12 January 2023 [Page 36] Internet-Draft MLS July 2022 uint64 epoch; Sender sender; opaque authenticated_data; ContentType content_type; select (MLSContent.content_type) { case application: opaque application_data; case proposal: Proposal proposal; case commit: Commit commit; } } MLSContent; struct { ProtocolVersion version = mls10; WireFormat wire_format; select (MLSMessage.wire_format) { case mls_plaintext: MLSPlaintext plaintext; case mls_ciphertext: MLSCiphertext ciphertext; 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 MLSPlaintext. See Section 13.1.8 and Section 13.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; MLSContent content; MLSContentAuthData auth; } MLSAuthenticatedContent; 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: Barnes, et al. Expires 12 January 2023 [Page 37] Internet-Draft MLS July 2022 Proposal Commit Application Data | | | +--------------+--------------+ | V MLSContent | | -. | | | +--------+ | | | | | V | +-- Asymmetric MLSContentAuthData | | Sign / Verify | | | +--------+ | | | | | V V -' MLSAuthenticatedContent | -. | | | | +--------+--------+ +-- Symmetric | | | Protect / Unprotect V V | Welcome KeyPackage GroupInfo MLSPlaintext MLSCiphertext -' | | | | | | | | | | +----------+----------+----+--------+-----------------+ | V MLSMessage 7.1. Content Authentication MLSContent is authenticated using the MLSContentAuthData structure. Barnes, et al. Expires 12 January 2023 [Page 38] Internet-Draft MLS July 2022 struct { ProtocolVersion version = mls10; WireFormat wire_format; MLSContent content; select (MLSContentTBS.content.sender.sender_type) { case member: case new_member_commit: GroupContext context; case external: case new_member_proposal: struct{}; } } MLSContentTBS; opaque MAC; struct { // SignWithLabel(., "MLSContentTBS", MLSContentTBS) opaque signature; select (MLSContent.content_type) { case commit: // MAC(confirmation_key, // GroupContext.confirmed_transcript_hash) MAC confirmation_tag; case application: case proposal: struct{}; } } MLSContentAuthData; The signature is computed using SignWithLabel with label "MLSContentTBS" 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 13.1.8.1). The content_type of the message MUST be proposal. Barnes, et al. Expires 12 January 2023 [Page 39] Internet-Draft MLS July 2022 * new_member_commit: The signature key in the LeafNode in the Commit's path (see Section 13.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 proposaland 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 MLSContentAuthData is said to be valid when both the signature and confirmation_tag fields are valid. 7.2. Encoding and Decoding a Plaintext Plaintexts are encoded using the MLSPlaintext structure. struct { MLSContent content; MLSContentAuthData auth; select (MLSPlaintext.content.sender.sender_type) { case member: MAC membership_tag; case external: case new_member_commit: case new_member_proposal: struct{}; } } MLSPlaintext; The membership_tag field in the MLSPlaintext object authenticates the sender's membership in the group. For messages sent by members, it MUST be set to the following value: struct { MLSContentTBS content_tbs; MLSContentAuthData auth; } MLSContentTBM; membership_tag = MAC(membership_key, MLSContentTBM) When decoding an MLSPlaintext into an MLSAuthenticatedContent, the application MUST check membership_tag and MUST check that the MLSContentAuthData is valid. Barnes, et al. Expires 12 January 2023 [Page 40] Internet-Draft MLS July 2022 7.3. Encoding and Decoding a Ciphertext Ciphertexts are encoded using the MLSCiphertext structure. struct { opaque group_id; uint64 epoch; ContentType content_type; opaque authenticated_data; opaque encrypted_sender_data; opaque ciphertext; } MLSCiphertext; encrypted_sender_data and ciphertext are encrypted using the AEAD function specified by the ciphersuite in use, using as input the structures MLSSenderData and MLSCiphertextContent. 7.3.1. Content Encryption The ciphertext content is encoded using the MLSCiphertextContent structure. struct { select (MLSCiphertext.content_type) { case application: opaque application_data; case proposal: Proposal proposal; case commit: Commit commit; } MLSContentAuthData auth; opaque padding[length_of_padding]; } MLSCiphertextContent; The padding field is set by the sender, by first encoding the content (via the select) and the auth field, then appending the chosen number of zero bytes. A receiver identifies the padding field in a plaintext decoded from MLSCiphertext.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 MLSCiphertext MUST be rejected as malformed. Barnes, et al. Expires 12 January 2023 [Page 41] Internet-Draft MLS July 2022 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 or 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; uint64 epoch; ContentType content_type; opaque authenticated_data; } MLSCiphertextContentAAD; When decoding an MLSCiphertextContent, the application MUST check that the MLSContentAuthData is valid. Barnes, et al. Expires 12 January 2023 [Page 42] Internet-Draft MLS July 2022 7.3.2. Sender Data Encryption The "sender data" used to look up the key for content encryption is encrypted with the ciphersuite'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]; } MLSSenderData; When constructing an MLSSenderData from a Sender object, the sender MUST verify Sender.sender_type is member and use Sender.leaf_index for MLSSenderData.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 7.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 Additional Authenticated Data (AAD) for the SenderData ciphertext is the first three fields of MLSCiphertext: struct { opaque group_id; uint64 epoch; ContentType content_type; } MLSSenderDataAAD; 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. Barnes, et al. Expires 12 January 2023 [Page 43] Internet-Draft MLS July 2022 8. 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. 8.1. Parent Node Contents As discussed in Section 5.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; uint32 unmerged_leaves; } 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 8.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. 8.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; Barnes, et al. Expires 12 January 2023 [Page 44] Internet-Draft MLS July 2022 CipherSuite ciphersuites; ExtensionType extensions; ProposalType proposals; CredentialType credentials; } Capabilities; struct { uint64 not_before; uint64 not_after; } Lifetime; // See IANA registry for registered values uint16 ExtensionType; struct { ExtensionType extension_type; opaque extension_data; } 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; } Extension extensions; // SignWithLabel(., "LeafNodeTBS", LeafNodeTBS) opaque signature; } LeafNode; struct { HPKEPublicKey encryption_key; SignaturePublicKey signature_key; Credential credential; Capabilities capabilities; Barnes, et al. Expires 12 January 2023 [Page 45] Internet-Draft MLS July 2022 LeafNodeSource leaf_node_source; select (LeafNodeTBS.leaf_node_source) { case key_package: Lifetime lifetime; case update: struct{}; case commit: opaque parent_hash; } Extension extensions; select (LeafNodeTBS.leaf_node_source) { case key_package: struct{}; case update: opaque group_id; case commit: opaque group_id; } } 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 6.3. The capabilities field indicates what protocol versions, ciphersuites, extensions, credential types, and non-default proposal types are supported by a client. Proposal and extension types defined in this document are considered "default" and thus need not be listed, while any credential types the application wishes to use MUST be listed. 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. 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. Barnes, et al. Expires 12 January 2023 [Page 46] Internet-Draft MLS July 2022 Whether these fields can be computed by the client represented by the LeafNode depends on when the LeafNode was created. 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 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 8.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. 8.3. Leaf Node Validation The validity of a LeafNode needs to be verified at a few 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 6.3.1. Barnes, et al. Expires 12 January 2023 [Page 47] Internet-Draft MLS July 2022 * 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. * 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. - 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 Barnes, et al. Expires 12 January 2023 [Page 48] Internet-Draft MLS July 2022 8.4. Ratchet Tree Evolution Whenever a member initiates an epoch change (i.e., commits; see Section 13.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 8.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: Barnes, et al. Expires 12 January 2023 [Page 49] Internet-Draft MLS July 2022 Y | .-+-. / \ X Z[C] / \ / \ A B C D 0 1 2 3 Figure 11: 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 After applying the UpdatePath, the tree will have the following structure, where lp and np[i] represent the leaf_priv and node_priv values generated as described above: node_priv[1] --------> Y' | .-+-. / \ node_priv[0] ----> X' Z[C] / \ / \ A B C D ^ leaf_priv -----------+ 0 1 2 3 Barnes, et al. Expires 12 January 2023 [Page 50] Internet-Draft MLS July 2022 8.5. Synchronizing Views of the Tree After generating fresh key material and applying it to ratchet forward their local tree state as described in the Section 8.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: 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 8.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. Barnes, et al. Expires 12 January 2023 [Page 51] Internet-Draft MLS July 2022 * 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 8.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. Barnes, et al. Expires 12 January 2023 [Page 52] Internet-Draft MLS July 2022 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 8.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. Barnes, et al. Expires 12 January 2023 [Page 53] Internet-Draft MLS July 2022 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 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. 8.6. Update Paths As described in Section 13.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; opaque ciphertext; } HPKECiphertext; struct { HPKEPublicKey encryption_key; HPKECiphertext encrypted_path_secret; } UpdatePathNode; struct { LeafNode leaf_node; UpdatePathNode nodes; } 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 computed as kem_output, context = SetupBaseS(node_public_key, group_context) ciphertext = context.Seal("", path_secret) Barnes, et al. Expires 12 January 2023 [Page 54] Internet-Draft MLS July 2022 where node_public_key is the public key of the node that the path secret is being encrypted for, group_context is the provisional GroupContext object for the group, and the functions SetupBaseS and Seal are defined according to [RFC9180]. Decryption is performed in the corresponding way, using the private key of the resolution node. context = SetupBaseR(kem_output, node_private_key, group_context) path_secret = context.Open("", ciphertext) 8.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 Section 13.1.1 and Section 13.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 12: 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. Barnes, et al. Expires 12 January 2023 [Page 55] Internet-Draft MLS July 2022 Y Y __|__ __|__ / \ / \ X _ ===> X _ ==> X <-- new root / \ / \ / \ / \ / \ A B C _ A B _ _ A B ^ | removed member --+ Figure 13: Cleaning up after removing the third member Concrete algorithms for these operations on array-based and link- based trees are provided in Appendix C and Appendix D. The concrete algorithms are non-normative. An implementation MAY use any algorithm that produces the correct tree in its internal representation. 8.8. Tree Hashes MLS hashes the contents of the tree in two ways to authenticate different properties of the tree. This section defines _tree hashes_, and _parent hashes_ are defined in Section 8.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) 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. Barnes, et al. Expires 12 January 2023 [Page 56] Internet-Draft MLS July 2022 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 leaf_node; } LeafNodeHashInput; struct { optional parent_node; opaque left_hash; opaque right_hash; } 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. 8.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 8.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. Barnes, et al. Expires 12 January 2023 [Page 57] Internet-Draft MLS July 2022 ph(Q) / / V P.public_key --> ph(P) / ^ / \ V \ N.parent_hash th(S) 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 14: Inputs to a parent hash. 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; opaque original_sibling_tree_hash; } 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 Barnes, et al. Expires 12 January 2023 [Page 58] Internet-Draft MLS July 2022 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 8.5). For example, in the following tree: W [F] ______|_____ / \ U Y [F] __|__ __|__ / \ / \ T _ _ _ / \ / \ / \ / \ A B C D E F G _ Figure 15: 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 _ Barnes, et al. Expires 12 January 2023 [Page 59] Internet-Draft MLS July 2022 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 is 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. 8.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 14, 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 also attests to which keys the group member introduced into the ratchet tree and to whom the corresponding secret keys were sent. 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. 8.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 the other child: Barnes, et al. Expires 12 January 2023 [Page 60] Internet-Draft MLS July 2022 * 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: 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. 9. Key Schedule Group keys are derived using the Extract and Expand functions from the KDF for the group's ciphersuite, 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: Barnes, et al. Expires 12 January 2023 [Page 61] Internet-Draft MLS July 2022 struct { uint16 length = Length; opaque label = "MLS 1.0 " + Label; opaque context = Context; } KDFLabel; 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 Key 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: Barnes, et al. Expires 12 January 2023 [Page 62] Internet-Draft MLS July 2022 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(.,