Draft: draft-ietf-mls-protocol

Commentary: The specification currently assumes that a Credential provides a singular identity for a client , when in reality that is not the case . For example , X509Credential can provide a whole collection of identities , and it 's up to the application to decide if its preferred identity is among them . Just like in TLS , a server can send a cert with 100 domains , but the TLS client knows which one it 's looking for . This PR refactors the parts of the spec that refer to identity to be consistent with this idea . The main impacts are to processing of Update and Remove - within - External - Commit , both cases in which you want the new KeyPackage to logically represent the same identity as the old one . This PR also removes the field from KeyPackage . Since we now reference KeyPackages by  , there 's no longer a need for a separate identifier . ( Unless we want an identifier that 's stable across epochs , but ( a ) it 's not clear to me that that is needed in general and ( b ) it can easily be in an extension , as in fact we have done in Webex . ) 
 How appropriate that this is PR ( X. ) ! 
 The advantage of keeping an is that we can mandate in the spec that it ca n't change across epochs . While if we have a proprietary extension that contains an identifier , every implementation would have to be aware of that extension and enforce that it does n't change across updates . So I 'd be in favor of keeping it . 
 This softens the requirements quite a bit , namely : There is no more requirement for identities to be unique across the group , e.g.  can double - join the tree by occupying two leaves , simply by issuing an Update . An identity can completely change in the course of an Update if the application allows it . I 'm worried the proposed solution can lead to UB , when clients try to remove a certain member that potentially occupies more than one leaf . 
 - We already have an identifier that is stable across epochs -- the leaf index ! We do n't have a use for it now ( as evidenced by the PR ) , but it 's still there . - I do n't think those concerns hold up . There 's no new risk of double - join ; a client can only present an identity for which it can obtain a Credential that is acceptable to other clients . If a client presents a legitimate identity twice , that 's not harm ; it might be multiple devices , which we can still uniquely reference by  . If a client can get Credentials for identities they do n't own , that 's a bug in the authentication system , not MLS . As far as identities completely changing -- one could consider that a feature , not a bug . TLS has had to go to to allow servers to assert additional identities over the course of a connection . It seems like we have an elegant solution to the problem here . Applications can of course always be stricter . 
 It 's stable across epochs until you remove the party in that leaf and add another one into it . The options that have been suggested are the following : leaf index : is not tied to any particular identity / key package key package ( id / hash ): potentially changes across epochs identity in the credential : not unique per group None of these variables / indices / identifiers really does the trick of uniquely and consistently ( across epochs ) identifying a client in a group . The endpoint id / identity tuple does all of the above . We do n't have to use it in message structs , where the key package ids are just fine , as messages are tied to an epoch anyway . I 'm just in favor of keeping the endpoint i d so it can serve as a consistent identifier for group members for use by the application . 
 - I can live with re - adding . I can imagine scenarios where it would be troublesome , but in the worst case , you just fill in some long random junk there . I have re- . Any other issues , or are we good to merge ? 
 I 'm ok with this approach , but I think this changes the concept of identity enought that we should not merge this without previous discussion either in a meeting or on the mailing list . Is there an interim planned before the WGLC ? 
 There is no interim planned . I 'll send a ping to the mailing list . 
 I thought about this some more and I managed to convince myself that the is not strictly needed . Not having it however puts a higher burden on either the implementation or on the AS to track changes across epochs in order to ensure continuity . In practical terms , the only constant thing about member X is that it occupies leaf node i between the time it was and removed ( regardless of updates during that time ) . If however X gets removed and a new member Y gets at the same leaf node , i now references Y and not X , which makes leaf node indices useless across epochs . For me this means one of the following two things must be true : a ) Implementations emulate the concept of an . They assign it to a member at the point in time when the member gets and delete it when the member gets removed . In between the two events , this is used as the only unique identifier for a member . b ) We put more load on the AS and mandate the AS must be able to correlate two KeyPackages from two different epochs to ascertain the two KeyPackages belong to the same user . For example , member X gets in epoch A , and updates its KeyPackage ( including its credential , HPKE init key , and signature key ) in epoch B. The AS must then be able to tell in epoch C whether it 's still the same member X or a new member Y , just by looking at the two KeyPackages . 
 Yeah , I think I 'm about in the same place as you . As I think I 've said before , to use MLS in Webex , we needed to add a KeyPackage extension for the application unique identifer anyway . With , we could have just used that field . But note that the PR has already been updated to re - add . So are you good with the PR in its current state ? 
  out on this problem , I will make a couple remarks about options for identifying parties . First , it seems that the above alternatives ( and adding some not discussed ) can generally be grouped into one of the following categories ( for these , ' persistence ' implies over the duration of the session / group , and ' directly authenticated ' implies either as a credential or an identifier signed through use of a credential ): identifiers change across epochs and directly authenticated along with that change identifiers are persistent across epochs and directly authenticated once identifiers are not persistent across epochs , but directly authenticated only once identifiers are persistent across epochs , but unauthenticated I note the above differentiators , since the role of endpoint identifiers begins to factor in when assessing E2EE . and I are working on some of the ' ends ' aspect of E2EE and I think the current PR change could prove non - trivial with respect to justifying E2EE in MLS . Option 3 is what Signal does and , throughout the development of MLS , Signal as been used as a guidepost for ' at least equivalent ' security . Naturally , if credentials are used directly , we meet Option 2 or 1 , dependent on handling . Please correct me if I am wrong , but it appears that the current PR would lead us into Option 4 . I support keeping credentials , at least in the sense of keys . Actually , in this respect , it is a little confusing with regard the issue with x509 . Since early on , " credential " in MLS has been used as denoting a signature key , not a certificate that may contain more . Maybe I am not quite seeing the issue as to why the application can not handle interpreting the certificate as separate to the credential in the spec . 
 Strongly disagree with ' Since early on , " credential " in MLS has been used as denoting a signature key , not a certificate that may contain more . ' The notion of a Credential has always included at least an identifier as well as the signature key , in order to address the Unknown Key Share / Identity Misbinding attacks that occur in Signal and elsewhere . If you put that together with the idea that Credentials are verifiable using some AS , you basically arrive at certificates . In your taxonomy , only option ( 1 ) actually works for MLS , assuming that by " endpoint identifiers " , you mean the authenticated ones , and not just the opaque , which just has to be unique . Option ( 4 ) is clearly unacceptable , because the whole point of these identifiers is that they 're authenticated by the AS . Options ( 2 ) and ( 3 ) do n't make sense because members can be to the group and need to be able to authenticate the other members when they join ( so " directly authenticate once " does n't work ) . Note that MLS is unlike Signal in that the membership is multi - party and dynamic , and that we seek to address UKS issues that Signal explicitly disclaims . Could you describe more what the issue is here ? Just because the endpoints can change the set of identities they express does n't seem like it undermines the notion of E2EE . 
 I agree that option ( 1 ) is what is needed for MLS . The discussion above seems to advocate for a variant of option ( 4 ) though . This variant question also seems to be the crux of the matter was pointing out above , so if something is being miscommunicated here it would help if you could clarify that , i.e. that we are at least on the same page regarding ( 1 ) being the goal . The ' Signal alignment ' only holds as a baseline , i.e. if you are advocating for ( 4 ) then I would say that we can and should do better . The claim about options ( 2 ) and ( 3 ) is incorrect though , since direct authentication occurs at time of group join . To avoid diverging down side discussion points and to keep this PR decision on track , it is essential to establish clarity on the claim that MLS ( with the current PR ) would be able to offer option ( 1 ) . Copying from notes above , we have that ( quote ): leaf index : is not tied to any particular identity / key package key package ( id / hash ): potentially changes across epochs identity in the credential : not unique per group ( end quote ) and as you say , the opaque endpoint_id is by no means sufficient . By elimination , this does not leave many options . So what aspect are you referring ref . " the authenticated ones " ? I.e. what persistent or rotated endpoint identifier is there which consistently links authenticity throughout the lifespan of the group ? Anything that is not persistent is insufficient as is anything that is authenticated in a disconnected manner ( e.g. can be replaced and authenticated with a new key that is not linked to the prior one ) . 
 What I mean by " the authenticated ones " is the identifier(s ) in the Credential , in the KeyPackage , which are supposed to be authenticated with the AS . To be specific : For BasicCredential , the field , and for X509Credential , identifiers in the or fields . So yes , we have a number of identifiers for endpoints : in credentials ( as above ) index : Unique within a group ; constant for a member 's lifetime in the group , by virtue of tree math : Unique within a group ; constant for a member 's lifetime in the group , by fiat (= = hash ):  within a group ; changes on Commit / Update by the member The point of this PR is just to clarify that the identifiers authenticated in credentials are neither unique within a group nor constant across Commit / Update by the member . ( And to clarify what must remain constant across Commit / Update . ) Does that seem problematic to you ? 
 The issue of credentials not being unique or constant is at the heart of this . Other items here are not authenticated or are reliant on those credentials and therefore the consistency of e.g. the leaf index does not actually imply consistency of identity . If credentials were not unique / constant in the sense that a prior one signs off on the next one , then we would inherit consistency from that ( which is different from the case here ) . Similarly , if a single root identity ( " identity " ) were to forward to other sub - identities , then there is consistency in the meaning of identity . What we have here is a backdoor on switching out identities which would be allowed by the spec - yes , they are subcomponents of a credential , but any sender is not actually assured of which identity they are conversing with . For example ,  may trust a domain name / email address from  , but when that switches part - way through the conversation , there is no opt - out point or notification to  . There is considerable drift available to  ( either unintentionally or maliciously ) that could occur without knowledge from other group members . This is noticeably different from the case that  simply maliciously forwards messages externally , as the drift occurs internally to the group . 
 You might think the simplest thing we could do here is just require that a Credential be stable for the lifetime of a member 's presence in the group . If you want to change the Credential , you have to be removed and re- . But ( a ) that seems like throwing out a bunch of useful functionality , and ( b ) it does n't actually remove the risk , just moves it over to the remove / re - add case , making it harder for the application to track continuity . 
 ( Force - pushed to address failed merge ) 
 +1 to this change . I think this clarifies how to handle application layer identity , and that is particularly helpful when using X509 as the credential where is a bit complicated . 
 shifted this discussion offline and it has been discussed extensively there with some of the issues more clearly outlined . To avoid copying it all into this PR , I suggest discussion at the next WG informal interim on 27 Jan. , or as seen suitable by the authors . 
 Thanks for some offline discussion here to help me understand your concerns . IIUC the core of your concern is that the spec does n't clearly require that new credentials be validated with the AS whenever they appear . I can see how if you believe credentials are only validated on Add , then you need everything to chain back to the Add , and changes are problematic . I do n't think the spec is actually broken in this way , since it says in that " each new credential that has not already been validated by the application MUST be validated against the Authentication Service " ( and has for 2 years according to ) . But I agree the spec should be clearer and more consistent on this point , and would be happy to make the edits required . 
 Latest commit attempts to address concerns by explicitly requiring credential validation on Update / full - Commit . 
 Given the push to shift the key points of discussion here , I am copying them avoid paraphrasing confusions : [ Responding to regarding the sufficiency of text that suggests developers determine whether identifiers should be constant based on whether they feel they have knowledge to make changes ] A recommendation for consistency of identifiers will likely be insufficient ; I suspect that this decision point underpins being able to show this as an AKE at all . It would be like making certs optional and changeable during TLS ’s handshake . What TLS does once , MLS does continuously ( the handshake ) . It is not a ‘ different ’ handshake per epoch , but all links through all back to the initialization . Proving security of an AKE is in part conditioned on the identities ( and commitment to those identities ) of the entities involved ( ‘ identity ’ being generic , not a specific term in MLS here ) . So if that changes part way through the handshake (= session in MLS ) , then one of the key properties of an AKE is likely going to break down . Relying on the group key state to fill the consistency check gap that is created would be circular logic . Some options are : 1 ) have a consistent identifier ( regardless of whether that is a cert , endpoint_id , or other ) , 2 ) have a logically linked chain of identifiers ( e.g. the last one signs the next as some type of cert chain if the identifier is taken to be a cert , or hash the last identifier to make the next in the chain , etc . ) , or 3 ) remove the member and add a ‘ new ’ member whenever the identifier changes . This really is not an optional piece of a protocol or something that can passably be left up to how the developer is feeling – we are really dealing with the fundamental question of whether MLS will be an AKE or not . I do not really see an advantage with us being loosie and shifting MLS to a KE vs an AKE at this point . It may be worthwhile instead to clarify the use case so we can see what the need is and then we can see how that may be solved . For example , if you want multiple identities / credentials for an entity , then we could require that those all be present somehow at the start of the protocol . Note that switching among a pre - announced set of identities for a member or removing an old identifier if the next one is already in the set could potentially be alright – it is the introduction of some new identifier or credential that carries no explicit , persistent link from prior ones that is a problem . Unsurprisingly , the consequence of fixing side case uses is that the protocol gets more complex , but if it is meaningful for some development case then that is the reality . 
 Also : [ In response to regarding the assertion that MLS authenticates in each epoch with credentials and via AS , making it a fresh AKE per epoch . ] The analogy of TLS authenticators is misconstruing the spec , since that is a single session – you see , using alternative identifiers for any given session is not a problem , but switching them out mid - session is . While it is true that ratcheted key exchange is normally looked at as epoch - level mini - sessions as far as key establishment goes , the ‘ A ’ part stretches the length of the entire session and ties to the very start ( ‘ Add ’ ) . This is intuitively noticeable in that the spec requires that the key package be validated and the credential verified only at an Add ( pg 54 ) and not every epoch . The credential ( issuer , keys , or identity ) could effectively change without group members even verifying the new credential ( and that is without touching on the legitimacy of the ‘ chain ’ between the two ) . That is why Updating / Committing can not be regarded as a remove and Add : the required operations for each differ . ( example on E2EE identities changing maliciously given that the verification requirements at the Add step differ from at the Update step when the cert changes ) In short , no , the identifiers are not authenticated in each epoch , only at the start . Confidentiality ratchets per epoch , but authenticity does not . That said , if you can require that every time there is a change in a credential then all of the prescribed steps in an Add are also followed ( with respect to verifying identities ) then my concerns are addressed and I would also agree that we have at least authentication per change ( although not per epoch ) . As an aside note , the source of this challenge for MLS is that , unlike TLS , we do not prescribe credentials from a certifying authority . In TLS the certificate authority and therefore means of verifying authenticity of identities is very explicit – no matter when those are verified , a certificate authority will always be listed . Thus TLS can easily require checks . In MLS ( section 6.2 ) we only say ‘ MAY verify identities ’ ( MLS requires any credential not validated by members to be validated by the AS by an unspecified method ) . If I recall correctly this choice was made early on to capture the loophole for ‘ trust on first use ’ type applications . For that case the game changes entirely though since both the initial authentication and any subsequent authentication both suffer the same challenge of needing an OOB solution for authenticating identity ( in other words , cert changes are no worse off than at the start ) . However , for MLS using normal certificates , the fact that this loophole exists creates a challenge on how to ensure that the same authentication functionality is being used when certs change ( the wording is simply harder to formulate while still allowing for the loophole ) . TLS in contrast is very explicit about certificate verification , but it can be because 1 ) there is only one point were this is done in the protocol as a single session and 2 ) there is really only one main method of handling cert authorities with x509 , with explicit exceptions given by e.g. the export exemption you name . In short , if you authenticate OOB the first time , OOB after certificate change is persistent . If you authenticate with cert authorities the first time , then changing the certificate should imply a re - validation of the new cert ’s chain . What we can not do is allow a functionality method that is not persistent ( i.e. the current problem ) where we verify once but allow changes later without equivalent oversight . 
 With the provided background context for the WG above , I will address the latest question from and the changes . First - thank you for the edits to the PR . The proposed changes do not fully address the above however . The key gap is on what is being required to be done for verification of identity at the point of change . We need to explicitly enforce that the same process at the Add needs to be done at the change . Right now there is still a bailout option , where credentials can be verified directly at the Add , but are slipped into a background / AS option . This is mixing and matching . 
 DIscussion on working call : Need to make sure we have consistent validation logic across Add / Update / Commit 
 The latest commit adds a consolidated " KeyPackage validation " section that describes the common rules that are applied across Add , Update , and Commit , including credential validation in particular . The only difference between those cases now is that only Update and Commit have a requirement to check that the new set of identifiers is OK . It seems like that check does n't make sense for Add . Let me know if that looks good to you !
Paragraph (version B):
A group represents a logical collection of clents 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.
Paragraph (version B):
A state of a group in which a specific set of authenticated
clients hold shared cryptographic state.
Paragraph (version A):
We describe the information stored by each client as _state_, which
includes both public and private data.  An initial state is set up by
a group creator, which is a group containing only itself.  The
creator then sends _Add_ proposals for each client in the initial set
of members, followed by a _Commit_ message which incorporates all of
the _Adds_ into the group state.  Finally, the group creator
generates a _Welcome_ message corresponding to the Commit and sends
this directly to all the new members, who can use the information it
contains to set up their own group state and derive a shared secret.
Members exchange Commit messages for post-compromise security, to add
new members, and to remove existing members.  These messages produce
new shared secrets which are causally linked to their predecessors,
forming a logical Directed Acyclic Graph (DAG) of states.
Paragraph (version B):
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, etc.
Paragraph (version B):
A _KeyPackage_ object describes a client's capabilities and
provides keys that can be used to add the client to a group.
Paragraph (version B):
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
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.
Paragraph (version B):
Before the initialization of a group, clients publish KeyPackages to
a directory provided by the Service Provider.
Paragraph (version B):
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.
Paragraph (version B):
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.
Paragraph (version B):
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.
Paragraph (version B):
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.
Paragraph (version B):
Ratchet trees allow a group to efficiently remove any member by
encrypting new entropy to a subset of the group.  A ratchet tree
assigns shared keys to subgroups of the overall group, so that, for
example, encrypting to all but one member of the group requires only
log(N) encryptions, 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).
Paragraph (version B):
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.
Paragraph (version B):
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.
Paragraph (version B):
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_).
Paragraph (version A):
The generator of the UpdatePath starts by sampling a fresh random
value called "leaf_secret", and uses the leaf_secret to generate
their leaf HPKE key pair (see key-packages) and to seed a sequence of
"path secrets", one for each ancestor of its leaf.  In this setting,
path_secret[0] refers to the node directly above the leaf,
path_secret[1] for its parent, and so on.  At each step, the path
secret is used to derive a new secret value for the corresponding
node, from which the node's key pair is derived.
Paragraph (version B):
The generator of the UpdatePath starts by sampling a fresh random
value called "leaf_secret", and uses the leaf_secret to generate
their leaf HPKE key pair (see key-packages) and to seed a sequence of
"path secrets", one for each ancestor of its leaf.  In this setting,
path_secret[0] refers to the leaf's parent, path_secret[1] to the
parent's parent, and so on.  At each step, the path secret is used to
derive a new secret value for the corresponding node, from which the
node's key pair is derived.
Paragraph (version B):
To add a new leaf: Add leaf L as the new rightmost leaf of the tree.
Add a blank parent node P whose right child is L.  P is attached to
the tree as the right child of the only appropriate node to make the
updated tree left-balanced (or set it as a new root).  The former
right child of P's parent becomes P's left child (or the old root
becomes P's left child if P is the new root).
Paragraph (version B):
To remove the rightmost leaf: Remove the rightmost leaf node L and
its parent node P.  If P was the root of the tree, P's left child is
now the root of the tree.  Otherwise, set the right child of P's
parent to be P's left child.
Paragraph (version B):
Note that in the rest of the protocol, the rightmost leaf will only
be removed when it is blank.
Paragraph (version B):
Concrete algorithms for these operations on array-based and link-
based trees are provided in array-based-trees and link-based-trees.
The concrete algorithms are non-normative.  An implementation MAY use
any algorithm that produces the correct tree in its internal
representation.
Paragraph (version A):
In this table, the value pk(ns[X]) represents the public key derived
from the node secret X, whereas pk(X) represents the public leaf key
for user X.  The value E(K, S) represents the public-key encryption
of the path secret S to the public key K (using HPKE).
Paragraph (version B):
For nodes where a path secret was recovered in step 1, compute
and store the node's updated private key.
Paragraph (version B):
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).
Paragraph (version B):
Note that a Credential can provide multiple identifiers for the
client.  If an application wishes to decided whether a credential
represents the correct identifier for a participant in a given
context, it is up to the application to decide what the correct value
is and compare it to the credential.  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.
Paragraph (version A):
For X509Credential, each entry in the chain represents a single DER-
encoded X509 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 algorithm for the "public_key" in the end-entity
certificate MUST match the relevant ciphersuite.
Paragraph (version A):
The signatures used throughout 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.
Paragraph (version A):
A KeyPackage object specifies a ciphersuite that the client supports,
as well as providing a public key that others can use for key
agreement.
Paragraph (version A):
The "identity" arising from the credential, together with the
"endpoint_id" in the KeyPackage serve to uniquely identify a client
in a group.
Paragraph (version B):
A BasicCredential is a raw, unauthenticated assertion of an identity/
key binding.  The format of the key in the "public_key" field is
defined by the relevant ciphersuite: the group ciphersuite for a
credential in a ratchet tree, the KeyPackage ciphersuite for a
credential in a KeyPackage object.  For ciphersuites using Ed25519 or
Ed448 signature schemes, the public key is in the format specified
RFC8032.  For ciphersuites using ECDSA with the NIST curves P-256 or
P-521, the public key is the output of the uncompressed Elliptic-
Curve-Point-to-Octet-String conversion according to SECG.
Paragraph (version B):
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 algorithm for the "public_key" in the end-
entity certificate MUST match the relevant ciphersuite.
Paragraph (version B):
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.
Paragraph (version B):
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.
Paragraph (version B):
The Credentials presented by the clients in a group authenticate
application-level identifiers for the clients.  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 will all present the user's application-layer identifiers.
Paragraph (version B):
Internally to the the protocol, group members are uniquely identified
by their leaves, expressed as KeyPackageRef objects.  These
identifiers are unstable: They change whenever the member sends a
Commit, or whenever an Update proposal from the member is committed.
Paragraph (version B):
The application may also provide application-specific unique
identifiers in the "extensions" field of KeyPackage object.
Paragraph (version B):
A protocol version and ciphersuite that the client supports,
Paragraph (version B):
a public key that others can use for key agreement,
Paragraph (version B):
an "endpoint_id" that uniquely identifies a client in a group.
Paragraph (version B):
KeyPackages are intended to be used only once and SHOULD NOT be
reused except in case of last resort.  (See keypackage-reuse).
Clients MAY generate and publish multiple KeyPackages to support
multiple ciphersuites.
Paragraph (version B):
The value for hpke_init_key MUST be a public key for the asymmetric
encryption scheme defined by cipher_suite, and it MUST be unique
among the set of KeyPackages created by this client.  The whole
structure is signed using the client's signature key.  A KeyPackage
object with an invalid signature field MUST be considered malformed.
Paragraph (version B):
KeyPackage objects MUST contain at least two extensions, one of type
"capabilities", and one of type "lifetime".  The "capabilities"
extension allows MLS session establishment to be safe from downgrade
attacks on the parameters described (as discussed in group-creation),
while still only advertising one version / ciphersuite per
KeyPackage.
Paragraph (version B):
As the "KeyPackage" is a structure which is stored in the Ratchet
Tree and updated depending on the evolution of the tree, each
modification of its content MUST be reflected by a change in its
signature.  This allows other members to verify the validity of the
KeyPackage at any time, particularly in the case of a newcomer
joining the group.
Paragraph (version A):
Within MLS, a KeyPackage is identified by its hash (see, e.g.,
welcoming-new-members).  The "external_key_id" extension allows
applications to add an explicit, application-defined identifier to a
KeyPackage.
Paragraph (version A):
Consider a ratchet tree with a parent node P and children V and S.
The parent hash of P changes whenever an "UpdatePath" object is
applied to the ratchet tree along a path traversing node V (and hence
also P).  The new "Parent Hash of P (with Co-Path Child S)" is
obtained by hashing P's "ParentHashInput" struct using the resolution
of S to populate the "original_child_resolution" field.  This way,
P's Parent Hash fixes the new HPKE public keys of all nodes on the
path from P to the root.  Furthermore, for each such key PK the hash
also binds the set of HPKE public keys to which PK's secret key was
encrypted in the commit packet that anounced the "UpdatePath" object.
Paragraph (version B):
Consider a ratchet tree with a parent node P and children V and S.
The parent hash of P changes whenever an "UpdatePath" object is
applied to the ratchet tree along a path traversing node V (and hence
also P).  The new "Parent Hash of P (with Co-Path Child S)" is
obtained by hashing P's "ParentHashInput" struct using the resolution
of S to populate the "original_child_resolution" field.  This way,
P's Parent Hash fixes the new HPKE public keys of all nodes on the
path from P to the root.  Furthermore, for each such key PK the hash
also binds the set of HPKE public keys to which PK's secret key was
encrypted in the Commit that contained the "UpdatePath" object.
Paragraph (version A):
Now the tree hash of any non-leaf node is recursively defined to be
the hash of its "ParentNodeTreeHashInput".  This includes an optional
"ParentNode" object depending on whether the node is blank or not.
Paragraph (version B):
The "extensions" field contains the details of any protocol
extensions that apply to the group.
Paragraph (version A):
Thus the "confirmed_transcript_hash" field in a GroupContext object
represents a transcript over the whole history of MLSPlaintext Commit
messages, up to the confirmation tag field in the current
MLSPlaintext message.  The confirmation tag is then included in the
transcript for the next epoch.  The interim transcript hash is
computed by new members using the confirmation tag in the GroupInfo
struct, and enables existing members to incorporate a Commit message
into the transcript without having to store the whole
MLSPlaintextCommitAuthData structure.
Paragraph (version B):
The "group_id" field is constant.
Paragraph (version B):
The "epoch" field increments by one for each Commit message that
is processed.
Paragraph (version B):
The "tree_hash" is updated to represent the current tree and
credentials.
Paragraph (version B):
The "extensions" field changes when a GroupContextExtensions
proposal is committed.
Paragraph (version B):
Thus the "confirmed_transcript_hash" field in a GroupContext object
represents a transcript over the whole history of MLSPlaintext Commit
messages, up to the confirmation_tag field of the most recent Commit.
The confirmation tag is then included in the transcript for the next
epoch.  The interim transcript hash is computed by new members using
the confirmation_tag of the GroupInfo struct, while existing members
can compute it directly.
Paragraph (version A):
Decryption is performed in the corresponding way, using the private
key of the resolution node and the ephemeral public key transmitted
in the message.
Paragraph (version B):
Decryption is performed in the corresponding way, using the private
key of the resolution node.
Paragraph (version A):
The public key "external_pub" can be published as part of the
"PublicGroupState" struct in order to allow non-members to join the
group using an external commit.
Paragraph (version B):
The public key "external_pub" can be published as part of the
GroupInfo struct in order to allow non-members to join the group
using an external commit.
Paragraph (version A):
Note that, as a PSK may have a different lifetime than an update, it
does not necessarily provide the same Forward Secrecy (FS) or Post-
Compromise Security (PCS) guarantees as a Commit message.  Unlike the
key pairs populated in the tree by an Update or Commit, which always
freshly generated, PSKs may be pre-distributed and stored.  This
creates the risk that a PSK may be compromised in the process of
distribution and storage.  The security that the group gets from
injecting a PSK thus depends on both the entropy of the PSK and the
risk of compromise.  These factors are outside of the scope of this
document, but should be considered by application designers relying
on PSKs.
Paragraph (version B):
Note that, as a PSK may have a different lifetime than an update, it
does not necessarily provide the same Forward Secrecy (FS) or Post-
Compromise Security (PCS) guarantees as a Commit message.  Unlike the
key pairs populated in the tree by an Update or Commit, which are
always freshly generated, PSKs may be pre-distributed and stored.
This creates the risk that a PSK may be compromised in the process of
distribution and storage.  The security that the group gets from
injecting a PSK thus depends on both the entropy of the PSK and the
risk of compromise.  These factors are outside of the scope of this
document, but should be considered by application designers relying
on PSKs.
Paragraph (version B):
Each PSK in MLS has a type that designates how it was provisioned.
External PSKs are provided by the application, while resumption PSKs
are derived from the MLS key schedule and used in cases where it is
necessary to authenticate a member's participation in a prior epoch.
Paragraph (version B):
For the generation of encryption keys and nonces, the key schedule
begins with the "encryption_secret" at the root and derives a tree of
secrets with the same structure as the group's ratchet tree.  Each
leaf in the Secret Tree is associated with the same group member as
the corresponding leaf in the ratchet tree.
Paragraph (version B):
Keys, nonces, and the secrets in ratchets are derived using
DeriveTreeSecret.  The context in a given call consists of the
current position in the ratchet.
Paragraph (version B):
all node secrets in the Secret Tree on the path from the root to
the leaf with node L,
Paragraph (version B):
"application_ratchet_nonce_[L]_[j]" and
"application_ratchet_key_[L]_[j]".
Paragraph (version A):
The "signature" field in an MLSPlaintext object is computed using the
signing private key corresponding to the public key, which was
authenticated by the credential at the leaf of the tree indicated by
the sender field.  The signature covers the plaintext metadata and
message content, which is all of MLSPlaintext except for the
"signature", the "confirmation_tag" and "membership_tag" fields.  If
the sender is a member of the group, the signature also covers the
GroupContext for the current epoch, so that signatures are specific
to a given group and epoch.
Paragraph (version B):
In principle, the above process could be streamlined by having the
creator directly create a tree and choose a random value for first
epoch's epoch secret.  We follow the steps above because it removes
unnecessary choices, by which, for example, bad randomness could be
introduced.  The only choices the creator makes here are its own
KeyPackage and the leaf secret from which the Commit is built.
Paragraph (version A):
This extension lists the extensions and proposal types that must be
supported by all members of the group.  For new members, it is
enforced by existing members during the application of Add commits.
Existing members should of course be in compliance already.  In order
to ensure this continues to be the case even as the group's
extensions can be updated, a GroupContextExtensions proposal is
invalid if it contains a "required_capabilities" extension that
requires capabililities not supported by all current members.
Paragraph (version A):
In both cases, the "psk_nonce" included in the "PreSharedKeyID"
object must be a randomly sampled nonce of length "KDF.Nh" to avoid
key re-use.
Paragraph (version B):
Resumption PSKs with usage "reinit" MUST NOT be used in other
contexts.  A PreSharedKey proposal with type "resumption" and usage
"reinit" MUST be considered invalid.
Paragraph (version B):
Resumption PSKs with usage "branch" MUST NOT be used in other
contexts.  A PreSharedKey proposal with type "resumption" and usage
"branch" MUST be considered invalid.
Paragraph (version A):
An Add proposal requests that a client with a specified KeyPackage be
added to the group.  The proposer of the Add MUST validate the
KeyPackage in the same way as receipients are required to do below.
Paragraph (version B):
An Add proposal requests that a client with a specified KeyPackage be
added to the group.  The proposer of the Add MUST verify the validity
of the KeyPackage, as specified in keypackage-validation.
Paragraph (version B):
An Add is applied after being included in a Commit message.  The
position of the Add in the list of proposals determines the leaf node
where the new member will be added.  For the first Add in the Commit,
the corresponding new member will be placed in the leftmost empty
leaf in the tree, for the second Add, the next empty leaf to the
right, etc.  If no empty leaf exists, the tree is extended to the
right.
Paragraph (version B):
For each non-blank intermediate node along the path from the leaf
L to the root, add L's leaf index to the "unmerged_leaves" list
for the node.
Paragraph (version A):
The values in the following fields of the KeyPackage contained in an
"Update" proposal MUST be the same as those of the KeyPackage it
replaces in the tree.  "version", "cipher_suite",
"credential.identity", "endpoint_id".  However, the value of the
"credential.signature_key" field of the new KeyPackage MUST be
different from that of all other KeyPackages in the tree.
Furthermore, the value of the "hpke_init_key" field of the new
KeyPackage MUST be different from that of the KeyPackage it replaces.
Paragraph (version B):
Verify that the "hpke_init_key" value is different from the
corresponding field in the KeyPackage being replaced.
Paragraph (version A):
Identify a leaf node containing a key package matching "removed".
This lookup MUST be done on the tree before any non-Remove
proposals have been applied (the "old" tree in the terminology of
commit), since proposals such as Update can change the KeyPackage
stored at a leaf.  Let "removed_index" be the node index of this
leaf node.
Paragraph (version A):
A ReInit proposal represents a request to re-initialize the group
with different parameters, for example, to increase the version
number or to change the ciphersuite.  The re-initialization is done
by creating a completely new group and shutting down the old one.
Paragraph (version B):
A ReInit proposal represents a request to reinitialize the group with
different parameters, for example, to increase the version number or
to change the ciphersuite.  The reinitialization is done by creating
a completely new group and shutting down the old one.
Paragraph (version B):
A member of the group applies a ReInit proposal by waiting for the
committer to send the Welcome message that matches the ReInit,
according to the criteria in reinitialization.
Paragraph (version A):
An ExternalInit proposal is used by new members that want to join a
group by using an external commit.  This propsal can only be used in
that context.
Paragraph (version B):
An ExternalInit proposal is used by new members that want to join a
group by using an external commit.  This proposal can only be used in
that context.
Paragraph (version A):
An application using AppAck proposals to guard against loss/
suppression of application messages also needs to ensure that AppAck
messages and the Commits that reference them are not dropped.  One
way to do this is to always encrypt Proposal and Commit messages, to
make it more difficult for the Delivery Service to recognize which
messages conatain AppAcks.  The application can also have clients
enforce an AppAck schedule, reporting loss if an AppAck is not
received at the expected time.
Paragraph (version B):
An application using AppAck proposals to guard against loss/
suppression of application messages also needs to ensure that AppAck
messages and the Commits that reference them are not dropped.  One
way to do this is to always encrypt Proposal and Commit messages, to
make it more difficult for the Delivery Service to recognize which
messages contain AppAcks.  The application can also have clients
enforce an AppAck schedule, reporting loss if an AppAck is not
received at the expected time.
Paragraph (version B):
If there are multiple proposals that apply to the same leaf, the
committer chooses one and includes only that one in the Commit,
considering the rest invalid.  The committer MUST NOT include any
Update proposals generated by the committer, since they would be
duplicative with the "path" field in the Commit.  The committer MUST
prefer any Remove received, or the most recent Update for the leaf if
there are no Removes.  If there are multiple Add proposals containing
KeyPackages with the same "endpoint_id", the committer again chooses
one to include and considers the rest invalid.  Add proposals that
contain KeyPackages with an "endpoint_id" tuple that matches that of
an existing KeyPackage in the group MUST be considered invalid.  The
committer MUST consider invalid any Add or Update proposal if the
Credential in the contained KeyPackage shares the same signature key
with a Credential in any leaf of the group, or indeed if the
KeyPackage shares the same "hpke_init_key" with another KeyPackage in
the group.
Paragraph (version B):
The Commit MUST NOT combine proposals sent within different epochs.
Due to the asynchronous nature of proposals, receivers of a Commit
SHOULD NOT enforce that all valid proposals sent within the current
epoch are referenced by the next Commit.  In the event that a valid
proposal is omitted from the next Commit, and that proposal is still
valid in the current epoch, the sender of the proposal MAY retransmit
it.
Paragraph (version A):
If populating the "path" field: Create an UpdatePath using the
provisional ratchet tree and GroupContext.  Any new member (from
an add proposal) MUST be exluded from the resolution during the
computation of the UpdatePath.  The "leaf_key_package" for this
UpdatePath must have a "parent_hash" extension.  Note that the
KeyPackage in the "UpdatePath" effectively updates an existing
KeyPackage in the group and thus MUST adhere to the same
restrictions as KeyPackages used in "Update" proposals.
Paragraph (version B):
If populating the "path" field: Create an UpdatePath using the
provisional ratchet tree and GroupContext.  Any new member (from
an add proposal) MUST be excluded from the resolution during the
computation of the UpdatePath.  The "leaf_key_package" for this
UpdatePath must have a "parent_hash" extension.  Note that the
KeyPackage in the "UpdatePath" effectively updates an existing
KeyPackage in the group and thus MUST adhere to the same
restrictions as KeyPackages used in "Update" proposals.
Paragraph (version B):
If the Commit included a ReInit proposal, the client MUST NOT use
the group to send messages anymore.  Instead, it MUST wait for a
Welcome message from the committer meeting the requirements of
reinitialization.
Paragraph (version B):
New members can join the group in two ways.  Either by being added by
a group member, or by adding themselves through an external Commit.
In both cases, the new members need information to bootstrap their
local group state.
Paragraph (version A):
If a Remove proposal is present, then the "credential" and
"endpoint_id" of the removed leaf MUST be the same as the
corresponding values in the Add KeyPackage.
Paragraph (version B):
Thus, a member of the group can enable new clients to join by making
a GroupInfo object available to them.  Note that because a GroupInfo
object is specific to an epoch, it will need to be updated as the
group advances.  In particular, each GroupInfo object can be used for
one external join, since that external join will cause the epoch to
change.
Paragraph (version B):
The "signature" on the GroupInfo struct authenticates the HPKE public
key, so that the joiner knows that the public key was provided by a
member of the group.  The fields that are not signed are included in
the key schedule via the GroupContext object.  If the joiner is
provided an inaccurate data for these fields, then its external
Commit will have an incorrect "confirmation_tag" and thus be
rejected.
Paragraph (version B):
The information in a GroupInfo is not deemed public in general, but
applications can choose to make it available to new members in order
to allow External Commits.
Paragraph (version B):
If a Remove proposal is present, then the "endpoint_id" of the
Add KeyPackage MUST be the same as the one in the removed node,
and the "credential" MUST present a set of identifiers that is
acceptable to the application for the removed participant (as
if this were an Update for that participant).
Paragraph (version B):
The new member's position in the tree is at the leaf "my_leaf",
as defined above.
Paragraph (version B):
Update the leaf "my_leaf" with the private key corresponding to
the public key in the node.
Paragraph (version B):
The base MLS protocol can be extended in a few ways.  New
ciphersuites can be added to enable the use of new cryptographic
algorithms.  New types of proposals can be used to perform new
actions within an epoch.  Extension fields can be used to add
additional information to the protocol.  In this section, we discuss
some constraints on these extensibility mechanisms that are necessary
to ensure broad interoperability.
Paragraph (version B):
As discussed in ciphersuites, MLS allows the participants in a group
to negotiate the cryptographic algorithms used within the group.
This extensibility is important for maintaining the security of the
protocol over time RFC7696.  It also creates a risk of
interoperability failure due to clients not supporting a common
ciphersuite.
Paragraph (version B):
The ciphersuite registry defined in mls-ciphersuites attempts to
strike a balance on this point.  On the one hand, the base policy for
the registry is Specification Required, a fairly low bar designed to
avoid the need for standards work in cases where different ciphers
are needed for niche applications.  There is a higher bar (Standards
Action) for ciphers to set the Recommended field in the registry.
This higher bar is there in part to ensure that the interoperability
implications of new ciphersuites are considered.
Paragraph (version B):
MLS ciphersuites are defined independent of MLS versions, so that in
principle the same ciphersuite can be used across versions.
Standards work defining new versions of MLS should consider whether
it is desirable for the new version to be compatible with existing
ciphersuites, or whether the new version should rule out some
ciphersuites.  For example, a new version could follow the example of
HTTP/2, which restricted the set of allowed TLS ciphers (see
Section 9.2.2 of RFC7540.
Paragraph (version B):
Any field containing a list of extensions MUST NOT have more than
one extension of any given type.
Paragraph (version B):
KeyPackages are intended to be used only once.  That is, once a
KeyPackage has been used to introduce the corresponding client to a
group, it SHOULD be deleted from the KeyPackage publication system.
Reuse of KeyPackages can lead to replay attacks.
Paragraph (version B):
The mandatory-to-implement ciphersuite for MLS 1.0 is
"MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519" which uses Curve25519
for key exchange, AES-128-GCM for HPKE, HKDF over SHA2-256, and
Ed25519 for signatures.