Subject: How many Initial packets shall carry the retry token?

From: Christian Huitema <[email-masked]>
Date: Tue, 27 Nov 2018 14:00:21 -0800

We had a small problem during testing of "stateless retry" interop. One
of the implementation expected a token to be present in every Initial
packet, the other would only send it in the first packet that carried
the client Hello. The spec says:

   Upon receiving the client's Initial packet, the server can request
   address validation by sending a Retry packet (Section 17.7 <https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-17.7>)
   containing a token.  This token is repeated by the client in an
   Initial packet after it receives the Retry packet.  In response to
   receiving a token in an Initial packet, a server can either abort the
   connection or permit it to proceed.

It is clear for the first Initial packet, but not entirely. Is it OK to
send consecutive packets like ACK without a token? Is it also OK to have
them carry a token?

-- Christian Huitema

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 28 Nov 2018 13:08:37 +0900

2018年11月28日(水) 7:01 Christian Huitema <[email-masked]>:
>
> We had a small problem during testing of "stateless retry" interop. One of the implementation expected a token to be present in every Initial packet, the other would only send it in the first packet that carried the client Hello. The spec says:
>
>    address validation by sending a Retry packet (Section 17.7)
> It is clear for the first Initial packet, but not entirely. Is it OK to send consecutive packets like ACK without a token? Is it also OK to have them carry a token?

I would assume that the answer is yes for both the questions.

It is obvious that there is no point in attaching a token to an
Initial packet sent in response to ServerHello.

Also consider 0-RTT packets; they do not have a token field even
though they are sent before seeing server's response. To put it
another way, servers should not expect every packet it receives from
the client before the path is validated to contain a token.

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Wed, 28 Nov 2018 15:58:38 +1100

I have a vague recollection of discussing this question in the past
and concluding that the token would be attached to all Initial
packets.

> Initial packet sent in response to ServerHello.

Maybe.  In any of these cases, if an external DoS mitigation box is
examining packets individually, then it will probably need state, or a
marking of some sort on every packet that has a potentially suspect
connection ID.

> the client before the path is validated to contain a token.

A client that receives Retry probably needs to restart (or abort) its
sending of 0-RTT.

---

From: Marten Seemann <[email-masked]>
Date: Wed, 28 Nov 2018 12:16:34 +0700

> Initial packet sent in response to ServerHello.

Assuming that we're fixing the Initial injection attack, you wouldn't send
any more Initial packets after receiving the ServerHello. However, I agree
there's no reason to send a token in reply to an HRR. My only fear here is
that HRR is so rare in practice that DoS mitigation boxes might neglect
this case and treat all Initial packets as if they were the first packet
sent on a connection. We should document this very clearly.

> A client that receives Retry probably needs to restart (or abort) its

The token could also be a token provided in a NEW_TOKEN frame on a previous
connection.

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 28 Nov 2018 15:44:26 +0900

> A client that receives Retry probably needs to restart (or abort) its

It's true that the client needs to restart sending 0-RTT packets. But
the thing is that while the Initial packets sent after receiving Retry
can be accompanied by the supplied token, 0-RTT packets cannot.

That means that middleboxes need to have a mechanism to remember that
the path has become valid once it sees an Initial packet with a valid
token in order to pass through the 0-RTT packets.

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 28 Nov 2018 15:45:18 +0900

2018年11月28日(水) 14:16 Marten Seemann <[email-masked]>:
> Assuming that we're fixing the Initial injection attack, you wouldn't send any more Initial packets after receiving the ServerHello.

That's not true when HRR is involved.

> However, I agree there's no reason to send a token in reply to an HRR. My only fear here is that HRR is so rare in practice that DoS mitigation boxes might neglect this case and treat all Initial packets as if they were the first packet sent on a connection. We should document this very clearly.
>
> The token could also be a token provided in a NEW_TOKEN frame on a previous connection.
>
> On Wed, Nov 28, 2018 at 11:59 AM Martin Thomson <[email-masked]> wrote:
>>

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Wed, 28 Nov 2018 19:41:04 +1100

> can be accompanied by the supplied token, 0-RTT packets cannot.

Yeah, that's a problem, but only where 0-RTT is supported.  Otherwise,
having the token means that you can support a properly stateless
Retry.  Not sure how much that matters in light of the need for state
to manage 0-RTT though.

---

From: Mirja Kühlewind <[email-masked]>
Date: Wed, 28 Nov 2018 11:12:18 +0100

I guess if a middlebox decided to block 0-RTT for any reason, you simply have to resend it…

> Am 28.11.2018 um 09:41 schrieb Martin Thomson <[email-masked]>:
>

---

From: Ian Swett <[email-masked]>
Date: Wed, 28 Nov 2018 05:42:07 -0500

I think sending the Token with all Initial packets is the only idea that is
clear enough to recommend in the transport draft.  It's pretty clear
Initials that contain retransmissions of the ClientHello need to have the
Token and creating potential failure modes that are only invoked when the
middlebox drops token-less Initials AND there's an HRR seems like we're
just creating problems for ourselves.

All the other options require more knowledge of the TLS state in the
transport, and I'd rather not increase the amount of that in QUIC.

On Wed, Nov 28, 2018 at 5:12 AM Mirja Kühlewind <
[email-masked]> wrote:

> > Am 28.11.2018 um 09:41 schrieb Martin Thomson <[email-masked]
> >:
> >

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 28 Nov 2018 22:01:46 +0900

> I guess if a middlebox decided to block 0-RTT for any reason, you simply have to resend it…

IMO, the question is what the expected behavior of a middlebox is,
when it receives a 0-RTT packet _after_ seeing an Initial with a valid
token.

If the middlebox is going to create a hole for the 5 tuple when it
receives a Initial packet with a valid token, not all Initial packets
need to carry the token. Assuming that packets are delivered in-order,
0-RTT packets that are sent after the client sees a Retry will pass
through, because they will be sent after the Initial that contains the
token.

The other expected behavior of a middlebox is that it passes through a
Initial packet with a valid token but does not create a hole
immediately. Instead, it creates a hole when it sees the Initial
packet sent by the server in response. This type of middlebox might
not be able to pass through the 0-RTT packets.

The question is if we need to support the latter type middleboxes. If
that's required, I would argue that we need to add token field to
0-RTT packets as well, so that they can reach the server.

However, I do not see why a middlebox needs to be implemented using
the first approach. The second approach seems like an unnecessarily
complex to me, assuming that the token will contain a cookie that
tells the middlebox that the packet containing the token can pass
through.

-- 
Kazuho Oku

---

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 28 Nov 2018 08:29:13 -0500

> and concluding that the token would be attached to all Initial

Would you agree that this is not document in the the current
draft?  As it stands, it only mentions the one packet:

  " This token is repeated by the client in an Initial packet
  " after it receives the Retry packet.

  - Dmitri.

---

From: Mirja Kühlewind <[email-masked]>
Date: Wed, 28 Nov 2018 16:26:23 +0100

Hi Kazuho,

I think in this case you cannot generalize middlebox behavior as such. There are different middleboxes with different functions. I can imagine that there could be security middleboxes which will not support any 0-RTT data at all and just drop until there is a return-routebility proof. However, this would even be independent of the token.

What I was rather trying to say it that there might be middleboxes that create state on the first packet, or others any time later. But while it important that all handshakes packets are able to pass through for the protocol to work at all, 0-RTT data can simply be retransmitted. Also when you get a retry token, you already have some additional delay due to the retry and in this case it’s probably not a big issue to also resent 0-RTT or not send 0-RTT at all.

Mirja

> Am 28.11.2018 um 14:01 schrieb Kazuho Oku <[email-masked]>:
>

---

From: Christian Huitema <[email-masked]>
Date: Wed, 28 Nov 2018 10:37:39 -0800

> What I was rather trying to say it that there might be middleboxes that create state on the first packet, or others any time later. But while it important that all handshakes packets are able to pa…

If we are concerned with middle-boxes, a plausible solution is to
coalesce the 0-RTT packets with token-carrying Initial packets -- maybe
Initial packets that just contain one byte of PAD. That way, the
middle-box will see the token in the Initial packet, and has enough
information to validate the address.

Or, we could just add a token field to the 0-RTT long header format,
aligning it with the Initial header format.

-- Christian Huitema

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 29 Nov 2018 09:54:06 +0900

Hi Mirja,

Thank you for elaborating. My response inline.

> I think in this case you cannot generalize middlebox behavior as such. There are different middleboxes with different functions. I can imagine that there could be security middleboxes which will no…

I am not sure if we need to take care of such middleboxes, but
assuming that we need to, I think adding the token field to 0-RTT
packets is the correct solution as Christian suggests. The reason is
that the impact is higher than just losing an RTT (stated below).

> What I was rather trying to say it that there might be middleboxes that create state on the first packet, or others any time later. But while it important that all handshakes packets are able to pa…

IMO, this is the case about a middlebox "dropping" 0-RTT packets,
rather than 0-RTT not being used.

IIUC, we have had discussion about having middleboxes (owned by IaaS
operators) that start operating when it sees an attack to the servers
used by their customers. In such case, it could well be the case that
the server would continue accepting 0-RTT packets (in sense that
EncryptedExtensions.EarlyDataIndication is sent). If the middlebox
drops 0-RTT packets under such condition, to the client it would look
that all the 0-RTT packets were lost, thereby activating the loss
recovery logic and shrinking CWND.

Hence my question about if we need to support this type of middleboxes
(and if yes, we should consider adding token field to 0-RTT packets).

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Thu, 29 Nov 2018 12:32:47 +1100

> recovery logic and shrinking CWND.

The easiest thing to do in this case is reject 0-RTT when you see that
the ClientHello has a token attached.

I suspect that slapping a token on 0-RTT is not going to be that
useful.  If you are paying the round trip for a Retry, then more round
trips for this case isn't the end of the world.  Especially when it's
under somewhat exceptional circumstances.

---

From: Christian Huitema <[email-masked]>
Date: Wed, 28 Nov 2018 17:36:35 -0800

> under somewhat exceptional circumstances.

Think of the "New Token" scenario. The new token is used without
incurring a Retry.

-- Christian Huitema

---

From: Martin Thomson <[email-masked]>
Date: Thu, 29 Nov 2018 12:40:52 +1100

> Think of the "New Token" scenario. The new token is used without

Good point.  I hadn't considered that.  It seems like that makes sense
at least.  The real question remains though: is anyone looking to have
a stateless DoS prevention thingy and a desire to support 0-RTT when
it is active?  If the box isn't active often, then maybe we don't need
to worry about special support.  Adding a token to every packet is
going to cut into the amount of 0-RTT that can be sent pretty
severely.

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 29 Nov 2018 11:06:41 +0900

> going to cut into the amount of 0-RTT that can be sent pretty

I agree with the framing.

IMO, the behavior of server-side endpoints that we need to consider in
terms of protocol design is ones that opens a hole when it receives an
Initial packet with Retry.

Then, 0-RTT packets do not need a token field. Initial packets sent in
response to server's Initial do not need to include a token.

-- 
Kazuho Oku

---

From: Martin Thomson <[email-masked]>
Date: Thu, 29 Nov 2018 13:15:37 +1100

> response to server's Initial do not need to include a token.

Thanks.  Could you confirm that you are OK with reordered 0-RTT
packets being dropped in this case?

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 29 Nov 2018 11:37:07 +0900

> packets being dropped in this case?

I think that is fine. As we have discussed, most endpoints that send
the Retry will (can) have the logic to reject the use of 0-RTT.

-- 
Kazuho Oku

---

From: Ian Swett <[email-masked]>
Date: Thu, 29 Nov 2018 04:26:03 -0500

I have no use for a token on 0RTT packets, so I'd rather not add one.

To come back to the original question, was it ever resolved what the rules
were for which Initial packets needed a token?  Is it all, and if it's not,
what should the rule be?

On Wed, Nov 28, 2018 at 9:37 PM Kazuho Oku <[email-masked]> wrote:

> 2018年11月29日(木) 11:15 Martin Thomson <[email-masked]>:
> >

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 08:44:16 -0500

> the Retry will (can) have the logic to reject the use of 0-RTT.

That's not obvious to me.  Why do you think that?

  - Dmitri.

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 08:52:27 -0500

On Thu, Nov 29, 2018 at 04:26:03AM -0500, Ian Swett wrote:
> were for which Initial packets needed a token?

It wasn't -- that subthread atrophied rather quickly.

> Is it all, and if it's not, what should the rule be?

It is easy to be conservative and set the token (either retry or
resume token) on all outgoing Initial packets.

On the server side, token validation is not strictly necessary once
the connection state exists, so the server only needs the token on
the first Initial packet.  This is how I implemented it.

The choice is either to specify that the server be smarter or that
the client be conservative.  And it should be in the draft.

  - Dmitri.

---

From: Ian Swett <[email-masked]>
Date: Thu, 29 Nov 2018 09:18:15 -0500

> the first Initial packet.  This is how I implemented it.

And by first Initial, if the handshake timer goes off and the content in
the Initial is retransmitted in a new packet, presumably that also contains
the token?

If the rule isn't going to be all Initials, then the other consistent rule
I can come up with is to send it in all Initials until a non-Retry/VN
packet has been received?

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 09:35:36 -0500

> the Initial is retransmitted in a new packet, presumably that also contains

Yes.

> packet has been received?

I think the simplest rule is that "the client MUST include the token
in the Initial packet containing ClientHello and MAY include the
token in other Initial packets."

The rule you have proposed above will work as well.

  - Dmitri.

---

From: Ian Swett <[email-masked]>
Date: Thu, 29 Nov 2018 09:43:55 -0500

> token in other Initial packets."

True, but that requires me knowing which packet contains the ClientHello,
which I don't think is necessary at the transport layer today?

---

From: Marten Seemann <[email-masked]>
Date: Thu, 29 Nov 2018 21:46:00 +0700

The packet sent in response to an HRR also contains a ClientHello, so these
two rules are different.

On Thu, Nov 29, 2018 at 21:44 Ian Swett <ianswett=
[email-masked]> wrote:

>
>
> On Thu, Nov 29, 2018 at 9:35 AM Dmitri Tikhonov <
> [email-masked]> wrote:
>

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 10:03:46 -0500

> which I don't think is necessary at the transport layer today?

You must be right.  Then change it to "include the token in the
very first ackent^Wretransmittable Initial packet."

  - Dmitri.

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 10:04:18 -0500

> The packet sent in response to an HRR also contains a ClientHello, so these

+1.  See my reply to Ian Swett for the rule update.

  - Dmitri.

---

From: Ian Swett <[email-masked]>
Date: Thu, 29 Nov 2018 10:09:39 -0500

All retransmittable Initial packets works for me, if the goal is to avoid
including it in ACK-only Initials.

---

From: Christian Huitema <[email-masked]>
Date: Thu, 29 Nov 2018 08:38:57 -0800

> On Nov 29, 2018, at 7:09 AM, Ian Swett <[email-masked]> wrote:
> 
> All retransmittable Initial packets works for me, if the goal is to avoid including it in ACK-only Initials.

That requires using knowledge of the packet content to format and validate the header, which doesn't look right. Also, we are making assumptions here that middle boxes properly maintain state, which is dubious.

I would prefer to just include the token in every initial packet. There is overhead indeed but that's only on the last ACK. And we can optimize that out by using implicit ACK.

 -- Christian Huitema

---

From: Ian Swett <[email-masked]>
Date: Thu, 29 Nov 2018 11:55:34 -0500

That's fine with me.  I'd also really like to get this written down before
we forget again.

On Thu, Nov 29, 2018 at 11:39 AM Christian Huitema <[email-masked]>
wrote:

> That requires using knowledge of the packet content to format and validate
> the header, which doesn't look right. Also, we are making assumptions here
> that middle boxes properly maintain state, which is dubious.
>
> I would prefer to just include the token in every initial packet. There is
> overhead indeed but that's only on the last ACK. And we can optimize that
> out by using implicit ACK.
>
>  -- Christian Huitema
>

---

From: Dmitri Tikhonov <[email-masked]>
Date: Thu, 29 Nov 2018 11:56:57 -0500

Works for me as well.

  - Dmitri.