Original text:
11. <del> The primary purpose of the handshake protocol is to provide an </del>  authenticated group key exchange to clients.  In order to protect <del> Application messages sent among those members of a group, the Application secret provided by the handshake key schedule is used to derive encryption keys for the Message Protection Layer. </del>  Application messages MUST be protected with the Authenticated- Encryption with Associated-Data (AEAD) encryption scheme associated messages MUST use asymmetric signatures to strongly authenticate the sender of a message. <del> Each member maintains their own chain of Application secrets, where the first one is derived based on a secret chained from the Epoch secret.  As shown in key-schedule, the initial Application secret is bound to the identity of each client to avoid collisions and allow support for decryption of reordered messages. Subsequent Application secrets MUST be rotated for each message sent in order to provide stronger cryptographic security guarantees.  The Application Key Schedule use this rotation to generate fresh AEAD encryption keys and nonces used to encrypt and decrypt future Application messages.  In all cases, a participant MUST NOT encrypt more than expected by the security bounds of the AEAD scheme used. Note that each change to the Group through a handshake message will cause a change of the group Secret.  Hence this change MUST be applied before encrypting any new Application message.  This is required for confidentiality reasons in order for members to avoid receiving messages from the group after leaving, being added to, or excluded from the group. </del> 11.1.  The group members MUST use the AEAD algorithm associated with the negotiated MLS ciphersuite to AEAD encrypt and decrypt their Application messages according to the Message Framing section. The group identifier and epoch allow a recipient to know which group secrets should be used and from which Epoch secret to start computing <del> other secrets and keys.  The "sender" identifier is used to derive the member's Application secret chain from the initial group Application secret.  The application generation field is used to determine which Application secret should be used from the chain to compute the correct AEAD keys before performing decryption. </del>  Application messages SHOULD be padded to provide some resistance against traffic analysis techniques over encrypted traffic.  CLINIC length of the plaintext by allowing to send a variable number of ciphertext blocks ? ]] <del> 11.2. </del>  Since each Application message contains the group identifier, the epoch and a message counter, a client can receive messages out of

Reviewer comments:
Basic idea: Application Key Schedule consists of a left balanced binary tree of secrets (the "AS Tree") and one symmetric ratchet per group member. The AS Tree has the same node/edge structure as the ratchet tree for that epoch. Members are assigned the same leaves.Each node in the AS Tree is assigned a secret. The root's secret = applicationsecret. The secrets of children are derived from that of their parent.The secret of a leaf is the initial secret of a symmetric hash ratchet. The ratchet generates the key/nonce sequence used by the leaf's group member to encrypt messages during that epoch. Other comments: I included a "Deletion Schedule": keys, nonces are 'consumed' if they are used to encrypt or successfully decrypt a message. secrets are 'consumed' if value derived from it is consumed. Any consumed value must be immediately deleted for reasons of forward secrecy.I was very generous with contexts for all calls to HKDF. E.g. I included Hash(GroupState[n]) in the context of every call to HKDF. True, I dont think its neccesary to prove security against more coarse adversarial models (e.g. that only do all-or-nothing state leakage). Still, as a matter of the "defense in depth" principle I think including as much relevant context as possible during all key/secret derivation is a good idea. Albeit only as long as the price (in computation, complexity, etc) is not to high. To that end, I purposefully use Hash(GroupState_[n]) in the context as it is short, needs only to be computed once at the start of the epoch and can then be used to very cheaply to construct all contexts needed for the rest of the new application key schedule.Disclaimer: I'm a bit of a noob when it comes to Markdown, RFCs and github so forgive me (and tell me!) if I've done something wrong here. Co-contributors: Benjamin Beurbouche, Sandro Coretti, Yevgeniy Dodis,
Merging this despite outstanding comments. NAME and I will handle our requested edits in a couple of follow-up PRs.
Here's the Weekly Digest for : This week, 8 issues were created. Of these, 4 issues have been closed and 4 issues are still open. :greenheart: , by :greenheart: , by :greenheart: , by :greenheart: , by :heart: , by :heart: , by :heart: , by :heart: , by The issue most discussed this week has been: :speaker: , by It received 9 comments. This week, no pull requests has been proposed by the users. This week, 4 users have contributed to this repository. They are , , , and . This week, no user has starred this repository. This week, there have been 4 commits in the repository. These are: :hammerandwrench: Merge pull request from rozbb/mlsplaintext-signature Multiple clarifications around Framing by :hammerandwrench: Merge pull request from rozbb/hpke-encrypt Clarify how HPKE ciphertexts are computed by :hammerandwrench: by :hammerand_wrench: by # RELEASES This week, no releases were published. That's all for this week, please watch :eyes: and star :star: to receive next weekly updates. :smiley:
Here's the Weekly Digest for : - - Last week 4 issues were created. Of these, 1 issues have been closed and 3 issues are still open. :greenheart: , by :greenheart: , by :greenheart: , by :heart: , by :speaker: , by It received 4 comments. - - Last week, 9 pull requests were created, updated or merged. Last week, 8 pull requests were updated. :yellowheart: , by :yellowheart: , by :yellowheart: , by :yellowheart: , by :yellowheart: , by :yellowheart: , by :yellowheart: , by :yellowheart: , by Last week, 1 pull request was merged. :purpleheart: , by - - Last week there were 4 commits. :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by - - Last week there was 1 contributor. :bustinsilhouette: - - Last week there was 1 stargazer. :star: You are the star! :star2: - - Last week there were no releases. - - That's all for last week, please :eyes: Watch and :star: Star the repository to receive next weekly updates. :smiley: You can also .
We should ensure that there is adequate anti-replay protection for both Handshake and Application messages. (In particular, we should define what anti-replay issues are a concern.) Could be related to if we want to solve it at that framing layer.
It looks like application key schedule on its own may not be enough to prevent replay attacks if out-of-order messages are supported (and it seems like they are supported according to section 9.2.1). Lets say we are at epoch x, and the receiver derives applicationsecret[sender][0] for epoch x. Then, the receiver receives message1 (generation = 1) first before message0. In order to decrypt message1, the receiver needs to advance the application secret forward once to applicationsecret[sender][1] to get message1 nonce and AEAD secret. The receiver then happily processes message 1. However, the receiver cannot forget applicationsecret[sender][0] at this time; otherwise it will never be able to decrypt message0 so it has to keep applicationsecret[sender][0] around. If the receiver receives message1 again, it can compute applicationsecret[sender][1] from applicationsecret[sender][0] and process the message. Hence, it seems that key schedule on its own will not prevent replay attacks. The receiver needs to remember that it has already processed message1. The same problem may apply to receiving a message from epoch N+1 while not all messages from epoch N have been received (if such case is possible). Replay attack counter-measures may be implemented as part of key schedule logic or separately, but it looks like implementors need to pay attention to this.
Obviously, if you keep a previous application secret, you are breaking FS. This is forbidden by the protocol. The protocol mandates: "Receivers MUST delete an Application Secret once it has been used to derive the corresponding AEAD key and nonce as well as the next Application Secret. Receivers MAY keep the AEAD key and nonce around for some reasonable period."
Cf. "Updating the Application Secret"
Does it mean that receiving out-of-order messages is not possible? If I abandon applicationsecret[sender][0] and advance to applicationsecret[sender][2] after receiving message 1 before message 0, I will never be able to process message 0. Is this intended behavior or am I missing something?
No, you can do out of order, but what you keep are the AEAD keys/nonces and not the Application Secrets. The idea is the following: 1 - Compute Application Secret[sender][0] 2 - Derive AEAD Key[Sender][0] and AEAD Nonce[Sender][0] from Application Secret[sender][0] 3 - Overwrite Application Secret[sender][0] with Application Secret[sender][1] Basically, you should see these 3 steps as a single operation Now, if you iterate over that you can get more AEAD Keys and nonces [0 ... N] to receive out of order. Because of step 3 you have local Forward Secrecy. Note that you never store more than a single (the latest) Application Secret per sender and that you have the keys [0...N] to decrypt out of order.
Makes sense. Thanks for explaining. I suspect receiving out of order messages from a different epoch works in a similar way. If I am at epoch 0, and I receive a message from epoch 2, I derive and keep applicationsecret for epoch 1 and roll the initsecret forward. From the implementation perspective, how do I know when I can safely discard an application secret for a particular epoch? Or how do I know that no more messages are coming for a particular sender/epoch? Do you think there is value in adding a paragraph clarifying how the key schedule ensures replay attack protection to the spec? I know these are probably all implementation questions, but I suspect these may be the questions the implementors may be asking.
NAME I have some text stashed for when to discard the previous application secrets after there is a new epoch, so I will handle that. The idea is that you "publish" the number of application messages you sent in the previous epoch, but that is to be discussed... Regarding replay, if you asked, it means clarification might be helpful here, do you want to submit a PR and assign me for review ? Otherwise just tell me and I'll handle it... : )
NAME I think you should review the below and update the spec as you see fit : ) -- I would update section 9.2.1 with something like: If receiver's application secret is at generation N, and the receiver receives an out of order message with generation N+x (where x>0), the receiver MUST advance the application secret forward to application secret N+x+1 after processing the out of order message. For every message with generation between N and N+x-1 (messages that have not been received), the receiver SHOULD derive AEAD nonce and AEAD key and store them in order to be able to decrypt these messages later. Application secret MUST NOT be kept at generation N in order allow for decryption of out-of-order messages. Instead, stored AEAD key and nonce will allow for decryption of out-of-order messages when received later. -- We may also introduce a short new section "Message Replay Protection" with something like: Application key schedule provides replay attack counter-measures. If a message is replayed, the receiver should not have the right AEAD key nor have the application secret that could be used for deriving the right AEAD key for the replayed message. Hence, replayed message will be rejected by the receiver.
I think this is adequately addressed by and

Revised text:
11.  <ins> The primary purpose of the Handshake protocol is to provide an </ins> authenticated group key exchange to clients.  In order to protect  <ins> Application messages sent among the members of a group, the Application secret provided by the Handshake key schedule is used to derive nonces and encryption keys for the Message Protection Layer according to the Application Key Schedule.  That is, each epoch is equipped with a fresh Application Key Schedule which consist of a tree of Application Secrets as well as one symmetric ratchet per group member. Each client maintains their own local copy of (parts of) the Application Key Schedule for each epoch during which they are a group member.  They derive new keys, nonces and secrets as needed while deleting old ones as soon as they have been used. </ins> Application messages MUST be protected with the Authenticated- Encryption with Associated-Data (AEAD) encryption scheme associated messages MUST use asymmetric signatures to strongly authenticate the sender of a message.  11.1. <ins> The Application schedule begins with the Application secrets which are arranged in an "Application Secret Tree" or AS Tree for short; a left balanced binary tree with the same set of nodes and edges as the epoch's ratchet tree.  Each leaf in the AS Tree is associated with the same group member as the corresponding leaf in the ratchet tree. Nodes are also assigned an index according to their position in the array representation of the tree (described in tree-math).  If V is a node in the AS Tree then IndexOf(V) denotes it's index while V.leftChild and V.rightChild denote the children of V (if they exist). Each node in the tree is assigned a secret.  The root's secret is simply the application_secret of that epoch.  (See key-schedule for the definition of application_secret.) The secret of any other node in the tree is derived from its parent's secret using a call to Derive-Secret.  The context for the call is the (hash of the) Group state of the epoch and the index of the node whose secret is being derived. If V is a node in the ASTree then ASTreeContext[V] denotes an ASTreeContext variable with: gshash = Hash(GroupState_[n]) node_index = IndexOf(V) Moreover, the secrets of the children of V are defined to be: Note that fixing concrete values for GroupState_[n] and application_secret completely defines all secrets in the AS Tree. 11.2. The secret of a leaf in the AS Tree is used to initiate a symmetric hash ratchet which generates a sequence of keys and nonces.  The group member assigned to that leaf uses the j-th key/nonce pair in the sequence to encrypt (using the AEAD) the j-th message they send during that epoch.  In particular, each key/nonce pair MUST NOT be used to encrypt more than one message. More precisely, the initial secret of the ratchet for the group member assigned to the leaf with index i is simply the secret of that leaf. Keys, nonces and secrets of ratchets are derived using HKDF-Expand- Label.  The context in a given call consists of (a hash of) the current Group state, the index of the sender's leaf in the ratchet tree and the position in the ratchet.  In particular, the index of the sender's leaf in the ratchet tree is the same as the index of the leaf in the AS Tree used to initialize the sender's ratchet. Ratchet_position is initialized to 1 for the first HKDF-Expand-Label call of a new ratchet and incremented for each subsequent call in that ratchet. HashRatCont[i, j] denotes a RatchetContext variable where: gshash = Hash(GropuState_[n]) leaf_index = i ratchet_position = j Using this notation the ratchet for the group member at leaf i is defined to be: Here, AEAD.nonceLen and AEAD.keyLength denote the lengths in bytes of the nonce and key for the AEAD scheme defined by the ciphersuite. 11.3. It is important to delete all security sensitive values as soon as they, or another value derived from them, is used for encryption or decryption. More precisely, the values application_[i]_[j]_key and application_[i]_[j]_nonce are said to be "consumed" if they were used either to: encrypt or (successfully) decrypt a message or if a key, nonce or secret derived from S has been consumed.  (This goes both for values derived via Derive-Secret and HKDF-Expand- Label). Here, S may be the init_secret, update_secret, epoch_secret, application_secret as well as any secret in the AS Tree or one of the ratchets. As soon as a group member consumes a value they MUST immediately delete (all representations of) that value.  This is crucial to ensuring Forward Secrecy for past messages.  Members MAY keep unconsumed values around for some reasonable amount of time even if their generating secret was already consumed (e.g. due to out of order message delivery). For example, suppose a group member encrypts or (successfully) decrypts a message using the j-th key and nonce in the i-th ratchet. Then, for that member, at least the following values have been consumed and MUST be deleted: the init_secret, update_secret, epoch_secret, application_secret of that epoch, all node secrets in the AS Tree on the path from the root to the leaf with index i, the first j secrets in the i-th ratchet and application_[i]_[j]_key and application_[i]_[j]_nonce. Concretely, suppose we have the following AS Tree. Then if a client uses key KD1 and nonce ND1 during epoch n then it must consume (at least) values G, F, D0, D1, KD1, ND1 as well as the update_secret and init_secret used to derive G (i.e. the application_secret). 11.4. During each epoch senders MUST NOT encrypt more messages than permitted by the security bounds of the AEAD scheme used. Note that each change to the Group through a Handshake message will also set a new application_secret.  Hence this change MUST be applied before encrypting any new Application message.  This is required both to ensure that any users removed from the group can no longer receive messages and to (potentially) recover confidentiality and authenticity for future messages despite a past state compromise. [[ OPEN ISSUE: At the moment there is no contributivity of Application secrets chained from the initial one to the next generation of Epoch secret.  While this seems safe because cryptographic operations using the application secrets can't affect the group init_secret, it remains to be proven correct. ]] 11.5. </ins> The group members MUST use the AEAD algorithm associated with the negotiated MLS ciphersuite to AEAD encrypt and decrypt their Application messages according to the Message Framing section. The group identifier and epoch allow a recipient to know which group secrets should be used and from which Epoch secret to start computing  <ins> other secrets and keys.  The sender identifier is used to identify the member's symmetric ratchet from the initial group Application secret.  The application generation field is used to determine how far into the ratchet to iterate in order to reproduce the required AEAD keys and nonce for performing decryption. </ins> Application messages SHOULD be padded to provide some resistance against traffic analysis techniques over encrypted traffic.  CLINIC length of the plaintext by allowing to send a variable number of ciphertext blocks ? ]]  <ins> 11.6. </ins> Since each Application message contains the group identifier, the epoch and a message counter, a client can receive messages out of