jiebi/CodeConvo huggingface dataset:
Code change:
If the EAP-TLS peer authenticates successfully, the EAP-TLS server MUST send an EAP-Request packet with EAP-Type=EAP-TLS containing TLS records conforming to the version of TLS used.  The message <del> flow ends with the EAP-TLS server sending an EAP-Success message. </del> <ins> flow ends with a protected success indication from the EAP-TLS server, follwed by an EAP-Response packet of EAP-Type=EAP-TLS and no data from the EAP-TLS peer, follwed by EAP-Success from the server. </ins> If the EAP-TLS server authenticates successfully, the EAP-TLS peer MUST send an EAP-Response message with EAP-Type=EAP-TLS containing

Related discussion:
text: The replace or amend strategy does not really work.... [Roman] I'd propose a simple fix by using (approximate phrases such as) either: This section updates Section xxx of [RFC5216] by amending it with the following text. (for the cases where the intent is to keep the existing text in rfc5216 but add this new text) This section updates Section xxx of [RFC5216] by replacing it with the following text. (for the cases where the intent is to replace an entire section in rfc5216)
NAME We should likely not do to much changes. Maybe we can write something like Amends with the following text. TLS 1.2 specific details in RFC 5216 are replaced. Requirement in the new takes precedence over requirements in the old text.
This review was addressed in earlier submissions. closing
Code change:
all streams other than the first will be marked as bundle-only. This policy aims to minimize candidate gathering and maximize multiplexing, at the cost of less compatibility with legacy <del> endpoints.  When acting as answerer, if there if no bundle group in the offer, the implementation will reject all but the first m= section. </del> <ins> endpoints.  When acting as answerer, the implementation will reject any m= sections other than the first m= section, unless they are in the same bundle group as that m= section. </ins> As it provides the best tradeoff between performance and compatibility with legacy endpoints, the default bundle policy MUST

Related discussion:
text: NAME NAME PTAL
From Berlin: "A clarification to that rule was found when an offer is received with some m= lines bundled and some not; you accept all m= lines that are possible to bundle with the first m= line. "
I think we'll also have to update section 5.3.1 (Initial Answers) where it lists conditions for rejecting an m= section. Also, do we need to make similar modifications for the "balanced" bundle policy? LG with nits
Code change:
Run by the client when processing the server response in the issuance phase of the protocol.  The output of this function is an array of "RedemptionToken" objects that are unlinkable from the server's <del> computation in "PP_Issue". </del> <ins> computation in "Issue". </ins> Inputs:

Related discussion:
text: These functions do not need the "PP_" namespace prefix as it's implied from the specification. I also removed underscores in favor of normal camel case notation.
Code change:
between a specific local address and a specific peer address, where an address is the two-tuple of IP address and port. <del> Path validation tests that packets can be both sent to (PATH_CHALLENGE) and received from (PATH_RESPONSE) a peer on the path.  Importantly, it validates that the packets received from the migrating endpoint do not carry a spoofed source address. </del> <ins> Path validation tests that packets sent on a path to a peer are received by that peer.  Path validation is used to ensure that packets received from a migrating peer do not carry a spoofed source address. Path validation does not validate that a peer can send in the return direction.  The peer performs independent validation of the return path. </ins> Path validation can be used at any time by either endpoint.  For instance, an endpoint might check that a peer is still in possession

Related discussion:
text: The original design for path validation attempted to validate return reachability by requiring that PATHRESPONSE followed the same path as PATHCHALLENGE. We removed that long ago, but the text retained echoes of that choice.
Currently, does not specify which path a PATHRESPONSE needs to be sent over. That was somewhat surprising to me, as I had expected it to be scoped to the path that PATHCHALLENGE was received on. If it isn't, could we add a sentence to the Path Validation Responses subsection to explicitly state that a PATH_RESPONSE is not scoped to a given path (and ideally explaining why it isn't)?
So I thought we were really crisp about this, but we were not. PATHRESPONSE does not need to follow the path on which PATHCHALLENGE was received. We're clear about this when it comes to preferred address handling, but there is some vestigial text that contradicts this. That should be fixed.
For the record, I personally believe that adequately resolves this issue while remaining purely editorial.
Thanks for being so prompt David. I will leave this for a bit to allow others a chance to spot errors, but I plan to merge this before we publish -30 (real soon now, I hope).
Yes, the requirement was removed but the inverse statement was never explicitly added. corrects that.
Thanks for writing this up, tiny wording suggestions, but looking great! Thanks for writing this up, I think this adequately resolves my concerns from .
Code change:
2.4.5. <del> The "count" function extension provides a way to obtain the number of nodes in a nodelist and make that available for further processing in the filter expression: </del> <ins> The "count()" function extension provides a way to obtain the number of nodes in a nodelist and make that available for further processing in the filter expression: </ins> Its only argument is a nodelist.  The result is a value, an unsigned integer, that gives the number of nodes in the nodelist.  Note that

Related discussion:
text: Use parentheses as an indication that something is a function. Also, don't confuse the reader by alluding to potential future alternatives to value(). Reviewers: is this an improvement? It's a draft PR for now until we decide the change is worthwhile.
I think we'll need to explain the () notation, which should be familiar to C programmers but not necessarily to people who grew up on other languages. I also think we have a few more examples that point to hypothetical functions, such as , , .
I don't think there's a great point at which to explain that notation and, based on your observation, I'm going off the idea.
NAME Let's see how pans out before taking the current PR any further. Once I remove the function parentheses, the two PRs are changing the same text.
would be the place.
NAME As you suggested, I introduced this in 1.1, but near the start since it's notation rather than terminology. I did a regexp search to find and fix the remaining examples (your list was complete). In doing so, I found the strange markup and removed the backticks since there was no good reason for them.
We could do the fun() explanation and completeness search in a separate PR.
Code change:
This document uses the following terms: Appraisal Policy for Evidence: A set of rules that direct how a <del> verifier evaluates the validity of information about an Attester. </del> <ins> Verifier evaluates the validity of information about an Attester. </ins> Compare /security policy/ in [RFC4949]. Appraisal Policy for Attestation Result: A set of rules that <del> direct how a Relying Party evaluates the validity of information about an Attester.  Compare /security policy/ in [RFC4949]. </del> <ins> direct how a Relying Party uses the evaluation results about an Attester generated by the Verifiers.  Compare /security policy/ in [RFC4949]. </ins> Attestation Result: The evaluation results generated by a Verifier, typically including information about an Attester, where

Related discussion:
text: When comparing the term 'Appraisal Policy for Evidence' and 'Appraisal Policy for Attestation Result', they are both saying 'evaluates the validity of information about an Attester'. This makes me feel Verifier and Relying Party are doing the same things and they are redundant. I think it's more appropriate to say that the Relying Party evaluates the evaluation results generated by the Verifiers.
Code change:
As QUIC is a general purpose transport protocol, there are no requirements that servers use a particular UDP port for QUIC.  For applications with a fallback to TCP that do not already have an <del> alternate mapping to UDP, the registration (if necessary) and use of the UDP port number corresponding to the TCP port already registered for the application is RECOMMENDED.  For example, the default port for HTTP/3 QUIC-HTTP is UDP port 443, analogous to HTTP/1.1 or HTTP/2 over TLS over TCP. </del> <ins> alternate mapping to UDP, usually the registration (if necessary) and use of the UDP port number corresponding to the TCP port already registered for the application is appropriate.  For example, the default port for HTTP/3 QUIC-HTTP is UDP port 443, analogous to HTTP/1.1 or HTTP/2 over TLS over TCP. </ins> Applications could define an alternate endpoint discovery mechanism to allow the usage of ports other than the default.  For example,

Related discussion:
text: Issue: “and use of the UDP port number corresponding to the TCP port already registered for the application is RECOMMENDED”. I agree with the intent, but here an RFC2119 keyword is used, but is this intended, and can this please cite the RFC that says this rather than just stating this.
Similarly noted in
PR removes normative language and says "usually ... appropriate" instead. Is that okay? Or should the wording be stronger?
Code change:
13.1.3. <del> A Remove proposal requests that the member with LeafNodeRef "removed" be removed from the group. </del> <ins> A Remove proposal requests that the member with the leaf index "removed" be removed from the group. </ins> A member of the group applies a Remove message by taking the following steps:

Related discussion:
text: This seems to be a layer of indirection that doesn't add any value to implementation.
The Credentials section claims there is an epoch id field in key packages. I don't think that actually exists. My apologies if this is a duplicate issue.
Addressed in but may need to be pulled out depending on the fate of that PR
contains all of the Proposals that were previously sent within the same epoch. This seems unnecessary, since all members should have them anyway. The list of in the actual message should be enough for members to parse and validate a message. We should discuss if we can de-duplicate this, since the list of Proposals might be quite long.
The current definition of is as follows; Maybe this issue is obsolete?
Seems it is now obsolete indeed.
I don't have a strong opinion on this question, but this change seems sensible to me. The use of LeafNodeRef requires either (a) a linear scan through the tree, which is time-expensive in large trees, or (b) keeping an index that maps LeafNodeRef values to indices, which is storage-intensive in large trees. IIRC, the change to LeafNodeRef was made in the context of NAME work to make the tree description less tied to the array representation. In general, that is the right thing to do, and it's good that we did it. But we still have leaf indices anyway, for . Since we still have the concept, we might as well use it where it makes sense. And it certainly seems to me like and make sense, since they are internal to the protocol. In case folks are worried about the application-facing API -- MLS stacks can certainly be more intelligent, e.g., exposing or or . But they can do that regardless of this PR.
Code change:
extension, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. <del> 4.4. </del> <ins> 4.4.4. </ins> The DATAGRAM capsule (see iana-types for the value of the capsule type) allows an endpoint to send a datagram frame over an HTTP

Related discussion:
text: Had offline conversation with Lucas, conclusion was that this is good enough to merge to allow interop - we'll have plenty of time to figure out details in subsequent issues and PRs.
Code change:
sequence 7b bd decodes to 15293; and the single byte 25 decodes to 37 (as does the two byte sequence 40 25). <del> Versions (versions) and error codes (error-codes) are described using integers, but do not use this encoding. </del> <ins> Versions (versions) and packet numbers sent in the header (packet- encoding) are described using integers, but do not use this encoding. </ins> 17.

Related discussion:
text: Error codes do use varints, but packet numbers (in the header) don't.
Code change:
in the credential field of the KeyPackage objects in the leaves of the tree (including the InitKeys used to add new members). <ins> To disambiguate different signatures used in MLS, each signed value is prefixed by a label as shown below: Here, the functions "Signature.Sign" and "Signature.Verify" are defined by the signature algorithm. </ins> The ciphersuites are defined in section mls-ciphersuites. 6.2.

Related discussion:
text: Signatures as specified in the MLS protocol document are ambiguous, in the sense that signatures produced for one purpose in the protocol can be (maliciously) used in a different place of the protocol. Indeed, we found that for example, a can have the same serialization as , which proves that one signature could be accepted for different structures. The collisions we have found so far are quite artificial, so it is not super clear how to exploit this, but at least it makes it impossible to have provable security. The solution is pretty simple, we simply prefix each signed value with a label, in a fashion similar to . That way, when calling you can give the structure name in the argument.
Something that is still bothering me is the structure: struct { select (URL) { case member: GroupContext context; case preconfigured: case newmember: struct{}; } WireFormat wireformat; opaque groupid; uint64 epoch; Sender sender; opaque authenticateddata; ContentType contenttype; select (MLSPlaintextTBS.contenttype) { case application: opaque applicationdata; case proposal: Proposal proposal; case commit: Commit commit; } } MLSPlaintextTBS; Since the first is done on a field defined after it, this structure is not parsable. We could say that's not a problem since we only need to serialize it, but for security purposes I would recommend to put it at the end, like this: struct { WireFormat wireformat; opaque groupid; uint64 epoch; Sender sender; opaque authenticateddata; ContentType contenttype; select (MLSPlaintextTBS.contenttype) { case application: opaque applicationdata; case proposal: Proposal proposal; case commit: Commit commit; } select (URL) { case member: GroupContext context; case preconfigured: case newmember: struct{}; } } MLSPlaintextTBS; What do you think about it?
Nice one! Crafting collisions is probably not straightforward, but eliminating the the risk altogether is the way to go.
It is actually quite easy to craft collisions, I made a script do find them: URL (I wanted to check whether there was accidentally a way do disambiguate the structures)
Introduced in .
Code change:
in the credential field of the KeyPackage objects in the leaves of the tree (including the InitKeys used to add new members). <ins> To disambiguate different signatures used in MLS, each signed value is prefixed by a label as shown below: Here, the functions "Signature.Sign" and "Signature.Verify" are defined by the signature algorithm. </ins> The ciphersuites are defined in section mls-ciphersuites. 6.2.

Related discussion:
text: s currently have two usages in the spec: Pre-published key packages that you can download and put in a leaf when adding a new member leaf node content that you update when doing a full Currently, things have been designed to use only one structure for both uses, leading to some weirdness such as: and are useful in the usage 1, but are parameters of the group in usage 2. is a good name in usage 1, but would better be named in usage 2. some data is important in usage 2 and have no meaning in usage 1, hence they were designed as "mandatory-when-updating extensions" (such as , and we were also discussing about adding the in to help prevent cross-group attacks) How about using different structures for these? // Essentially identical to KeyPackage struct { ProtocolVersion version; CipherSuite ciphersuite; HPKEPublicKey hpkeinitkey; opaque endpointid; Credential credential; Extension extensions; opaque signature; } PrePublishedKeyPackage; struct { HPKEPublicKey hpkekey; opaque endpointid; Credential credential; opaque parenthash; opaque groupid; Extension extensions; opaque signature; } LeafNodeContent; enum { reserved(0), prepublishedkeypackage(1), leafnodecontent(2), (255) } LeafNodeType; struct LeafNode { // This is not included in the signature, but with the "unambiguous signature" PR that's not a problem LeafNodeType type; select(URL) { case prepublishedkeypackage: PrePublishedKeyPackage data; case leafnode_content: LeafNodeContent data; } } What would you think about refactoring like this?
If we're doing this, I'd suggest including a dedicated public key to encrypt Welcome messages to for the . NAME suggested this at some point. It gives us better FS guarantees, because the receiver of the can delete the corresponding private key immediately after decryption, while they might have to keep the other key around for a bit until they can actually issue an update. This might also help clarify .
Ties into as well because is an example of an extension that is required and should be a field instead
NAME one concern I have is how is that field in created?
When sending a full , the participant includes a new in the (it replaces the field).
Code change:
in the credential field of the KeyPackage objects in the leaves of the tree (including the InitKeys used to add new members). <ins> To disambiguate different signatures used in MLS, each signed value is prefixed by a label as shown below: Here, the functions "Signature.Sign" and "Signature.Verify" are defined by the signature algorithm. </ins> The ciphersuites are defined in section mls-ciphersuites. 6.2.

Related discussion:
text: It computes the signature with where: corresponds to all the fields of except (the usual thing) comes from
What about the scenario where Alice pulls down Bob's key package to add him to the group? In that case Alice can't do the conversion between formats on Bob's behalf.
Alice don't have to do the conversion, this is why either contain a (when adding someone to the group) or a (when updating your own key package).
Ah somehow I missed that part in your original post. Makes sense
I like this general direction. It solves a few things. Instead of having leaf nodes contain either a prepublished thing or a normal leaf node, how about having the prepublished thing wrap the leaf node thing? As a bonus, we get separation between the key pair used for Welcome encryption and the key pair that goes in the leaf for TreeKEM. Then when Alice adds Bob, she extracts his LeafNodeContent and sends that in the Add. That doesn't let the other members of the group verify that Alice did the right thing w.r.t. expiry, but I'm not heartbroken about that. We might also be able to remove the extensions field from the outer (KeyPackage) wrapping if we turn the extension into KeyPackage field. I expect we probably need leaf extensions, but would be open to making into a field.
Why not keep sending the KeyPackage in the Add? That wouldn't cost much and would allow everyone to validate the lifetime. Note, that the lifetime is crucial in achieving PCS for pre-published key material. If I compromise Bob and get hold of the private key material of a bunch of his KeyPackages, I can add "Bob" to any group I want as long as the Credential inside the LeafNodeContent remains valid and Bob doesn't revoke the LeafNodeContent somehow. Also, we'll have to do this if we want to enable any member to send the Welcome message as you proposed here: URL
I agree that including inside is quite clean, but something is bothering me with this approach: I'd like that the is signed by the participant occupying that leaf, to protect against cross-group attacks. In the first message of this issue I did this by including in , but in fact we don't need to store it in the leaf, we just need to include it in the .
Code change:
in the credential field of the KeyPackage objects in the leaves of the tree (including the InitKeys used to add new members). <ins> To disambiguate different signatures used in MLS, each signed value is prefixed by a label as shown below: Here, the functions "Signature.Sign" and "Signature.Verify" are defined by the signature algorithm. </ins> The ciphersuites are defined in section mls-ciphersuites. 6.2.

Related discussion:
text: In any case, if we want to include in the signature, we need a way to differentiate between leaves that triggered a commit and the ones that are "fresh". And for that I think using a tagged-union struct is the cleanest way to do it.
It always feels a bit lazy to use an extension (and implementations have to be careful to check for their presence), but we could use a extension in the same way that we use a extension. You will find both of them only on LeafContents that were updated at least once. Another result of including GroupId in the KeyPackage is that the signature will explicitly sign the and I'm not sure if that doesn't completely destroy any deniability guarantees we can still get from MLS.
I don't think there's really a good way to get the into the leaf. Because of prepublication, it would have to be optional, but in order to prevent attacks, you need rules to decide whether it's required in a given situation. It seems like the best you can do is basically TOFU: When you first get the tree, you can't validate whether the groupid should be in a given leaf or not Once you're a member, you require that groupid is sent in Update and UpdatePath.leafkey_package I could live with a solution of that character, but given it's a bit complex, might prefer to leave it out unless we get a useful property from it. NAME - Re: Sending KeyPackage in Add - Yep, that makes sense. So you would send KeyPackage in Add, and LeafNode in Update.
I tried to worked through what would be necessary to implement this. It looks like it would require some fairly invasive changes to be made to rationalize the document's structure before making this change. But those changes should probably be made anyway.