Section 5.1 Endorsers Comment > Does this section have difference with the definition of Endorser in architecture draft? If not, is it necessary to keep this section? Comment > This section only describes the Layered Attestation, but the scope of Endorsement is more than what's described here. Endorsement indicates the Attester's various capabilities such as Claims collection and Evidence signing. For other situations than Layered Attestation, the Endorser and Endorsement are also needed. So why only mention Layered Attestation here? I don't see any special relationship between DAA and Layered Attestation. Section 5.2 Endorsers for Direct Anonymous Attestation In order to enable the use of DAA, an Endorser role takes on the duties of a DAA Issuer in addition to its already defined duties. DAA Issuers offer zero-knowledge proofs based on public key certificates used for a group of Attesters [DAA]. Effectively, these certificates share the semantics of Endorsements, with the following exceptions: Comment > In the first sentence, I suggest saying that "a DAA Issuer takes on the role of an Endorser". o The associated private keys are used by the DAA Issuer to provide an Attester with a credential that it can use to convince the Verifier that its Evidence is valid. To keep their anonymity the Attester randomizes this credential each time that it is used. Comment > How to understand "Evidence is valid"? Does it mean the Evidence is sent from an authentic Attester and not tampered during the conveyance? Or does it mean the Evidence comes from a RoT and is trustable (although the Evidence can diverge from the Reference Values)? Comment > When saying "Attester randomizes this credential", how many credentials does an Attester have? 1) Can a DAA Issuer have multiple key pairs and use them for one Attester? 2) Can a DAA Issuer use one key pair to generate multiple credentials for one Attester? o A credential is conveyed from an Endorser to an Attester in combination with the conveyance of the public key certificates from Endorser to Verifier.


Comment > Is there another way to convey the public key certificate, for example, can the public key certificates be conveyed from Endorser to Attester first and then from Attester to Verifier? The zero-knowledge proofs required cannot be created by an Attester alone - like the Endorsements of RoTs - and have to be created by a trustable third entity - like an Endorser. Due to that semantic overlap, the Endorser role is augmented via the definition of DAA duties as defined below. This augmentation enables the Endorser to convey trustable third party statements both to Verifier roles and Attester roles. Comment > For "the definition of DAA duties as defined below", what is the definition of DAA duties? Comment > In the last sentence, the Endorsement with its original definition is the third party statement for Verifier and Attester, isn't it? So, "augmentation" isn't the correct expression. Section 6 Normative Prerequisites Attester Identity: The provenance of Evidence with respect to a distinguishable Attesting Environment MUST be correct and unambiguous. Comment > The Attester Identity is to identify which Attester the Evidence comes from. But if the Attester has multiple Attesting Environments, what should be the Attester Identity? Comment > The TPM's AIK certificate is one kind of Attester Identity, right? Attestation Evidence Authenticity: Attestation Evidence MUST be correct and authentic. Comment > Is it appropriate to say "correct Evidence"? If saying so, I think it means that the Evidence satisfies the Attestation Policy for Evidence. Authentication Secret: An Authentication Secret MUST be available exclusively to an Attester's Attesting Environment. The Attester MUST protect Claims with that Authentication Secret, thereby proving the authenticity of the Claims included in Evidence. The Authentication Secret MUST be established before RATS can take place. Comment > Does the Authentication Secret represent the identity of the Attesting Environment? Comment > How to understand the Authentication Secret, and is it necessary all the time? For example, in our implementation, during the router booting up, the BIOS measures the BootLoader and records the measured hash value into the TPM, and the BootLoader measures the OS Kernel and records the measured hash value into the TPM as well.


From the Layered Attestation perspective, I think (BIOS + TPM) is the Attesting Environment and (BootLoader + TPM) is also the Attesting Environment. But the Claims (measured hash values) aren't protected separately, and they finally becomes the Evidence (TPM Quote) and it's only protected by the TPM's AIK. So, what is the Authentication Secret? Section 7 Generic Information Elements Attester Identity ('attesterIdentity'): mandatory A statement about a distinguishable Attester made by an Endorser without accompanying evidence about its validity - used as proof of identity. Comment > Previous section says "Attester Identity" is about "a distinguishable Attesting Environment", and here says it's about "a distinguishable Attester". Comment > How to understand "without accompanying evidence about its validity"? Attester Identity ('attesterIdentity'): mandatory In DAA, the Attester's identity is not revealed to the verifier. The Attester is issued with a credential by the Endorser that is randomized and then used to anonymously confirm the validity of their evidence. The evidence is verified using the Endorser's public key. Comment > I think here means the DAA credential represents the Attester Identity. Comment > There is ambiguity of "that is randomized", does it mean randomized Endorser or randomized credential? Comment > For "confirm the validity of their evidence", what does "their" refer to? And what does "the validity of evidence" mean? Authentication Secret IDs ('authSecID'): mandatory A statement representing an identifier list that MUST be associated with corresponding Authentication Secrets used to protect Evidence. Comment > Previous section says "Authentication Secret" is used to protect Claims, but here says it's used to protect Evidence. Comment > As I understand, if Authentication Secret represents the identity of Attesting Environment, then it's not mandatory, at least in our implementation. Authentication Secret IDs ('authSecID'): mandatory In DAA, Authentication Secret IDs are represented by the Endorser (DAA issuer)'s public key that MUST be used to create DAA credentials for the corresponding Authentication Secrets used to protect Evidence. In DAA, an Authentication Secret ID does not identify a unique Attesting Environment but associated with a group of Attesting Environments.


This is because an Attesting Environment should not be distinguishable and the DAA credential which represents the Attesting Environment is randomised each time it used. Comment > In my understanding, here says that the DAA credential identities the Attesting Environment. Compared with the description in the "Attester Identity" part, what does the DAA credential represent actually? Reference Claims ('refClaims') mandatory Reference Claims are components of Reference Values as defined in [I-D.ietf-rats-architecture]. [Editor's Note: Definition might become obsolete, if replaced by Reference Values. Is there a difference between Claims and Values here? Analogously, why is not named Reference Claims in the RATS arch?] Comment > I suggest using Reference Values to keep consistent with the RATS arch. Reference Claims are used to appraise the Claims received from an Attester via appraisal by direct comparison. Comment > "Direct comparison" isn't the correct expression, the comparison can have other rules. Claim Selection ('claimSelection'): optional A statement that represents a (sub-)set of Claims that can be created by an Attester. Claim Selections can act as filters that can specify the exact set of Claims to be included in Evidence. An Attester MAY decide whether or not to provide all Claims as requested via a Claim Selection. Comment > The "all Claims" may be ambiguous, I'd like to double check, does it refer to all Claims that the Attester can create or refer to all Claims requested in the Claim Selection? Section 8.1 Challenge/Response Remote Attestation Comment > In the sequence diagram, some elements in the bracket are not defined in the "Information Elements" section, such as targetEnvironment, collectedClaims, eventLog. Should these elements be defined? Section 9 Additional Application-Specific Requirements Depending on the use cases covered, there can be additional requirements. An exemplary subset is illustrated in this section. Comment > Here starts to talk about "additional requirements", but I wonder there is no other places in this draft talking about requirement, so what are the basic requirements? Regards & Thanks! Wei Pan


N was introduced in to describe how a sender might pace at a rate that allows it to send a congestion window's worth of data in a period that is shorter than an RTT. This PR clarifies text that goes into unnecessary detail, trying to describe assumptions (the network is spreading the packets out, for example, resulting in an ack clock).
Can we make progress in this one?
Yes, I'm waiting for the design issues to get done before moving on the remaining editorial ones.
I think that has happened now :-)
Nudge


The client configuration section says: ... but the examples contain: Which is it?
This was an accident, I suspect it dates back to when the document referred to which contains both path and query. Fixing to mention both path and query via .


NAME does this look better?
LGTM, though I'd change the attacker from a "he" to a "they" on general principles.
Not a huge fan of the singular "they", but can't be bothered to rewrite around it :)
Yes, this is clearer. Thanks. Saying "will cause the server to query an arbitrary URI" is good. Technically you can even specify a non-HTTP protocol in an HTTP redirect, and this language should cover that too. (Go's net/http used by Boulder only does HTTP and HTTPS I think, but things like libcurl support a slightly insane number of protocols.) I'm not sure if the usages of "URI" vs "URL" in this section are correct, you may want to make them consistent. I never know which one to actually use. This looks good to me.


This replaces all mentions of capport (other than document slugs) with "captive portal". Note: this change includes the title of the document.
Joel Halpern writes, We should do this.
Or erase all mentions of 'capport'


The definition was a little loose, so I rewrote it. We only need to use 0x0a and 0x0b, which is lucky and it lets us avoid much of the mess that QUIC has around bits in the type. I've also added definitions for the fields in the frame.


Section 3.1 says to include the PPM task ID in a field on the problem details JSON object, but the task ID may be any 32 byte value, and may not be representable as a Unicode string. I propose that we base64-encode the task ID here to resolve this.


URL Greetings! I got as far as I could with time constraints through the rest of the document. There are a few sections I'll likely go back over again as I was short on time when reviewing them, but do hope this is helpful towards improving the document. This review is from the editors revision on github that I started my review earlier int he week. Section 4.2: I find the following grouping a bit confusing: "Places that Attesting Environments can exist include Trusted Execution Environments (TEE), embedded Secure Elements (eSE), and BIOS firmware." This has an attesting environment as a processor, an element, and as compiled code. That doesn't seem right, especially when you refer to the attesting environment as a "place". Do you mean where BIOS is executed perhaps? I would expect a TEE and maybe other components where security functions are offloaded, which is in some cases to a processor other than a TEE like a GPU (I'm not making a recommendation to do that here, just stating what is happening in ecosystems that exist). The following text is a little confusing, in particular, the last sentence: "An execution environment may not, by default, be capable of claims collection for a given Target Environment. Attesting Environments are designed specifically with claims collection in mind." If the attesting environment is a place, TEEs and other processors were not necessarily designed with claims in mind. If you can help to explain an attesting environment better, I can help to phrase it more clearly to convey the intended set of points as I think there are several. Section 4.3 Consider changing from: "By definition, the Attester role takes on the duty to create Evidence." To: "By definition, the Attester role creates Evidence." The following sentence is a run on and I think some additional information will help provide clarity. I don't think it's the role that is composed of nest environments. Current: "The fact that an Attester role is composed of environments that can be nested or staged adds complexity to the architectural layout of how an Attester can be composed and therefore has to conduct the Claims collection in order to create believable attestation Evidence." How about: "An Attester may be one or more nested or staged environments, adding complexity to the architectural structure.


The unifying component is the root of trust and the nested, staged, or chained attestations produced. The nested or chained structure should include claims, collected by the attester to aid in the assurance or believability of the attestation Evidence." The following sentence should be broken into two: "This example could be extended further by, say, making the kernel become another Attesting Environment for an application as another Target Environment, resulting in a third set of Claims in the Evidence pertaining to that application." Proposed: "This example could be extended further by making the kernel become another Attesting Environment for an application as another Target Environment. This results in a third set of Claims in the Evidence pertaining to that application." How about changing the following sentence from: "Among these routers, there is only one main router that connects to the Verifier. " To: "A multi-chassis router, provides a management point and is the only one that connects to the Verifier. " For the following sentence, trying to remove the use of a word twice in a row and convey the same intent. Old: "After collecting the Evidence of other Attesters, this inside Verifier verifies them using Endorsements and Appraisal Policies (obtained the same way as any other Verifier), to generate Attestation Results." Proposed: "After collecting the Evidence of other Attesters, this inside Verifier uses Endorsements and Appraisal Policies (obtained the same way as any other Verifier) in the verification process to generate Attestation Results." I may try another pass at section 4 to improve readability. Section 5, Consider breaking this into 2 sentences, from: "This section includes some reference models, but this is not intended to be a restrictive list, and other variations may exist." To: "This section includes some reference models. This is not intended to be a restrictive list, and other variations may exist." Section 5.1 Two result words together is not necessary. Change from: "The second way in which the process may fail is when the resulting Result is examined by the Relying Party, and based upon the Appraisal Policy, the result does not pass the policy. "


To: "The second way in which the process may fail is when the Result is examined by the Relying Party, and based upon the Appraisal Policy, the result does not pass the policy. " I suggest making the last paragraph the second paragraph. It's easier to read than the others and provides an introduction to the model before you begin talking about how it might fail. ** I may come back to this section to provide wording suggestions. Section 5.2 I suggest moving the last paragraph to the first in this instance. It also provides a nice high-level overview. The current paragraph 1&2 flow well together, hence this order suggestion. The third paragraph is a really long way of stating that interoperability is required. Entities must be able to create, send, receive, and process data (hence the need for a standard). It's fine, but could be shorter. Section 5.3: OLD: "One variation of the background-check model is where the Relying Party and the Verifier on the same machine, and so there is no need for a protocol between the two." Proposed: "One variation of the background-check model is where the Relying Party and the Verifier are on the same machine, performing both functions together. In this case, there is no need for a protocol between the two." I think the addition is necessary or you could scratch your head wondering why no protocol is needed. If they are separate functions on the same system, you'd need some way for the relying party to access the results of the verifier. The next sentence could benefit from being made into several. OLD: "It is also worth pointing out that the choice of model is generally up to the Relying Party, and the same device may need to create Evidence for different Relying Parties and different use cases (e.g., a network infrastructure device to gain access to the network, and then a server holding confidential data to get access to that data). As such, both models may simultaneously be in use by the same device." If the server holds confidential data, why does it need to create evidence to access the data? I'm not following the second example as written, so my proposed text may not be as intended.


Proposed: "It is also worth pointing out that the choice of model is generally up to the Relying Party. The same device may need to create Evidence for different Relying Parties and/or different use cases. For instance, a network infrastructure device may attest evidence to gain access to the network or a server holding confidential data may require attestations of evidence to gain access to the data. As such, both models may simultaneously be in use by the same device." Section 6: The first 3 sentences are fine, but if you wanted to reduce it, it could be one sentence. Current: "An entity in the RATS architecture includes at least one of the roles defined in this document. As a result, the entity can participate as a constituent of the RATS architecture. Additionally, an entity can aggregate more than one role into itself. " Proposed: "An entity in the RATS architecture includes at least one [or more] of the roles defined in this document. " Or more is redundant, so that really isn't necessary to convey the same point. Then the last sentence: I'd change it a little from: "In essence, an entity that combines more than one role also creates and consumes the corresponding conceptual messages as defined in this document." To: "In essence, an entity that combines more than one role may create and consume the corresponding conceptual messages as defined in this document." It might not, it could be the verifier and relying party. Section 5: Consider changing from: "That is, it might appraise the trustworthiness of an application component, or operating system component or service, under the assumption that information provided about it by the lower-layer hypervisor or firmware is true. " To: "That is, it might appraise the trustworthiness of an application component, operating system component, or service under the assumption that information provided about it by the lower-layer hypervisor or firmware is true. " Section 7: I'd say it's really a stronger level of assurance of security rather than a stronger level of security in the following: "A stronger level of security comes when information can be vouched for by hardware or by ROM code, especially if such hardware is physically resistant to hardware tampering. "


Then with the following sentence, "The component that is implicitly trusted is often referred to as a Root of Trust." I think it would be worth mentioning that a hardware RoT is immutable and mutable RoTs in software are also possible, offering different levels for an assurance of trust/security. Section 9. Since ROLIE [RFC8322] has been added to SCAP2.0, it would be good to list that as an option since a lot of time and effort went into how to secure the exchange of formatted data for that protocol. Section 11. Privacy This is a good start. Remote attestation also provides a way to profile systems as well as the user behind that system. If attestation results go higher in the stack to include containers and applications, it could reveal even more about a system or user. The scope of access needs to be emphasized, including the administrators access to data (or restrictions). If there is a way to make inferences about attestations from their processing, that should be noted as well. Section 12: This will need to state an explicit requirement for transport encryption. In the introductory paragraph, the text is as follows: "Any solution that conveys information used for security purposes, whether such information is in the form of Evidence, Attestation Results, Endorsements, or Appraisal Policy, needs to support end-to-end integrity protection and replay attack prevention, and often also needs to support additional security protections. For example, additional means of authentication, confidentiality, integrity, replay, denial of service and privacy protection are needed in many use cases. " Proposed: "Any solution that conveys information used for security purposes, whether such information is in the form of Evidence, Attestation Results, Endorsements, or Appraisal Policy must support the security properties of confidentiality, integrity, and availability. A conveyance protocol includes the typical transport security considerations: o end-to-end encryption, o end-to-end integrity protection, o replay attack prevention, o denial of service protection, o authentication, o authorization, o fine grained access controls, and o logging in line with current threat models and zero trust architectures." Best regards, Kathleen


This was inspired by the comment by afrind at URL For each representation, uniformly use the word "representation" in the first sentence; use the word "identifies" if it's a verbatim entry; "encodes" otherwise; identify relative versus post-base indexing in the first sentence; move drawing right after first sentence; use consistent language describing binary format.


I like this structure. We might come up with more validity requirements, so we may want to keep this even if =~ goes away (which is pretty much what we decided last week).


Describe how GET (not POST) is used with server push. This will ensure that you answer the bigger question: what do you do with a server push from an arbitrary server? I assume that this won't be privileged in any way, and only the configured DNS API server will have its answers routed to the DNS stack, but that needs to be explicit.
Server push in a request-response protocol like DNS would take a lot of designing. It isn't really needed in DNS because the server can always slap in additional answers in the Additional section of a request. I propose we close this by saying "HTTP server push is not defined for this protocol, but might be defined in a future version". If someone wants to define an EDNS0 or session-signal extension for it, that should be just fine.
HTTP already has server push, so I would prefer something closer to "this protocol does not alter the semantics of HTTP server push".
I think NAME is closer to what I'm thinking.. (though I don't really think that needs to be stated beyond other clarifications that this document just uses http in a particular manner, it does not define it.) additionally RR's don't quite address the same use case by the way as push can operate in more of a pub-sub fashion if you like where an additional RR is definitely a poll model.
Of course this protocol does not alter the semantics of server push, but what does it mean for a DNS client? In the DNS protocol, the only thing even vaguely like server-initiated information is stuff in the Additional section of an answer, and even then, there are pretty strict rules about ignoring it if it is at all smelly.
an often times misunderstood part of push is that a server pushes both a response and the request that it is responding to. (like dns, http is always a request/response pair, so if the client doesn't provide the request the server needs to). So that's what it means - its an answer to a particular question and you can cache it or not depending on whether that's a request you would have asked/trusted the peer to handle. That's pretty much the same rule for dns and traditional http clients. A client who would rather not have things pushed at them has existing protocol mechanisms to disable that (SETTINGS) which doh doesn't need to specify.


I think all of this gets at what NAME was originally commenting on - you need to make a decision on whether or not you trust the server for the query/response being pushed (i.e is this your dns api server otherwise don't accept) before processing it.. this is already true for anything pushed via http but a sentence making it explicit is fine.


PR for I considered referring to RFC6724, but that raises more questions than it answers it seems.
From Tom Pusateri: When more than one IPv4 or more than one IPv6 address is present, it seems like it would be better to first prefer an address that is on a shared network instead of always taking the first one (which doesn’t mean anything in DNS). If you want others to use the same address you should prefer the lowest one or the highest one or something sortable instead of the first one which could be different depending on hashing in a cache.
Discussed and agreement was to find a simple alternate algorithm.
Closed by PR


/cc NAME Signed-off-by: Thomas Fossati
In this second paragraph, does this mean T=1s or RTT=1s ?
FMPOV: (because that refers to the default timeout of DTLS 1.2 RFC6347)


No context and empty context are now declared to be the same. Add some ALL CAPS WORDS for future specifications to deprecate no context. I used SHOULD to forbid no context because, if some protocol currently uses no context, switching it to empty context is a breaking change and probably not worth it. We just want new ones to always provide a context. This affects the rules for using exporters, so RFC 5705 is added to the list of updated documents. Closes issue .


Improves example description
https://ietf-wg-URL The example with just RateLimit-Limit and RateLimit-Reset In it seems this is a case where the RateLimit-Reset value is not able to be used to determine how long one should wait, but is rather just a Limit definition ? Why not then just use RateLimit-Limit: 10;w=1 and omit the other two headers ? Is this to cater for the inevitable 429 to provide a RateLimit-Reset value at that point ? If that is the case I question the value of using the two headers in “successful” responses.
This example is related to an implementation that uses the "old" ratelimit field set, that do not support . We should improve the description.
:+1:


This attempts to address the remaining feedback on PR on issues that were not fixed before it was merged. Signed-off-by: Dave Thaler
The simple word choice / grammar changes seem OK. I still don't understand the difference between a "claims collector" and a "verifier" (in the case where Attester B, C,... are signing evidence) and a "target environment" (in the case where Attester B, C, ... are not signing evidence). It seems this term isn't actually necessary. The case where Composite Attester is relying Evidence from "sub" attesters, the composite attester (aka claims collector) is relying Evidence not "collecting claims" in the sense that an attester "collects claims about a target environment". I think it is confusing to overload this terminology to also mean "rely Evidence".


I was just going to add something about correlating requests based on their content, but then it seemed like the text was duplicated some. Here is my attempt at making this better. I also expanded the notion of "configuration" to include the identity of the relay. That made it a little tricky - we really do want diversity of relays - but it makes more sense to talk about minimum anonymity set size rather than to imply that there can be a single configuration, because that is unrealistic.
Hi, The specification talks about State. Could I suggest that it explicitly mention 'or other user identifiable payloads.' Because things like JSON documents (e.g. a JWT) and SAML assertions are not 'cookies' but can carry information that might be user identifiable. Thoughts?
I think we've given short shrift to the way in which the content of requests can be used to link them. Perhaps some new text for Section 8...
NAME that text looks good to me Wanna toss up a PR?


NAME NAME PTAL
LGTM
lgtm
Don't forget no_certificate.
Not relevant: nocertificateRESERVED(41), / fatal / , Martin Thomson EMAIL wrote:
Right. I just noticed that we send an empty certificate instead.


We've been getting help from people, but the ACKs section hasn't changed much since -03 was submitted in November 2020.
I found like two names that we had missed, and added them to the ACKs section. I think we can merge this any time.


This is an error that can be detected in frame parsing without additional context.
Over on URL we had a discussion about whether a MAXSTREAMS frame with value exceeding 2^60 generates a FRAMEENCODING or a STREAMLIMIT error. Draft 29 Section 19.11 says: corresponding type that can be opened over the lifetime of the connection. This value cannot exceed 2^60, as it is not possible to encode stream IDs larger than 2^62-1. Receipt of a frame that permits opening of a stream larger than this limit MUST be treated as a FRAMEENCODINGERROR. but as NAME points out, Section 4.5 says with a value greater than 2^60, this would allow a maximum stream ID that cannot be expressed as a variable-length integer; see Section 16. If either is received, the connection MUST be closed immediately with a connection error of type STREAMLIMITERROR Meanwhile, for the STREAMSBLOCKED frame in Section 19.15 we have: I suspect both Vidhi and I are correct, bogus MAXSTREAMS can be treated as either STREAMLIMIT or FRAME_ENCODING. If so, its probably a minor editorial fix to state either/or in both the sections.
NAME suggested that it should only be a FRAMEENCODINGERROR, as it's invalid to send a MAX_STREAMS larger than 2^60 under any circumstance, regardless of connection state, and I agree that's the clearest application of our principles.
I agree that requiring the use of FRAMEENOCDINGERROR is fine. Even though we occasionally allow an endpoint to use multiple error codes when there is more than one way of checking the status (i.e. FLOWCONTROLERROR vs. FRAMEENCODINGERROR for STREAM frames), the check required in this particular case is purely unrelated to the connection state. Hence my +1.
I would be happy with a single error too. I'm not fussy about the actual code used as long as the spec is clear and consistent. That means that we'd need to reduce STREAMS_BLOCKED to one error code too, and potentially any other situation that allows either.
I'm going to drop . I agree with the comments suggesting that FRAMEENCODINGERROR is the right answer. Note that you might still receive a different error, as we permit endpoints that detect multiple errors to send any that it detects, and this case clearly justifies use of STREAMLIMITERROR.


As of , the client MUST use the same handshake message.
NAME That's quite complicated, and I'm not sure if we've chosen the right design here. I'd like to keep this PR editorial though. I opened to discuss this.
In URL, NAME points out that after a Retry, all 0-RTT packets sent in the first flight are still valid, although they will probably have been dropped by the server (unless there's significant reordering). That means that a client SHOULD retransmit all 0-RTT packets in the second flight. We now have two different scenarios: In the case of a HelloRetryRequest, the client is prohibited from sending 0-RTT, and has to cancel retransmissions for all outstanding 0-RTT packets. In the case of Retry, the 0-RTT packets from the first flight are declared lost (without any effect on the cwnd though) and retransmitted. Considering that Retry adds a roundtrip anyway (and thereby limits the usefulness of 0-RTT), and that we only expect it to be used by a server that's under attack (which makes it likely to refuse 0-RTT later in the handshake), does it really make sense to send 0-RTT in that case?
NAME I am not sure if I agree with the observation. The transport draft states that a server MAY send Retry packets in response to Initial and 0-RTT packets. A server can either discard or buffer 0-RTT packets that it receives (). Notice that the server is allowed to "buffer" 0-RTT packets. I am not sure if I like this ambiguity (because I think most if not all of us will be dropping 0-RTT packets that carry the original DCID when sending a Retry), but IMO the draft is clear.
NAME thanks for pointing that out. My point is that we should change the draft (i.e. this is a design issue, not an editorial issue).


The reason a server (or a LB) performs a Retry is that it either has reasons to suspect that the client isn't reachable at the 2-tuple it sent the packet from, or that it is under load, and either uses the Retry to redirect traffic to a different backend server, or just to buy itself some time Under both circumstances, a server wouldn't want to allocate additional state for buffering 0-RTT packets. I'm therefore suggesting to change the draft such that: A server that performs a Retry MUST discard 0-RTT packets. A client MUST NOT use 0-RTT after a Retry was performed. Does that make sense to you?
Yeah, I can envision a server that considers buffering some number of packets to be cheaper than doing a TLS handshake. For such servers, delaying the TLS handshake until client proves it's existence but buffering the 0-RTT packets in the meantime would make sense. That said, I'd be fine with this, assuming that the discarded 0-RTT packets are the ones that carry the original DCID. I would prefer not having this requirement. Once the client is known to exist, a server needs to communicate with the client. Use of 0-RTT helps reduce the server load, because when used, average lifetime of connections becomes 1-RTT less. That leads us to having less concurrent connections.
When our implementation does Retry, it's because we've hit a memory pressure limit and we want to protect ourselves from attack. If a client supplies us with a valid token, we will accept 0-RTT still, but we won't buffer it from the previous Initial (without a token). So, if the client gets a Retry and still wants to do 0-RTT, they need to retransmit it, with the new CID, in a new packet (with a new packet number). I don't see why that design should be prevented.
Ok, I see that there's value in doing 0-RTT after a Retry, and furthermore, there seem to be good reasons (prevention of tampering by middle boxes) to disallow 0-RTT after a HelloRetryRequest in TLS 1.3, as NAME pointed out OOB. Since we can assume that most (all?)


server implementation will drop 0-RTT packets when sending a Retry, the only reasonable thing to do for a client is to treat all 0-RTT packets as lost and retransmit them. Considering that, it would make sense to require servers to drop all Retry packets from the first flight, as NAME suggests.
NAME Thank you for suggesting a path forward. I think my weak preference goes to something slightly different. I think we are in agreement that most if not all the servers would not buffer the 0-RTT packets carrying the original DCIDs when they send Retrys. It makes sense to acknowledge the fact in the specification and suggest clients to retransmit 0-RTT data it has already sent. What I am not sure is if there is a reason to forbid servers from buffering such 0-RTT packets. From client's point of view, sending 0-RTT data once per connection is an optimization. Retransmitting 0-RTT data when the server sends a Retry is further optimization. If we think that way, servers that buffer 0-RTT packets when sending a Retry has increased chance of utilizing 0-RTT data. Compared to that, there is no reason to mandate servers to drop 0-RTT packets. To summarize, I think all we need to clarify is that servers responding with Retries are likely to discard 0-RTT packets that carry the original DCIDs and therefore that retransmitting 0-RTT data makes sense. But nothing more.
What if client takes action on Retry, and the old 0-RTT state lingers - wouldn't that make servers more vulnerable to DDoS attacks from packet sniffers?
This also bears on . If the DCID doesn't change, then the server won't be able to differentiate the first flight of 0-RTT packets, which you're proposing to drop, from the second flight of 0-RTT packets which it accepts. The current text says that the server MAY buffer and process them later; you're saying that servers probably won't. I think that's fine, but some might -- hence, I favor NAME suggestion to retain the permission to buffer but the caution to the client that the packets were quite possibly lost/dropped.


In terms of actual spec change, I think that means this text in : ...becomes a SHOULD instead of a MAY.
It seems like you have sorted this out. I have no problem with using "SHOULD" over "MAY" here. Note that the reason we have this distinction is logical separation of the mechanism of Retry and 0-RTT acceptance. Retry strictly precedes the connection attempt. No point in blocking 0-RTT if you have to Retry. HelloRetryRequest is different in that certain characteristics it might cause to reset affect whether the 0-RTT works. Retry is required to use the same ClientHello, so there is no need to have the two interact; you can treat a Retry almost as a loss event for the first Initial and everything works fine.
So, the effect of not changing the handshake message is that all previously-sent 0-RTT data is still valid, but has potentially/probably been lost rather than queued. Clients obviously MUST NOT reuse the packet number for different data, but in their not-resetting, they also can't change the data that they've already sent in those packets. They'll need to retransmit it, because otherwise there's a potential DoS attack by delaying/replaying a 0-RTT packet by one RTT against a server that does Retries.This PR looks good to me as an editorial improvement. Regarding NAME point, the transport draft explicitly states that a server sending a Retry can buffer 0-RTT packets that carried the original DCID, and process them after receiving a response to the Retry. To put it differently, I think we are clear on the semantics and that there are ways to implement this without having security concerns. That said, I understand that NAME has opened a design issue () to discuss if that is the design we want to have.LGTM


Proposal to clarify "stream fragmentation". Suggested by Issue .
I don’t understand what section 21.6 is about… the title seems to suggests it is about IP Fragmentation and Reassembly Attacks, but elsewhere the spec already prohibits IP Fragmentation in section 14? And I have seen no encouragement to do any form of network-layer fragmentation - so I don’t understand a security consideration in this topic. Is this therefiore some other thing? It may about something different where a sender originates data with “holes” of missing packet to try and exercise the server? or soemthing? What is this?
Hi NAME 21.6 is titled "Stream Fragmentation and Reassembly Attacks". It refers to streams, not IP packets. The attack involves sending stream frames with holes such as and some receivers might allocate the entire stream receive buffer between 0 and 10000001. I found the section pretty clear, but we should make it clear to everyone - could you perhaps suggest text that would make it clearer?
OK. I see. I can try a PR, if I can find words that avoid "fragment": Is this close enough to start: /An adversarial sender might intentionally omit to send portions of the stream data causing the receiver to commit resources for the omitted data, this could cause a disproportionate receive buffer memory commitment and/or creation of a large and inefficient data structure.
Do we really need to avoid the term "fragment"? It's not the only overloaded networking term in the spec. Perhaps adding a "Note that stream fragmentation is unrelated to IP fragmentation" could suffice?
I don't think this clarification is necessary. The context makes it clear what fragmentation this is, and talking about IP fragmentation only leads to confuse the reader. (I like the first part of your PR though, as I've noted on my review of it.)


b=TIAS is specified in bits per second, b=AS in kbps. Hence the formula needs to multiply by 1000 to change units. Thanks NAME for catching this in code review.
Even though I noticed it in the code review I had not noticed it as an issue in the spec. Good catch!
nice catch - lgtm with minor comment
LGTM
LGTM to me as well. I updated the text in


` 1) Is this a normative statement? 2) I think the next paragraph says that maybe it’s not an asymmetric key, and anyways, keys are out of scope for RATS Arch
In a layered device architecture the previous layer "provisions" the next layer. Hence, it isn't possible for the 'manufacturer' entity to do that. I don't know why a section on "Verifier" is going into so much detail about the Attester.


The idea of a session is important, both because it is used in the API document, and because it helps to tie everything together. Define it in the terminology.
This is a first stab at defining the session. I suspect we may need to iterate on it once or twice. Let me know if you think it deserves its own section on top of the terminology.
Thanks for doing this! Here’s a suggested alternate way to explain this. Feel free to modify as desired. Captive Portal Session: Also referred to simply as the “session”, a Captive Portal Session is the association for a particular User Equipment that starts when it interacts with the Captive Portal and gains open access to the network, and ends when the User Equipment moves back into the original captive state. The Captive Network maintains the state of each active Session, and can limit Sessions based on a length of time or a number of bytes used. The Session is associated with a particular User Equipment using the User Equipment's identifier (see ).
Your phrasing is better. It manages to work in the session limits while keeping it about the same lenght. I've taken it almost verbatim. NAME Do you have any input on this topic?
From Ben's review of the API document, we should define "session" formally in the architecture. The architecture doc mentions it in passing once already. The API doc uses the term session much more.


I noticed this in the Transport Draft (ID-30): Is this intentional? Should an invalid transport parameter result in a frame encoding error?
I believe this aligns with our principles that a framing error which can be detected with no connection context is a FRAMEENCODINGERROR. Is there another error you'd suggest?
My concern is that transport parameter values have nothing to do with framing and using FRAMEENCODINGERROR is therefore misleading.
We only ever applied this principle to frames though, so I'm not sure we can use it as a precedent here. The name is indeed confusing, as it's FRAMEENCODINGERROR and not FRAMINGERROR or ENCODINGERROR.
I always rationalized this as "the encoded content of the CRYPTO frame is erroneous".
Well, if we've been through this before, I won't insist -- it's just something that jumped out at me.
That's even more confusing. The CRYPTO frame itself is totally fine. I'd be in favor of changing it to a TRANSPORTPARAMETERERROR.


Interim 2022-12-08: Distinguish "time-invalid" from "invalid" There is a slightly more general issue: When catching up, there might be messages sent by members whose credentials were valid when the message was sent, but have since expired Recommend accepting messages from members with time-invalid credentials when catching up
I think a note on consistency would work a little better in the architecture document, especially because it applies in the general case as well as the time-varying case. I filed URL
Latest change uses "expired" to refer generically to all time based reasons for a transition. (So, excluding , as NAME suggests.)
We ran into this case, which does not seem to have a defined solution within the RFC and I'm wondering if this ambiguity should be resolved at the RFC level, or be left up to the application. Existing group with Alice, and Bob. Bob had a valid certificate upon being added to the group by Alice. Bob's certificate expires . Alice does a commit to add Charlie to the group. Bob accepts the valid commit to add Charlie. Charlie follows 8.3 and validates the tree. In this process if certificate expiration is enforced, then Charlie would drop the Welcome, which would not be optimal. Solution 1: Leave this behavior up to the application, consider it part of the AS. Solution 2: Add an explicit mention that credentials that expire should be considered valid after expiration once they are a member of the group. Solution 3: A committer MUST validate that all existing credentials in the tree are still considered valid at the time a commit is made. If an existing credential is no longer considered valid, then the resulting commit MUST contain a Remove proposal for the leaf containing that credential.
Of course it would be better to have the same credential validation algorithm, but at the protocol level, there is no reason to constrain all clients to that, applications can enforce a consistent policy across clients. So, in my mind this is not symmetric between senders and receivers and solutions 1 and 3 are not incompatible, however 2 is not acceptable IMO.


I would suggest the following: Alice MUST verify that she considers all credentials valid before adding Charlie and act if it is not the case (Solution 3) Charlie MUST check all the credentials upon joining and act according to its authentication policy* Charlie MUST NOT send any application message before she considers all credentials valid
Are you suggesting that it should not be a requirement that each member of the group has the same validation algorithm? That would create forks in any case that individuals disagree on a particular credential's validity. We can of course punt to the application, but I feel like that should at least be cautioned against?
I don't quite see how the validation algorithms are different. They are the same, just executed at different points in time. Or am I missing something here? In any case it would be unfortunate if Charlie couldn't send any messages until someone committed to their proposal. So I would propose to change point 2 of the algorithm suggested by NAME to the following: Charlie MUST check all the credentials upon joining. If any group members have expired credentials, Charlie MUST issue a commit to remove the affected members.
I am saying that it is not a requirement. Most applications will want to use the same algorithm, but the protocol doesn't need to make that mandatory, it is just a convenience for applications. The protocol is designed so that each client can make its own choice. It would not create forks, as for example the case Alice decides to remove Bob, Bob is removed for everyone. I would be - ok - with the change proposed by Konrad but we need to be aware that this is a restriction on what clients can decide with respect to authentication (especially in a context where there is no AS).
I think it's also important to remember that there may be a delay between when a user is sent a Welcome and when they process it. So when a user processes a Welcome, the first epoch they see after joining may be quite old and have expired credentials for that reason, and this epoch may not even be the most recent epoch anymore. So I would lean towards solution 2 actually, of "members that are joining a group just need to ignore expired credentials." And if the application wants to have a policy of not sending new messages to a group if there are expired credentials present, then that's fine but not something we need to require in the spec.


Edit: Or maybe we do want to specify that, but I'd be clear that it's a check done before sending new messages, not part of processing the Welcome.
Although I started the dialog here around certificates and expiration, I think maybe it is useful to ignore the idea of "expired" credentials for now, because I agree with the comment by NAME that we should try to avoid being opinionated in that regard. I think what I am trying to get across is that regardless of what credential system you use that the protocol can only operate without forks if the validation of that credential is consistent across all members while also taking into account the asynchronous nature of the protocol. If each member of the group has the same state for epoch N, they should all independently determine that new credentials presented as part of a commit are valid or invalid regardless of when they process that commit. I'm viewing a credential being invalid as a trigger for rejecting a commit, which maybe in itself is a bias. Not sure if the above belongs in the protocol, the AS definition, or no where at all :-). If everyone thinks this is too restrictive of a statement I'm fine with that. Maybe a better solution to this issue is that there could be a separately defined standard way of dealing with certificates within MLS that can be more opinionated than the base protocol and introduce concepts discussed above like MUST remove of expired certs on commit, use an external packet timestamp for consistent expiration checking on the receive side, etc. I think a lot of applications would benefit from that and NAME NAME and I have been doing a lot of experimentation in that area.
After a couple long chats with NAME and NAME here's where I stand on this. A guiding thought I have is this: IMO creds aren't just for getting in to a group. They should also be necessary for continued participation. After all MLS is designed for sessions that can last years. That means, I'm uneasy with an MLS design that allows me to join a group (epoch even) where someone has an invalid (e.g. expired) cred. Worse yet, I don't want MLS to let me send application messages to users with invalid creds at the time of my sending.


With that in mind, how about this approach which tries to leave as much freedom to an app/AS while still giving guidance to an app/AS that wants to ensure valid creds are needed for ongoing participation in a group and, optionally, that forks are being avoided as much as possible. MLS clients MUST validate the creds at all leaves in a ratchet tree (via the AS) in the following cases: a. Sending a commit (validation done on new epoch's tree after applying commit). b. Receiving a commit (validation done on new epoch's tree after applying commit). c. When joining a group. d. When client wants to send an application message. Based on this MLS now gives 3 guarantees. Call an application/AS "consistent" if it ensures that for any given epoch and cred in its ratchet tree, the result of any client validating the cred is the same (i.e. regardless of the time the validation is performed and which rule of a. b. or c. triggered it). (Edit: Just to further clarify "consistency" doesnt mean validating the same cred but when taken from different ratchet trees should have the same result. It only concerns validations pertaining to the same epoch but performed by different clients at different times.) 1) Regardless of the app/AS's consistency and any insider attacks, clients only ever join epochs in which all members have valid creds. 2) Regardless of the app/AS's consistency and any insider attacks, clients will never send application messages to receiver with invalid creds (at the time of sending). 3) If the app/AS is consistent, all parties follow the protocol and all packets are delivered by the DS then no forks will occur. My justification for this approach is that it strikes the following balance: On the one hand, we now give guidance to app/AS devs for how they can enforce (1-3) if thats what they want. On the other hand, we don't actually tie an app/AS's hands at all (e.g. compared to mandating almost no checks ever). That's because MLS says nothing about how cred validation should be implemented. Hard-coding always returning true is an MLS spec compliant AS. So if an app/AS doesn't want the constraints imposed by the above rules it is still free to hard-code those validations as returning true; i.e.


it can skip the checks if it really needs to. In summary: the idea is basically to tell app/AS devs when/which are the right checks to perform to get good security & availability but also to leave it up to them to make those checks meaningful. Finally, regarding "consistency": in my mind creds are validated relative to a context (e.g. a time-stamp for checking expiration, a root CA cert, a blockchain or even particular block for checking wallets and/or balances, etc.) One way to get consistency is for the app/AS to ensure that all clients use the same context when checking the creds in a ratchet tree regardless of when they perform their checks.
In my mind, applications are only ever in one of two states: A.) I'm reading backlogged messages, or B.) I've read all the messages and I'm waiting for new ones. When you're in state B, you can send messages and also check time-related things. When you're in state A, you have no idea when the messages you're reading were truly sent. We don't currently provide any way to communicate a "context" against which time-related things should be validated in state B. So I don't see how we can implement b or c from this list?
Implementing b. and c. in some spec compliant way is actually trivial because the spec doesnt require "consistency" (in the sense that I defined that term in my previous post.) The only thing the spec says about consistency is that if you want guarantee (3.) then you need consistent cred validation. So e.g. always returning true when validating in cases b. and c. while doing something more interesting for cases (a.) would be fine; i.e. spec compliant. You just wouldn't necessarily get guarantee (3.) is all. But I figure what you meant is how to implement (a.) b. and c. to be consistent, right? And that'd be a good question that any app trying to avoid forks would have to think about. (Notice, the RFC already creates this concern for such apps with out my proposed changes because to avoid forks now you already need commit sender and receivers to agree on their validation.)


In our opinion, we landed on leaving it up to the app/AS how it guarantees consistent validations because we think there are a bunch of different but reasonable ways this could be done. Yet, which of those is best (even among just the couple we could come with on the fly) depends on things like the app's security assumptions, communication models and access to third-party services, not to mention the details of how the AS works. To start off with, it wasn't even totally clear to us that the "context"-based syntax really applies to all reasonable AS designs. (Thats how we ended up on the notion of "consistency" as that is the more abstract and minimal guarantee we really needed to avoid forks. Context is just one way we thought of to get consistency.) But say the AS does conform to "context"-based syntax. Maybe the app/AS ensure consistency by only ensuring that the (possibly different!) contexts being used by clients still produce the same result. Further, even if we are more opinionated and assume an app/AS will ensure an identical context is used in all validation cases this still leaves room for many variations. Who chooses the context used for a given epoch? Maybe the commitor? Maybe the AS? Maybe the DS (which we already have to trust it to avoid forks)? Maybe a group-context extension? Also, how is the context distributed? Out-of band? By the AS? By the DS along with commit/welcome packets? Along with group contexts? Each made sense to us in the right setting... One thing we toyed with for a while was the requirement that the commitor authenticates the particular context C they used when creating a commit packet (e.g. by using C as associated data or a PSK or something). But, not only is that already pretty opinionated about how consistency should be enforced, it also wasn't clear to us what the actual point is. TBH at first I was for it at first out of instinct (and ignoring the being opinionated part for the moment), but NAME did a good job of convincing me that I couldn't actually justify it beyond "it feels right". What kind of, otherwise not possible, attack is this trying to defend against?


In the end, the point is there were enough plausible but diverging options for how to get consistency that we didnt feel comfortable enforcing anything that constrained an app/AS's options. But it's not due to lack of ways to solve for consistency. We just didn't want to be opinionated in a way we couldn't STRONGLY justify.
Thanks NAME I'm not sure I agree with checking every time I send an application message as TLS sets a precedent for not checking in that case. I do agree though that I view each epoch as a session renegotiation of sorts, which means that you reevaluate if credentials you previously thought were valid are still valid according to whatever rules that are in place. I believe this conversation winds up in a place where its a very small statement in the main doc that explains how to avoid forks, and then an entirely separate document for each credential type (starting with certificates) that aims to set guidelines on how one could achieve various goals like not allowing expired certs etc. Im all for helping write that document as Wickr will be using the x509 system in production quite a bit.
Solution 4: Bob has to do an UpdatePath before his Credential expires with a LeafNode with a valid Credential (certificate). If he doesn't, the other members should Remove him from the group. Same goes if Bob's Credential is revoked.
NAME I think the core of the discussion at this point is more around the fact that the base protocol does not have any concept of "expiration" of credentials, so their behavior is undefined. Either we put an opinionated statement around it in the core protocol, or just punt to applications / another RFC. Thoughts on that?
Hi NAME , My opinion is that whatever credentials you have in an MLS group should be valid (including not expired, not revoked, not too early, etc.). Therefore it would logically follow: It is the responsibility of each member to make sure their LeafNode credentials are valid and consistent with the group policy at all times. Any member of the group that detects another member is out of policy or invalid can remove the offending member. To the extent possible a DS that detects that a member is out of compliance with group policy or no longer has valid credentials, can try to remove the member (ex: via an external proposal). The definition of "valid" could be done per-credential type or per profile.


Side note: under the general rubric of "validity changes over time", revocation is also an issue! Overall, my thinking aligns with what NAME says here. Saying that the credentials presented by group members should be valid at all times is a concise, clear standard. It is arguably implied by the current requirement to validate credentials on joining (if you also assume that the group should be joinable at any time). The more difficult question is how it is implemented in practical reality. I don't think we can really write hard requirements around this. The only remediation is Remove, and we don't have other situations where we say a client MUST send a specific proposal. In part because this might conflict with application-level policies about who is allowed to send Proposals/Commits. And it seems like there are valid situations where availability might trump authenticity (cf. browsers' click-through on expired certs). Overall, this seems like more of an operational question than a core protocol question here. In terms of how to reflect all this in documents: The details of how to manage credential freshness seem better suited for an implementation guidance document. (I believe NAME is gathering ideas for one?) In the MLS protocol spec, we could add some high-level guidance, something like the following: I think that would fit well either in the Credentials section (between "Credential Validation" and "Uniquely Idenitfying Clients") or in the security considerations.
We could use the sender_generation field of the MLS message to signal what was the global app generation of the sender. Functionally, this allows receivers to know if they received all previous application messages from the sender. In the current design, if S sent M0, M1, M2 you can know if you missed M1 when receiving M2, but you cannot know if you missed M2. There are many ways of doing this: global sender counter, counter between two operations of the sender...
We seemed in agreement at the interim because it prevents the application message suppression attacks
Looks great thanks NAME I like the separate treatment of expired vs. revoked. Looks good to me now!


I think the spirit of this change is good, but the last two sentences are confusing talking about the client trying to join and an existing member trying to prevent them from seeing anything confidential after joining. My initial reaction to this idea was always that post-hoc removing someone who should never have joined is a terrible architectural decision. Post-hoc removal either allows an undesirable member a window to see messages sent by some members, or it requires consistent policy across members. If there is consistent policy across members the members should simply treat the Commit from the undesirable client as invalid. Rather than further condone post-hoc removal (which doesn't require any normative change to the MLS protocol), why not just delete mentions of post-hoc removal?
Compromise - Deleted the sentence that talks about the security implications of post-hoc removal, left the mention of it simply being possible.
Following on from discussion in Even once a GroupInfo has been published to a prospective new joiner, there are still a few opportunities to apply authorization policy to the join: The DS can block the external Commit from reaching the group members (requires intelligent DS) The clients in the group can all refuse to apply the external Commit (requires consistent policy) Any client can remove the member after allowing them to join (might expose some group comms to the joiner)
Comment by NAME This seems rather risky? What could such a member do in the short time between getting added and getting kicked? Would they see message history? Group membership? How many devices a user has? When members were last online? Why support such a group type? Wouldn't it be better to not support this and have an automated "special member" being a bot that handles member addition?
Until someone else sends a message, a new joiner doesn't learn anything non-public. If you think about it, how would they? They're outside the group before they send an external join, and the external join just establishes a new shared secret with the group for future communications. More specifically: Message history - MLS's forward secrecy guarantees mean that new joiners don't get message history.


Group membership - This is public anyway via the GroupInfo that an external joiner needs to join How many devices - To the degree this is exposed, it would be in the group membership Last online - MLS doesn't have any notion of this As for an "add me bot", it's a useful idea, but not applicable to a bunch of cases. The bot has to be a member of the group and has to be always-online. So now you have the group's secrets on a server somewhere, instead of just in the communicating endpoints, already an additional point of compromise. And it can't be the DS's server, since the whole point is to protect against the DS.
This statement in the draft is just plain wrong. In our implementation, we actually do validation of External joins at the application layer. I addressed this in (dating from WGLC) which says the following: "External joins do not allow for more granular authorization checks to be done before the new member is added to the group, so if an application wishes to both allow external joins and enforce such checks, then either all the members of the group must all have the ability to check and reject invalid External joins autonomously, or the application needs to do such checks when a member joins and remove them if those checks fail."


Builds on .
Initial packets need to be in 1200 byte datagrams for DoS amplification reasons. We have an exception for the case where an ACK for a Handshake packet has been received from the peer. In that case, we remove the requirement to pad. That condition is extraordinarily obscure, especially if we are suggesting that endpoints not send any more Initial packets once they have Handshake keys. Removing this text is the right answer.
+1 to the proposed resolution.


I think the motivations section as-is is too long. It spends a lot of time talking about what are effectively the tradeoffs. IMO the motivations section should specify why it's useful to have the sender control the receiver's ACK frequency, and then we can have a separate section for the tradeoffs. This takes a stab at that section, lifting things from motivations and adding some new text specifically addressing the nascent stages of a connection. I also made some editorial changes to the existing text. I am happy to add any additional considerations we think might need to be called out. This attempts to
Thanks for the PR, NAME ! I like the new text you propose (I've proposed some changes), but I think you might be assuming that ACK_FREQUENCY is only used for delaying acks further. An important point that bears bringing out in the motivation is that a sender might want more frequent acks as well, for example during startup. That's worth capturing in the modified motivation section.
NAME this PR is almost done, any chance you can do another round of updates and we can get it in?
NAME sorry, I'll do some updates today.
NAME NAME I've updated the PR, I'll watch and iterate on any remaining feedback quickly this time.
thanks NAME Something about vim and the macbook pro keyboard apparently makes me incapable of spelling things properly. I want my desk keyboard back
As discussed on in the base draft, we have some confidence in a particular heuristic (default tolerance of 2 for the first 100 packets, followed by a tolerance of 10) which we know to work fairly well in multiple deployments serving "typical" Internet resources to typical users. Do we want to make that recommendation explicit, or otherwise give guidance in this extension?
I think it's a good idea to describe the values for which we have experience, while encouraging experimentation. We don't need to recommend the strategy, we just need to document it as an example strategy.
I think a section on considerations and maybe past experience would be very helpful. I think it's going to be a bit of a challenge to write, but I'm happy to take a stab if no one else wants to.
What I'd want to see is just a simple explanation of what a sender could do... I would not describe results from experience, since those are anecdotal and are going to change over time. This could be a fairly short section.


NAME NAME I can take a stab at writing something and we can go from there.
Thanks, NAME !
I do think the pitfalls of e.g. should be conveyed in such "cautionary" text as well. I will submit a PR this week time permitting between interop.
Thanks, NAME


Need to be explicit say that it's the ExtensionType registry from RFC 4366.
I literally was making the same change in my editor when the notification came in! (Should it be the "TLS Extensions ExtensionType registry"?)


MGF1 got unhelpfully spelled out as "mask generation function 1" in RFC 8446. I'm guessing this is the result of an acronym expansion editting pass, but the function is simply called "MGF1". There is no such thing as "mask generation function 1". Correct this back to MGF1. In hopes this doesn't get hit the same editing pass later, I've tweaked the wording and moved the citation so that "mask generation function" is still uttered before MGF1, and it's clearer that both primitives are defined in RFC 8017.


This mainly wiggles the existing text around and tries to fully qualify transport vs application to help explain the ways an implementation might do things, which is independent of how an application protocol might be designed (for example H3 doesn't require incremental processing but most people come to a realizatopm that it is the best way to do things).
The new text is good and clear, but it doesn't really explain that the when credit is released at the receiver, could we say a little more: it takes 1/2 RTT for cerdit to reach the sender, that causes new data to be released, for a large RTT, this means that credit has to be sufficient to avoid blocking or to be sent promptly, otherwise transfers will stall for periods of an RTT. (I know TCP does this stuff for the app and grows the window, but QUIC I suspect needs something to happen to release the credit). I know people closer to the Apps can write this sentence better than me; from my perspective I just see the effects when an app blocks or release credit in big chunks... over a large path RTT and the network performance suffers.
Thanks Gorry. I think I agree. How about I tweak "Timely updates can improve performance" paragraph to say "Timing of updates can affect performance". I can add a mention that the extension of credits on the data recever side is enacted by emitting MAXDATA/MAXSTREAM_DATA frames, which take at least a 1/2 RTT to reach the data sender side. I think the useful additional applicability statement to be made based on the above is that the data consumer read rate may be disjoint from the delivery rate and responsiveness of signalling channel back. For a highly asymmetric link, the download rate can be application-limited well below the theoretical bandwidth simply because an application is spending too much share of the time reading packets and not giving enough time to emit QUIC packets. Does that sound ok, or am I missing your ask?
This is definitely heading in the direction I was hoping, it helps avoid people developing on a LAN and then discovering the effects on other paths later. Please add something.
I've reworked the paragraph with my attempt to address NAME comment. I've introduced the terms uplink and downlink, which I'm not totally happy with. If someone has a better suggestion I'm all ears.
Issue: Sect 4.3.


Flow Control - we should have a subsection also encouraging timely credits This ID discusses flow control deadlock, whichI think is important. I suggest we should also note that timely release of flow control credit is also important (QUIC transport has some text to point to). This need is evident when the path has a large RTT, and there can be a large BDP, where the whole of operation of QUIC can be dominated by the way in which the application manages the flow credit. This might not be obvious, because the equivalent rwnd update in TCP is handled by the transport rather than the application.
The point is the audience for this draft is applications that use a quic library. I would assume that the actual credit handling is performed in the transport/in quic directly, usually without an interface for the application to directly impact it. Do you propose the application should have more direct impact on flow credit handling? I guess we can add a pointer to the right section in the transport draft but not sure we should/can say more here...?
I agree this seems mostly like a QUIC transport/library issue and I wouldn't expect the application to have much control here. I can imagine applications setting a max value?
I generally agree with Mirja and Ian. However, on a closer inspection of this section I think it would benefit from a crisper definition of what it means to read data vs. process data. Its a reasonable application mapping implementation design to read data out of the transport in order to release flow control but still buffer it (or just dropping it on the floor) in application space before processing that as application data.
NAME can you propose text?
I'm content that flow control is something the libraries need to get correct - the TCP people spent energy to get this automated, although QUIC's multi-streaming makes the trickier. Lucas text suggestion would improve things by making it clearer how the API is intended to be used.
NAME ?
I will add some text (just need to find the time).


o If the m= section is not bundled into another m= section, an "a=rtcp" attribute line MUST be added with of the default RTCP candidate, as indicated in [RFC5761], Section 5.1.3.


NAME This definitely needs to be reviewed.
This looks good to me.
I like the idea of a special compound error type to indicate that the subproblems field is used.
In s7.6, it seems like we should indicate what error is returned: If the revocation fails, the server returns an error. The draft this nicely in many others places in the draft.
I mentioned this earlier on the mailing list, but it did not receive any feedback: as a ACME client developer, I would like to be able to distinguish between errors which do not require user interaction (that would be "certificate is already revoked, so can't revoke it again"), and ones where the user must be warned that the operation did not succeed ("certificate could not be revoked", "bad credentials", etc.). This is currently only possible with server-specific ugly hacks (for example, returns this information, but other servers might return it differently or this might change in later versions of Boulder as it is not specified).
This is a good idea, sorry for missing it earlier. NAME - Do you have any thoughts on other cases besides "already revoked" that would (a) not require user interaction and (b) not be covered by other current error codes? NAME - Would you mind making a PR to add an error code (and anything else that NAME comes up with), and note it in the revocation section?
I thought of one to consider in :
It looks like Boulder uses 404 and a generic malformed problem type for this case: URL URL
NAME So far I couldn't think of anything else. I'm totally happy with :-)
Fixed by
:+1: Thanks!


Addresses .
.Add some additional text to highlight that sig on server cert and DC can be different. from . Hi Sean, Thanks for the follow-up. I refreshed my memory as much as I could. Please see my responses in line. Yours, Daniel Sean Turner wrote: I think I would rather take the structure: 1 - Use case 2 - Problem description 3 - Solution I am fine with whatever fits best to you. Server operators often deploy TLS termination services in locations such as remote data centers or Content Delivery Networks (CDNs) where it may be difficult to detect key compromises. Short-lived certificates may be used to limit the exposure of keys in these cases. However, short-lived certificates need to be renewed more frequently than long-lived certificates. If an external CA is unable to issue a certificate in time to replace a deployed certificate, the server would no longer be able to present a valid certificate to clients. With short-lived certificates, there is a smaller window of time to renew a certificates and therefore a higher risk that an outage at a CA will negatively affect the uptime of the service. Typically, a TLS server uses a certificate provided by some entity other than the operator of the server (a "Certification Authority" or CA) [RFC8446 ] [RFC5280 ]. This organizational separation makes the TLS server operator dependent on the CA for some aspects of its operations, for example: Whenever the server operator wants to deploy a new certificate, it has to interact with the CA. The server operator can only use TLS signature schemes for which the CA will issue credentials. To reduce the dependency on external CAs, this document proposes a limited delegation mechanism that allows a TLS peer to issue its own credentials within the scope of a certificate issued by an external CA. These credentials only enable the recipient of the delegation to speak for names that the CA has authorized. Furthermore, this mechanism allows the server to use modern signature algorithms such as Ed25519 [RFC8032 ] even if their CA does not support them. We will refer to the certificate issued by the CA as a "certificate", or "delegation certificate", and the one issued by the operator as a "delegated credential" or "DC". I think my concern has been clarified by Ilari. It was resolved by your b). I am fine with both text. works for me.


The text does not address my concern and will recap my perspective of the discussion. My initial comment was that the reference [KEYLESS] points to a solution that does not work with TLS 1.3 and currently the only effort compatible with TLS 1.3 is draft-mglt-lurk-tls13. I expect this reference to be mentioned and I do not see it in the text proposed text. If the intention with [KEYLESS] is to mention TLS Handshake Proxying techniques, then I argued that other mechanisms be mentioned and among others draft-mglt-lurk-tls12 and draft-mglt-lurk-tls13 that address different versions of TLS. This was my second concern and I do not see any of these references being mentioned. The way I understand your response is that the paper pointed out by [KEYLESS] is not Cloudflare's commercial product but instead a generic TLS Handshake proxying and that you propose to add a reference to an academic paper that discusses the LURK extension for TLS 1.2. I appreciate that other solutions - and in this case LURK, are being considered. I am wondering however why draft-mglt-lurk-tls12 is being replaced by an academic reference [REF2] and why draft-mglt-lurk-tls13 has been omitted. It seems that we are trying to avoid any reference of the work that is happening at the IETF. Is there anything I am missing ? My suggestion for the text OLD: (e.g., a PKCS interface or a remote signing mechanism [KEYLESS]) NEW: (e.g., a PKCS interface or a remote signing mechanism such as [draft-mglt-lurk-tls13] or [draft-mglt-lurk-tls12] ([LURK-TLS12]) or [KEYLESS]) with [KEYLESS] Sullivan, N. and D. Stebila, "An Analysis of TLS Handshake Proxying", IEEE TrustCom/BigDataSE/ISPA 2015, 2015.


[LURK-TLS12] Boureanu, I., Migault, D., Preda, S., Alamedine, H.A., Mishra, S. Fieau, F., and M. Mannan, "LURK: Server-Controlled TLS Delegation”, IEEE TrustCom 2020, URL, 2020. [draft-mglt-lurk-tls12] IETF draft [draft-mglt-lurk-tls13] IETF draft It is unclear to me what is generic about the paper pointed by [KEYLESS] or [REF1]. In any case, for clarification, the paper clearly refers to Cloudflare commercial products as opposed to a generic mechanism, and this will remain whatever label will be used as a reference. Typically, Cloudflare co-authors the paper appears 12 times in the 8 page paper. The contribution section mentions: """ Our work focuses specifically on the TLS handshake proxying system implemented by CloudFlare in their Keyless SSL product [6], [7] """ The methodology mentions says: """ We tested TLS key proxying using CloudFlare’s implementation, which was implemented with the following three parts: """ """ The different scenarios were set up through CloudFlare’s control panel. In the direct handshake handshake scenario, the site is set up with no reverse proxy. In the scenario where the key is held by the edge server, the same certificate that was used on the origin is uploaded to CloudFlare and the reverse proxy is enabled for the site. """ Cloudflare appears in at least references URL CloudFlare Inc., “CloudFlare Keyless SSL,” Sep. 2014, URL N. Sullivan, “Keyless SSL: The nitty gritty technical details,” Sep. 2014, URL works for me. works for me seems clearer. I suspect earlier clarifications addressed this. thanks that it way clearer. Daniel Migault Ericsson


NAME
NAME PTAL
LG with nits
para break and typo comment were missed
In the current draft we have addTransceiver [TODO] We need this text before WGLC, so it's being added to the punchlist.


It appears we should have included rules for populating a registry for the pskkeyexchange_modes extension.
Yes, an obvious oversight in our oversite. :) I approve.
+1
FWIW, +1
+1 to a new registry.
Yes, we should create a registry. But: We need to update the "this document defines a new registry" to match the new number of registries (two) the space of allowed values is only one byte, so we don't need to talk about "first byte"


AggregateShareReq should have an aggregation parameter field instead of aggregation job ID.
Thanks NAME for spotting this!


... as suggested by NAME
The section on partial send says: "All data sent with the same MessageContext object will be treated as belonging to the same Message, and will constitute an in-order series until the endOfMessage is marked. Once the end of the Message is marked, the MessageContext object may be re-used as a new Message with identical parameters." Can we reconsider for a second if that is really the way we want to design this? This is really implicit and therefore an easy source for errors. I guess we could alternatively use an explicit message identifier...? Or the send action always return an identifier and for subsequent sends we input this identifier again? Or someone has a smarter idea?
I don't have my head buried in code like some others here (NAME NAME , ..), so I guess that these folks should speak up - but just from reading this, I agree that the current design sounds like an easy source for errors.
I'd prefer to just remove the part that mentions reusing the same object. That's an implementation detail (and a perf optimization). The rest seems correct.


I think this helps, but one of the confusions is the distinction between a framing to provide a message-oriented API, and the use of framers underneath that API to change the representation of messages on the wire. I wonder if some of the difficulties we've had with framers is that some of us have been using the term to represent one of these concepts, and some the other? One is the concept of a framer that accumulates data and returns an object from a call, rather than returning a byte array containing a (partial) HTTP response. That's the API-level framer. The other is the sort of framer that performs TLS encryption on the HTTP request, after has been called. This transforms data, below the API. Do we need two different terms?
NAME - personally, I always thought that Framers can do both of these things; if this wasn't clear enough before, then I think your part 1 (returning an HTTPResponse object) was clear from before, and now this PR makes it clear that they also intercept the send call to transform data afterwards. So IMHO that's just the clarification that was needed.
Sorry! Obviously I only wanted to comment, but hit the wrong button :)
I know we moved some text about framers into the implementation doc but that really doesn't seem right when I look at it now. The section about framers in the implementation doc is the only section that defines an interface which probably is already an indication that just moving this text there was not right. However, also the text in the API doc seems now incomplete. I think we should move it back and rather define some real simple examples framers in the implementation document (just a prefixed length field (as many UDP mapping use) or maybe even an example implementation for STARTTLS). Further after moving it back we could figure out if really all parts of the interface are necessary or if there would be a more minimal interface that we could use. E.g. I'm not sure about the FailConnection() call or at least I think this could need more explanation.
Also I think it would be good to the section on framers earlier in the doc. I will open a separate section to propose some restructuring (as I also think it would be good to have the connection properties earlier).


I think the real problem with framers is that we left them vague to avoid having to worry about all the implications they bring with them (which are a lot as they impact almost every stage of the life of a connection) but also to not limit what implementations can do with them by making them very rigid. But I do agree that the text in API feels somewhat incomplete. Maybe one solution would be to explain what a framer should at least be able to do in the interface draft without specifying the actual API that is in implementation. I think we all agree at when a framer should be able to interact with the connection just not how that interaction is supposed to look like (as that is highly implementation specific).
I disagree that we should move the text back into the API document, since the group was very clear before that the details should be moved to implementation. The boundary we defined was to leave in the API: (a) the definition of what a framer is and why it's used and (b) the interface an application uses to add a framer to the connection. The API text should be complete with regards to how a user of a framer performs actions. What specific text would we want to add here?
First as I say that's the only piece of additional interface we define in the implementation draft which already is a sign that it's maybe not ideal. But for the API draft the part of how a framer interact with the transport is really unclear and looking at the part of interface, that now defined in the implementation doc, makes it really clear. I disagree that this part of the interface can or should be left to the implementation. The fact that you have to call the framer before you start any transmission and the events a framer should be aware of are generic and nothing implementation specific.
In the implementation draft we say: "A Message Framer is primarily defined by the set of code that handles events for a framer implementation" My assumption is that a custom framer implementation could be part of the application logic and therefore we need to define this interface as well. However looking at the implementation draft I guess I now confused myself about how this actually works. Why is the sending logic asynchronous? Isn't this something that happens iteratively when the application calls send(). How would that actually work?


I thought the application could just call URL() and then the connection could call URL() and that would simply return a modified message... can you give an example for sending and receiving based on the interfaces currently defined in the implementation draft? Also please note that while I think the interface definition belongs in API draft, however, there are comments about copying and curser handling which should/could probably say in the implementation draft.
Interim: Add to -interface: Explain that framer(s) is in between the rest of the protocol stack and the application Intercepts calls to start/stop and send/receive And just leave as is, and have another framers document in the future once we get more details.
I think it'll be helpful to be a bit clearer on the timing here, see comment.Thanks a lot for doing this - to me, this looks really good. It makes things much clearer for readers of this document.I think this should clarify it, thanks!


Thanks for your comment, Russ. Here is the issue: Only after the swap has been completed the plaintext firmware image is in the primary slot. Before the swap, the encrypted firmware image was in the secondary slot. It would be possible to do a "dummy decrypt" to compute the hash prior to doing the decrypt with swapping.
Yes, the AES-CTR and AES-CBC document in the COSE WG states that the signature provides the integrity protection, so this description needs to say how that happens.
Russ, I have added text to address your comment.


"A client MUST provide a 'pskkeyexchangemodes' extension if it offers a 'preshared_key' extension."


Not quite. It specifies secure bootstrapping of the individual nodes. It's RFC 8994 that bootstraps the ACP.


NAME Sure. I've just posted this: URL
LGTMThe bullet points improve readability quite a bit, thanks NAME !also not purely editorial, but okay. I realize it's very late for making non-editorial changes to draft-ietf-acme-acme, but I'd like to propose adding a new badPublicKey error. This error would be returned by the server whenever it does not support, or wishes to reject, a "jwk" public key supplied in a client's request. Proposed text: URL The 'array of supported "alg" values' in a badSignatureAlgorithm response is useful, but ISTM that it doesn't provide detailed enough information to assist a client in generating a suitable public key. (If the consensus is that it's too late to add a new error type, then my alternative proposal will be to use "malformed" instead of adding "badPublicKey", but keep the rest of PR 478 as is; I think it's a good idea to call out the need for a server to sanity check each client-supplied public key). Rob Stradling Senior Research & Development Scientist Sectigo Limited


The reason for the SHOULD is that the current text says: do a key update as described in {{key-update}} prior to reaching these limits. Note that it is not possible to perform a KeyUpdate for early data and therefore implementations SHOULD not exceed the limits when sending early data. We could of course change both.
DTLS 1.3 introduces integrity limits for the AEAD algorithms, which is good. TLS 1.3 does not have any AEAD integrity limits, probably because the assumption that only a single AEAD forgery can be attempted. My understanding is that this is not true for 0-RTT data which works more like DTLS and where an attacker can attempt any number of forgery attempts on a single AEAD key. RFC 8446 has relatively strong anti-replay protection: "The server MUST ensure that any instance of it (be it a machine, a thread, or any other entity within the relevant serving infrastructure) would accept 0-RTT for the same 0-RTT handshake at most once." but this does not stop an attacker from attempting an unlimited number of forgeries. I think consideration / mitigation of this is missing from RFC8446. Some alternative suggestions: Should the 0-RTT requirement above be strengthen to: "The server MUST ensure that any instance of it (be it a machine, a thread, or any other entity within the relevant serving infrastructure) would process a 0-RTT handshake with the same PSK, URL pair at most once." should RFC8446bis continue to ignore AEAD limits for 0-RTT? 0-RTT data already has lower security (weaker replay protection)? In this case I think some considerations should be added describing that the integrity protection of is weaker than for normal application data. should RFC8446bis introduce DTLS 1.3 type integrity limits for clientearlytraffic_secret? This aligns the integrity limits of 0-RTT data in TLS with the normal application data in DTLS.
Could you say a bit more about how this would work in practice? I did not consult the spec just now, but I had the impression that 0-RTT still had only a single attempt at forgery (at least, per replay cache instance/backend server).
Ah, the linked DTLS issue mentions long-lived external PSKs specifically.


I agree that our story for those is less well specified and probably not great. Off the top of my head, I would suggest "don't use 0-RTT with long-lived PSKs".
I think that the original is fine. I don't think that there is any meaningful distinction between 0-RTT handshake and the (PSK, URL) tuple, at least as far as the derived keys go. Change the PSK, PSK identity, or random and you get a new key derivation. I had expected that early data was subject to the same constraints as later epochs. The only caveat being that it is impossible to update early data keys using KeyUpdate. The answer is to finish the handshake of course, so a hard error is fine. We might advise servers to cap maxearlydata_size to help avoid any issues of overrun, though with certain perverse padding arrangements, that might not provide any real guarantee. As above integrity limits should also apply.
URL fixes (1) The case for (3) is actually more subtle, as the problem is not clientearlytraffic_secret but rather the trial decryption skipping phase. We might need to apply DTLS 1.3 like limits there.


According to suggeestion in issue
Alan has suggested that more Profiling / guidance regarding NewSessionTicket would be good. TLS 1.3 allows any number of newsessionticket to be send in any of the server flights. All ways are secure. TLS 1.3 leaves how and when to the TLS implementation.
This is a new request for technical change not related to the IESG DISUCUSS. Based on earlier discussions changes to the TLS layer are likely a bit controversial. John: I don't see what is special with EAP-TLS here. I also don't know what a good recommendation for the TLS layer would be or what can be enforced in TLS implementations. This would likely need interaction with TLS people,
Note also that draft-ietf-tls-ticketrequests is in the RFC Editor's queue and goes into a bit more detail about when different numbers of tickets might be desired (as well as a mechanism to indicate the client's desires, though it's not entirely clear to me whether that will be very helpful for the EAP-TLS usage).
Based on your earlier comment on draft-ietf-tls-ticketrequests, I already added a reference to ietf-tls-ticketrequests in version -14 "A mechanism by which clients can specify the desired number of tickets needed for future connections is defined in [I-D.ietf-tls-ticketrequests]."
Oops, shame on me for not checking. (Thanks for adding the reference the last time I mentioned it!)
I think it would be fine to include a SHOULD send only one NewSessionTicket since EAP clients will typically only need one at a time.
I am not comfortable adding such guidance without a thorough survey of libraries. As draft-ietf-tls-ticketrequests says: "servers vend some (often hard-coded) number of tickets per connection. Some server implementations return a different default number of tickets for session resumption than for the initial connection that created the session. No static choice, whether fixed, or resumption-dependent is ideal for all situations." I know that openssl allows to control number of tickets with URL but I don't we think we can be sure about behavior of all libraries out there. Also some noteworthy text from draft-ietf-tls-ticketrequests: "Especially when the client was initially authenticated with a client certificate, that session may need to be refreshed from time to time.


Consequently, a server may periodically force a new connection even when the client presents a valid ticket. When that happens, it is possible that any other tickets derived from the same original session are equally invalid. A client avoids a full handshake on subsequent connections if it replaces all stored tickets with new ones obtained from the just performed full handshake. The number of tickets the server should vend for a new connection may therefore need to be larger than the number for routine resumption."
How about removing the normative SHOULD, something like: desired number of tickets needed for future connections is defined in [I-D.ietf-tls-ticketrequests]. >
This non-normative suggestion sounds good to me.
John's suggested text looks good. By the way, I checked boringssl: URL It seems to issue 2 tickets by default (static const int kNumTickets = 2). As far as I can tell, the only way to limit to 1 ticket is by changing the code manually and re-compiling the library.
This is resolved in PR
Merged PR


Authentication alone is never sufficient; with the First-Come-Fist-Remembered policy of , it should be easier to see how this is still authorization. See-Also: URL Thanks for addressing my DISCUSS and COMMENT feedback


E.g.,
I propose a slightly more compact naming of ABNF of - and -segment, which should be more consistent between them two. is well known from LaTeX and means or there.
above is wrong (and so it is in the current spec). It needs to read ... to not allow triple dot ( :-)
NAME Wouldn't dotdot-wildcard etc. be less cryptic?
Here are some quibbles with the current ABNF (prior to PR being merged) which we can sort out after The Great Renaming:
Yes, yes. See. Fixed in I like the way this looks like now. Maybe I don't understand; can you elaborate? Fixed this (and following) in Removed in To be fixed in overall overhaul, next Yes! To be fixed in overall overhaul, next To be fixed in overall overhaul, next Fixed in Discuss this in its own issue, I'd say. Fixed in It certainly does not -- it is the subset that is actually needed for normalized paths. To stay normalized, we don't allow random other ones.
Of course ... I'm quite dispassionate here.
Please see my proposal in
With merged, we still have the expression cleanup the separate issue (enhancement) whether should be allowed, to mean
My remaining points are covered by PRs , , and .
Shouldn't be named according to all other above ?
Yes, I agree. See URL
NAME Are we ready to close this issue now the PRs have been merged or did you have more expression cleanup in mind?
The only thing that comes to my mind is standardizing on the column where the is -- this is currently rather chaotic. But that can be a new issue.
Indentation of : number of lines such indented
(And it doesn't need to be consistent, just a bit less chaotic.)
Let's make the a new issue. (I haven't got a good feel for the optimal solution.)
Before we close this issue, URL slipped through the net in my earlier PRs.
Then could resolve to either or . We would introduce an ambiguity, we already found with Json Pointer () ...
OK, with the latest blank space realignments that are part of (5e2cc85), I think we are done with this.
Thank you!


... or do we need two selectors here (Ch.2.61) child-longhand = "[" S selector 1(S "," S selector) S "]" given that '1' means 'at least one'.


The 0-RTT key might differ between TLS versions (as demonstrated with the draft -20 changes). Be explicit about storing this version number since section 4.2.9 requires this information too.


The CID format figure has been removed since draft-ietf-quic-load-balancers-08


Ticket is a term that refers to a PSK identity established using an handshake. For out-of-band PSK, we do not use the term.


as suggested by Russ in the genart review: NAME did I get the intention of the expression right?
LGTM


The I-D checklist requires that updates and obsoletes be included in the abstract; thought RFC. I personally feel this is [redacted] stupid, but I do not think that we should risk a process appeal to fight this battle.