The value of the Destination Connection ID field from the first Initial packet sent by the client.  This transport parameter is <del> only sent by a server.  A server MUST include the original_connection_id transport parameter if it sent a Retry packet. </del>  The idle timeout is a value in milliseconds that is encoded as an integer; see (idle-timeout).  If this parameter is absent or zero opening.  If the transport parameter is absent, streams of that type start with a flow control limit of 0. <del> A client MUST NOT include an original connection ID, a stateless reset token, or a preferred address.  A server MUST treat receipt of any of these transport parameters as a connection error of type </del>  TRANSPORT_PARAMETER_ERROR. 19.

Note that may want to change the phrasing of the ODCID field, depending on which PR lands first.
End of section 18, transport It seems the term is "initial connection ID" not "original connection ID", at least I can't find it defined anywhere in transport.
Two different things, but you're probably right that they should both be explicitly defined: The "Original destination connection ID" is the DCID used in the client's very first Initial packet. If the server responded with a Retry, the server needs to: include the ODCID in the Retry packet to verify the Retry packet came from something on-path include the ODCID in the eventual handshake's transport parameters to verify that the Retry packet originated from the server or something cooperating with it, not a MITM The "Initial connection ID" is the DCID used in the client's Initial packet to which the server responded with an Initial. This CID determines the keys used for Initial packets throughout the handshake. (But see .) This CID might have been server-chosen (from a Retry) or client-chosen (no Retry). If there's no Retry packet, they refer to the same CID, but I don't think there's a reference to the ODCID outside the context of a Retry.
I think that we already concluded this in .
This is a separate issue, about definition of these terms; is about whether these need to be separate concepts depending on the outcome of other issues. NAME notes that the term "original connection ID" appears only to say that a client MUST NOT send one, and that literal string appears nowhere else in the document except the changelog. This refers to the transport parameter , whose definition matches the description of the "Original Destination Connection ID" field in Retry and references Retry, but doesn't use that term. I'd suggest using the names of the prohibited TPs in stating the client restriction, and referencing the "Original Destination Connection ID" field by name from the TP definition.

The value of the Destination Connection ID field from the first Initial packet sent by the client.  This transport parameter is  <ins> only sent by a server.  This is the same value sent in the "Original Destination Connection ID" field of a Retry packet (see packet-retry).  A server MUST include the original_connection_id transport parameter if it sent a Retry packet. </ins> The idle timeout is a value in milliseconds that is encoded as an integer; see (idle-timeout).  If this parameter is absent or zero opening.  If the transport parameter is absent, streams of that type start with a flow control limit of 0.  <ins> A client MUST NOT include server-only transport parameters (original_connection_id, stateless_reset_token, or preferred_address).  A server MUST treat receipt of any of these transport parameters as a connection error of type </ins> TRANSPORT_PARAMETER_ERROR. 19.


different connections; validating the port is therefore unlikely to be successful. <del> If the client has a token received in a NEW_TOKEN frame on a previous connection to what it believes to be the same server, it SHOULD include that value in the Token field of its Initial packet. </del>  Including a token might allow the server to validate the client <del> address without an additional round trip. </del>  A token allows a server to correlate activity between the connection where the token was issued and any connection where it is used.

This PR clarifies that the scope of a NEW_TOKEN is equivalent to that of the TLS connection (i.e., the scope of the server certificate), in a minimalistic way.
I'm not sure that this is the right scoping. Consider that NST is explicitly tied just to the server you connected to, not to any server found in the certificate. Why isn't this "same server name"?
Retry is a server controlled method that can be used for various things including client address validation, but also load balancing or redirects to a more local or somehow better service. Requiring these alternative locations to be tightly coupled to the original connection would work against this.
NAME Quoting from , the requirement for NST is: MUST NOT added in this PR achieves parity with the "MUST only" statement in TLS 1.3. Regarding the SHOULD in TLS 1.3, I do not think we need feature parity. Compared to TLS 1.3 running over TCP, it is extremely difficult in QUIC to create a proxy that extracts the SNI and then let's different backend server handle the connection. It is natural to assume that a QUIC server that presents a wildcard certificate to be directly hosting all those server identities.
At the moment, states that a resumption token can be used "if the client has a token received in a NEWTOKEN frame on a previous connection to what it believes to be the same server._" But what does "the same server" actually mean? Some possible answers include: a) the same server IP address b) the same server IP address and port c) any server name that was presented in the certificate provided in the previous connection (the scope of session tickets; see ) d) the same server-name e) the same server-name and ALPN (the scope of 0-RTT; see ) I'd presume it to be one of a, b, or c, but I think it'd be better to clarify what "the same server" actually means.
IIRC, NAME pointed out that the scope of tokens should be as tight as that of the session tickets (i.e. option c), due to the following reason. Consider the case of a split-server deployment (i.e. a gateway with a single IP address mapping connections to different QUIC servers in the backend, based on SNI). If we are to adopt option a or option b, one of those backend servers might issue a token, that would then be used by the client when connecting to a different backend server that shares the same gateway. This means that the party controlling the server that issued the token can see that the same client connected to a different server, assuming that the party can observe the traffic that goes into the load balancer. To avoid the leak, the scope of NEW_TOKEN tokens should be at least as tight as the set of the server-names that the issuer of the token is authoritative for; which means option c.
is an attempt to clarify option c being the choice.
I agree that a or b is not restrictive enough based on the example given above. I wonder if c/d/e are also not restrictive enough though. Consider URL hosted on multiple CDNs (where QUIC is terminated by the CDN). A client makes an initial connection to URL (which gets served by CDN A) and receives a NEW_TOKEN token. Later, this client looks up URL, gets directed to CDN B, and sends the token it received on the connection to CDN A. I wouldn't expect CDN B to be able to process that token. We could also decide that it's not worth solving the case above. Being overly restrictive in scoping tokens could mean we don't save tokens often enough (resulting in connections being established with no token when we could have used a token), which might be worse than occasionally sending the wrong token to a server.
NAME I think that is a performance concern rather than a security concern? Assuming that it is the case where sending a token does not have any positive impact on performance, I think we might not need to care about that. We could, but I think it would be hard to draw a line on when sending a NEW_TOKEN token can be considered beneficial enough..., and there is no negative performance impact on sending an unusable token.
Agreed, it's a performance concern, not a security concern. If the client sends an unreadable token, worst case is the server sends a Retry packet and we burn a round trip.
FWIW, the discussion here relates to issue (PR ). If we are to say that the scope of a token is tied to the identity of the server (i.e. server certificate), it becomes impractical to use token-based greasing for hosts that are hosted by multiple entities (i.e. multi-CDN use-case). This is because owners of such hosts would not want to see an additional round-trip due to Version Negotiation packet being sent in response to an unknown version. If we are to say that the scope of a token is a tuple of the server identity and the server address, maybe that becomes an non-issue, as we can assume that the tuple uniquely identifies the operator of the server.
I think that is good enough. There are lots of ways to slice this and what is proposed there seems like the most tractable. I'm sure that it's not perfect, but I don't think that there will be a perfect answer here.
As I wrote in URL I think there is an aspect of certificate privacy where you can reconnect with a different server certificate after you obtain a secret salt. Making "same server" too narrow would prevent the privacy benefits of such an approach.` Publishing a link between such certificates would kind of defeat the point, so there is a chicken/egg problem here. However, if the client has out of band knowledge of another domain that works, it should be allowed to use it.
NAME I think I tend to agree with this statement. And aside from the privacy benefits, I'd note that there is a performance benefit that I am interested in (i.e. URL). As an example, it would be safe to say that servers sharing the ESNI keys are covered by a single token, considering the fact that ESNI keys is assumed to be retained by a single authority that can decrypt the Initial packet payload.
I see a lot of value in alternative "a or c" for CDNs. The purpose of the token is to prove to the server that the client owns the address. It should not matter why the client received the token (similar to TFO token). As for the privacy, I do not see a problem. The gateway already sees everything and knows everything. If the backends cooperate, they already know everything. If they do not cooperate, this is no different than a multi-CDN case.
NAME Only when the gateway is encrypting / decrypting the traffic. Counterexample is QUIC-LB, where the gateway just forwards the packets to different backend servers. (c) is exactly the same as what we state for TLS session tickets in RFC 1.3, which covers the multi-CDN case. If we want to be more lax, I think we need to present that there is no privacy concerns in doing so.
NAME If gateway does not have the keys, it has no more info than a multi-CDN case. In fact, it has less info -- it cannot tell when the new connection is for the same or different hostname than the one that issued the token. I am interested in anyone presenting a material reduction in privacy in case (a) that is absent in a multi-CDN case with case (c). (I am not aware of a way to prove lack of privacy concerns other than making an attempt to find some and falling to do so).
NAME How about URL
NAME I did see this but am confused where the risk is. If a party can see all traffic going to a specific IP, is the concern that it is giving them some extra information when there are multiple clients behind a NAT?
NAME No. The concern is on the server-side, where three parties are involved: a) owner of LB (that only sees unencrypted traffic), b) owner of one server behing a, c) owner of another backend server behind a, who can also monitor the traffic between clients and a. The attack goes like this: c accepts a connection from a legitimate client (through a), and issues a NEWTOKEN token The client reconnects to b (through a), using the the token obtained in step 1. At this point, c can tell that who connected to b. Going back to our design principle; we require NEWTOKEN tokens (and also TLS session tickets) to be sent using an encrypted channel, and to be used only once, because the fact that the client is connecting to a particular server should not be exposed to a third party. In this example, we are violating that requirement.
NAME So why is the answer to my question of whether the scheme above gives out extra information only in case of multiple users behind a NAT: no? If there is only a single user behind an IP, a party that can observe all traffic to load balancer "a" can know who is connecting to "c" and "b" just by matching on the src ip and seeing that they are the same.
NAME I think the hidden assumption in your argument is that the client is connecting to "b" and "c" at the same time. When that assumption is met, I think you are correct that the attack is only viable when the client is behind a NAT. But it could also be the case that the client first connects to "c", disconnects, then connect to "b" using the token obtained from "c" from a different address. In that case, the attack becomes concerning even when the client is not behind a NAT.
NAME This is an address validation token. It is coded for a particular client address. The client will not use the token if it has migrated to a different address. This is very similar to TFO Cookie handling.
The specification is not written as such. Section 8.1.2 states, that if the client has a token received in a NEWTOKEN frame on a previous connection to what it believes to be the same server, it SHOULD include that value in the Token field of its Initial packet. There is no requirement for the client to check it's address (or the network). I think that the approach used by the specification is correct. In practice, I think we cannot assume that all the clients would correctly deal with their source address explicitly (as well as the change of the address). Besides, a change of source address does not necessarily mean that the client has migrated to a different network. Consider the case where a client goes out of one DHCP network, then returns to that network. In such case, the client might receive a different address, but it is still on the same network. After all, we are requiring the server to associate NEWTOKEN tokens and the original source address. Then, why not let the server decide if a token can be reused?
For the client, the consequences of a bad guess is a wasted token and (maybe) the wasted bytes. That's all. So in general, there is no reason to constrain use of tokens where the client thinks that they might be useful AND that the client is willing to risk linkability between sessions. The latter condition is where the various linkages come into play, but the point remains that the client is responsible for making an assessment. This text is about setting a common baseline for that. If a client wants to extend the set of servers that might be able to link sessions, I think that's OK, but it has to do this on the understanding of what that means. The server that issued the token might see this new usage and link it to a specific prior context. Without ESNI, that means things like knowing where previous users are now trying to connect. As NAME says, a client might choose to constrain token use to particular networks, but it doesn't have to. I might even go so far as to say that they should probably not reuse a token from a different network location, but that depends on having information that I know is hard to acquire. A requirement that the token only be used from a certain network location wouldn't be implemented because in some cases it couldn't be implemented reliably.
I think it is a good thing to cover multiple networks because you can hide from external observers. But, if you are on a corporate or government MITM proxy matters are only going to get worse. That said, QUIC cannot possibly accommodate deliberately broken networks. Also, clients have interests adverse to users as well - for example Google and Facebook need qualified advertising traffic and if QUIC tokens can slip under the Cookie radar, they will. I can't manage a Google cloud cluster without logging in to Youtube on an account that has never signed up for Youtube, and now I can't watch cat videos without getting cluster management commercials which really goes against the point of watching cat videos in the first place (or something roughly equivalent), so on. So, there is tension in how much to leave for the client to decide vs actual user privacy.
NAME NAME Indeed, that's correct, no requirement to check address/network on first use. There is language about reuse that does require the check (but the reuse itself is not required / actually discouraged): "A client MUST NOT reuse a token if it believes that its point of network attachment has changed since the token was last used; that is, if there is a change in its local IP address or network interface." I think I can live with the new language, since it gives clients enough flexibility in case they believe that the server that issued the token and the new server cooperate in managing the tokens (including a belief that they are the same server). So no objection to the current language in on my part.

different connections; validating the port is therefore unlikely to be successful.  <ins> A token received in a NEW_TOKEN frame is applicable to any server that the connection is considered authoritative for (e.g., server names included in the certificate).  When connecting to a server for which the client retains an applicable and unused token, it SHOULD include that token in the Token field of its Initial packet. </ins> Including a token might allow the server to validate the client  <ins> address without an additional round trip.  A client MUST NOT include a token that is not applicable to the server that it is connecting to, unless the client has the knowledge that the server that issued the token and the server the client is connecting to are jointly managing the tokens. </ins> A token allows a server to correlate activity between the connection where the token was issued and any connection where it is used.


causes all streams to immediately become closed; open streams can be assumed to be implicitly reset. <del> After sending a CONNECTION_CLOSE frame, endpoints immediately enter the closing state.  During the closing period, an endpoint that sends a CONNECTION_CLOSE frame SHOULD respond to any packet that it receives with another packet containing a CONNECTION_CLOSE frame.  To minimize the state that an endpoint maintains for a closing connection, endpoints MAY send the exact same packet.  However, endpoints SHOULD limit the number of packets they generate containing a CONNECTION_CLOSE frame.  For instance, an endpoint could </del>  progressively increase the number of packets that it receives before sending additional packets or increase the time between packets.  Allowing retransmission of a closing packet contradicts other advice in this document that recommends the creation of new packet numbers for every packet.  Sending new packet numbers is primarily

The PR clarifies the following: An endpoint that drops the keys when entering closing state MUST back-off the frequency of CONNECTIONCLOSE packets that it sends. An endpoint that does not drop the keys stops sending CONNECTIONCLOSE packet once it receives a packet containing CONNECTION_CLOSE. The first point is what we have discussed in . The second point is an editorial clarification, which is explained far below in the original text
Is there a risk of amplification attacks if an attacker sends bad packets during handshake that triggers a connection close, possible to a spoofed address. Sorry, not really up to speed on handshake details, just want to make sure this isn't overlooked. I think it should be OK, since it would be below a factor 3.
Yes, amplification using CONNECTION_CLOSE is impossible because we require that - if you don't apply other rate limiting methods - the closing packet you send is smaller than the packet you receive. That is, the factor is <1 in that case. If you apply other rate limiting methods, then the 3x limit would apply, though it would be unlikely that you would ever have cause to hit that limit.
At the moment, the backoff is merely a recommendation. Quoting from : endpoints SHOULD limit the number of packets they generate containing a CONNECTIONCLOSE frame. However, there is a DoS attack vector unless we make this a MUST, as an attacker can create bounce of packets carrying CONNECTIONCLOSE frames between two servers. Consider the case where you have two servers (A, B) that use the original DCIDs supplied by the client as the server CIDs. The attacker sends the following two Initial packets: srcaddr=A, destaddr=B, srcCID=X, destCID=Y srcaddr=B, destaddr=A, srcCID=Y, destCID=X Both of the two packets would contain an invalid payload. Then, both server A and server B would enter the CLOSING state sending CONNECTION_CLOSE frame to the peer. While in the CLOSING state, the specification allows endpoints to respond to packets from peer without decrypting them. Therefore, this creates a ping-pong. To prevent this type of attack, I think we need to change "SHOULD limit" of the quoted text to "MUST limit". The alternative might be to forbid servers adopting the DCID given by the clients as their server CIDs.
In this case, I believe both sides are in the server role. Servers don't need to pad Initial packets and servers drop Initials less than 1200 bytes, so I believe the other 'Server' would drop the Initial CONNECTIONCLOSE and this would stop quickly. However, if an implementation padded all Initials, this could be a problem, so more clarity on Initial padding may be necessary? ie: Servers SHOULD NOT pad Initial packets containing only CONNECTIONCLOSE.
Oh I missed that point. Thank you for pointing it out. Though it is still possible to mount this attack by sending an invalid 0-RTT packet Consider the case where an attacker obtains a session ticket from both servers beforehand, and sends datagrams to the servers, each consisting of Initial and 0-RTT packets (of which 0-RTT packet contains an invalid frame). Then, assuming that both servers accept 0-RTT, they would send to each other a series of Initial, Handshake, and 1-RTT packets, of which the 1-RTT packet would contain an CONNECTION_CLOSE frame. So that would cause a ping-pong.
PS. Though I now realize that the maximum about of bytes that each server would ping-pong is limited to 3x the size of the datagram that the attacker sends. So it might be possible to call this a non-issue, though the number of UDP packets that the servers would send might be less concerning (it would be like 30 UDP packets, assuming that the packets containing CONNECTION_CLOSE would be around 100 bytes each).
Discussed in Cupertino. NAME to write up a PR that replaces SHOULD by MUST in this case.
Note that this is only MUST in the case where the server drops state and uses a canned packet.
I would suggest saying that impls MUST implement one of the two solutions: MUST NOT use the client's DCID as the SCID, or MUST do an exponential backoff if it does.
An alternative would be to simply require backoff always. Whether or not a canned packet is used. Not backing off seems like a live wire, and it might be better to neutralize it in general.
I think that a "SHOULD" is enough generally; the problem only exists because you are blindly sending packets without understanding the packet that triggers them.
In , I've gone with SHOULD limit when you retain packet protection keys (as you can stop sending packets once you receive CONNECTION_CLOSE) MUST limit when you drop packet protection keys (as you do not know when to stop) Re URL, while we can define a rule based on how endpoints use CIDs, I think I prefer having a rule based on how a stack is implemented (i.e. when you drop packet protection keys) rather than how a stack is configured (i.e. the way CIDs are used). IMO, the latter is harder to test and therefore fragile.

causes all streams to immediately become closed; open streams can be assumed to be implicitly reset.  <ins> After sending a CONNECTION_CLOSE frame, an endpoint immediately enters the closing state. During the closing period, an endpoint that sends a CONNECTION_CLOSE frame SHOULD respond to any incoming packet that can be decrypted with another packet containing a CONNECTION_CLOSE frame.  Such an endpoint SHOULD limit the number of packets it generates containing a CONNECTION_CLOSE frame.  For instance, an endpoint could </ins> progressively increase the number of packets that it receives before sending additional packets or increase the time between packets. <ins> An endpoint is allowed to drop the packet protection keys when entering the closing period (draining) and send a packet containing a CONNECTION_CLOSE in response to any UDP datagram that is received. However, an endpoint without the packet protection keys cannot identify and discard invalid packets.  To avoid creating an unwitting amplification attack, such endpoints MUST reduce the frequency with which it sends packets containing a CONNECTION_CLOSE frame.  To minimize the state that an endpoint maintains for a closing connection, endpoints MAY send the exact same packet. </ins> Allowing retransmission of a closing packet contradicts other advice in this document that recommends the creation of new packet numbers for every packet.  Sending new packet numbers is primarily


Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such <del> bursts to the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize, 14720)), the same as the recommended initial congestion window. </del>  As an example of a well-known and publicly available implementation of a flow pacer, implementers are referred to the Fair Queue packet

From discussion on people prefer the normative text to apply to the initial congestion window, not the specific value recommended in the recovery document. URL
I approve of this editorial change

Sending multiple packets into the network without any delay between them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such  <ins> bursts to the initial congestion window, which is recommended to be the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize, 14720)). </ins> As an example of a well-known and publicly available implementation of a flow pacer, implementers are referred to the Fair Queue packet


PADDING and PING frames MAY appear in packets of any encryption level. <del> CRYPTO and CONNECTION_CLOSE frames MAY appear in packets of any encryption level except 0-RTT. </del>  ACK frames MAY appear in packets of any encryption level other than 0-RTT, but can only acknowledge packets which appeared in beyond the Error Code.  This SHOULD be a UTF-8 encoded string RFC3629.  19.20. QUIC frames do not use a self-describing encoding.  An endpoint

As discussed in , use of application-level close is problematic in Initial / Handshake packets. This PR address the issue by limiting the use of that to 1-RTT packets, at the same time advising applications to use user_canceled TLS alert to abort the connection during the handshake.
At the moment, CONNECTIONCLOSE (0x1d) (i.e. the application-level close) is allowed "in packets of any encryption level except 0-RTT." (). I think that it cannot be sent or received in an Initial or Handshake packets, as only the QUIC and TLS are interacting at that layer. Note that the application protocol might not have been determined when Initial / Handshake packets are exchanged (before the server returns the EE indicating which application protocol has been chosen).
Two choices: no problem: let the application decide to use Handshake to abort a connection it doesn't want any more. problem: force the application to use 1-RTT packets to express its discontent. I can see reasons for either.
As stated above, I think option 1 is problematic in sense that the endpoint might not know which application protocol it is taking, though the error code being used is specific to the application protocol. Even for Handshake packets it is hard to tell if the peer has learnt the application protocol in use, as CRYPTO frames and CONNECTION_CLOSE might get delivered out of order.
Another issue with option 1 is that we might leak sensitive data. Consider the case where a server receives a coalesced Initial / 0–RTT packet, and decides to respond with an application-close as the outcome of processing the 0-RTT application data. In this case, application-close should not be sent in Initial packet, as it would be an act of an application responding to the client in cleartext.
I believe I prefer 2, but if the application tries to close the connection with an application close before any data can be sent in 1-RTT, advise the transport close the connection at Initial or Handshake instead? I believe that both honors the intent of the application and maintains some separation.
NAME Agreed. And for that purpose, I think transport close with an error code of 0x15a (TLS alert usercanceled) fits naturally. Quoting from , this alert notifies the recipient that the sender is canceling the handshake for some reason unrelated to a protocol failure.
I disagree with making a change. We discussed this exact topic when we allowed CONNECTION_CLOSE in Initial, and it was decided at the time that if an application wanted to terminate the connection at this stage, it may do so.
NAME Would you mind pointing out the link to the discussion? Besides, if we are to allow CONNECTION_CLOSE in Initial / Handshake, I think we need to clarify how an endpoint selects the error code (see URL) and how it is interpreted (URL). I think that would be more complex to implement and maintain than limiting the use of application-level close to 1-RTT.
I can't seem to find the discussion right now. I believe a lot of it was in person at the time as well. Things may be difficult in some scenarios, but we can leave the decision on how to handle things up to the application layer. For the 0-RTT scenario, you can use a generic application error code. There's no ALPN ambiguity there, right, since they have to use the same one as previous? I don't think we should add extra restrictions at the transport layer.
Would it make sense to allow connection-level CONNECTION_CLOSE in 0-RTT, while forbidding it in Initial and Handshake?
NAME I assume you mean application-level CONNECTIONCLOSE in 0-RTT. I do not have a strong opinion on that, though I might point out that allowing that creates a wired state; a client would might send CONNECTIONCLOSE before it knows if the server has accepted or rejected 0-RTT. The question here is if the client is required to retransmit CONNECTION_CLOSE in 1-RTT when the server rejects 0-RTT. Considering that, I think we can just forbid the use of application-close in 0-RTT. The client can either wait for the handshake to complete then send an application-level close in 1-RTT, or it can close the connection using a QUIC-level close during the handshake (without exposing why).
NAME Thank you for checking. The problem is that then there would be two requirements: Application protocols MUST define a generic error code that can be exposed unencrypted. QUIC stacks need to provide an API that tells the application if a CONNECTIONCLOSE frame is going to be sent using Initial packets. Each application needs to consult that in order to determine the error code to be sent. There is. The case is where there is an error in the 0-RTT data that the client sends, and the server responds with a CONNECTIONCLOSE frame. In this case, there is no ambiguity on the server-side, as the server has committed to processing a particular application protocol. However, there is an issue on the client-side. The client cannot tell which application protocol has been selected, as the CONNECTION_CLOSE frame (carried in either Initial or Handshake) may arrive before it receives the Encrypted Extensions handshake message that carries the name of the negotiated protocol. We can say that a server sending an application-level close before the client sends an 1-RTT packet is an alternative way of negotiating the protocol. But are we really going to say that? I think it's too complicated.
I agree with NAME there is an age old discussion on handling errors in early connection. Simply forbidding them without understanding this would be unfortunate. Consider errors in early handshake where the server does not wish to proceed. It doesn't like the client, it doesn't have the resources, it is about to reboot, or whatever. It can either drop the packets or wait if it cannot close immediately. It doesn't want to wait so it drops. Drops then probably results in unnecessary resets.
NAME That's not what this issue is about. CONNECTION_CLOSE using a transport error would still be permitted in Initial and Handshake. This is only about application-level error codes.
Ah I see. I agree that application errors should not happen at that level.
So with improved understanding, I think the correct approach is for send a PROTOCOL_VIOLATION the other direction, but since that is kind of pointless, all you can do it is to report a protocol violation the client. It would be wrong to forward the error code because that would promote bad behaviour and assumptions on application level design that might not hold in general.
NAME For the first bullet, that's a decision for the application protocols. For the second, I'd argue you don't need any special API. If the app terminates the connection before the "handshake complete" notification then any error code it would pass down to the QUIC API would not be sent in a 1-RTT packet. That state is enough for the app to make an intelligent decision. Another option is to have an API flag that indicate the application close is allowed to be send unencrypted. If you assume this is not the common case, then I don't think we need optimize for it. The app just closes the connection after the handshake completes.
NAME At the very least, the transport draft needs to suggest that, otherwise an application protocol might leak information through APPLICATIONCLOSE frames carried in Initial packets. Requiring such interaction seems more complicated than just forbidding the use of APPLICATIONCLOSE in Initial and Handshake packets in favor of CONNECTIONCLOSE(usercanceled). How a QUIC stack enforces that is an implementation issue, but for example, when an application instructs the QUIC stack to close the connection, the stack can decide which of the two frames to send based on the current state. I'd dispute that this is an optimization. This is about addressing a security concern that we have so far left open. PS. I agree that apps willing to postpone the closing of a connection can do so, please see the PR.
Maybe we need to add an API recommendation (not requirement) that says that "an application could be allowed to close a connection during handshake using a transport connection close frame". This is similar to my earlier suggestion that an application could be allowed to reject incoming connections because the server is busy or whatever - this suggestion was not accepted as a requirement because it isn't necessary, but it is still a good thing to support. The question is then, how is the connection taken down - i.e. silently or with a transport close?
NAME Ok. You've convinced me that it is just easier (and probably safer) to restrict application close to 1-RTT. Though, I'd like to point out, there's nothing preventing an implementation from doing it anyways.
I agree with that observation. I think the specification does not clarify what should be done when a CONNECTIONCLOSE frame is invalid. For example, we do not define how an endpoint should react when it receives a CONNECTIONCLOSE frame with a Reason that goes beyond the end of the packet payload. I think there are two logical ways of handing the situation: a) An endpoint that receives an invalid CONNECTIONCLOSE frame acts as if it received a valid CONNECTIONCLOSE frame. b) An endpoint that receives an invalid CONNECTIONCLOSE frame responds with a CONNECTIONCLOSE frame carrying an appropriate error code. We can mandate either a or b, or leave it up to the implementors (saying nothing in the text). Leaving it unspecified is a valid option here because the connection would promptly close regardless. Anyways, I think the problem deserves a separate issue, if some of us are interested in mandating a specific behavior. Personally, I do not care.
To NAME point b) Transport section 11.1 An endpoint that receives an invalid CONNECTION_CLOSE frame MUST NOT signal the existence of the error to its peer.
Clients don't send GOAWAY and when a client sends one, the server treats it as HTTPUNEXPECTEDFRAME. By contrast, servers don't send MAXPUSHID but the client treats receiving one as HTTPMALFORMEDFRAME. By contrast, if GOAWAY is sent on !control it's HTTPUNEXPECTEDFRAME, but if MAXPUSHID is sent on !control, it's HTTPWRONGSTREAM. I think the answers here are HTTPUNEXPECTEDFRAME and HTTPWRONGSTREAM respectively, but we should be consistent.
I think you're correct. There are some situations where newer errors would be more appropriate.

PADDING and PING frames MAY appear in packets of any encryption level.  <ins> CRYPTO frames and CONNECTION_CLOSE frames signaling errors at the QUIC layer (type 0x1c) MAY appear in packets of any encryption level except 0-RTT. CONNECTION_CLOSE frames signaling application errors (type 0x1d) MUST only be sent in packets at the 1-RTT encryption level. </ins> ACK frames MAY appear in packets of any encryption level other than 0-RTT, but can only acknowledge packets which appeared in beyond the Error Code.  This SHOULD be a UTF-8 encoded string RFC3629. <ins> The application-specific variant of CONNECTION_CLOSE (type 0x1d) can only be sent using an 1-RTT packet (QUIC-TLS, Section 4).  When an application wishes to abandon a connection during the handshake, an endpoint can send a CONNECTION_CLOSE frame (type 0x1c) with an error code of 0x15a ("user_canceled" alert; see TLS13) in an Initial or a Handshake packet. </ins> 19.20. QUIC frames do not use a self-describing encoding.  An endpoint


them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such bursts to the initial congestion window, which is recommended to be <del> the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize, 14720)). </del>  As an example of a well-known and publicly available implementation of a flow pacer, implementers are referred to the Fair Queue packet

Clarifies that this is the maximum datagram size currently in use on the connection.
kMaxDatagramSize is currently set to the minimum packet size of 1200 bytes. It should be set instead to the max packet size used by the connection, which is discussed in Section 14.1 of the transport draft. (Issue raised by Timo Völker on the mailing list.)
My reading is that this value is the actual max packet size used in the connection, it's just not clear from the explanation. kInitialWindow and kMinimumWindow are also per-connection fields defined directly below. URL There is one potential detail, which is if the MTU increases after the handshake, do the min CWND and Reno behavior change accordingly? I think it's simpler to reason about them not changing, but I can see both arguments and in the end I don't think it'll matter that much.
WinQuic uses the currently calculated path MTU instead a constant kMaxDatagramSize.

them creates a packet burst that might cause short-term congestion and losses.  Implementations MUST either use pacing or limit such bursts to the initial congestion window, which is recommended to be  <ins> the minimum of 10 * max_datagram_size and max(2* max_datagram_size, 14720)), where max_datagram_size is the current maximum size of a datagram for the connection, not including UDP or IP overhead. </ins> As an example of a well-known and publicly available implementation of a flow pacer, implementers are referred to the Fair Queue packet


22.  22.1. <del> IANA [SHALL add/has added] a registry for "QUIC Transport Parameters" under a "QUIC Protocol" heading. </del>  <del> The "QUIC Transport Parameters" registry governs a 16-bit space. This space is split into two spaces that are governed by different policies.  Values with the first byte in the range 0x00 to 0xfe (in hexadecimal) are assigned via the Specification Required policy RFC8126.  Values with the first byte 0xff are reserved for Private Use RFC8126. </del>  <del> Registrations MUST include the following fields: </del>  <del> The numeric value of the assignment (registrations will be between 0x0000 and 0xfeff). </del>  <del> A short mnemonic for the parameter. </del>  A reference to a publicly available specification for the value. <del> The nominated expert(s) verify that a specification exists and is readily accessible.  Expert(s) are encouraged to be biased towards approving registrations unless they are abusive, frivolous, or actively harmful (not merely aesthetically displeasing, or architecturally dubious). </del>  The initial contents of this registry are shown in iana-tp-table. Additionally, each value of the format "31 * N + 27" for integer <del> values of N (that is, "27", "58", "89", ...) MUST NOT be assigned by IANA. </del>  <del> 22.2. </del>  IANA [SHALL add/has added] a registry for "QUIC Frame Types" under a <del> "QUIC Protocol" heading. </del>  <del> The "QUIC Frame Types" registry governs a 62-bit space.  This space is split into three spaces that are governed by different policies. Values between 0x00 and 0x3f (in hexadecimal) are assigned via the Standards Action or IESG Review policies RFC8126.  Values from 0x40 to 0x3fff operate on the Specification Required policy RFC8126.  All other values are assigned to Private Use RFC8126. </del>  <del> Registrations MUST include the following fields: The numeric value of the assignment (registrations will be between 0x00 and 0x3fff).  A range of values MAY be assigned. </del>  A short mnemonic for the frame type. <del> A reference to a publicly available specification for the value. The nominated expert(s) verify that a specification exists and is readily accessible.  Specifications for new registrations need to describe the means by which an endpoint might determine that it can send the identified type of frame.  An accompanying transport parameter registration (see iana-transport-parameters) is expected for most registrations.  The specification needs to describe the </del>  format and assigned semantics of any fields in the frame. <del> Expert(s) are encouraged to be biased towards approving registrations unless they are abusive, frivolous, or actively harmful (not merely aesthetically displeasing, or architecturally dubious). </del> The initial contents of this registry are tabulated in frame-types. <del> 22.3. </del>  IANA [SHALL add/has added] a registry for "QUIC Transport Error <del> Codes" under a "QUIC Protocol" heading. </del>  The "QUIC Transport Error Codes" registry governs a 62-bit space. This space is split into three spaces that are governed by different <del> policies.  Values between 0x00 and 0x3f (in hexadecimal) are assigned via the Standards Action or IESG Review policies RFC8126.  Values from 0x40 to 0x3fff operate on the Specification Required policy RFC8126.  All other values are assigned to Private Use RFC8126. Registrations MUST include the following fields: </del>  <del> The numeric value of the assignment (registrations will be between 0x0000 and 0x3fff). </del>  A short mnemonic for the parameter. A brief description of the error code semantics, which MAY be a summary if a specification reference is provided. <del> A reference to a publicly available specification for the value. The nominated expert(s) verify that a specification exists and is readily accessible.  Expert(s) are encouraged to be biased towards approving registrations unless they are abusive, frivolous, or actively harmful (not merely aesthetically displeasing, or architecturally dubious). </del> The initial contents of this registry are shown in iana-error-table. 11.  11.1. This document creates a new registration for the identification of 11.2.  This document establishes a registry for HTTP/3 frame type codes. <del> The "HTTP/3 Frame Type" registry governs a 62-bit space.  This space is split into three spaces that are governed by different policies. Values between "0x00" and "0x3f" (in hexadecimal) are assigned via the Standards Action or IESG Review policies RFC8126.  Values from "0x40" to "0x3fff" operate on the Specification Required policy RFC8126.  All other values are assigned to Private Use RFC8126. </del>  While this registry is separate from the "HTTP/2 Frame Type" registry defined in HTTP2, it is preferable that the assignments parallel each one registry, every effort SHOULD be made to avoid assigning the corresponding value to an unrelated operation. <del> New entries in this registry require the following information: </del>  A name or label for the frame type. <del> The 62-bit code assigned to the frame type. </del>  <del> A reference to a specification that includes a description of the frame layout and its semantics, including any parts of the frame that are conditionally present. The entries in the following table are registered by this document. </del>  Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. <del> 11.3. </del>  This document establishes a registry for HTTP/3 settings.  The <del> "HTTP/3 Settings" registry governs a 62-bit space.  This space is split into three spaces that are governed by different policies. Values between "0x00" and "0x3f" (in hexadecimal) are assigned via the Standards Action or IESG Review policies RFC8126.  Values from "0x40" to "0x3fff" operate on the Specification Required policy RFC8126.  All other values are assigned to Private Use RFC8126.  The designated experts are the same as those for the "HTTP/2 Settings" registry defined in HTTP2. </del>  While this registry is separate from the "HTTP/2 Settings" registry defined in HTTP2, it is preferable that the assignments parallel each SHOULD be made to avoid assigning the corresponding value to an unrelated operation. <del> New registrations are advised to provide the following information: </del>  A symbolic name for the setting.  Specifying a setting name is optional. <del> The 62-bit code assigned to the setting. </del>  <del> An optional reference to a specification that describes the use of the setting. The value of the setting unless otherwise indicated.  SHOULD be the most restrictive possible value. The entries in the following table are registered by this document. </del>  Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA. <del> 11.4. </del>  This document establishes a registry for HTTP/3 error codes.  The <del> "HTTP/3 Error Code" registry manages a 62-bit space.  The "HTTP/3 Error Code" registry operates under the "Expert Review" policy RFC8126. </del>  Registrations for error codes are required to include a description of the error code.  An expert reviewer is advised to examine new registrations for possible duplication with existing error codes. Use of existing registrations is to be encouraged, but not mandated. <del> New registrations are advised to provide the following information: </del>  A name for the error code.  Specifying an error code name is optional. <del> The 62-bit error code value. A brief description of the error code semantics, longer if no detailed specification is provided. </del>  <del> An optional reference for a specification that defines the error code. The entries in the following table are registered by this document. </del>  <del> 11.5. </del>  This document establishes a registry for HTTP/3 unidirectional stream types.  The "HTTP/3 Stream Type" registry governs a 62-bit space. <del> This space is split into three spaces that are governed by different policies.  Values between "0x00" and 0x3f (in hexadecimal) are assigned via the Standards Action or IESG Review policies RFC8126. Values from "0x40" to "0x3fff" operate on the Specification Required policy RFC8126.  All other values are assigned to Private Use RFC8126. </del>  <del> New entries in this registry require the following information: </del>  A name or label for the stream type. <del> The 62-bit code assigned to the stream type. A reference to a specification that includes a description of the stream type, including the layout semantics of its payload. </del> Which endpoint on a connection may initiate a stream of this type. Values are "Client", "Server", or "Both".  The entries in the following table are registered by this document. Additionally, each code of the format "0x1f * N + 0x21" for integer

This overhauls the system for IANA registries to use a unified scheme that allows provisional registration. This seems pretty complicated in terms of nailing down all the corner cases, but it is fairly simple in practice: Provisional registration is easy, it only requires that the requester provide contact information and (ideally) the codepoint they want. They could provide more, but at their discretion. Permanent registration requires that you fill out the fields. Experts are required for both, but only really to prevent spam. We have a few more requirements for permanent registrations of frame types, but that is more for the purposes of advice, because sending an new frame leads to protocol errors if you haven't agreed to that in the past. I've sketched out a strawman for a codepoint reclamation process. That advises that experts try to find some use of the codepoint. There is a date on registrations that can guide the selection of codepoints to reclaim, but these can be updated any time by anyone who wants to keep the registration "live". I wanted to sketch this out for transport first, but I intend to update this PR with changes to the HTTP draft if these policies are agreeable.
Could contact information be replaced with a domain name. There is much abuse of contact information and domain names can have private contact information? Also, maintaining an email address is harder over time. I realize the field contact field doesn't say email, but that is sort of implied.
You can specify this so that IANA collects the information and thus can follow up if needed, but where the registry does not display this information. I understand that the authors of RFC 8126 are working on a bis that will make this much more common, if not the default. You can also split the contact information from the change controller, if you want to have, say Joe be the contact but Example Corp be the change controller. There's also a presumption that if the change controller is gone that the change controller for the entire registry (usually the IESG) can make a determination of what to do in the case that a change is needed. For many registries this amounts to "do nothing" since there is no scarcity of code points. In the case of scarcity, that's how you get re-use when the change controllers are gone. Ted
I did that intentionally, mostly just to avoid the wordy reference. I'm happy to defer to you on that. (Julian can say "told you so" again if he likes :)
We have nice registration policies for everything, but that doesn't serve for experimentation very well, because those experiments can clobber each other. See also RFC 6648. The proposal here is to allow for permanent registrations (under the same rules we have now), but to allow FCFS provisional registrations so that we avoid collisions when people start experiments that could be widely deployed. We should also encourage people to choose random values rather than sequential ones.
Does resolve this?
As of , transport parameter identifiers are 16bit integers, with a registry where uses the is reserved for experimentation While keeping Specification Required makes sense for a good chunk of the registry space, I think there will be many experiments that are conducted before a full specification is written (some already exist today and I expect there to be many many more once the protocol is standardized). However, those experiments only have 256 values to play with, and that is bound to cause collisions and headaches down the road. I think the simplest solution to this problem is to use variable length integers for transport parameter identifiers. The TLS presentation language doesn't support them but since we already use VLIs for the values of several transport parameters we're no longer bound by the TLS presentation language. I think there was also support for doing this when it was discussed on , but that issue was closed when the values were changed to VLI with , without changing the identifiers. I'm happy to write the PR if this issue gathers support.
You aren't the first to suggest this one. Let's make sure we at least discuss this directly. We did discuss this in the context of the issues that you cite and decided not to, but that was never the central question. From our perspective, this isn't a significant change to code.
The same for us, too. Am I understanding correctly that the concern here is that extensions of TLS structures tend to use uint16_t as their type identifiers, and that the reusable parser might be constrained to that design pattern?
I thought that this might be the case originally, but it turns out that the blob for transport parameters is generated by QUIC code in mostly all of the cases I have seen. If there is someone out there who is relying on passing a TLS stack a structured grammar and letting the TLS stack perform serialization, then we might want to just leave this alone.
Thank you for the clarification. We do use the TLS stack to encode / decode the transport parameters, therefore we do want see the TLS grammar-based design being preserved. The reason we do not mind the extension type being a varint is because our codec is flexible enough to handle that. URL
We should definitely do something to increase the number of experimentation codepoints from 256. Changing to a varint sounds good. If not, then we should allocate more of the space(ie: [0xf000 - 0xffff]) to experiments.
I agree with NAME and I don't think we need to go varint here, that seems like a bit of an overkill. How about reserving 4096 codepoints for spec required, and leaving the rest (2^16 - 2^12 = 61440) for experimentation: [0x0000 - 0x0fff] uses the RFC8128 Specification Required policy [0x1000 - 0xffff] is reserved for experimentation
Apart from the fact that we want to limit changes at this stage, are there arguments against going varint here? It feels pretty odd that many transport parameters are TLVs where T and L are 16bit and V is varint.
I don't have much of an argument here besides the general principle that we shouldn't provide more flexibility than is necessary. I don't think it's odd that T is fixed-length while the V is varint, FWIW. If no implementations are bothered by the change to varint, then it's a bit of a bikeshed. Let's see if other implementers are bothered.
Split in two ? what the same size ? Don't forget there is also GREASE TP now
From looking at all the integer fields in QUICv1, it looks like at this point everything is a varint except the versions, packet numbers, connection ID lengths (which all have valid reasons for their lengths), and the transport parameter identifier and transport parameter lengths. Switching transport parameters to QUIC format (as opposed to TLS presentation language) feels fitting to me, saves bytes on the wire, and will facilitate innovation down the road.
I'm happy to make transport parameter identifier a varint. NAME Are you(implicitly) suggesting that transport parameter lengths should be varint as well?
I think so, yes. If we're changing implementations might as well make both changes at once (assuming no one wants one of them to be varint but not the other).
I'd be opposed to changing the transport parameter lengths to varints, as that means departure from the TLS notation that we use for defining TPs. It's very different from changing the IDs to varints, which is just changing the type of a particular variable. IIRC, we discussed if we should switch to a different notation, and decided to go with the TLS-based design. At least I have built (or maintained) code based on that.
I agree with Kazuho here: splitting it in half would make plenty of room
I'm in favor of the change that NAME is suggesting in . There's no reason for us to use TLS presentation language, if anything, it just makes the spec harder to read for people who are unfamiliar with the TLS presentation language (if I remember correctly, this came up multiple times on issues here and / or on Slack).
Remember the experience with the X-Options in SMTP or HTML? Do we really want to replicate that?
Discussed in Cupertino. NAME to open a new Editorial issue to only replace the TLS syntax with something easier to understand. NAME to also do a Design PR to shuffle the assigned ranges in the registry.
As discussed in Cupertino, I have closed previous PR and replaced it with: editorial-only PR IANA policy PR
I think that the RFC 6648 lessons need to be considered carefully here. I think that it would be better to use a combination of random selection and provisional registration as a means of handling experiments. Random selection means that we end up colliding with very low probability; provisional registration ensures that registrations are protected. Making the private use space larger does neither. I would prefer to instead remove the private use space completely.
In lots of places, you reference {{iana-policy}} for things that aren't actually described there -- it just contains a pointer to the QUIC spec for the policy. It might be better to point directly to the QUIC spec in those places. (Though given that the section number in QUIC could potentially change, it's also a reasonable argument that we want to have one place to update.) Just want to make sure that's intentional, rather than a copy-paste of the policy from the QUIC registries.

22. <ins> This document establishes several registries for the management of codepoints in QUIC.  These registries operate on a common set of policies as defined in iana-policy. </ins> 22.1.  <ins> All QUIC registries allow for both provisional and permanent registration of codepoints.  This section documents policies that are common to these registries. </ins>  <ins> 22.1.1. </ins>  <ins> Provisional registration of codepoints are intended to allow for private use and experimentation with extensions to QUIC.  Provisional registrations only require the inclusion of the codepoint value and contact information.  However, provisional registrations could be reclaimed and reassigned for another purpose. </ins>  <ins> Provisional registrations require Expert Review, as defined in Section 4.5 of RFC8126.  Designated expert(s) are advised that only registrations for an excessive proportion of remaining codepoint space or the very first unassigned value (see iana-random) can be rejected. </ins>  <ins> Provisional registrations will include a date field that indicates when the registration was last updated.  A request to update the date on any provisional registration can be made without review from the designated expert(s). All QUIC registries include the following fields to support provisional registration: The assigned codepoint. "Permanent" or "Provisional". </ins> A reference to a publicly available specification for the value.  <ins> The date of last update to the registration. Contact details for the registrant. Supplementary notes about the registration. Provisional registrations MAY omit the Specification and Notes fields, plus any additional fields that might be required for a permanent registration.  The Date field is not required as part of requesting a registration as it is set to the date the registration is created or updated. 22.1.2. New uses of codepoints from QUIC registries SHOULD use a randomly selected codepoint that excludes both existing allocations and the first unallocated codepoint in the selected space.  Requests for multiple codepoints MAY use a contiguous range.  This minimizes the risk that differing semantics are attributed to the same codepoint by different implementations.  Use of the first codepoint in a range is intended for use by specifications that are developed through the standards process STD and its allocation MUST be negotiated with IANA before use. For codepoints that are encoded in variable-length integers (integer- encoding), such as frame types, codepoints that encode to four or eight bytes (that is, values 2^14 and above) SHOULD be used unless the usage is especially sensitive to having a longer encoding. Applications to register codepoints in QUIC registries MAY include a codepoint as part of the registration.  IANA MUST allocate the selected codepoint unless that codepoint is already assigned or the codepoint is the first unallocated codepoint in the registry. 22.1.3. A request might be made to remove an unused provisional registration from the registry to reclaim space in a registry, or portion of the registry (such as the 64-16383 range for codepoints that use variable-length encodings).  This SHOULD be done only for the codepoints with the earliest recorded date and entries that have been updated less than a year prior SHOULD NOT be reclaimed. A request to remove a codepoint MUST be reviewed by the designated expert(s).  The expert(s) MUST attempt to determine whether the codepoint is still in use.  Experts are advised to contact the listed contacts for the registration, plus as wide a set of protocol implementers as possible in order to determine whether any use of the codepoint is known.  The expert(s) are advised to allow at least four weeks for responses. If any use of the codepoints is identified by this search or a request to update the registration is made, the codepoint MUST NOT be reclaimed.  Instead, the date on the registration is updated.  A note might be added for the registration recording relevant information that was learned. If no use of the codepoint was identified and no request was made to update the registration, the codepoint MAY be removed from the registry. This process also applies to requests to change a provisional registration into a permanent registration, except that the goal is not to determine whether there is no use of the codepoint, but to determine that the registration is an accurate representation of any deployed usage. 22.1.4. Permanent registrations in QUIC registries use the Specification Required policy RFC8126, unless otherwise specified.  The designated expert(s) verify that a specification exists and is readily accessible.  Expert(s) are encouraged to be biased towards approving registrations unless they are abusive, frivolous, or actively harmful (not merely aesthetically displeasing, or architecturally dubious). The creation of a registry MAY specify additional constraints on permanent registrations. The creation of a registries MAY identify a range of codepoints where registrations are governed by a different registration policy.  For instance, the registries for 62-bit codepoints in this document have stricter policies for codepoints in the range from 0 to 63. Any stricter requirements for permanent registrations do not prevent provisional registrations for affected codepoints.  For instance, a provisional registration for a frame type iana-frames of 61 could be requested. All registrations made by Standards Track publications MUST be permanent. All registrations in this document are assigned a permanent status and list as contact both the IESG (ietf@ietf.org) and the QUIC working group (quic@ietf.org). 22.2. IANA [SHALL add/has added] a registry for "QUIC Transport Parameters" under a "QUIC" heading. The "QUIC Transport Parameters" registry governs a 16-bit space. This registry follows the registration policy from iana-policy. Permanent registrations in this registry are assigned using the Specification Required policy RFC8126. In addition to the fields in iana-provisional, permanent registrations in this registry MUST include the following fields: A short mnemonic for the parameter. </ins> The initial contents of this registry are shown in iana-tp-table. Additionally, each value of the format "31 * N + 27" for integer  <ins> values of N (that is, "27", "58", "89", ...) are reserved and MUST NOT be assigned by IANA. </ins>  <ins> 22.3. </ins> IANA [SHALL add/has added] a registry for "QUIC Frame Types" under a  <ins> "QUIC" heading. </ins>  <ins> The "QUIC Frame Types" registry governs a 62-bit space.  This registry follows the registration policy from iana-policy.  Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins>  <ins> In addition to the fields in iana-provisional, permanent registrations in this registry MUST include the following fields: </ins> A short mnemonic for the frame type.  <ins> In addition to the advice in iana-policy, specifications for new permanent registrations SHOULD describe the means by which an endpoint might determine that it can send the identified type of frame.  An accompanying transport parameter registration (see iana- transport-parameters) is expected for most registrations. Specifications for permanent registrations also needs to describe the </ins> format and assigned semantics of any fields in the frame.  The initial contents of this registry are tabulated in frame-types.  <ins> 22.4. </ins> IANA [SHALL add/has added] a registry for "QUIC Transport Error  <ins> Codes" under a "QUIC" heading. </ins> The "QUIC Transport Error Codes" registry governs a 62-bit space. This space is split into three spaces that are governed by different  <ins> policies.  Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins>  <ins> In addition to the fields in iana-provisional, permanent registrations in this registry MUST include the following fields: </ins> A short mnemonic for the parameter. A brief description of the error code semantics, which MAY be a summary if a specification reference is provided.  The initial contents of this registry are shown in iana-error-table. 11. <ins> This document registers a new ALPN protocol ID (iana-alpn) and creates new registries that manage the assignment of codepoints in HTTP/3. </ins> 11.1. This document creates a new registration for the identification of 11.2. <ins> New registries created in this document operate under the QUIC registration policy documented in Section 22.1 of QUIC-TRANSPORT. These registries all include the common set of fields listed in Section 22.1.1 of QUIC-TRANSPORT. The initial allocations in these registries created in this document are all assigned permanent status and list as contact both the IESG (iesg@ietf.org) and the HTTP working group (ietf-http-wg@w3.org). 11.2.1. </ins> This document establishes a registry for HTTP/3 frame type codes.  <ins> The "HTTP/3 Frame Type" registry governs a 62-bit space.  This registry follows the QUIC registry policy; see iana-policy. Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins> While this registry is separate from the "HTTP/2 Frame Type" registry defined in HTTP2, it is preferable that the assignments parallel each one registry, every effort SHOULD be made to avoid assigning the corresponding value to an unrelated operation.  <ins> In addition to common fields as described in iana-policy, permanent registrations in this registry MUST include the following field: </ins> A name or label for the frame type.  <ins> Specifications of frame types MUST include a description of the frame layout and its semantics, including any parts of the frame that are conditionally present. </ins>  <ins> The entries in iana-frame-table are registered by this document. </ins> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA.  <ins> 11.2.2. </ins> This document establishes a registry for HTTP/3 settings.  The  <ins> "HTTP/3 Settings" registry governs a 62-bit space.  This registry follows the QUIC registry policy; see iana-policy.  Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins> While this registry is separate from the "HTTP/2 Settings" registry defined in HTTP2, it is preferable that the assignments parallel each SHOULD be made to avoid assigning the corresponding value to an unrelated operation.  <ins> In addition to common fields as described in iana-policy, permanent registrations in this registry MUST include the following fields: </ins> A symbolic name for the setting.  Specifying a setting name is optional.  <ins> The value of the setting unless otherwise indicated.  A default SHOULD be the most restrictive possible value. </ins>  <ins> The entries in iana-setting-table are registered by this document. </ins> Additionally, each code of the format "0x1f * N + 0x21" for integer values of N (that is, "0x21", "0x40", ..., through "0x3FFFFFFFFFFFFFFE") MUST NOT be assigned by IANA.  <ins> 11.2.3. </ins> This document establishes a registry for HTTP/3 error codes.  The  <ins> "HTTP/3 Error Code" registry manages a 62-bit space.  This registry follows the QUIC registry policy; see iana-policy.  Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins> Registrations for error codes are required to include a description of the error code.  An expert reviewer is advised to examine new registrations for possible duplication with existing error codes. Use of existing registrations is to be encouraged, but not mandated.  <ins> In addition to common fields as described in iana-policy, permanent registrations in this registry MUST include the following fields: </ins> A name for the error code.  Specifying an error code name is optional.  <ins> A brief description of the error code semantics. </ins>  <ins> The entries in the iana-error-table are registered by this document. </ins>  <ins> 11.2.4. </ins> This document establishes a registry for HTTP/3 unidirectional stream types.  The "HTTP/3 Stream Type" registry governs a 62-bit space.  <ins> This registry follows the QUIC registry policy; see iana-policy. Permanent registrations in this registry are assigned using the Specification Required policy RFC8126, except for values between 0x00 and 0x3f (in hexadecimal; inclusive), which are assigned using Standards Action or IESG Approval as defined in Section 4.9 and 4.10 of RFC8126. </ins>  <ins> In addition to common fields as described in iana-policy, permanent registrations in this registry MUST include the following fields: </ins> A name or label for the stream type.  Which endpoint on a connection may initiate a stream of this type. Values are "Client", "Server", or "Both". <ins> Specifications for permanent registrations MUST include a description of the stream type, including the layout semantics of the stream contents. </ins> The entries in the following table are registered by this document. Additionally, each code of the format "0x1f * N + 0x21" for integer


2.1.2. <del> A dynamic table entry is considered blocking and cannot be evicted until its insertion has been acknowledged and there are no outstanding unacknowledged references to the entry.  In particular, a dynamic table entry that has never been referenced can still be blocking. An encoder MUST NOT insert an entry into the dynamic table (or duplicate an existing entry) if doing so would evict a blocking entry.  In order to avoid this, an encoder that uses the dynamic table has to keep track of blocking entries. A blocking entry is unrelated to a blocked stream, see blocked- streams. </del>  2.1.2.1. The Header Acknowledgement and Stream Cancellation instructions permit the encoder to remove references to entries in the dynamic table.  When an entry with absolute index lower than the Known <del> Received Count has zero references, then it is no longer considered blocking (see blocked-insertion). </del>  2.2.2.3. Before a new entry is added to the dynamic table, entries are evicted from the end of the dynamic table until the size of the dynamic table is less than or equal to (table capacity - size of new entry).  The <del> encoder MUST NOT cause a blocking dynamic table entry to be evicted (see blocked-insertion).  The new entry is then added to the table. It is an error if the encoder attempts to add an entry that is larger than the dynamic table capacity; the decoder MUST treat this as a connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR". </del>  A new entry can reference an entry in the dynamic table that will be evicted when adding this new entry into the dynamic table. connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR". Reducing the dynamic table capacity can cause entries to be evicted <del> (see eviction).  This MUST NOT cause the eviction of blocking entries (see blocked-insertion).  Changing the capacity of the dynamic table is not acknowledged as this instruction does not insert an entry. </del>  4.3.2.

Acting on NAME suggestion.
Thank you, this greatly improves clarity.
Technically, all reviews request rather than require. Those are good suggestions, though.
Incorporated, though the parenthetical reads even more awkwardly now. Suggestions on improving that (or consensus to drop it) are welcome.
This review suggests changes, not "requires" them.

2.1.2.  <ins> Inserting entries into the dynamic table might not be possible if the table contains entries which cannot be evicted. A dynamic table entry cannot be evicted immediately after insertion, even if it has never been referenced.  Once the insertion of a dynamic table entry has been acknowledged and there are no outstanding unacknowledged references to the entry, the entry becomes evictable. If the dynamic table does not contain enough room for a new entry without evicting other entries, and the entries which would be evicted are not evictable, the encoder MUST NOT insert that entry into the dynamic table (including duplicates of existing entries). In order to avoid this, an encoder that uses the dynamic table has to keep track of whether each entry is currently evictable or not. </ins> 2.1.2.1. The Header Acknowledgement and Stream Cancellation instructions permit the encoder to remove references to entries in the dynamic table.  When an entry with absolute index lower than the Known  <ins> Received Count has zero references, then it is considered evictable (see blocked-insertion). </ins> 2.2.2.3. Before a new entry is added to the dynamic table, entries are evicted from the end of the dynamic table until the size of the dynamic table is less than or equal to (table capacity - size of new entry).  The  <ins> encoder MUST NOT cause a dynamic table entry to be evicted unless that entry is evictable (see blocked-insertion).  The new entry is then added to the table.  It is an error if the encoder attempts to add an entry that is larger than the dynamic table capacity; the decoder MUST treat this as a connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR". </ins> A new entry can reference an entry in the dynamic table that will be evicted when adding this new entry into the dynamic table. connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR". Reducing the dynamic table capacity can cause entries to be evicted  <ins> (see eviction).  This MUST NOT cause the eviction of entries which are not evictable (see blocked-insertion).  Changing the capacity of the dynamic table is not acknowledged as this instruction does not insert an entry. </ins> 4.3.2.


An indexed header field representation identifies an entry in the static table, or an entry in the dynamic table with an absolute index <del> less than the Base. </del>  This representation starts with the '1' 1-bit pattern, followed by the 'T' bit indicating whether the reference is into the static or An indexed header field with post-base index representation identifies an entry in the dynamic table with an absolute index <del> greater than or equal to the Base. </del>  This representation starts with the '0001' 4-bit pattern.  This is followed by the post-base index (post-base) of the matching header A literal header field with name reference representation encodes a header field where the header field name matches the header field name of an entry in the static table, or the header field name of an <del> entry in the dynamic table with an absolute index less than the Base. </del>  This representation starts with the '01' two-bit pattern.  The following bit, 'N', indicates whether an intermediary is permitted to A literal header field with post-base name reference representation encodes a header field where the header field name matches the header field name of a dynamic table entry with an absolute index greater <del> than or equal to the Base. </del>  This representation starts with the '0000' four-bit pattern.  The fifth bit is the 'N' bit as described in literal-name-reference.

This change has been suggested by afrind at URL on the basis that the Base is a count, and comparing an index to a count feels awkward.

An indexed header field representation identifies an entry in the static table, or an entry in the dynamic table with an absolute index  <ins> less than the value of the Base. </ins> This representation starts with the '1' 1-bit pattern, followed by the 'T' bit indicating whether the reference is into the static or An indexed header field with post-base index representation identifies an entry in the dynamic table with an absolute index  <ins> greater than or equal to the value of the Base. </ins> This representation starts with the '0001' 4-bit pattern.  This is followed by the post-base index (post-base) of the matching header A literal header field with name reference representation encodes a header field where the header field name matches the header field name of an entry in the static table, or the header field name of an  <ins> entry in the dynamic table with an absolute index less than the value of the Base. </ins> This representation starts with the '01' two-bit pattern.  The following bit, 'N', indicates whether an intermediary is permitted to A literal header field with post-base name reference representation encodes a header field where the header field name matches the header field name of a dynamic table entry with an absolute index greater  <ins> than or equal to the value of the Base. </ins> This representation starts with the '0000' four-bit pattern.  The fifth bit is the 'N' bit as described in literal-name-reference.


Either the client or server of the connection. The smallest unit of communication on a stream in HTTP/3, <del> consisting of a header and a variable-length sequence of octets </del>  structured according to the frame type.  Protocol elements called "frames" exist in both this document and QUIC-TRANSPORT.  Where frames from QUIC-TRANSPORT are referenced, the frame name will be A variable-length integer that identifies the frame type. <del> A variable-length integer that describes the length of the Frame Payload. </del>  A payload, the semantics of which are determined by the Type field.

Probably a bit overkill, but since it wasn't explicitly stated + I thought we had replaced "octets" with bytes everywhere else.

Either the client or server of the connection. The smallest unit of communication on a stream in HTTP/3,  <ins> consisting of a header and a variable-length sequence of bytes </ins> structured according to the frame type.  Protocol elements called "frames" exist in both this document and QUIC-TRANSPORT.  Where frames from QUIC-TRANSPORT are referenced, the frame name will be A variable-length integer that identifies the frame type.  <ins> A variable-length integer that describes the length in bytes of the Frame Payload. </ins> A payload, the semantics of which are determined by the Type field.


The largest offset delivered on a stream - the sum of the offset and data length - cannot exceed 2^62-1.  Receipt of a frame that exceeds this limit MUST be treated as a connection error of type <del> FRAME_ENCODING_ERROR. </del>  Unlike STREAM frames, which include a Stream ID indicating to which stream the data belongs, the CRYPTO frame carries data for a single

As NAME pointed out in URL, I missed that there's a CRYPTOBUFFEREXCEEDED that would equally valid to send when a CRYPTO frame exceeds the 2^62-1 limit.
I can see how this can simplify some decoding logic, but I am not sure we should consider such a value valid in the first place. If the value is invalid it is meaningless to discuss length and then there is only a frame error left. Otherwise we could probably revisit a gazillion other places where this principle could also apply.
NAME yes this is largely what I meant. The PR introduces a new principle.
NAME : I'm confused too. For consistency, I would keep it at FRAMEENCODINGERROR, since that's what we do for the flow control error too.
NAME NAME I am with NAME Let me explain why. There are two reasons we decided to allow use of FLOWCONTROLERROR for STREAM frames: The overflow can be detected by the flow control logic. Then, there is not need to have a logic to detect the error in the frame decoder. The flow control logic might be capable of returning only one error. FLOWCONTROLERROR is more specific than FRAMEENCODINGERROR. These reasons equally hold for CRYPTO streams sending CRYPTOBUFFEREXCEEDED, as CRYPTOBUFFEREXCEEDED is the error code used to indicate flow control error with CRYPTO streams. To paraphrase this PR applies the principles that we agreed for STREAM frame to CRYPTO frames.
Thanks for clarifying, NAME This LGTM.
From the original issue, the proposed principle was: "If you can detect an error while parsing the frame, and without consulting any connection state, it should be a FRAMEENCODINGERROR." It seems clear you can do that in this case, but maybe we changed the principle?
NAME That would also apply to the STREAM frame then. I'd be fine just using the FRAMEENCODINGERROR in all these cases, but people pushed back against that.
NAME Yeah I think I should have said that the exceptional rule within the principles. Specifically, I mean the discussion starting from URL, that talks if we should allow FLOWCONTROLERROR and why.
NAME I thought that might have been the relevant discussion. In general, I'd prefer to have principles decided on issues, but I understand these things happen. I don't think this is the end of the world, but I prefer the original principle because I think it's easy to reason about. If we've decided against that principle, I'd suggest we state a new principle.
NAME I don't think we ever actually discussed this in the working group. If I remember correctly, using two error codes was a suggestion that came up on my original PR, and then the editors decided in Cupertino that I should update the PR accordingly. Actually, I'd prefer to take the principled approach, and just use FRAMEENCODINGERROR wherever possible.
NAME I think we did discuss at the interim. URL
To be precise, we discussed that two error codes were OK at the interim, then declared that as a consensus in the call started on Oct 22 URL I do not think we should be revisiting the discussion.
I think we should either: 1) Espouse a new principle that fits the existing text and this PR and use that going forward 2) Stick with the original principle and remove the OR FLOWCONTROLERROR from the text. If we don't have a principle that matches the text, we're prone to having this discussion a few more times.
NAME kindly shared our principles, and this PR aligns with that. URL
Chairs and editors, I think we agree that this is an amendment to that has been shipped as part of -24. Does that mean that this would be merged as an editorial correction? Or if not, do we need an issue?
I think we can merge it because it agrees with the stated principles. But its NAME call
Let's open an issue. At this stage, I want to be very particular about this sort of change, even if it is quite clearly within the bounds of established principles.
NAME did as .
When discussing at Cupertino, we agreed that either of the following two errors can be sent when the payload of the STREAM frame exceeds 2^62 bytes: FRAMEENCODINGERROR FLOWCONTROLERROR And we've merged PR that made that change, along with other changes. However, in that PR, we failed to apply the rule that we agreed for SRTEAM frame to CRYPTO frame. Editors' draft now allows use of FRAMEENCODINGERROR for CRYPTO frames, but not CRYPTOBUFFEREXCEEDED. As CRYPTOBUFFEREXCEEDED is the flow control error for CRYPTO streams, that should be permitted too. To be fixed by PR .
Thanks for doing all of this Kazuho.
fixed this one.
Thank you! LGTM. The following issues have proposals for resolution, and discussion so far seems to support consensus to accept them. If you object, please do so on the issue or in response to this message (changing the Subject appropriately!). Absent any pushback, we'll direct the editors to incorporate them next week. See for the current state of issues in the Late Stage process, itself defined at . : Is CONNECTIONCLOSE ACK-eliciting? The proposal is : Stateless reset detection should be datagram-based The proposal is : Label for key updates The proposal is : Handling of Retire Prior To field The proposal is : Require peers to check if RETIRECONNECTION_ID sequence number is valid The proposal is : Codes for frame encoding errors The proposal is : Layout of PreferredAddress The proposal is to close with no action. : Lift single-packet ClientHello requirement? The proposal is : unrecoverable loss pattern leads to deadlock The proposal is : Do Initial secrets change after Retry packet? The proposal is : Re-visit initial keys discard The proposal is to close with no action. : Why does stateless reset have to be checked after MAC failure The proposal is Mark Nottingham URL

The largest offset delivered on a stream - the sum of the offset and data length - cannot exceed 2^62-1.  Receipt of a frame that exceeds this limit MUST be treated as a connection error of type  <ins> FRAME_ENCODING_ERROR or CRYPTO_BUFFER_EXCEEDED. </ins> Unlike STREAM frames, which include a Stream ID indicating to which stream the data belongs, the CRYPTO frame carries data for a single


client or server MAY advertise support for any of these reserved versions. <del> Reserved version numbers will probably never represent a real protocol; a client MAY use one of these version numbers with the expectation that the server will initiate version negotiation; a server MAY advertise support for one of these versions and can expect that clients ignore the value. </del>  [[RFC editor: please remove the remainder of this section before publication.]]

This seems unnecessarily wishy-washy. Either they're reserved by definition, and therefore will never represent a real protocol, or they're available for use. We should remove the "probably" unless there's a good reason to keep it that I'm missing.
Use of that word was entirely intentional. If there is certainty about this status, then it creates a temptation to apply certain optimizations that could be disruptive. What if middleboxes cached Version Negotiation packets from servers and helpfully provided responses to greased connection attempts?
We fear that someone might ossify if they discover that these are definitely not real protocol versions. On the other hand, the thing that breaks is use of these as real protocol versions, which I don't believe we're trying to achieve. If the middlebox is generating accurate VN packets, that seems entirely reasonable (and indistinguishable from actual VN packets). If they're generating inaccurate VN packets, then our anti-downgrade protections that we've decided to implement RSN will break. On the other hand, if these ever are real protocol versions, then a junk grease packet using the reserved version will fail to parse as a valid Initial and will just fail rather than eliciting a VN response. This seems like an impossible battle to win, and a lot of subtlety to expect of middlebox vendors. Write what we mean and move on.

client or server MAY advertise support for any of these reserved versions.  <ins> Reserved version numbers will never represent a real protocol; a client MAY use one of these version numbers with the expectation that the server will initiate version negotiation; a server MAY advertise support for one of these versions and can expect that clients ignore the value. </ins> [[RFC editor: please remove the remainder of this section before publication.]]