Draft: draft-ietf-mls-protocol

Commentary: As discussed in , this PR makes the following terminology changes : It might be useful to review the two commits here separately . The first is just a global search - and - replace . The second is a light review for grammar ( " a " vs. " an " ) , and makes a few small copy edits . 
 I have a slight preference for SignedMessage and EncryptedMessage instead of PublicMessage and PrivateMessage 
 As discussed in the interim 2022 - 12 - 16 : Keeping Public / Private GroupContent -FramedContent ContentAAD -PrivateContentAAD I also : AuthenticatedContentTBE -PrivateContentTBE ( to be parallel with PrivateContentAAD ) 
 For anyone wondering , here are the final changes made by this PR . Which makes me wonder : since is only meant to be encrypted , should n't it be ? 
 Does anyone know why the MLS draft uses the " MLS " prefix for some structs , e.g. , and not just ? Is there ( still ) some logic behind this ? None of the explanations I could come up with hold for all structs . Maybe this is something that just evolved over the years ? If so , I would be happy to make an editorial PR to remove all of those :-) 
 Historic ... , and from RFC 8446 This also helps disambiguating between message formats 
 Can you say more ? One of my theories was that it was used to avoid naming collisions with other possibly " imported " structs from other RFCs . But its and not , so ... :-) 
 Eg . A " plaintext " can be pretty much anything like a containing an while an MLSPlaintext has a specific format content . Structures which have more internal constraints on their values have less chances to be confused with each other . 
 First of all , sorry if I widen the scope of this issue a bit . But when you said that the terminology comes from TLS , it clicked . When I started to work with MLS a few weeks ago , I got confused by the term MLSPlaintext . In TLS , a TLSPlaintext is not protected and only used as a stepping stone . This is different in MLS because an MLSPlaintext is always signed and not " converted " into an MLSCiphertext afterwards.¹ It seems close to TLS but is n't . Which brings me back to the " MLS " prefix thing . Not sure how peoples ' heads work , but mine tries to get rid of not useful information such as an " MLS " prefix . And when we remove all " MLS " prefixes , it becomes more clear that  is probably not the right term to describe a signed message . The prefix " MLS " in MLSPlaintext blurries that because now we have something " MLS - specific " . But still , it has " plaintext " in its name . Also , I thought that -- similar to the fact that " ... TBS " is " never send over the wire " -- the " MLS " prefix denotes things that are send over the wire -- which is not true , e.g. , in the case of MLSContentTBS . Furthermore , the MLS prefix makes MLSCiphertext and MLSPlaintext stand out in ... What makes these variants different ? What would have made more sense to me is something like ... However , I have no good idea what a much better name would be . and is a bit better IMO but clunky . ¹ This was the case in the past , see 
 For correctness , this was done in . Before this PR , the procedure was to generate an MLSPlaintext and convert it to an MLSCiphertext . I this this is an heritage of TLS 1.3 which does the same thing ( ) . After this PR , the procedure is to generate a MLSContent and convert it to MLSPlaintext or MLSCiphertext . Otherwise I agree , it would be nice to have consistent names in the document ! 
 I agree that the current use of " MLS " in struct names is inconsistent , and MLSPlaintext / MLSCiphertext are n't accurate for what those messages do now . This will be a large - ish change , but probably worth doing to increase clarity . I did an audit of struct names in the document and tried to think through what else they could be called . Here 's a proposal : The latter two are the most challenging . It 's difficult to get across precisely what they 're about without getting super verbose . Another route would be to use something like SignedMessage and EncryptedMessage . 
 Thanks for bringing this up and thanks for the proposal I like the proposed changes , although might I suggest the prefix " Message " instead of " Group " for -Content -ContentTBS and -ContentAuthData ? It is targeted to a group , but it 's really the core content of a message . 
 Thanks , This looks really promising ! and are the best terms I heard so far . While we 're at it , should we add a " ... TBE " ( To - Be - Encrypted ) to the ( possibly new ) ? While the , and appendices may seem intimidating at first , they provide a very good idea where to expect ( and how to use ) them . 
 Earlier , we had considered a " masking " approach for sender data , much like QUIC does for . This approach would save 28 bytes of overhead ( nonce + tag ) , but was abandoned because of uncertainty around the security of the masking approach . Since then , Bellare et al . published , which includes what is effectively a proof of the security properties of the QUIC scheme . The QUIC scheme is essentially scheme HN1 of the paper , the main difference being that QUIC encrypt not the nonce directly , but a packet number which is used to compute the nonce . Our application would be similar , since we would encrypt metadata used to encrypt the key and the nonce . Given this new analysis , is it time to bring back masking ? 
 Fixed by 
 Thanks for tackling this , I hope to help a bit with a review . I grepped for the old names ... ... and verified that the remaining instances of are all in the section . Furthermore , I checked that no accidental renames were made to this section . I could n't find any ( grammatical or visual ) mistakes in the second commit . Also , doing some spot - checks for the first commit , I could n't find anything wrong either . So , it all looks excellent to me : +1 : I agree with  that is very weird . Here is a proposal . Also should be changed to
Paragraph (version A):
An MLSPlaintext or MLSCiphertext message carrying an MLS Proposal
or Commit object, as opposed to application data.
Paragraph (version A):
An MLSCiphertext message carrying application data.
Paragraph (version B):
A PublicMessage or PrivateMessage carrying an MLS Proposal or
Commit object, as opposed to application data.
Paragraph (version B):
A PrivateMessage carrying application data.
Paragraph (version A):
The MLSPlaintext and MLSCiphertext formats are defined in message-
framing; they represent integrity-protected and confidentiality-
protected messages, respectively.  Security notions such as forward
secrecy and post-compromise security are defined in security-
considerations.
Paragraph (version B):
The PublicMessage and PrivateMessage formats are defined in message-
framing; they represent integrity-protected and confidentiality-
protected messages, respectively.  Security notions such as forward
secrecy and post-compromise security are defined in security-
considerations.
Paragraph (version A):
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):
Proposal and Commit messages are sent from one member of a group to
the others.  MLS provides a common framing layer for sending messages
within a group: A _PublicMessage_ provides sender authentication for
unencrypted Proposal and Commit messages.  A _PrivateMessage_
provides encryption and authentication for both Proposal/Commit
messages as well as any application data.
Paragraph (version A):
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.
Paragraph (version B):
Each of these operations is "proposed" by sending a message of the
corresponding type (Add / Update / Remove).  The state of the group
is not changed, however, until a Commit message is sent to provide
the group with fresh entropy.  In this section, we show each proposal
being committed immediately, but in more advanced deployment cases an
application might gather several proposals before committing them all
at once.  In the illustrations below, we show the Proposal and Commit
messages directly, while in reality they would be sent encapsulated
in PublicMessage or PrivateMessage objects.
Paragraph (version A):
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).
Paragraph (version B):
The signature algorithm specified in the ciphersuite is the mandatory
algorithm to be used for signatures in FramedContentAuthData 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).
Paragraph (version A):
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.
Paragraph (version B):
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 AuthenticatedContent
carrying the proposal.  In the latter two cases, the KDF is
determined by the group's ciphersuite.
Paragraph (version A):
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 content-authentication).  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.
Paragraph (version A):
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.
Paragraph (version A):
Messages from senders that aren't in the group are sent as
MLSPlaintext.  See external-proposals and joining-via-external-
commits for more details.
Paragraph (version B):
In most of the protocol, messages are handled in the form of
AuthenticatedContent objects.  These structures contain the content
of the message itself as well as information to authenticate the
sender (see content-authentication).  The additional protections
required to transmit these messages over an untrusted channel (group
membership authentication or AEAD encryption) are added by encoding
the AuthenticatedContent as an PublicMessage or PrivateMessage
message, which can then be sent as an MLSMessage.  Likewise, these
protections are enforced (via membership verification or AEAD
decryption) when decoding an PublicMessage or PrivateMessage into an
AuthenticatedContent object.
Paragraph (version B):
PrivateMessage represents a signed and encrypted message, with
protections for both the content of the message and related metadata.
PublicMessage represents a message that is only signed, and not
encrypted.  Applications MUST use PrivateMessage to encrypt
application messages and SHOULD use PrivateMessage to encode
handshake messages, but MAY transmit handshake messages encoded as
PublicMessage objects in cases where it is necessary for the Delivery
Service to examine such messages.
Paragraph (version B):
Messages from senders that aren't in the group are sent as
PublicMessage.  See external-proposals and joining-via-external-
commits for more details.
Paragraph (version A):
MLSContent is authenticated using the MLSContentAuthData structure.
Paragraph (version A):
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.
Paragraph (version B):
FramedContent is authenticated using the FramedContentAuthData
structure.
Paragraph (version B):
The signature is computed using "SignWithLabel" with label
""FramedContentTBS"" and with a content that covers the message
content and the wire format that will be used for this message.  If
the sender's "sender_type" is "member", the content also covers the
GroupContext for the current epoch so that signatures are specific to
a given group and epoch.
Paragraph (version A):
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.
Paragraph (version A):
Plaintexts are encoded using the MLSPlaintext structure.
Paragraph (version A):
When decoding an MLSPlaintext into an MLSAuthenticatedContent, the
application MUST check "membership_tag" and MUST check that the
MLSContentAuthData is valid.
Paragraph (version A):
Ciphertexts are encoded using the MLSCiphertext structure.
Paragraph (version A):
"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.
Paragraph (version A):
The ciphertext content is encoded using the MLSCiphertextContent
structure.
Paragraph (version A):
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.
This check ensures that the padding process is deterministic, so
that, for example, padding cannot be used as a covert channel.
Paragraph (version B):
The confirmation tag value confirms that the members of the group
have arrived at the same state of the group.  A FramedContentAuthData
is said to be valid when both the "signature" and "confirmation_tag"
fields are valid.
Paragraph (version B):
Messages that are authenticated but not encrypted are encoded using
the PublicMessage structure.
Paragraph (version B):
When decoding an PublicMessage into an AuthenticatedContent, the
application MUST check "membership_tag" and MUST check that the
FramedContentAuthData is valid.
Paragraph (version B):
Authenticated and encrypted messages are encoded using the
PrivateMessage structure.
Paragraph (version B):
"encrypted_sender_data" and "ciphertext" are encrypted using the AEAD
function specified by the ciphersuite in use, using as input the
structures SenderData and PrivateContentTBE.
Paragraph (version B):
Content to be encrypted is encoded in an PrivateContentTBE structure.
Paragraph (version B):
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 "PrivateMessage.ciphertext" by first
decoding the content and the "auth" field; then the "padding" field
comprises any remaining octets of plaintext.  The "padding" field
MUST be filled with all zero bytes.  A receiver MUST verify that
there are no non-zero bytes in the "padding" field, and if this check
fails, the enclosing PrivateMessage MUST be rejected as malformed.
This check ensures that the padding process is deterministic, so
that, for example, padding cannot be used as a covert channel.
Paragraph (version A):
When decoding an MLSCiphertextContent, the application MUST check
that the MLSContentAuthData is valid.
Paragraph (version B):
When decoding an PrivateContentTBE, the application MUST check that
the FramedContentAuthData is valid.
Paragraph (version A):
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.
Paragraph (version B):
When constructing a SenderData object from a Sender object, the
sender MUST verify Sender.sender_type is "member" and use
Sender.leaf_index for SenderData.leaf_index.
Paragraph (version A):
The "confirmed_transcript_hash" field is updated with the data for
an MLSAuthenticatedContent encoding a Commit message as described
below.
Paragraph (version B):
The "confirmed_transcript_hash" field is updated with the data for
an AuthenticatedContent encoding a Commit message as described
below.
Paragraph (version A):
The transcript hashes computed in MLS represent a running hash over
all Proposal and Commit messages that have ever been sent in a group.
Commit messages are included directly.  Proposal messages are
indirectly included via the Commit that applied them.  Both types of
message are included by hashing the MLSAuthenticatedContent object in
which they were sent.
Paragraph (version B):
The transcript hashes computed in MLS represent a running hash over
all Proposal and Commit messages that have ever been sent in a group.
Commit messages are included directly.  Proposal messages are
indirectly included via the Commit that applied them.  Both types of
message are included by hashing the AuthenticatedContent object in
which they were sent.
Paragraph (version A):
Each Commit message updates these hashes by way of its enclosing
MLSAuthenticatedContent.  The MLSAuthenticatedContent struct is split
into ConfirmedTranscriptHashInput and InterimTranscriptHashInput.
The former is used to update the confirmed transcript hash and the
latter to update the interim transcript hash.
Paragraph (version B):
Each Commit message updates these hashes by way of its enclosing
AuthenticatedContent.  The AuthenticatedContent struct is split into
ConfirmedTranscriptHashInput and InterimTranscriptHashInput.  The
former is used to update the confirmed transcript hash and the latter
to update the interim transcript hash.
Paragraph (version A):
On receiving an MLSContent containing a Proposal, a client MUST
verify the signature inside MLSContentAuthData and that the "epoch"
field of the enclosing MLSContent is equal to the "epoch" field of
the current GroupContext object.  If the verification is successful,
then the Proposal should be cached in such a way that it can be
retrieved by hash (as a ProposalOrRef object) in a later Commit
message.
Paragraph (version B):
On receiving a FramedContent containing a Proposal, a client MUST
verify the signature inside FramedContentAuthData and that the
"epoch" field of the enclosing FramedContent is equal to the "epoch"
field of the current GroupContext object.  If the verification is
successful, then the Proposal should be cached in such a way that it
can be retrieved by hash (as a ProposalOrRef object) in a later
Commit message.
Paragraph (version A):
An external proposal MUST be sent as an MLSPlaintext object, since
the sender will not have the keys necessary to construct an
MLSCiphertext object.
Paragraph (version B):
An external proposal MUST be sent as a PublicMessage object, since
the sender will not have the keys necessary to construct a
PrivateMessage object.
Paragraph (version A):
Each proposal covered by the Commit is included by a ProposalOrRef
value, which identifies the proposal to be applied by value or by
reference.  Commits that refer to new Proposals from the committer
can be included by value.  Commits for previously sent proposals from
anyone (including the committer) can be sent by reference.  Proposals
sent by reference are specified by including the hash of the
MLSAuthenticatedContent object in which the proposal was sent (see
hash-based-identifiers).
Paragraph (version B):
Each proposal covered by the Commit is included by a ProposalOrRef
value, which identifies the proposal to be applied by value or by
reference.  Commits that refer to new Proposals from the committer
can be included by value.  Commits for previously sent proposals from
anyone (including the committer) can be sent by reference.  Proposals
sent by reference are specified by including the hash of the
AuthenticatedContent object in which the proposal was sent (see hash-
based-identifiers).
Paragraph (version A):
Construct an MLSContent object containing the Commit object.  Sign
the MLSContent using the old GroupContext as context.
Paragraph (version A):
Use the MLSContent to update the confirmed transcript hash and
update the new GroupContext.
Paragraph (version B):
Construct a FramedContent object containing the Commit object.
Sign the FramedContent using the old GroupContext as context.
Paragraph (version B):
Use the FramedContent to update the confirmed transcript hash
and update the new GroupContext.
Paragraph (version A):
Calculate the interim transcript hash using the new confirmed
transcript hash and the "confirmation_tag" from the
MLSContentAuthData.
Paragraph (version A):
If encoding as MLSPlaintext, compute the "membership_tag" value
using the "membership_key".
Paragraph (version A):
If encoding as an MLSCiphertext, encrypt the message using the
"sender_data_secret" and the next (key, nonce) pair from the
sender's handshake ratchet.
Paragraph (version B):
Calculate the interim transcript hash using the new confirmed
transcript hash and the "confirmation_tag" from the
FramedContentAuthData.
Paragraph (version B):
If encoding as PublicMessage, compute the "membership_tag"
value using the "membership_key".
Paragraph (version B):
If encoding as an PrivateMessage, encrypt the message using the
"sender_data_secret" and the next (key, nonce) pair from the
sender's handshake ratchet.
Paragraph (version A):
If the message is encoded as MLSCiphertext, decrypt the message
using the "sender_data_secret" and the (key, nonce) pair from
the step on the sender's hash ratchet indicated by the
"generation" field.
Paragraph (version A):
Verify that the signature on the MLSContent message as described
in Section content-authentication.
Paragraph (version B):
If the message is encoded as PrivateMessage, decrypt the
message using the "sender_data_secret" and the (key, nonce)
pair from the step on the sender's hash ratchet indicated by
the "generation" field.
Paragraph (version B):
Verify that the signature on the FramedContent message as
described in Section content-authentication.
Paragraph (version A):
Use the "confirmation_key" for the new epoch to compute the
confirmation tag for this message, as described below, and verify
that it is the same as the "confirmation_tag" field in the
MLSContentAuthData object.
Paragraph (version B):
Use the "confirmation_key" for the new epoch to compute the
confirmation tag for this message, as described below, and verify
that it is the same as the "confirmation_tag" field in the
FramedContentAuthData object.
Paragraph (version A):
External Commits MUST be signed by the new member.  In particular,
the signature on the enclosing MLSAuthenticatedContent MUST verify
using the public key for the credential in the "leaf_node" of the
"path" field.
Paragraph (version A):
The sender type for the MLSAuthenticatedContent encapsulating the
External Commit MUST be "new_member_commit".
Paragraph (version B):
External Commits MUST be signed by the new member.  In particular,
the signature on the enclosing AuthenticatedContent MUST verify
using the public key for the credential in the "leaf_node" of the
"path" field.
Paragraph (version B):
The sender type for the AuthenticatedContent encapsulating the
External Commit MUST be "new_member_commit".
Paragraph (version A):
Each Commit message is premised on a given starting state, indicated
by the "epoch" field of the enclosing MLSContent.  If the changes
implied by a Commit message are made starting from a different state,
the results will be incorrect.
Paragraph (version B):
Each Commit message is premised on a given starting state, indicated
by the "epoch" field of the enclosing FramedContent.  If the changes
implied by a Commit message are made starting from a different state,
the results will be incorrect.
Paragraph (version A):
The length of the "padding" field in "MLSCiphertextContent" can be
chosen at the time of message encryption by the sender.  Senders may
use padding to reduce the ability of attackers outside the group to
infer the size of the encrypted content.  Note, however, that the
transports used to carry MLS messages may have maximum message sizes,
so padding schemes SHOULD avoid increasing message size beyond any
such limits that exist in a given deployment scenario.
Paragraph (version B):
The length of the "padding" field in "PrivateContentTBE" can be
chosen by the sender at the time of message encryption.  Senders may
use padding to reduce the ability of attackers outside the group to
infer the size of the encrypted content.  Note, however, that the
transports used to carry MLS messages may have maximum message sizes,
so padding schemes SHOULD avoid increasing message size beyond any
such limits that exist in a given deployment scenario.
Paragraph (version A):
A group's extensions are first set by the group's creator and then
updated by GroupContextExtensions proposals.  A GroupContextExtension
proposal sent as MLSPlaintext leaks the groups' extensions.
Paragraph (version B):
A group's extensions are first set by the group's creator and then
updated by GroupContextExtensions proposals.  A GroupContextExtension
proposal sent as a PublicMessage leaks the groups' extensions.
Paragraph (version A):
Changes to the group's membership are made by means of Add and Remove
proposals.  If these proposals are sent as MLSPlaintext, then
information will be leaked about the corresponding changes to the
group's membership.  A party that sees all of these changes can
reconstruct the group membership.
Paragraph (version B):
Changes to the group's membership are made by means of Add and Remove
proposals.  If these proposals are sent as PublicMessage, then
information will be leaked about the corresponding changes to the
group's membership.  A party that sees all of these changes can
reconstruct the group membership.