Draft: draft-ietf-quic-load-balancers

Commentary: Takes the RSCID out of the token body because the server can catch mismatches with the DCID if it 's used as associated data . 
 I have read but still do n't understand why we need to include it again in token . I 'd thought that that server or retry service can read it from the Initial packet ( invariant long header packet ) . What happen if they are different ? Which one server should take to initiate the connection ? 
 I recommend Section 7.3 of RFC 9000 to understand this : " The values provided by a peer for these transport parameters MUST match the values that an endpoint used in the Destination and Source Connection ID fields of Initial packets that it sent ( and received , for servers ) . Endpoints MUST validate that received transport parameters match received connection ID values . " The connection IDs in Retry and Initial packets are not effectively authenticated unless they are included in transport parameters , which are included in key computation . If the server does n't have a trustworthy record of the CID it picked ( this token ) , it has no way of confirming that the Retry 's SCID was n't modified in flight . 
 yeah , I get that server needs to verify SCID in Retry packet . I still do not get why we need to include Retry SCID again in the token . 
 How would it verify the SCID was unchanged if it was n't in the token ? 
 I think it 'd be authenticated by including in the associated data ,    , this is a clever proposal . I 'll reopen to reconsider properly . 
 Trying to wrap my head around this . The server wants to verify that the RSCID is correct , so the current solution is to copy that in the token . If the client messes up , the server compares the value in the token to the value sent by the client . Yes , putting that in the pseudo header will mostly work . If the client does not use the specified RSCID , the token will just not decode . But there are two potential issues : 1 ) Debugging is harder . For example , there will not be any way to differentiate between wrong RSCID and wrong IP 2 ) If the token came as " NEW TOKEN " , there is no RSCID specified . There will need to be a special case for constructing the pseudo header , but that means exposing the difference between Retry Token and New Token in clear text . In any case , we would need additional text for the New Token case . 
 Christian , good point on ( 2 ) . The NSS Token already distinguishes the types in cleartext , so perhaps that 's not such a big deal . But yes , we 'd need to take a bit from the key sequence to indicate the token type . 
 I filed , please take a look .
RSCIL: The retry source connection ID length.
Retry Source Connection ID: This also in cleartext and authenticated
later.
Opaque Data: This data MUST contain encrypted information that allows
the retry service to validate the client's IP address, in accordance
with the QUIC specification.  It MUST also provide a
cryptographically secure means to validate the integrity of the
entire token.
Opaque Data: This data contains the information necessary to
authenticate the Retry token in accordance with the QUIC
specification.  A straightforward implementation would encode the
Retry Source Connection ID, client IP address, and a timestamp in the
Opaque Data.  A more space-efficient implementation would use the
Retry Source Connection ID and Client IP as associated data in an
encryption operation, and encode only the timestamp and the
authentication tag in the Opaque Data.  If the Initial Packet has
altered the Connection ID or source IP address, authentication of the
token will fail.
If a server receives an Initial Packet with the first bit set to '1',
it could be from a server-generated NEW_TOKEN frame and should be
processed in accordance with the QUIC specification.  If a server
receives an Initial Packet with the first bit to '0', it is a Retry
token and the server MUST NOT attempt to validate it.  Instead, it
MUST assume the address is validated and MUST extract the Original
Destination Connection ID and Retry Source Connection ID, assuming
the format described in nss-service-requirements.
If a server receives an Initial Packet with the first bit set to '1',
it could be from a server-generated NEW_TOKEN frame and should be
processed in accordance with the QUIC specification.  If a server
receives an Initial Packet with the first bit to '0', it is a Retry
token and the server MUST NOT attempt to validate it.  Instead, it
MUST assume the address is validated, MUST include the packet's
Destination Connection ID in a Retry Source Connection ID transport
parameter, and MUST extract the Original Destination Connection ID
from the token cleartext for use in the transport parameter of the
same name.
An 8 bit token key identifier.
A token body, encoding the Original Destination Connection ID, the
Retry Source Connection ID, and the Timestamp, optionally followed
by server specific Opaque Data.
The token protection uses an 128 bit representation of the source IP
address from the triggering Initial packet.  The client IP address is
16 octets.  If an IPv4 address, the last 12 octets are zeroes.
A 1 bit token type identifier.
A 7 bit token key identifier.
A token body, encoding the Original Destination Connection ID and
the Timestamp, optionally followed by server specific Opaque Data.
The token protection uses an 128 bit representation of the source IP
address from the triggering Initial packet.  The client IP address is
16 octets.  If an IPv4 address, the last 12 octets are zeroes.  It
also uses the Source Connection ID of the Retry packet, which will
cause an authentication failure if it differs from the Destination
Connection ID of the packet bearing the token.
ODCIL: The original destination connection ID length.  Tokens in
NEW_TOKEN frames MUST set this field to zero.
RSCIL: The retry source connection ID length.  Tokens in NEW_TOKEN
frames MUST set this field to zero.
Original Destination Connection ID: The server or Retry Service
copies this from the field in the client Initial packet.
Retry Source Connection ID: The server or Retry service copies this
from the Source Connection ID of the Retry packet.
ODCIL: The original destination connection ID length.  Tokens in
NEW_TOKEN frames do not have this field.
Original Destination Connection ID: The server or Retry Service
copies this from the field in the client Initial packet.  Tokens in
NEW_TOKEN frames do not have this field.
The Key Sequence is the 8 bit identifier to retrieve the token key
and IV.
The Key Sequence is the 7 bit identifier to retrieve the token key
and IV.
The associated data is a formatted as a pseudo header by combining
the cleartext part of the token with the IP address of the client.
The associated data is a formatted as a pseudo header by combining
the cleartext part of the token with the IP address of the client.
The format of the pseudoheader depends on whether the Token Type
bit is '1' (a NEW_TOKEN token) or '0' (a Retry token).
RSCIL: The Retry Source Connection ID Length in octets.  This field
is only present when the Token Type is '0'.
Retry Source Connection ID: To create a Retry Token, populate this
field with the Source Connection ID the Retry packet will use.  To
validate a Retry token, populate it with the Destination Connection
ID of the Initial packet that carries the token.  This field is only
present when the Token Type is '0'.
In inactive mode, the Retry service forwards all packets without
further inspection or processing.
When in active mode, the service MUST generate Retry tokens with the
format described above when it receives a client Initial packet with
no token.
If the token verification passes, and the ODCIL and RSCIL fields are
both zero, then this is a NEW_TOKEN token generated by the server.
Processing of NEW_TOKEN tokens is subtly different from Retry tokens,
as described below.
The service SHOULD drop a packet containing a token where the ODCIL
is greater than zero and less than the minimum number of octets for a
client-generated CID (8 in QUIC version 1).  The service also SHOULD
drop a packet containing a token where the ODCIL is zero and RSCIL is
nonzero.
If the Timestamp of a token points to time in the past, the token has
expired; however, in order to allow for clock skew, it SHOULD NOT
consider tokens to be expired if the Timestamp encodes a few seconds
in the past.  An active Retry service SHOULD drop packets with
expired tokens.  If a NEW_TOKEN token, the service MUST generate a
Retry packet in response.  It MUST NOT generate a Retry packet in
response to an expired Retry token.
If a Retry token, the service SHOULD drop packets where the port
number encoded in the token does not match the source port in the
encapsulating UDP header.
All other packets SHOULD be forwarded to the server.
When issuing Retry or NEW_TOKEN tokens, the server MUST include the
client IP address in the authenticated data as specified in token-
protection-with-aead.  The ODCIL and RSCIL fields are zero for
NEW_TOKEN tokens, making them easily distinguishable from Retry
tokens.
The server MUST validate all tokens that arrive in Initial packets,
as they may have bypassed the Retry service.
For Retry tokens that follow the format above, servers SHOULD use the
timestamp field to apply its expiration limits for tokens.  This need
not be precisely synchronized with the retry service.  However,
servers MAY allow retry tokens marked as being a few seconds in the
past, due to possible clock synchronization issues.
After decrypting the token, the server uses the corresponding fields
to populate the original_destination_connection_id transport
parameter, with a length equal to ODCIL, and the
retry_source_connection_id transport parameter, with length equal to
RSCIL.
As discussed in RFC9000, a server MUST NOT send a Retry packet in
response to an Initial packet that contains a retry token.
In inactive mode, the Retry service forwards all packets without
further inspection or processing.  The rest of this section only
applies to a service in active mode.
The service MUST generate Retry tokens with the format described
above when it receives a client Initial packet with no token.
If there is a token of either type, the service MUST attempt to
decrypt it.
To decrypt a packet, the service checks the Token Type and constructs
a pseudoheader with the appropriate format for that type, using the
bearing packet's Destination Connection ID to populate the Retry
Source Connection ID field, if any.
it uses unknown key sequence,
the AEAD ICV does not match the expected value (By construction,
it will only match if the client IP Address, and any Retry Source
Connection ID, also matches),
the ODCIL, if present, is invalid for a client-generated CID (less
than 8 or more than 20 in QUIC version 1),
the port number, if present, does not match the source port in the
encapsulating UDP header.
Packets with valid tokens MUST be forwarded to the server.
The service MUST drop packets with invalid tokens.  If the token is
of type '1' (NEW_TOKEN), it MUST respond with a Retry packet.  If of
type '0', it MUST NOT respond with a Retry packet.
The server MAY issue Retry or NEW_TOKEN tokens in accordance with
RFC9000.  When doing so, it MUST follow the format above.
The server MUST validate all tokens that arrive in Initial packets,
as they may have bypassed the Retry service.  It determines validity
using the procedure in ss-service.
If a valid Retry token, the server populates the
original_destination_connection_id transport parameter using the
corresponding token field.  It populates the
retry_source_connection_id transport parameter with the Destination
Connection ID of the packet bearing the token.
In all other respects, the server processes both valid and invalid
tokens in accordance with RFC9000.