Subject: Re: [quicwg/base-drafts] Address validation is stateless reject (#482)

From: Martin Thomson <[email-masked]>
Date: Mon, 01 May 2017 02:39:21 -0700

martinthomson commented on this pull request.

> @@ -1059,6 +1059,27 @@ could either be absent or it could indicate that an address validation token is
 not present.

+### Stateless Address Validation
+
+A server can use the cookie extension to store all state necessary to continue

It's in TLS.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114112525

---

From: Martin Thomson <[email-masked]>
Date: Mon, 01 May 2017 02:41:07 -0700

+A server can use the cookie extension to store all state necessary to continue
+the connection.  This allows a server to avoid committing state for clients that
+have unvalidated source addresses.
+
+For instance, a server could use a statically-configured key to encrypt the
+information that it requires and include that information in the cookie.  In
+addition to address validation information, a server that uses encryption also
+needs to be able recover the hash of the ClientHello and its length, plus any
+information it needs in order to reconstruct the HelloRetryRequest.
+
+A client proceeds as though the server were stateful.  It constructs a second
+ClientHello and sends it following the initial ClientHello.  Note that this
+means a server that doesn't maintain state between the intial and second
+ClientHello will receive the second ClientHello in STREAM frames with a non-zero
+offset.  The resulting gap in the received stream data needs to be ignored and

This isn't a hack, it's just physics.  The first ClientHello takes N bytes, the second takes M.  The offset for the first is 0, the second is N because it follows immediately after.  The point here is that the client proceed as if this were the same connection; the server - if it does a stateless reject - has to account for that and deal with the fact that after the reject it won't ever receive the first N bytes - they were already received.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114112599

---

From: MikkelFJ <[email-masked]>
Date: Mon, 01 May 2017 03:57:05 -0700

mikkelfj commented on this pull request.

Why is the stream abstraction important during handshake?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114116310

---

From: MikkelFJ <[email-masked]>
Date: Mon, 01 May 2017 06:59:37 -0700

Here is a proposal that might help simplify handshake without interfering with 0-RTT stream semantics. For 1-rtt it could be required that streams are not permitted before handshake is complete. https://github.com/quicwg/base-drafts/issues/489 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114127887

---

From: Ryan Hamilton <[email-masked]>
Date: Mon, 01 May 2017 16:33:45 -0700

RyanAtGoogle commented on this pull request.

Is this predicated on the idea that a ClientHello must fit into a single packet? If a ClientHello can span multiple packets, then I don't think I understand how a server would distinguish between a packet which contains part 2 of a ClientHello from a packet which contains a post-stateless-reject ClientHello. 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114223760

---

From: Martin Thomson <[email-masked]>
Date: Mon, 01 May 2017 16:43:33 -0700

We already require that ClientHello fits in a single packet.  Even the possibility of a two-part ClientHello makes DoS mitigation very difficult.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114224883

---

From: janaiyengar <[email-masked]>
Date: Mon, 01 May 2017 17:36:05 -0700

janaiyengar commented on this pull request.

 not present.

Just to be pedantic: please use "the TLS cookie extension."

What's the reason for making it transparent to the client? Why can the client not try with a new connection ID?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114222543

---

From: Martin Thomson <[email-masked]>
Date: Mon, 01 May 2017 18:15:57 -0700

The server is the one that cares, so it takes on the extra effort of dealing with the complexity.  Why would the client retry with a new connection ID?

Also, logically, TLS maintains a handshake transcript.  Having the transcript appear to be on the same connection is less surprising than the odd gap you get with a stateless reject.  Besides, it's not a gap to the client, just the server.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114233541

---

From: janaiyengar <[email-masked]>
Date: Mon, 01 May 2017 18:43:44 -0700

I'm trying to understand how this would work at the server and it's not clear to me. So, when the server receives a packet that basically has one stream frame with stream ID 1 and offset 1050, what should it do? Should it deliver it up to TLS, or should it buffer? Since this retry logic is only known to the TLS part, how is QUIC to determine that this is a retry and not just a reordered packet?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114235720

---

From: Martin Thomson <[email-masked]>
Date: Mon, 01 May 2017 18:59:08 -0700

Yes, deliver it to TLS.  When TLS asks whether the address validation is correct, it will provide the address validation token.  That token should include the length of the original ClientHello.  If TLS doesn't provide a token, or the length doesn't match, then it's bad and you can abort at that point.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114236897

---

From: abraud <[email-masked]>
Date: Tue, 02 May 2017 00:54:54 -0700

abraud commented on this pull request.

What about the packet number on the SHLO ? 
>From what i gathered, the one on the retryRequest was randomly generated. If we generate one randomly again then the client will most likely have issues.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114265073

---

From: abraud <[email-masked]>
Date: Tue, 02 May 2017 00:56:32 -0700

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114265279

---

From: MikkelFJ <[email-masked]>
Date: Tue, 02 May 2017 01:00:27 -0700

And what are the rules for dealing with other streams and retransmittable frames such as ping in the initial packet?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114265837

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 02 May 2017 10:01:31 -0700

I can understand how this could be made to work, but I worry a bit about the state of the crypto stream being different between the two endpoints. The client believes it has send 2 ClientHellos as bytes [0,N] on stream 0. If the server is required to process pre-handshake stream frames even with non-0 offsets, then it seems like it might be possible for an active attacker to rewrite the second ClientHello to start at, say, offset 2N. This would mean that any post-handshake messages from the client to the server would be ignored as duplicates.

I presume the solution to this is for the server to include in the data it sends to the client (and the client sends back to the server) the byte offset that the follow-up ClientHello is expected to start at, and to validate that when it process the follow-up ClientHello.

Does that sound right?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114369975

---

From: Martin Thomson <[email-masked]>
Date: Tue, 02 May 2017 16:01:22 -0700

@abraud is correct.  What makes this hard is that the server might have generated multiple HelloRetryRequest packets, each with their own randomized packet number.  That's a real issue because it means that it can't save that value without changing the HelloRetryRequest.  Then the client will receive two conflicting bits of stream data.  That's bad because we allow endpoints to reject connections if that happens.  Separately, @janaiyengar suggests that we treat a stateless reject as a clean break.  I will see if I can use that; it will need a lot more text :(

@mikkelfj, you can't send anything other than a STREAM frame.

@RyanAtGoogle, you got it right.  The server saves the offset, then pretends that it received those missing bytes once it has validated the token.  If we take @janaiyengar's suggestion though, that's won't be necessary.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114445062

---

From: janaiyengar <[email-masked]>
Date: Wed, 03 May 2017 15:32:45 -0700

Yeah, this doesn't need QUIC connection continuity, just TLS continuity. A new connection with a new connection ID should achieve that. (The connection doesn't need to go back to the same server, does it?)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114668743

---

From: Martin Thomson <[email-masked]>
Date: Wed, 03 May 2017 15:44:08 -0700

The whole point of a stateless reject is to avoid creating state, so if it had to go back to the same server, something is wrong :)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114670477

---

From: janaiyengar <[email-masked]>
Date: Wed, 03 May 2017 16:47:15 -0700

Good point.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#discussion_r114678473

---

From: Martin Thomson <[email-masked]>
Date: Wed, 10 May 2017 17:20:29 -0700

Closed #482 via #493.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/482#event-1077399827