-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework Retry packet #1498
Rework Retry packet #1498
Changes from all commits
b375544
bf3f675
55e910f
fdb837f
dd13b0e
c96058f
e375657
555ae81
19174cf
21f9ba5
7d96aa9
dbc58a1
cd9cdb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -532,6 +532,87 @@ See {{version-negotiation}} for a description of the version negotiation | |
process. | ||
|
||
|
||
## Retry Packet {#packet-retry} | ||
|
||
A Retry packet uses a long packet header with a type value of 0x7E. It carries | ||
an address validation token created by the server. It is used by a server that | ||
wishes to perform a stateless retry (see {{stateless-retry}}). | ||
|
||
~~~ | ||
0 1 2 3 | ||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
+-+-+-+-+-+-+-+-+ | ||
|1| 0x7e | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Version (32) | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
|DCIL(4)|SCIL(4)| | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Destination Connection ID (0/32..144) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Source Connection ID (0/32..144) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| ODCIL(8) | Original Destination Connection ID (*) | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Retry Token (*) ... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm realizing the lack of length means one can't 'coalesce' a RETRY and another packet type in a single datagram. I can't think why this is a practical issue, but it wouldn't surprise me if there was a use for it at some point, so I think it makes sense to add a length. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically, you could; just that, like a short-header packet, the Retry would have to come last. But as you say, I can't imagine a use for it in this version of QUIC, and since these are version-specific packets.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be a bit esoteric, but here's possible use cases: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @marten: I am not sure this is a valid use case. The main use case for the retry packet is that it is sent by some kind of firewall as part of DOS defense. The VN is sent end-to-end, and already carries a token of sorts with the Source CID. I don't see the use case of sending both retry and VN end to end. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In p2p, you won't have a separate firewall, but a peer might still want to use the Retry mechanism if it's under attack. I'm aware that this is not a very strong argument, since in that case you'd probably be ok with incurring an additional RTT, on the other hand, adding a varint to the header doesn't cost us a lot either. |
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
~~~ | ||
{: #retry-format title="Retry Packet"} | ||
|
||
A Retry packet (shown in {{retry-format}}) only uses the invariant portion of | ||
the long packet header {{QUIC-INVARIANTS}}; that is, the fields up to and | ||
including the Destination and Source Connection ID fields. The contents of the | ||
Retry packet are not protected. Like Version Negotiation, a Retry packet | ||
contains the long header including the connection IDs, but omits the Length, | ||
Packet Number, and Payload fields. These are replaced with: | ||
|
||
ODCIL: | ||
|
||
: The length of the Original Destination Connection ID field. The length is | ||
encoded in the least significant 4 bits of the octet, using the same encoding | ||
as the DCIL and SCIL fields. The most significant 4 bits of this octet are | ||
reserved. Unless a use for these bits has been negotiated, endpoints SHOULD | ||
send randomized values and MUST ignore any value that it receives. | ||
|
||
Original Destination Connection ID: | ||
|
||
: The Original Destination Connection ID contains the value of the Destination | ||
Connection ID from the Initial packet that this Retry is in response to. The | ||
length of this field is given in ODCIL. | ||
|
||
Retry Token: | ||
|
||
: An opaque token that the server can use to validate the client's address. | ||
|
||
The server populates the Destination Connection ID with the connection ID that | ||
the client included in the Source Connection ID of the Initial packet. | ||
|
||
The server includes a connection ID of its choice in the Source Connection ID | ||
field. The client MUST use this connection ID in the Destination Connection ID | ||
of subsequent packets that it sends. | ||
|
||
A Retry packet does not include a packet number and cannot be explictly | ||
acknowledged by a client. | ||
|
||
A server MUST only send a Retry in response to a client Initial packet. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could a server not send a Retry in response to a 0-RTT packet? Say the Initial was lost/reordered, and the 0-RTT arrived first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. The server cannot decrypt 0-RTT, so it's only option is to
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, for a DDoS mitigation device that just sees a 0-RTT packet (assuming the Initial was lost/reordered) it should just drop it instead of sending a Retry? That works, but I just wonder why not use that extra info to do the Retry immediately. Otherwise, the client will eventually retransmit the Initial, and then have to pay an additional RTT for the retry. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what Martin has is good, but I can imagine a DDoS device doing what you said, especially if it kept a small amount of state to ensure it didn't sent too many RETRY packets to a given IP/port. So this could be a SHOULD instead of a MUST. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not even sure it's necessary for it to be a SHOULD; there's no interoperability risk if it sends a Retry in response to a lone 0-RTT packet, is there? In which case it sounds more like servers MAY omit sending Retry in response to 0-RTT when they haven't seen the Initial. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think there's much value in sending Retry in response to 0RTT packets. Sending it without decrypting the incoming packet makes me queasy, and sending it a few times after receiving the Initial sounds like a strange retransmission strategy. It's easy to see a server generating a ton of Retry packets in response to Initial + 0RTT packets, so it seems reasonable to recommend better behavior here, and I like the text that's there. I don't mind weakening it to a SHOULD though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bump for changing this to a SHOULD for now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer to leave this as SHOULD for now, but will open a new issue. This wasn't the focus of this change (this is not my text), so let's have an explicit discussion about it. |
||
|
||
If the Original Destination Connection ID field does not match the Destination | ||
Connection ID from the most recent Initial packet it sent, clients MUST discard | ||
the packet. This prevents an off-path attacker from injecting a Retry packet. | ||
|
||
The client responds to a Retry packet with an Initial packet that includes the | ||
provided Retry Token to continue connection establishment. | ||
|
||
A server that might send another Retry packet in response to a subsequent | ||
Initial packet MUST set the Source Connection ID to a new value of at least 8 | ||
octets in length. This allows clients to distinguish between Retry packets when | ||
the server sends multiple rounds of Retry packets. Consequently, a valid Retry | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of requiring the server to use a new CID, why not just make the client use a new random CID for every new token it sends in the Initial packet? That way the client has direct control to be able to differentiate between the possibly Retry responses? And no additional complexity on the server side. Going further, I was thinking during the talks today, if we are going to recommend that initial packet routing not take the client Initial's DCID into account (because it would be an attack surface) then I don't see any reason to support the Retry packet changing the CID at all. The primary reason for adding that support initially was for routing/load balancing; but that seems to be ill advised now. It just adds unnecessary complexity in the client code, IMO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The clients source SCID must be new. The clients original DCID is always new and random in an initial packet. Only the source is reflected back by the server. this is why it must be new. The alternative would be to have a separate nonce in the handshake, separate from SCID, which is what I suggest. On the going further: The server must set is own SCID - otherwise the server is forced to use a client chosen SCID which is not only a load balancer issue and it also goes against the point of a retry. A retry is a redirect to another server, not try again until you get lucky, although that can also be implemented if the server randomizes its SCID. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mikkelfj if the client uses a new SCID then it would be considered an entirely new connection, and might elicit another Retry. I am talking about removing the requirement from the server in generating new random CID, and instead have the client generate a new random DCID for each try. Also, on the going further, I am only talking about Retry. After that, in the handshake the server can/will change the CID to whatever it wants. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is nothing wrong with getting a new retry, the problem is stopping when too many happen. If the client changes SCID each time, it can stop after 1-3 retries - but it helps if it can know that all retries are from the same chain. I think a nonce is better for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The clients original DCID disappears once it reaches the server. Since the server sets its own SCID and the client is not allowed to change its SCID, the context is lost. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am considering only the Retry scenario right now. During the handshake, after the Retry, the server has the opportunity to change its SCID once again (independent of if it was changed during Retry). I am trying to make two points:
So, Retry just shouldn't change the CID at all, IMO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nibanks, I think that the idea was to give the server better control over where to send subsequent Retry packets. That is, it can choose a value that is better for load, DoS prevention, or whatever it needs. The server can use the token to validate that the value was its own choice as well, removing concerns about the client stacking load on certain servers. (I thought that this was one of your design constraints, but I realize now I don't know where that idea came from.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe @mcmanus originally requested the ability to change CID with the (old) Retry packet. For DoS, I only require the Token field. Is it true or not that we recommend not using the client Initial CID for load balancing decisions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack. I don't think that we have a concrete statement about using the Destination Connection ID from the client Initial. With a token from Retry, you could; without, it's fraught, I agree. |
||
packet will always have an Original Destinagion Connection ID that is at least 8 | ||
octets long; clients MUST discard Retry packets that include a shorter value. A | ||
server that will not send additional Retry packets can set the Source Connection | ||
ID to any value. | ||
|
||
|
||
## Cryptographic Handshake Packets {#handshake-packets} | ||
|
||
Once version negotiation is complete, the cryptographic handshake is used to | ||
|
@@ -548,58 +629,83 @@ provide confidentiality or integrity against on-path attackers, but | |
provides some level of protection against off-path attackers. | ||
|
||
|
||
### Initial Packet {#packet-initial} | ||
## Initial Packet {#packet-initial} | ||
|
||
The Initial packet uses long headers with a type value of 0x7F. It carries the | ||
first CRYPTO frames sent by the client and server to perform key exchange, and | ||
may carry ACKs in either direction. The Initial packet is protected by Initial | ||
carries ACKs in either direction. The Initial packet is protected by Initial | ||
keys as described in {{QUIC-TLS}}. | ||
|
||
The Initial packet has two additional header fields that follow the normal Long | ||
Header. | ||
The Initial packet (shown in {{initial-format}}) has two additional header | ||
fields that are added to the Long Header before the Length field. | ||
|
||
~~~ | ||
0 1 2 3 | ||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
+-+-+-+-+-+-+-+-+ | ||
|1| 0x7f | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Version (32) | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
|DCIL(4)|SCIL(4)| | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Token Length (i) ... | ||
| Destination Connection ID (0/32..144) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Source Connection ID (0/32..144) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Token Length (i) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Token (*) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Length (i) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Packet Number (8/16/32) | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Payload (*) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. This new design solves issue #1535. |
||
~~~ | ||
{: #initial-format title="Initial Packet"} | ||
|
||
These fields include the token that was previously provided in a Retry packet or | ||
NEW_TOKEN frame: | ||
|
||
Token Length: | ||
|
||
: A variable-length integer specifying the length of the Token field, in bytes. | ||
It may be zero if no token is present. Initial packets sent by the server | ||
MUST include a zero-length token. | ||
This value is zero if no token is present. Initial packets sent by the server | ||
MUST set the Token Length field to zero; clients that receive an Initial | ||
packet with a non-zero Token Length field MUST either discard the packet or | ||
generate a connection error of type PROTOCOL_VIOLATION. | ||
|
||
Token: | ||
|
||
: An optional token blob previously received in either a Retry packet or | ||
NEW_TOKEN frame. | ||
: The value of the token. | ||
|
||
The client and server use the Initial packet type for any packet that contains | ||
an initial cryptographic handshake message. In addition to the first | ||
packet(s). This includes all cases where a new packet containing the initial | ||
cryptographic message needs to be created, such as the packets sent after | ||
receiving a Version Negotiation ({{packet-version}}) or Retry packet | ||
({{packet-retry}}). | ||
an initial cryptographic handshake message. This includes all cases where a new | ||
packet containing the initial cryptographic message needs to be created, such as | ||
the packets sent after receiving a Version Negotiation ({{packet-version}}) or | ||
Retry packet ({{packet-retry}}). | ||
|
||
A server sends its first Initial packet in response to a client Initial. A | ||
server may send multiple Initial packets. The cryptographic key exchange could | ||
require multiple round trips or retransmissions of this data. | ||
|
||
The payload of an Initial packet includes a CRYPTO frame (or frames) containing | ||
a cryptographic handshake message, ACK frames, or both. The first CRYPTO frame | ||
sent always begins at an offset of 0 (see {{handshake}}). The client's complete | ||
first message MUST fit in a single packet (see {{handshake}}). Note that if the | ||
server sends a HelloRetryRequest, the client will send a second Initial packet | ||
with a CRYPTO frame with an offset starting at the end of the CRYPTO stream in | ||
the first Initial. | ||
sent always begins at an offset of 0 (see {{handshake}}). | ||
|
||
The first packet sent by a client always includes a CRYPTO frame that contains | ||
the entirety of the first cryptographic handshake message. This packet, and the | ||
cryptographic handshake message, MUST fit in a single UDP datagram (see | ||
{{handshake}}). | ||
|
||
Note that if the server sends a HelloRetryRequest, the client will send a second | ||
Initial packet. This Initial packet will continue the cryptographic handshake | ||
and will contain a CRYPTO frame with an offset matching the size of the CRYPTO | ||
frame sent in the first Initial packet. Cryptographic handshake messages | ||
subsequent to the first do not need to fit within a single UDP datagram. | ||
|
||
|
||
#### Connection IDs | ||
### Connection IDs | ||
|
||
When an Initial packet is sent by a client which has not previously received a | ||
Retry packet from the server, it populates the Destination Connection ID field | ||
|
@@ -624,10 +730,24 @@ server, it MUST discard any packet it receives with a different Source | |
Connection ID. | ||
|
||
|
||
#### Tokens | ||
### Tokens | ||
|
||
If the client has a suitable token available from a previous connection, it | ||
SHOULD populate the Token field. | ||
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 can include that value in the | ||
Token field of its Initial packet. | ||
|
||
A token allows a server to correlate activity between connections. | ||
Specifically, the connection where the token was issued, and any connection | ||
where it is used. Clients that want to break continuity of identity with a | ||
server MAY discard tokens provided using the NEW_TOKEN frame. Tokens obtained | ||
in Retry packets MUST NOT be discarded. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The prohibition below is on using a token on two different network paths. But since the token is likely to contain address validation information, should we recommend against using the token from a different address than the one where it was received? Or is that solely a risk of server tracking and it's covered in the privacy-from-server paragraph here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the intent of this paragraph is to cover that. The paragraph below is privacy-from-network. |
||
|
||
A client SHOULD NOT reuse a token. Reusing a token on allows connections to be | ||
linked by entities on the network path (see {{migration-linkability}}). 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. A client needs to start | ||
the connection process over if it migrates prior to completing the handshake. | ||
|
||
If the client received a Retry packet from the server and sends an Initial | ||
packet in response, then it sets the Destination Connection ID to the value from | ||
|
@@ -649,85 +769,27 @@ Note: | |
the packet is that the client might have received the token in a previous | ||
connection using the NEW_TOKEN frame, and if the server has lost state, it | ||
might be unable to validate the token at all, leading to connection failure if | ||
the packet is discarded. | ||
the packet is discarded. A server MAY encode tokens provided with NEW_TOKEN | ||
frames and Retry packets differently, and validate the latter more strictly. | ||
|
||
|
||
#### Starting Packet Numbers | ||
### Starting Packet Numbers | ||
|
||
The first Initial packet contains a packet number of 0. Each packet sent after | ||
the Initial packet is associated with a packet number space and its packet | ||
number increases monotonically in that space (see {{packet-numbers}}). | ||
The first Initial packet sent by either endpoint contains a packet number of | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SHOULD contain? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or MUST contain? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Certainly not MUST. Consider the case where the Initial packet is resent after a version negotiation, or repeated after time-out. Then the "natural" value of the sequence number will be 1. I don't see how saying "must be zero" would improve interoperability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Christian got it. MUST doesn't work, and throwing normative language at this is too heavy. I think that this is fine. |
||
0. The packet number MUST increase monotonically thereafter. Initial packets | ||
are in a different packet number space to other packets (see | ||
{{packet-numbers}}). | ||
|
||
|
||
#### Minimum Packet Size | ||
### Minimum Packet Size | ||
|
||
The payload of a UDP datagram carrying the Initial packet MUST be expanded to at | ||
least 1200 octets (see {{packetization}}), by adding PADDING frames to the | ||
Initial packet and/or by combining the Initial packet with a 0-RTT packet (see | ||
{{packet-coalesce}}). | ||
|
||
|
||
### Retry Packet {#packet-retry} | ||
|
||
A Retry packet uses long headers with a type value of 0x7E. It carries an | ||
address validation token created by the server. It is used by a server that | ||
wishes to perform a stateless retry (see {{stateless-retry}}). | ||
|
||
~~~ | ||
0 1 2 3 | ||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| ODCIL(8 | Original Destination Connection ID (*) | | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
| Retry Token (*) ... | ||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
~~~ | ||
|
||
A Retry packet is not encrypted at all. Instead, the payload of a | ||
Retry packet contains two values in the clear. | ||
|
||
ODCIL: | ||
|
||
: The length of the Original Destination Connection ID. | ||
|
||
Original Destination Connection ID: | ||
|
||
: The Destination Connection ID from the Initial packet that this | ||
Retry is in response to. The length of this field is given in DCIL. | ||
|
||
Retry Token: | ||
|
||
: An opaque token that the server can use to validate the client's | ||
address. | ||
|
||
The server populates the Destination Connection ID with the connection ID that | ||
the client included in the Source Connection ID of the Initial packet. This | ||
might be a zero-length value. | ||
|
||
The server includes a connection ID of its choice in the Source Connection ID | ||
field. The client MUST use this connection ID in the Destination Connection ID | ||
of subsequent packets that it sends. | ||
|
||
The Packet Number field of a Retry packet MUST be set to 0. This value is | ||
subsequently protected as normal. \[\[Editor's Note: This isn't ideal, because | ||
it creates a "cheat" where the client assumes a value. That's a problem, so I'm | ||
tempted to suggest that this include any value less than 2^30 so that normal | ||
processing works - and can be properly exercised.]] | ||
|
||
A Retry packet is never explicitly acknowledged in an ACK frame by a client. | ||
|
||
A server MUST only send a Retry in response to a client Initial packet. | ||
|
||
If the Original Destination Connection ID field does not match the | ||
Destination Connection ID from most recent the Initial packet it sent, | ||
clients MUST discard the packet. This prevents an off-path attacker | ||
from injecting a Retry packet with a bogus new Source Connection ID. | ||
|
||
Otherwise, the client SHOULD respond with a new Initial | ||
packet with the Token field set to the token received in the Retry packet. | ||
|
||
|
||
### Handshake Packet {#packet-handshake} | ||
## Handshake Packet {#packet-handshake} | ||
|
||
A Handshake packet uses long headers with a type value of 0x7D. It is | ||
used to carry acknowledgments and cryptographic handshake messages from the | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I am missing something, len(token_length) is only available after the PN has been decrypted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we have a circular dependency when decrypting. See issue #1535.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. This is actually addressed later, as the token has now moved in front of the PN.