Question: A Preconnection Object holds properties reflecting the application's requirements and preferences for the transport.  These include Selection Properties for selecting protocol stacks and paths, as well <del> as Connection Properties for configuration of the detailed operation of the selected Protocol Stacks. </del> <ins> as Connection Properties and Message Properties for configuration of the detailed operation of the selected Protocol Stacks on a per- Connection and Message level. </ins> The protocol(s) and path(s) selected as candidates during establishment are determined and configured using these properties.

Applied requested changes
In 3.2 it is clear that you can set Message Properties on Connections and Preconnections, but the rest of the document is not very clear about this. In 4.2 for instance the text only talks about setting Selection Properties and Connection Properties on PreConnections. In 7.1.3 the text says "Connection Properties describe the default behavior for all Messages on a Connection". But I think that Message Properties set on a Connection or PreConnection may also describe the default behavior so this relationship should be clarified. Also, the Message Property defaults given for Properties that do not depend on other Properties sets the defaults for all Messages in a Connection I assume? I also assume that a Message Property set on a Message Context overrides a Message Property set on a PreConnection or Connection, but this is also not specified. In 5.4. Connection Groups, I assume that setting Message Properties on a Connection applies to all Connections in the Connection Group? This is not clear.
In general, I agree. If you set a message property dynamically on a connection, though, I don't think it would affect the group—I could have one stream in a multiplexed protocol have separate behavior, such as priority.
+1 to tfpauly. But this is already written in 5.4, maybe you missed it (Anna)? "Message Properties are also not entangled. For example, changing Lifetime (see Section 7.1.3.1) of a Message will only affect a single Message on a single Connection."
I am fine with an update of a Message Property to a connection applying only to that connection. Priority is not a good example as it is already a special case, but my main issue was that we need to be more clear about the behavior in the specification. NAME the issue is about setting a Message Property on a Connection. The text you refer to talk about setting Message Properties on a message. You could interpret the first part as a general statement, but the way the text is structured it is easy to think it refers to setting Message Properties on a message so I think we should be explicit also about setting Message Properties on a Connection. Could be a second example.
So after looking at the text again, I think the example talking about setting Message Properties on a message should be removed, see comment in the pull request.
Thanks!!


Question: Number by one.  Compute the AEAD nonce from the Sender ID, Common IV, and Partial IV. <del> Add the following step after step 5: B.  If the message is an Observe notification, store it in memory for use with re-registrations (see replay-protection), and delete from memory any older one previously stored. </del> 8.4. A client receiving a response containing the OSCORE option SHALL

This PR should (hopefully) conclude the main rewrite of Observe which was triggered by the security analysis and additional reviews of Observe. It should (hopefully) now be clear what part of the Observe related processing can be omitted in case Observe is not supported or in case intermediaries are not used. A new appendix E is covering the latter case.


Question: single underlying transport connection where possible.  This is not a strict requirement.  The default is to not have this option. <del> 5.2.6. </del> <ins> 5.2.7. </ins> Type: Boolean

This closed As we have no methods on a connection object that query properties, cansend/canreceive also became connection properties. As with all the other connection properties, these are indeed a little underspecified. I want to keep it that way till we fix it for all connection properties with and
Aehm… that comes surprising – NAME why didn't you bring this up in ? Do you think this pull-request is the right place to discuss this issue? I would prefer we merge it now and make a new issue for the question whether the uni-directional connection should be more reflected in the connection. I am not particularly found on keeping it a selection property but would like to have the concept of unidirectional connections rather sooner than later. Our consensus in was that unidirectional connection should use the same abstraction for QUIC unidirectional streams, multicast sources/sinks, and half-closed connections – despite they are constructed in completely different ways. The Selection property is just for the QUIC style ones…

Aehm… that comes surprising – NAME why didn't you bring this up in ? Do you think this pull-request is the right place to discuss this issue? Happy to move the discussion back over to the issue if you like. Will continue the thread here for now though since you've got points to address below. fine, but keep open then, because adding the selection property is possibly-necessary but definitely-not-sufficient to fully address unidirectional connection semantics. good, I agree with this. then I'm confused why this PR purports to since it only addresses part of the issue...?
NAME agreed. The question (and discussion) was about support for including some support for unidirectional connections (with focus on QUIC and half-closed), but omitted details on multicast, as this has not laned yet. So indeed, this pull-requests does everything requested by , but does not fully capture the topic. I will move the open issues (Multicast support, is the Selection Property enough, find some place for more explanation of Uni/Bidi Streams) to once this PR is merged.
In Section 9 – "Setting and Querying of Connection Properties" – the properties of an established connection and path are heavily underspecified. Should be fixed along with .
I'm working on this issue within our pull request for , using the terminology as simplified there.


Question: single underlying transport connection where possible.  This is not a strict requirement.  The default is to not have this option. <del> 5.2.6. </del> <ins> 5.2.7. </ins> Type: Boolean

For Section 9, I'm proposing the following: An application can query Connection Properties on a connection. Connection Properties include the status of the connection and whether it is possible to send and to receive data on it. (One of them might not be possible, e.g., in a unidirectional connection.) Additionally, Connection Properties include the Connection's Transport Properties. Transport Properties include Selection Properties, so the application can know which Protocol Selection Properties had been specified, and which ones are actually supported by the protocol that has been chosen. For Establishing connections (i.e., we are not done racing yet, the final protocols have not been selected yet), the application gets the Selection Properties that had been specified on the Preconnection earlier. For Established, Closing, or Closed connections (i.e., the protocols have been selected), the application learns whether the Selection Properties are actually provided by the selected protocols. For example, if the application specified earlier, "Control Checksum Coverage: Prefer", now it will get "Control checksum coverage: True", indicating that on this connection it can indeed control the checksum coverage. Transport Properties also include Protocol Properties (Generic and Specific). These Protocol Properties can still be modified by the application. Basically, Protocol Properties are the only thing that the application can still set, everything else it can only query at this point. Finally, the application can query properties of the path. Not sure how well we have to specify them, probably this part will be implementation-specific just like, e.g., the Interface Instance or Type. Does everyone agree, or is there anything to discuss here? For me this is not a big change, it's just putting what was already there in terms of . The only thing I'm wondering if whether the Protocol Selection Properties of the finally chosen protocols are still "Selection Properties", as the selection is already done. That's why they were called "Transport Features" before, but now I want less terms and they're almost the same thing...
OK - so I commented on these things before - but in these things I think I agree. I'd personally prefer to keep the features as attributes implemented in the transport (etc) and the properties as the things requested. Indeed this begs the question about what to call the resulting transport when you selected properties and now get a transport. I think still calling them (for consistency) properties seems really good to me. :-).


Question: single underlying transport connection where possible.  This is not a strict requirement.  The default is to not have this option. <del> 5.2.6. </del> <ins> 5.2.7. </ins> Type: Boolean

As QUIC has unidirectional streams, we might want to be able to accommodate them in our transport API. Do we want to handle them fundamentally different from a half-closed connection? This should match the decisions made in .
Side note: we don't support half-closed connections to begin with. As for unidirectional streams, is this the final decision in QUIC's design, or might it change? I'd suggest postponing this until we can be sure.
NAME regarding half-closed connections: we don't have any top-level state in the connection for being half-closed. However, being able to express that a message is final in a given direction when sending allows the same functionality. As I've discussed before, we absolutely need the ability to express sending a TCP FIN, but I whole-heartedly agree it doesn't need to be a top level concept. I think this is somewhat different from half-closing, since a unidirectional stream never allows sending on one end. You could imagine that it is a connection object that returns an error if you ever try to send on it, etc. If you wanted it to look like half-closing, you could open a connection (stream), and then mark it complete in a direction immediately? But that's a bit odd.
All ok, I agree with your suggestion to fin-mark a message
I agreee with NAME regarding half-closed. My suggestion is to explicitly state that connections can be uni- or bi-directional and to add a method to query that (cansend / canrecv). This aligns nicely with final messages after which can_send becomes false. I can do a PR for that.
Thanks! I like this
Still missing unidirectional stream for multicast. – please continue discussion of multicast aspects in The connection properties (can send/receive data) are still a little under-specified - please discuss in details in – we should fix this together with .
We need unidirectional connections. You know, for multicast. And ICN. And unidirectional streaming protocols.
This is a dup of , which has more discussion
I am re-opening this ticket as only dealt with unidirectional streams in unicast context (added with PR ): Current status: The current model for unidirectional streams supports half-closed connections and QUIC style unidirectional streams so far.


Question: single underlying transport connection where possible.  This is not a strict requirement.  The default is to not have this option. <del> 5.2.6. </del> <ins> 5.2.7. </ins> Type: Boolean

We don't know yet whether it is sufficient to have canread/canwrite property on the connection level to model unidirectional connections We don't have pre-connection methods to create multicast sessions yet
there's a selection property for this, tagged discuss, which we haven't discussed yet. I'm moving this down to the appendix as part of my restructuring in my work on
If help is still wanted here, I'm maybe up for an attempt or 2 at adding multicast support. Has there been some prior discussion I can review about rough ideas on pre-connection methods for multicast sessions, or should I just try making something up?

ok, with the caveat that we need to keep multicast as an open issueLGTM About the multicast concern: I agree that it would be good if this could function for multicast reception too, and I couldn't tell if this is suitable for multicast. I suspect that multicast support is much harder anyway - see RFC 3678... so for now, this is a good step forward IMO, and let's discuss how this relates to multicast when we see a concrete text proposal that addresses it.


Question: 14. <del> I-D.draft-ietf-quic-datagram specifies a QUIC extension to enable sending and receiving unreliable datagrams over QUIC.  Unlike operating directly over UDP, applications that use the QUIC datagram service do not need to implement their own congestion control, per RFC8085, as QUIC datagrams are congestion controlled. </del> <ins> I-D.ietf-quic-datagram specifies a QUIC extension to enable sending and receiving unreliable datagrams over QUIC.  Unlike operating directly over UDP, applications that use the QUIC datagram service do not need to implement their own congestion control, per RFC8085, as QUIC datagrams are congestion controlled. </ins> QUIC datagrams are not flow-controlled, and as such data chunks may be dropped if the receiver is overloaded.  While the reliable

Some section refs weren't linked to the sections; some objects were defined multiple ways; one reference wasn't actually cited in the text.
Thanks a lot!


Question: Calling "Close" on a UDP Multicast Receive Connection (ABORT.UDP(- Lite)) releases the local port reservation and leaves the group. <ins> The Connection then issues a "Closed" Event. </ins> Calling "Abort" on a UDP Multicast Receive Connection (ABORT.UDP(- <del> Lite)) is identical to calling "Close". </del> <ins> Lite)) is identical to calling "Close", except that the Connection will send a "ConnectionError" Event rather than a "Closed" Event. </ins> Calling "CloseGroup" on a UDP Multicast Receive Connection (ABORT.UDP(-Lite)) is identical to calling "Close" on this

Takes care of item 5 and .
See discussion on
Provide a complete template that covers all functions/properties from the API. Indicate how the template should be used (e.g. leave out the parts that are not relevant for a particular protocol or include all fields and mark fields that are not relevant as such.
I'm wondering if this is really something that's in scope that we should cover. We do have the message properties section that explains how to implement various properties, but I think adding each property to every protocol mapping will be a huge amount of text that will be difficult to get exactly right.
I agree, we have added additional properties since we opened this issue to check the mapping and make sure we have a complete coverage. We should still be consistent in how we treat things though, and perhaps add a sentence that we do not describe all the properties for instance. I have made a pass through to check the mapping from the API to impl. draft for all the protocol mappings as a basis for making things consistent. Here is the summary. We cover the same actions and events for all the protocols with the exceptions that UDP Multicast does not cover the ConnectionError event and SCTP covers the Priority connection property. And MPTCP and UDP-lite are special as they refer back to the base protocols. There is one terminology inconsistency where the impl. draft refers to InitiateError and this has been generalized to EstablishmentError in the API Unless I missed something, there are only two actions that can be made on a connection that are not covered, addRemote and removeRemote. This is probably fine as they do not mean much for most of the protocols (or we could add them to be complete). We should perhaps mention how they relate to MPTCP though if we leave them out. We also do not cover the Preconnection.Rendezvous action. Again this may be fine as it is a bit special (or we can mention it for consistency.) For the events, we cover a subset with main focus on the connection related events. The Closed Event and some events related to connection setup are missing. As we cover ConnectionError we should perhaps cover the Closed event as well? We do not cover any of the Send or Receive events which seems fine.


Question: Calling "Close" on a UDP Multicast Receive Connection (ABORT.UDP(- Lite)) releases the local port reservation and leaves the group. <ins> The Connection then issues a "Closed" Event. </ins> Calling "Abort" on a UDP Multicast Receive Connection (ABORT.UDP(- <del> Lite)) is identical to calling "Close". </del> <ins> Lite)) is identical to calling "Close", except that the Connection will send a "ConnectionError" Event rather than a "Closed" Event. </ins> Calling "CloseGroup" on a UDP Multicast Receive Connection (ABORT.UDP(-Lite)) is identical to calling "Close" on this

In relation to Connection and Message properties, we do not cover any of them except for the Connection priority covered for SCTP and we talk about some properties in connection to UDP-lite and MPTCP. SCTP also has support for partial reliability and unordered messages so not sure why the priority part was singled out and added. NAME any particular reasoning behind this part? Possibly we should remove the priority part for SCTP or discuss it in running text in a similar fashion as for UDP-lite and MPTCP We may want to update the UDP-lite description to also say something about what properties it supports over UDP. The current description sounds like it is a subset. Once we agree on how to deal with the bullets above, only smaller modifications should be needed to the text.
ConnectionError should be added; SCTP priority should be removed Fix the inconsistency Add addRemote and removeRemote text related to MPTCP No action Mention Closed Event See item 1, no further action Update UDP-Lite description


Question: Knowledge that a header block with references to the dynamic table has been processed permits the encoder to evict entries to which no <del> unacknowledged references remain, regardless of whether those references were potentially blocking (see blocked-insertion).  When a </del> <ins> unacknowledged references remain (see blocked-insertion).  When a </ins> stream is reset or abandoned, the indication that these header blocks <del> will never be processed serves a similar function; see stream- cancellation. </del> <ins> will never be processed serves a similar function (see stream- cancellation). </ins> The decoder chooses when to emit Insert Count Increment instructions (see insert-count-increment).  Emitting an instruction after adding

A dynamic table entry that has not been acknowledged by the decoder must not be evicted by the encoder, even if there has never been any references to it. This is already alluded to in the current spec at URL by the phrase "acknowledged by the decoder", but since "acknowledged" is used interchangeably for acknowledging the insertion instruction and acknowledging references, a reader could understand this to mean "all references acknowledged". In addition, at three other places eviction of entries with unacknowledged references are banned, with unambigously no ban on eviction of unacknowledged entries with no references. I argue that more explicit language would be beneficial. This issue has already been discussed at URL and below. Note that avoiding this kind of corruption could also be achieved by banning an encoder from inserting entries that it does not immediately reference, but this is probably way too restrictive. For example, an encoder might wish to achieve best latency and speculatively improve future compression ratio at the expense of potentially wasting current bandwidth by encoding header fields as literals while inserting them at the same time for potiential future use. This is already alluded to in the spec at multiple places. Below is a specific scenario when this issue might cause corruption: Suppose MaxEntries is 5. Suppose that there is a fresh connection, with an empty dynamic table, and there is a header list to be sent that has two header fields which fit in the dynamic table together. Suppose one encoder implementation inserts these two header fields into the dynamic table, and encodes the header list using two Indexed Header Field instructions, referring to absolute indices 1 and 2. This header block will have an abstract Largest Reference value of 2, which is encoded as 3 on the wire. A spec compliant decoder should have no difficultly correctly decoding this header block. Suppose another encoder implementation starts by adding 10 unique entries, all different from the two header fields in the header list to be sent, to the dynamic table, but does not emit references to any of them. Of course in the end only the last couple will stay in the dynamic table, the rest will be evicted. This can be considered spec compliant depending on how one interprets the spec, see above.


Question: Knowledge that a header block with references to the dynamic table has been processed permits the encoder to evict entries to which no <del> unacknowledged references remain, regardless of whether those references were potentially blocking (see blocked-insertion).  When a </del> <ins> unacknowledged references remain (see blocked-insertion).  When a </ins> stream is reset or abandoned, the indication that these header blocks <del> will never be processed serves a similar function; see stream- cancellation. </del> <ins> will never be processed serves a similar function (see stream- cancellation). </ins> The decoder chooses when to emit Insert Count Increment instructions (see insert-count-increment).  Emitting an instruction after adding

Suppose that after this, this encoder implementation encodes our header list by inserting both header fields into the dynamic table, with absolute indices 11 and 12, and using two Indexed Header Field instructions on the request stream. The abstract Largest Reference value is 12, which is encoded as 3 on the wire since 2 * MaxEntries == 10. Now suppose that out of the 12 instructions on the encoder stream, only the first two arrive before all the request stream data are received. The remaining 10 instructions on the encoder stream are delayed on the wire. Now a spec compliant decoder sees the same header block on the request stream, bit by bit, as above, and two insertions on the encoder stream. It will emit dynamic table entires 1 and 2, which are different from the encoded header list.
You should really create a new issue for these things. Because this comment relates only to the issue, not the proposed fix. I haven't read the proposed changes, though I will if you think that there is a fix in there that is worth keeping after this. Anyhow, the example is invalid here: Because: And you can only ever fit 5 entries in that table.
That's exactly the issue: "it has first been acknowledged by the decoder" is ambigous. "Acknowledged" is being used throughout the text with two different meanings, most often to refer to references, not insertions. The ban on evicting an entry the insertion of which has not been acknowledged, that you are quoting, only occurs once out of four different locations talking about when an entry can be evicted. The other three places clearly only ban evicting an entry with unacknowledged references (note the use of the same word), giving the impression that acknowledgement of the insertion is not necessary before eviction. Since the design is correct if you read it right, but wording is not as clear as I think it should be, I consider this issue editorial. The change I propose in this PR is meant to be an improvement on clarity.
OK, having read the changes, I agree with them. They consolidate the fix by creating two conditions that cause an entry to be "blocking".
Rebased on . Please let me know if anybody can come up with a term better than "blocking" which is confusing given that streams can be "blocked".


Question: Knowledge that a header block with references to the dynamic table has been processed permits the encoder to evict entries to which no <del> unacknowledged references remain, regardless of whether those references were potentially blocking (see blocked-insertion).  When a </del> <ins> unacknowledged references remain (see blocked-insertion).  When a </ins> stream is reset or abandoned, the indication that these header blocks <del> will never be processed serves a similar function; see stream- cancellation. </del> <ins> will never be processed serves a similar function (see stream- cancellation). </ins> The decoder chooses when to emit Insert Count Increment instructions (see insert-count-increment).  Emitting an instruction after adding

NAME Thank you for your feedback.
Thanks for this. I don't have a better name for blocking entries right now, but I will keep thinking on it as I agree it could confuse people even more.
This looks reasonable.


Question: I-D.ietf-tls-dtls13.  The presentation language used in this document is described in Section 4 of RFC8446. <ins> This document reuses the definition of "anti-amplification limit" from RFC9000 to mean three times the amount of data received from an unvalidated address.  This includes all DTLS records originating from that source address, excluding discarded ones. </ins> 3. The use of RRC is negotiated via the "rrc" DTLS-only extension.  On

and
For example, allow multiple outstanding path_challenge messages to cater for potential packet loss.
We want to limit the application data sent to a reasonable threshold while we run the RRC.
RFC 9000, section 8 "address validation" (second paragraph, last line): 3 times the amount of data received.
Here is the text: Address Validation Address validation ensures that an endpoint cannot be used for a traffic amplification attack. In such an attack, a packet is sent to a server with spoofed source address information that identifies a victim. If a server generates more or larger packets in response to that packet, the attacker can use the server to send more data toward the victim than it would be able to send on its own. The primary defense against amplification attacks is verifying that a peer is able to receive packets at the transport address that it claims. Therefore, after receiving packets from an address that is not yet validated, an endpoint MUST limit the amount of data it sends to the unvalidated address to three times the amount of data received from that address. This limit on the size of responses is known as the anti-amplification limit.


Question: have a route for the destination address, or if it is configured to reject a destination prefix by policy, or if the MTU of the outgoing link is lower than the size of the packet to be forwarded.  In such <del> scenarios, CONNECT-IP endpoints SHOULD use ICMP ICMP to signal the forwarding error to its peer. </del> <ins> scenarios, CONNECT-IP endpoints SHOULD use ICMP ICMP ICMPV6 to signal the forwarding error to its peer. Endpoints are free to select the most appropriate ICMP errors to send.  Some examples that are relevant for CONNECT-IP include: For invalid source addresses, send Destination Unreachable ICMPV6 with code 5, "Source address failed ingress/egress policy". For unroutable destination addresses, send Destination Unreachable ICMPV6 with a code 0, "No route to destination", or code 1, "Communication with destination administratively prohibited". For packets that cannot fit within the MTU of the outgoing link, send Packet Too Big ICMPV6. In order to receive these errors, endpoints need to be prepared to receive ICMP packets.  If an endpoint sends ROUTE_ADVERTISEMENT capsules, its routes SHOULD include an allowance for receiving ICMP messages.  If an endpoint does not send ROUTE_ADVERTISEMENT capsules, such as a client opening an IP flow through a proxy, it SHOULD process proxied ICMP packets from its peer in order to receive these errors.  Note that ICMP messages can originate from a source address different from that of the CONNECT-IP peer. </ins> 8.

If one is using IPPROTO to select a particular protocol to be tunneled, one may still received ICMP in the context of this request. To my understanding there are two reasons for this. a) ICMP generated by the Connect-IP peer endpoint b) ICMP sent back by node beyond the Connect-IP that is directly related to forward traffic sent by this endpoint and which the tunnel endpoint maps back to the Connect-IP request. I think we could add a clarification of this in , or we could do it later.
Totally agree. I added fb1578626de4d3073ac31f5cb89c06efae2ebc51 to address this as part of .
Based on the discussion in issue we recommend to use ICMP for error signal. ICMP works for MTU issue or destination unreachable, however, there is no appropriate message type if the IP header of the packet provided by the client contains an IP that wasn't assigned to the client. So we need a different kind of error handling for this case?
I think ICMP works for this, I'd send See . Would that work?
I guess that could do it. Should we be more specific in the draft? Also, we probably would need to be more explicit in the draft that you should request a scope for your CONNECT request that allows you to received ICMP messages.
Can you write a PR for this please?
IETF 114: Recommend including ICMP if providing routes to the peer, and clients should always be prepared to receive ICMP. Also add note that ICMP may have other source/destination addresses so as to not surprise endpoints.
Also look at RFC 4301 for some potentially helpful text.
Where is the ICMPv4 detail?


Question: 6. Clients MUST ignore any received Version Negotiation packets that <del> contain the version that they initially attempted.  Once a client has reacted to a Version Negotiation packet, it MUST drop all subsequent Version Negotiation packets on that connection. </del> <ins> contain the version that they initially attempted.  A client that makes a connection attempt based on information received from a Version Negotiation packet MUST ignore any Version Negotiation packets it receives in response to that connection attempt. </ins> Both endpoints MUST parse their peer's Version Information during the handshake.  If parsing the Version Information failed (for example,

The draft says explicitly that receiving Version Negotiation terminates a connection attempt. This isn't consistent with that. This probably needs to say something like this instead:
That sounds good to me, can you make this a PR?


Question: This section defines how proxies operate in a group communication scenario.  In particular, sec-proxy-forward defines operations of forward-proxies, while sec-proxy-reverse defines operations of <del> reverse-proxies. </del> <ins> reverse-proxies.  Security operations for a proxy are discussed later in chap-proxy-security. </ins> 3.5.1.

text for proxy security cases
Reverse proxy may act as origin server and hence client doesn't use e2e security to server group. However, in other cases a reverse proxy may assume the client uses e2e OSCORE security and not add any security by itself. To consider all the different, possible/valid cases for this. And see if it's different for forward proxies.
One particular example is a client that connects over CoAP+TLS+TCP (or CoAP+DTLS) to the reverse-proxy, where the proxy uses OSCORE security for the multicast request. The client is not aware of the (group) security material which the proxy and servers have.
At high level, there are 4 different potential cases of "proxying with security". Forward proxy with e2e security [=Group oscore e2e via proxy] Forward proxy with two-leg security [=unicast OSCORE or DTLS on 1st leg, with group OSCORE on 2nd leg] Reverse proxy with e2e security [=Group oscore e2e via proxy] Reverse proxy with two-leg security [=unicast OSCORE or DTLS on 1st leg, with group OSCORE on 2nd leg] Currently the draft doesn't say anything about these combinations, which are valid, which not, and where to find the security solution to them (e.g. a pointer to draft-groupcomm-proxy for covering most of these cases) This text/analysis could be a new Section 5.3 "Proxy Security" or so. Note: cases 2 and 4 depend on a 100% trusted proxy so no e2e security model. The client in this case is not even aware necessarily of the existence of Group-OSCORE. The proxy stores the "group member identity" to be used to make the Group OSCORE protected request. This may be a single identity, or a separate identity for each authorized user of the Proxy service. Case 1 and 3 most likely means OSCORE-in-OSCORE is needed?
It seems like a good idea. Intermediaries are usually considered non-trusted, hence the interest for an actual e2e security model between origin client and origin servers. How would the proxy store and use a "group member identity" ?


Question: This section defines how proxies operate in a group communication scenario.  In particular, sec-proxy-forward defines operations of forward-proxies, while sec-proxy-reverse defines operations of <del> reverse-proxies. </del> <ins> reverse-proxies.  Security operations for a proxy are discussed later in chap-proxy-security. </ins> 3.5.1.

Even if the proxy somehow obtains multiple different Sender IDs from the Group Manager (i.e., one for each authorized user of the proxy service), the proxy would have to sign a Group OSCORE protected request with a private key of its own (possibly one per corresponding Sender ID), which is not in control of the actual origin client. With such a level of trust on the proxy, and with a client not interested in e2e security anyway, it would be just easier to think of the proxy simply as another single member of the same OSCORE group including the servers, thus sacrificing verifiable data authorship/origin. Maybe this might be useful/applicable for case 4, with a client anyway likely unaware of what happens beyond the reverse-proxy and to be actually reaching a group of servers. Not sure about case 2, where the client would be aware of an actual group of servers it tries to reach. Yes, when exactly OSCORE is also conveniently used between Client and Proxy, to fulfill REQ2 from URL : REQ2. The CoAP proxy MUST identify a client sending a CoAP group request, in order to verify whether the client is allowed-listed to do so. For example, this can rely on one of the following ... Note that this requirement applies even in case end-to-end security is not enforced between client and servers.
Agree, in the two-legs security case it seems sufficient that the proxy has one "identity" within the group. And I agree that this proxy would most likely be a reverse proxy Case 4 i.e. it operates like a (trusted!) origin server. By definition of a reverse proxy , it has to be trusted just like a client trusts an origin server with being able to know and manipulate the served content.
This issue was addressed in Section 5.3 of version -04. NAME , can we close it?
Yes!
Looks good! See inline some proposed rephrasing.


Question: The rsabssa_blind_sign function is defined in BLINDRSA, Section 5.1.2..  The Issuer generates an HTTP response with status code 200 whose body consists of TokenResponse, with the content type <del> set as "message/token-response". </del> <ins> set as "application/private-token-response". </ins> 6.3.

I also moved from the message namespace to the application namespace. The difference is helpfully summarized .
I see in the current draft that they register and . Since "token" is a very broad term, I'm wondering if something slightly more specific to Privacy Pass such as and might be reasonable?
If we make it more specific, it should be "private" instead of "privacy", to be "private-token" and align with the auth scheme. There's a fair amount of deployment on these types today, so this would be a relatively large change, or servers would need to tolerate both versions.
I'm in favor of making this change and having issuers support both for a little while.
Cool, that would work. NAME want to make the proposed update?
Will do!
NAME PR's up!
Looks good!


Question: content.  Before being encrypted, the sender data is encoded as an object of the following form: <del> MLSSenderData.sender is assumed to be a "member" sender type.  When constructing an MLSSenderData from a Sender object, the sender MUST verify Sender.sender_type is "member" and use Sender.sender for MLSSenderData.sender. </del> <ins> When constructing an MLSSenderData from a Sender object, the sender MUST verify Sender.sender_type is "member" and use Sender.leaf_index for MLSSenderData.leaf_index. </ins> The "reuse_guard" field contains a fresh random value used to avoid nonce reuse in the case of state loss or corruption, as described in

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


Question: 7. <del> The Homenet Zone provides information about the home network.  Some users may be tempted to have provide responses dependent on the origin of the DNS query.  More specifically, some users may be tempted to provide a different view for DNS queries originating from the home network and for DNS queries coming from the Internet.  Each view could then be associated with a dedicated Homenet Zone. <!--Regarding {{fig-naming-arch}}, an example of an implementation of two distinct view could be the Homenet Zone that describes the homenet view and the Public Homenet Zone that contains the Internet view, with these two zones being different.--> Note that this document does not specify how DNS queries originating from the home network are addressed to the Homenet Zone.  This could be done via hosting the DNS resolver on the HNA for example. This section is not normative. sec-reasons details why some nodes may only be reachable from the home network and not from the global Internet. sec-consequences briefly describes the consequences of having distinct views such as a "home network view" and an "Internet view".  Finally, sec-guidance provides guidance on how to resolve names that are only significant in the home network, without creating different views. 7.1. The motivation for supporting different views is to provide different answers dependent on the origin of the DNS query, for reasons such as: 1: An end user may want to have services not published on the Internet.  Services like the HNA administration interface that provides the GUI to administer your HNA might not seem advisable to publish on the Internet.  Similarly, services like the mapper that registers the devices of your home network may also not be desirable to be published on the Internet.  In both cases, these services should only be known or used by the network administrator.  To restrict the access of such services, the home network administrator may choose to publish these pieces of information only within the home network, where it might be assumed that the users are more trusted than on the Internet.  Even though this assumption may not be valid, at least this may reduce the surface of any attack. 2: Services within the home network may be reachable using non global IP addresses.  IPv4 and NAT may be one reason.  On the other hand IPv6 may favor link-local or site-local IP addresses.  These IP addresses are not significant outside the boundaries of the home network.  As a result, they MAY be published in the home network view, and SHOULD NOT be published in the Public Homenet Zone. 7.2. Enabling different views leads to a non-coherent naming system. Depending on where resolution is performed, some services will not be available.  This may be especially inconvenient with devices with multiple interfaces that are attached both to the Internet via a 3G/4G interface and to the home network via a WLAN interface. Devices may also cache the results of name resolution, and these cached entries may no longer be valid if a mobile device moves between a homenet connection and an internet connection e.g. a device temporarily loses wifi signal and switches to 3G. Regarding local-scope IP addresses, such devices may end up with poor connectivity.  Suppose, for example, that DNS resolution is performed via the WLAN interface attached to the HNA, and the response provides local-scope IP addresses, but the communication is initiated on the 3G/4G interface.  Communications with local-scope addresses will be unreachable on the Internet, thus aborting the communication.  The same situation occurs if a device is flip / flopping between various WLAN networks. Regarding DNSSEC, if the HNA does not sign the Homenet Zone and outsources the signing process, the two views are different, because one is protected with DNSSEC whereas the other is not.  Devices with multiple interfaces will have difficulty securing the naming resolution, as responses originating from the home network may not be signed. For devices with all its interfaces attached to a single administrative domain, that is to say the home network, or the Internet.  Incoherence between DNS responses may still also occur if the device is able to perform DNS resolutions both using the DNS resolving server of the home network, or one of the ISP.  DNS resolution performed via the HNA or the ISP resolver may be different than those performed over the Internet. 7.3. As documented in sec-consequences, it is RECOMMENDED to avoid different views.  If network administrators choose to implement multiple views, impacts on devices' resolution SHOULD be evaluated. As a consequence, the Homenet Zone is expected to be an exact copy of the Public Homenet Zone.  As a result, services that are not expected to be published on the Internet SHOULD NOT be part of the Homenet Zone, local-scope addresses SHOULD NOT be part of the Homenet Zone, and when possible, the HNA SHOULD sign the Homenet Zone. The Homenet Zone is expected to host public information only.  It is not the scope of the DNS service to define local home network boundaries.  Instead, local scope information is expected to be provided to the home network using local scope naming services. mDNS RFC6762 DNS-SD RFC6763 are two examples of these services.  Currently mDNS is limited to a single link network.  However, future protocols are expected to leverage this constraint as pointed out in RFC7558. 7.4. </del> This section is focused on the Homenet Reverse Zone. Firstly, all considerations for the Homenet Zone apply to the Homenet

…ument, dealing with issue
handling different views (7.0) .... some would like to have different views, This document deals with the view that the Internet gets from the CPE(s) only.


Question: RD registration URI (mandatory).  This is the location of the RD, as obtained from discovery. <del> Endpoint name (mandatory).  The endpoint name is an identifier that MUST be unique within a domain.  The maximum length of this parameter is 63 bytes. </del> <ins> Endpoint name (mostly mandatory).  The endpoint name is an identifier that MUST be unique within a domain.  The maximum length of this parameter is 63 bytes.  If the RD is configured to recognize the endpoint (eg. based on its security context), the endpoint can elide the endpoint name, and assign one based on the configuration. </ins> Domain (optional).  The domain to which this endpoint belongs. The maximum length of this parameter is 63 bytes.  When this

This allows registration without endpoint names, which is important for clients that only keep their absolutely essential cryptographic state (see URL, which this closes). The wording in simple registration was changed to not repeat the individual parameters of registration but to only refer there.
Currently, we prescribe that the registering endpoint needs to identify itself with at least an endpoint name, while we allow the RD to be configured to assign a domain based on its configuration. We could allow the endpoint identifier to be absent as well, at least in principle (eg. make it a "SHOULD be set" but no syntactical requirement on its presence), and the RD's configuration then would need to set an endpoint name (like it can now do with a domain), or the RD would refuse the registration like it can now do for unauthenticated hosts. (The RD interface right now doesn't allow a 4.01 Unauthorized response, even though the security considerations indicate that that can happen.) This would allow endpoints that have just enough persistent state to have their cryptographic identity in form of a PSK to register at the RD. Note that for those cases (and PSK seems not to be too uncommon in the CoRE security scenarios), the RD already needs to have received (or have a way to fetch) configuration about that key, which easily can contain a default (or the only permissible) endpoint name for that key. I'd write a pull request to that respect unless controversial discussion about this starts here. (This was fleshed out from in a discussion with Pekka Nikander during ACM ICN about very constrained devices).
First, domain is optional. The RD should not invent a domain for registrations that did not include a domain parameter. If the RD sets the endpoint name, then a client should be able to learn it from the registration resource, which will then depend on the implementation of read from the rd resource returning the registration parameters in the link for the registration resource, and/or the inclusion of a "self" link in the registration resource that includes "ep" as a link attribute.
Currently, we say that "When this parameter is elided, the RD MAY associate the endpoint with a configured default domain." (And it doesn't say that that default would be the absent domain).


Question: RD registration URI (mandatory).  This is the location of the RD, as obtained from discovery. <del> Endpoint name (mandatory).  The endpoint name is an identifier that MUST be unique within a domain.  The maximum length of this parameter is 63 bytes. </del> <ins> Endpoint name (mostly mandatory).  The endpoint name is an identifier that MUST be unique within a domain.  The maximum length of this parameter is 63 bytes.  If the RD is configured to recognize the endpoint (eg. based on its security context), the endpoint can elide the endpoint name, and assign one based on the configuration. </ins> Domain (optional).  The domain to which this endpoint belongs. The maximum length of this parameter is 63 bytes.  When this

It'd need to learn it from the registration resource's metadata (because the registration resource contains right what the host posted, and a self-link would be semantically ambiguous there), but it can be looked up like that: POST /rd: ;rt="temp" Created, Location: /registration/42 GET /rd-lookup/ep?href=/registration/42 Content: ;con="coaps://your-address";ep="what-i-decided" I doubt that those nodes would be really interested in doing that (I reckon they'd even tend to do simple registrations which won't even tell them their registration resource), but they can. Best regards Christian
To add to my example, the client could just as well have asked to get the same result, although I'd recommend that a client in that situation should use the query instead. NAME would that lookup interface address your concerns? Unless not, I'd go ahead and write a patch that allows such behavior (but makes it clear that this can only be used where explicitly configured or allowed in a given setting).
The changes in implement the proposed. With many things now using registration resources rather than names (cf. ), I frankly don't see a reason to mandate names anywhere (Why would a group need a name? The operations don't require it, and we sure can store one if the user desires; same for the end point…), but I won't stir that any further (we should finish rather than starting such discussions; I'd be game for it, but milestones says hurry), as just allowing the name to be configured is sufficient for the ACM ICN use case.


Question: verification) or make sure there is common context for the server to verify the address using a service-generated token. <ins> The service must also communicate the source connection ID of the Retry packet to the server so that it can include it in a transport parameter for client verification. </ins> There are two different mechanisms to allow offload of DoS mitigation to a trusted network service.  One requires no shared state; the server need only be configured to trust a retry service, though this

After thinking it through, various XOR schemes were extremely vulnerable to manipulation, so I went with a brute force approach.
The server now needs to include this field. For the no-shared state service, we just need language that the Retry service needs to encode enough information validate the packet DCID as well and drop if it fails validation. If it does, the server MUST use the packet DCID in the retrysourceconnection_id TP. For the shared state service, the retry source connection ID is going to have to be in the token. We might be able to compress this by xoring some fields; I'll think about it.


Question: to "cid_spare", then either existing or new CID MAY be used. Endpoints SHOULD use receiver-provided CIDs in the order they were <del> provided.  Endpoints MUST NOT have more than one NewConnectionId message outstanding. </del> <ins> provided.  Implementations which receive more spare CIDs than they wish to maintain MAY simply discard any extra CIDs.  Endpoints MUST NOT have more than one NewConnectionId message outstanding. </ins> Implementations which either did not negotiate the "connection_id" extension or which have negotiated receiving an empty CID MUST NOT

Thanks for this document -- badly needed and easy to read. Thanks also to Bernard Adoba for his recent tsvart review. I support his comments. COMMENTS: Sec 2. It might be useful to introduce the term "epoch" in the glossary, for those who read this front to back. Sec 4.2.3: "The encrypted sequence number is computed by XORing the leading bytes of the Mask with the sequence number. Decryption is accomplished by the same process." The text is unclear if the XOR is applied to the expanded sequence number or merely the 1-2 octets on the wire. I presume it's the latter, but this should be clarified. Sec 4.2.3: It's implied here that the snkey rotates with the epoch. As this is different from QUIC, it's probably worth spelling out. Sec 5.1 is a bit vague about the amplification limit; why not at least RECOMMEND 3, as we've converged on this elsewhere? Sec 5.1. Reading between the lines, it's clear that the cookie can't be used as address verification across connections in the way that a NEWTOKEN token is. It would be good to spell this out for clients -- use the resumption token or whatever instead. Sec 7.2 "As noted above, the receipt of any record responding to a given flight MUST be taken as an implicit acknowledgement for the entire flight." I think this should be s/entire flight/entire previous flight? Sec 7.2 "Upon receipt of an ACK that leaves it with only some messages from a flight having been acknowledged an implementation SHOULD retransmit the unacknowledged messages or fragments." This language appears inconsistent with Figure 12, where Record 1 has not been acknowledged but is also not retransmitted. It appears there is an implied handling of empty ACKs that isn't written down anywhere in Sec 7.2 Sec 9. Should there be any flow control limits on newconnectionid? Or should receivers be free to simply drop CIDs they can't handle? It might be good to specify. Finally, a really weird one. Reading this document and references to connection ID prompted to me to think how QUIC-LB could apply to DTLS.


Question: to "cid_spare", then either existing or new CID MAY be used. Endpoints SHOULD use receiver-provided CIDs in the order they were <del> provided.  Endpoints MUST NOT have more than one NewConnectionId message outstanding. </del> <ins> provided.  Implementations which receive more spare CIDs than they wish to maintain MAY simply discard any extra CIDs.  Endpoints MUST NOT have more than one NewConnectionId message outstanding. </ins> Implementations which either did not negotiate the "connection_id" extension or which have negotiated receiving an empty CID MUST NOT

The result is here: URL Please note the rather unfortunate third-to-last paragraph. I'm happy to take the answer that this use case doesn't matter, since I made it up today. But if it does, it would be very helpful if (1) DTLS 1.3 clients MUST include a connectionid extension in their ClientHello, even if zero length, and/or (2) this draft updated 4.1.4 of 8446 to allow the server to include connectionid in HelloRetryRequest even if the client didn't offer it. Thoughts? NITS: s/select(HandshakeType)/select(msg_type). Though with pseudocode your mileage may vary as to what's clearer. s/consitute/constitute Sec 5.7 In table 1, why include one ACK in the diagram but not the other? It's clear from the note, but the figure is a weird omission.
Addressed in URL


Question: request that is made to the target.  This means that only the gateway or target are in a position to identify abuse.  A gateway MAY send signals toward the relay to provide feedback about specific requests. <del> A relay that acts on this feedback could - either inadvertently or by design - lead to clients being deanonymized. </del> <ins> For example, a gateway could respond differently to requests it cannot decapsulate, as mentioned in errors.  A relay that acts on this feedback could - either inadvertently or by design - lead to client deanonymization. </ins> 7.2.2.

This seems fine to me, but doesn't seem to include URL
NAME after trying to work that text in it became clear (to me) that a better outcome was modify the existing text we have about anonymity set reduction. So I went with that approach rather than open the can of consistency worms that NAME alluded to.
Let's say HPKE public key A was valid from 2022-07-01 to 2022-07-02. The client encapsulates a request X using pubkey A, but buffers it because of network issues, in order to retry later. Now it rotates and public key B is valid as of 2022-07-03. X encapsulated using pubkey A would not be decryptable by pubkey B. So if you receive X on 2022-07-03, then you know that X was generated between 2022-07-01 and 2022-07-02.
I'm not inclined to add this. "Don't do that" seems pretty obvious to me, especially when we recommend that requests include a Date.
While this advice seems fine, I agree that it's not really necessary. It also brings up more questions to me — what stops any layer below the OHTTP layer or an intermediary from arbitrarily buffering messages? Maybe just have a note that the key config that's used as well as explicit date markings can leak the time that the request was generated?
This seems like a reasonable way to deal with the problem. Liveness information can leak in a number of places, including through noting which public key was used. It might also leak via the date. Maybe this can become part of the differential treatment section?
That sounds good to me
I think that while this text is true, I believe that it is also unnecessary. Discussion of key liveness are dealt with in the key-consistency draft, so this is really about requests that are transmitted well after they are constructed. If we start to document that, there are lots of other things that start to come up.
I agree, but the content I'm proposing here relates to how liveness affects differential treatment. We've already noted a few key ways in which this can happen, so it seems pretty harmless to me to include one more. I don't think we need to say anything more about how to deal with liveness or how it pertains to consistency. I'll propose some text to make this more clear. No more than one sentence.


Question: This document defines two new DATAGRAM QUIC frame types, which carry application data without requiring retransmissions. <ins> Note that DATAGRAM frames are only meant for unreliable transmissions.  Reliable transmission is already supported by QUIC via STREAM frames. </ins> Discussion of this work is encouraged to happen on the QUIC IETF mailing list quic@ietf.org [3] or on the GitHub repository which contains the draft: https://github.com/quicwg/datagram [4].

Some applications might want to send messages, and not care about the order of delivery, but still get reliability. QUIC streams give them reliability, but within a stream it enforces order of delivery. This datagram proposal gives unordered delivery of messages, but without reliability. Why not provide datagrams with optional (opt-in) reliability? It shouldn't be a lot of extra work for QUIC implementors to provide reliable datagrams as well as unreliable, given that retransmission is already there for QUIC streams. (I guess an application could create a separate QUIC stream for each unordered reliable message. That might work, but seems ugly and may have some overhead.)
What you describe can already be accomplished using streams: each “reliable datagram” is its own stream. That provides reliable delivery without ordering between independent datagrams. I don’t think we need to add optional reliability to the datagram spec.
Streams are very lightweight, and well suited to this task. Beware applying intuition from TCP too heavily.
So, here's a suggestion then: since I'm sure I'm not the only person who is going to think of this, maybe add some verbiage to the spec explaining why supporting reliable datagrams is unnecessary?
Sounds good. We can keep this issue open as requesting an editorial change.


Question: This specification defines the following protocol messages, along with their corresponding media types: <del> TokenRequest: "message/token-request" </del> <ins> TokenRequest: "application/private-token-request" </ins> <del> TokenResponse: "message/token-response" </del> <ins> TokenResponse: "application/private-token-response" </ins> The definition for each media type is in the following subsections. 8.2.1. <del> message </del> <ins> application </ins> <del> token-request </del> <ins> private-token-request </ins> N/A


Question: 4. <del> This section describes a typical RTCWeb session and shows how the </del> <ins> This section describes a typical WebRTC session and shows how the </ins> various security elements interact and what guarantees are provided to the user.  The example in this section is a "best case" scenario in which we provide the maximal amount of user authentication and

I've found a few typos and fixed some sentences that didn't quite make sense. I don't think the meaning has been changed in any significant way.


Question: An intermediary can reencode HTTP Datagrams as it forwards them.  In other words, an intermediary MAY send a DATAGRAM capsule to forward <del> an HTTP Datagram which was received in a QUIC DATAGRAM frame, and vice versa. </del> <ins> an HTTP Datagram that was received in a QUIC DATAGRAM frame, and vice versa.  Intermediaries MUST NOT perform this reencoding unless they have identified the use of the Capsule Protocol on the corresponding request stream; see capsule-protocol. </ins> Note that while DATAGRAM capsules that are sent on a stream are reliably delivered in order, intermediaries can reencode DATAGRAM

End of section 3.5 () says: First of all this paragraph seems to be in the wrong section because it's more generally about the capsule protocol and not the datagram capsule. However, it's also confusing. I believe if you negotiate http datagram with the H3DATAGRAM SETTINGS parameter, you always need to also support capsules even if QUIC datagrams are supported, as the other end (e.g. an intermediary) could send you anyway a capsule. Or is this text meant to say that new extensions that use the http datagram but have a new settings parameter for negotiation may not need to support the capsule protocol? I think it would be good to clarify both: what this sentence/paragraph means and what is required if you negotiate http datagrams using the H3DATAGRAM SETTINGS parameter.
I want to extended on this issue a bit more. A lot about the implementation requirement on different nodes are implied rather than being explicit. "Secondly, I will note that the above text combined with what is written in Section 3.4: Intermediaries MAY use this header field to allow processing of HTTP Datagrams for unknown HTTP Upgrade Tokens; note that this is only possible for HTTP Upgrade or Extended CONNECT." If an intermediary is doing this unaware re-encoding and the HTTP extension is an extended connect version it can result in interoperability failure when a Datagram capsule arrives at the endpoint that only supports HTTP/3 Datagrams over QUIC Datagram.
If we build off the notion that H3DATAGRAM setting communicates a willingness to receive the HTTP/3 datagrams (in QUIC datagrams), they still require some request to bootstrap the association, otherwise those datagrams would be ignored. In theory, I could define a new method called "ALWAYSUNRELIABLE" that can be used to bootstrap a request stream and it be defined to never use a capsule protocol. If a server sends me data on that stream, I could ignore it or throw an error. I don't need a new setting to caveat this behaviour.
NAME but then you can't have "blind" re-encoding of HTTP/3 Datagram to Datagram capsules, I think it is that simple.


Question: An intermediary can reencode HTTP Datagrams as it forwards them.  In other words, an intermediary MAY send a DATAGRAM capsule to forward <del> an HTTP Datagram which was received in a QUIC DATAGRAM frame, and vice versa. </del> <ins> an HTTP Datagram that was received in a QUIC DATAGRAM frame, and vice versa.  Intermediaries MUST NOT perform this reencoding unless they have identified the use of the Capsule Protocol on the corresponding request stream; see capsule-protocol. </ins> Note that while DATAGRAM capsules that are sent on a stream are reliably delivered in order, intermediaries can reencode DATAGRAM

So we need to choose if HTTP Intermediaries can re-encode when they don't know the Upgrade Token or if they can't and must be aware and thus enable cases where some have different behaviors. See
There is no such thing as "blind re-encoding". Intermediaries can only perform re-encoding when they know that the capsule protocol is in use. Intermediaries can learn that by knowing the HTTP Upgrade Token, or by watching for the Capsule-Protocol header. But I think we can make that clearer by spelling out in the "DATAGRAM Capsule" section that intermediaries MUST NOT re-encode to capsules unless they know for sure that the capsule protocol is in use.
PR did not address the editorial point that this paragraph is in the wrong section.
I don't agree with that editorial point. The paragraph is about the interaction between HTTP datagrams and the capsule protocol, so having in the DATAGRAM capsule section makes sense to me.
It about the interaction about http datagrams (section 2) and the capsule protocol (section 3). There is nothing related to datagram capsules (section 3.5) in this paragraph. I guess you could just add a new subsection 3.6 if you prefer to have it at the end.
LGTM


Question: conditions that irrevocably lead to the termination of the Connection are signaled using ConnectionError instead (see termination). <del> The ReceiveError event passes an optional associated messageContext. </del> <ins> The ReceiveError event passes an optional associated MessageContext. </ins> This may indicate that a Message that was being partially received previously, but had not completed, encountered an error and will not be completed.

Message Context Parameters/Properties are now Message Properties, and associated terminology cleanup. Addresses part of the resolution to .
Looks good, thanks for the cleanup!LGTM


Question: a POST request with an empty update.  That is, it should send a JWS whose payload is an empty object ({}). <del> 7.3.1. </del> <ins> 7.3.4. </ins> As described above, a client can indicate its agreement with the CA's terms of service by setting the "terms-of-service-agreed" field in

This PR is a first go at addressing the following points I raised on the mailing list.
This allows us to address the account URL recovery use case in without having special handling for empty payloads.


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

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


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

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


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

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


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

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


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

Proposal: Preparatory PR: Rationalize layout Move "Cryptograhic Objects" to before "Ratchet Trees" Update "Ratchet Tree Nodes" to define ParentNode and LeafNode structs, with LeafNode initially just equal to KeyPackage Move subsections of "Key Packages" to under "Ratchet Trees" Parent Hash Tree Hashes Update Paths Move Group State to its own top-level section Main PR: Change LeafNode to have the required content: HPKE key for TreeKEM Credential Parent hash Capabilities Extensions Signature Change KeyPackage to refer to LeafNode for internals, plus: HPKE key for Welcome Lifetime Extensions Signature Add continues to send KeyPackage Update and Commit send LeafNode instead of KeyPackage Remove and Sender refer to LeafNodeRef instead of KeyPackageRef We should probably do the preparatory PR regardless of this issue.
Discussion on working call: General agreement on the approach Should sign group_id when possible Include in TBS if we at least have a flag for pre-published / in-group Or we can store it Or we could have independent structs for pre-published / in-group leaves Do we need extensions at both levels? Capabilities / lifetime should probably be promoted to fields
From what I can see, there is no reason not to sign the context in the case of an external init. I'm not sure why it got taken out, but while implementing external inits, verification went through even when including the context.
As I commented in , it's not even clear that we need this context any more for members any more, given for MLSPlaintext and the AEAD of MLSCiphertext. So I would propose we just remove the context added to MLSPlaintextTBS altogether. NAME IIRC you were the one that proposed adding the context. WDYT?
This was fixed in
Here's the Weekly Digest for : - - Last week 9 issues were created. Of these, 6 issues have been closed and 3 issues are still open. :greenheart: , by :greenheart: , by :greenheart: , by :heart: , by :heart: , by :heart: , by :heart: , by :heart: , by :heart: , by :speaker: , by It received 2 comments. - - Last week, 13 pull requests were created, updated or merged. Last week, 3 pull requests were updated.


Question: The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite.  The whole structure is signed using the client's signature key.  A KeyPackage object with an <del> invalid signature field MUST be considered malformed.  The input to the signature computation comprises all of the fields except for the signature field. </del> <ins> invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. </ins> KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities"

:yellowheart: , by :yellowheart: , by :yellowheart: , by Last week, 10 pull requests were merged. :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by :purpleheart: , by - - Last week there were 38 commits. :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by :hammerandwrench: by - - Last week there were 2 contributors. :bustinsilhouette: :bustin_silhouette: - - Last week there was 1 stargazer. :star: You are the star! :star2: - - Last week there were no releases. - - That's all for last week, please :eyes: Watch and :star: Star the repository to receive next weekly updates. :smiley: You can also .*


Question: Clients encapsulate a request "request" using values from a key configuration: <del> the key identifier from the configuration, "keyID", </del> <ins> the key identifier from the configuration, "keyID", with the corresponding KEM identified by "kemID", </ins> the public key from the configuration, "pkR", and

and . Given (either assuming a fixed key ID, or looking up the KEM based on key ID), I think this is a nice simplification. It also authenticates more, even if redundant. (The kemID is already part of the HPKE key schedule.) I implemented this change and it's straightforward.
Currently, an encapsulated request carries a key ID which maps to a KEM key that determines the size of the encapsulated public key in a request. This means that code parsing a request needs to know the ID -> KEM mapping in order to parse things correctly, which is somewhat annoying. I propose we add KEMID to the request so that this mapping isn't needed to just parse the message. As a bonus, that would also fold in the KEMID explicitly into the AAD alongside the KDFID and AEADID.
We currently length-prefix it, but we don't have to. Think about this a little.
Both the public key and encapsulated secret are fixed length. I think making these fixed length on the wire is good. However, it does require the parsing code to know the corresponding size, which depends on the KEM. This requires there to be a function to map the kem_id to the corresponding size(s). NAME do you have such an API in your implementation? I have one in mine, which would make this pretty straightforward to implement.


Question: 2. <del> Flows are bidirectional exchanges of datagrams within a single QUIC connection.  These are conceptually similar to streams in the sense that they allow multiplexing of application data.  Flows are identified within a connection by a numeric value, referred to as the flow ID.  A flow ID is a 62-bit integer (0 to 2^62-1). </del> <ins> In order to allow multiple exchanges of datagrams to coexist on a given QUIC connection, HTTP datagrams contain two layers of multiplexing.  First, the QUIC DATAGRAM frame payload starts with an encoded stream identifier that associates the datagram with a given QUIC stream.  Second, datagrams carry a context identifier (see datagram-contexts) that allows multiplexing multiple datagram contexts related to a given HTTP request.  Conceptually, the first layer of multiplexing is per-hop, while the second is end-to-end. </ins> <del> Flows lack any of the ordering or reliability guarantees of streams. Beyond this, a sender SHOULD ensure that DATAGRAM frames within a single flow are transmitted in order relative to one another. </del> <ins> 2.1. </ins> <del> 3. </del> <ins> Within the scope of a given HTTP request, contexts provide an additional demultiplexing layer.  Contexts determine the encoding of datagrams, and can be used to implicitly convey metadata.  For example, contexts can be used for compression to elide some parts of the datagram: the context identifier then maps to a compression context that the receiver can use to reconstruct the elided data. Contexts are identified within the scope of a given request by a numeric value, referred to as the context ID.  A context ID is a 62-bit integer (0 to 2^62-1). While stream IDs are a per-hop concept, context IDs are an end-to-end concept.  In other words, if a datagram travels through one or more intermediaries on its way from client to server, the stream ID will most likely change from hop to hop, but the context ID will remain the same.  Context IDs are opaque to intermediaries. 2.2. </ins> Implementations of HTTP/3 that support the DATAGRAM extension MUST <del> provide a flow ID allocation service.  That service will allow applications co-located with HTTP/3 to request a unique flow ID that they can subsequently use for their own purposes.  The HTTP/3 implementation will then parse the flow ID of incoming DATAGRAM </del> <ins> provide a context ID allocation service.  That service will allow applications co-located with HTTP/3 to request a unique context ID that they can subsequently use for their own purposes.  The HTTP/3 implementation will then parse the context ID of incoming DATAGRAM </ins> frames and use it to deliver the frame to the appropriate application context. <del> Even-numbered flow IDs are client-initiated, while odd-numbered flow IDs are server-initiated.  This means that an HTTP/3 client implementation of the flow ID allocation service MUST only provide </del> <ins> Even-numbered context IDs are client-initiated, while odd-numbered context IDs are server-initiated.  This means that an HTTP/3 client implementation of the context ID allocation service MUST only provide </ins> even-numbered IDs, while a server implementation MUST only provide <del> odd-numbered IDs.  Note that, once allocated, any flow ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. </del> <ins> odd-numbered IDs.  Note that, once allocated, any context ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization.  Additionally, note that the context ID namespace is tied to a given HTTP request: it is possible for the same numeral context ID to be used simultaneously in distinct requests. </ins> <del> 4. </del> <ins> 3. </ins> When used with HTTP/3, the Datagram Data field of QUIC DATAGRAM frames uses the following format (using the notation from the "Notational Conventions" section of QUIC): <del> A variable-length integer indicating the Flow ID of the datagram (see datagram-flows). </del> <ins> A variable-length integer that contains the value of the client- initiated bidirectional stream that this datagram is associated with, divided by four.  (The division by four stems from the fact that HTTP requests are sent on client-initiated bidirectional streams, and those have stream IDs that are divisible by four.) A variable-length integer indicating the context ID of the datagram (see datagram-contexts). The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. Intermediaries parse the Quarter Stream ID field in order to associate the QUIC DATAGRAM frame with a stream.  If an intermediary receives a QUIC DATAGRAM frame whose payload is too short to allow parsing the Quarter Stream ID field, the intermediary MUST treat it as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. Intermediaries MUST ignore any HTTP/3 Datagram fields after the Quarter Stream ID. Endpoints parse both the Quarter Stream ID field and the Context ID field in order to associate the QUIC DATAGRAM frame with a stream and context within that stream.  If an endpoint receives a QUIC DATAGRAM frame whose payload is too short to allow parsing the Quarter Stream ID field, the endpoint MUST treat it as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR.  If an endpoint receives a QUIC DATAGRAM frame whose payload is long enough to allow parsing the Quarter Stream ID field but too short to allow parsing the Context ID field, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. If a DATAGRAM frame is received and its Quarter Stream ID maps to a stream that has already been closed, the receiver MUST silently drop that frame.  If a DATAGRAM frame is received and its Quarter Stream ID maps to a stream that has not yet been created, the receiver SHALL either drop that frame silently or buffer it temporarily while awaiting the creation of the corresponding stream. 4. CAPSULE allows reliably sending request-related information end-to- end, even in the presence of HTTP intermediaries. CAPSULE is an HTTP/3 Frame (as opposed to a QUIC frame) which SHALL only be sent in client-initiated bidirectional streams. Intermediaries MUST forward all received CAPSULE frames in their unmodified entirety on the same stream where it would forward DATA frames.  Intermediaries MUST NOT send any CAPSULE frames other than the ones it is forwarding. This specification of CAPSULE currently uses HTTP/3 frame type 0xffcab5.  If this document is approved, a lower number will be requested from IANA. The Type and Length fields follows the definition of HTTP/3 frames from H3.  The payload consists of: The type of this capsule. Data whose semantics depends on the Capsule Type. Endpoints which receive a Capsule with an unknown Capsule Type MUST silently drop that Capsule.  Intermediaries MUST forward Capsules, even if they do not know the Capsule Type or cannot parse the Capsule Data. 4.1. The REGISTER_DATAGRAM_CONTEXT capsule (type=0x00) allows an endpoint to inform its peer of the encoding and semantics of datagrams associated with a given context ID.  Its Capsule Data field consists of: The context ID to register. A string of comma-separated key-value pairs to enable extensibility.  Keys are registered with IANA, see iana-keys. The ABNF for the Extension String field is as follows (using syntax from Section 3.2.6 of RFC7230): Note that these registrations are unilateral and bidirectional: the sender of the frame unilaterally defines the semantics it will apply to the datagrams it sends and receives using this context ID.  Once a context ID is registered, it can be used in both directions. Endpoints MUST NOT send DATAGRAM frames using a Context ID until they have either sent or received a REGISTER_DATAGRAM_CONTEXT Capsule with the same Context ID.  However, due to reordering, an endpoint that receives a DATAGRAM frame with an unknown Context ID MUST NOT treat it as an error, it SHALL instead drop the DATAGRAM frame silently, or buffer it temporarily while awaiting the corresponding REGISTER_DATAGRAM_CONTEXT Capsule. Endpoints MUST NOT register the same Context ID twice on the same stream.  This also applies to Context IDs that have been closed using a CLOSE_DATAGRAM_CONTEXT capsule.  Clients MUST NOT register server- initiated Context IDs and servers MUST NOT register client-initiated Context IDs.  If an endpoint receives a REGISTER_DATAGRAM_CONTEXT capsule that violates one or more of these requirements, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. 4.2. The CLOSE_DATAGRAM_CONTEXT capsule (type=0x01) allows an endpoint to inform its peer that it will no longer send or parse received datagrams associated with a given context ID.  Its Capsule Data field consists of: The context ID to close. A string of comma-separated key-value pairs to enable extensibility, see the definition of the same field in register- capsule for details. Note that this close is unilateral and bidirectional: the sender of the frame unilaterally informs its peer of the closure.  Endpoints can use CLOSE_DATAGRAM_CONTEXT capsules to close a context that was initially registered by either themselves, or by their peer. Endpoints MAY use the CLOSE_DATAGRAM_CONTEXT capsule to immediately reject a context that was just registered using a REGISTER_DATAGRAM_CONTEXT capsule if they find its Extension String to be unacceptable. After an endpoint has either sent or received a CLOSE_DATAGRAM_CONTEXT frame, it MUST NOT send any DATAGRAM frames with that Context ID.  However, due to reordering, an endpoint that receives a DATAGRAM frame with a closed Context ID MUST NOT treat it as an error, it SHALL instead drop the DATAGRAM frame silently. Endpoints MUST NOT close a Context ID that was not previously registered.  Endpoints MUST NOT close a Context ID that has already been closed.  If an endpoint receives a CLOSE_DATAGRAM_CONTEXT capsule that violates one or more of these requirements, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. 4.3. The DATAGRAM capsule (type=0x02) allows an endpoint to send a datagram frame over an HTTP stream.  This is particularly useful when using a version of HTTP that does not support QUIC DATAGRAM frames. Its Capsule Data field consists of: A variable-length integer indicating the context ID of the datagram (see datagram-contexts). </ins> The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. <del> Endpoints MUST treat receipt of a DATAGRAM frame whose payload is too short to parse the flow ID as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. </del> <ins> Datagrams sent using the DATAGRAM Capsule have the exact same semantics as datagrams sent in QUIC DATAGRAM frames. </ins> 5.

This PR aims to take the design discussions we had at the last interim, and propose a potential solution. This PR should in theory contain enough information to allow folks to implement this new design. That will allow us to perform interop testing and confirm whether the design is sound.
I'm confused by this pull request (probably because I was out of the loop for a while). My understanding, at least when I first read the proposal a month ago was that we would separate multiplexing streams and multiplexing contexts into different layers, so that methods that need context would get it (CONNECT-UDP), and features that don't (WebTransport/extended CONNECT) could use stream-associated datagrams directly.
NAME you're referring to which this PR isn't trying to address. That'll happen in a subsequent PR.
In , capsules, contexts and context IDs are explicitly defined as end-to-end and there are requirements for intermediaries to not modify them, and to not even parse them. The motivation for this was to ensure that we retain the ability to deploy extensions end-to-end without having to modify intermediaries. NAME mentioned that these requirements might be too strict, as he would like to have his intermediary be able to parse the context ID, for logging purposes.
Part of the comment from the PR is also about consistency of interface for generic HTTP libraries that can be used to build either endpoints or intermediaries. If the context ID is always present, it's overly prescriptive to say that an intermediary can't parse it, and such a requirement couldn't be enforced anyways. If context IDs are negotiated on/off, whether this is possible depends on the negotiation mechanism.
I think its fine for a component that has bytes passing through it to look at those bytes. The import thing to do is set expectations on what that means for the protocol behaviour we are defining. We don't expect intermediaries to do anything with a context ID; they should not enforce the protocol semantic rules (odd, even, reuse etc). H2 and H3 somewhat solve this problem by decoupling frame parsing from frame payload interpretation. E.g. if the form of a request or response is invalid, an intermediary shouldn't pass it on. DATAGRAM is different because it isn't defined as an actual HTTP/3 frame with frame headers and frame payload.