Subject: [quicwg/base-drafts] Clarification: HRR which does not perform address validation (#1094)

From: Tatsuhiro Tsujikawa <[email-masked]>
Date: Sun, 04 Feb 2018 13:49:34 +0000 (UTC)

https://quicwg.github.io/base-drafts/draft-ietf-quic-tls.html#rfc.section.7.1 says that HRR may be sent for a reason other than address validation (e.g., requesting different client key share).
In that case, should such HRR also be sent in Retry packet?

https://quicwg.github.io/base-drafts/draft-ietf-quic-tls.html#rfc.section.7.1.2 says that HRR must be sent in Retry packet.  So it feels like it should.

I tried several endpoints in order to see the beahviour when HRR is generated without address validation.  I saw 2 actions.  One action is HRR is received in Retry packet.  Another is in regular Handshake packet.

* quicly: Handshake
* picoquic: Retry
* mozquic: Handshake
* ngtcp2: Handshake

If HRR should be sent in HRR which does not perform address validation, then server should perform just like stateless retry, but in this case it is stateful, no cookie is required.  Still server has to re-generate handshake secret using conneciton ID in 2nd Initial packet from client (which was chosen by server).  Is that 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/issues/1094

---

From: Martin Thomson <[email-masked]>
Date: Sun, 04 Feb 2018 23:13:09 +0000 (UTC)

Yes, this is one of the most horrible parts of the mapping.  I don't have an easy answer for you.  We should discuss it.  The intent was to have HRR -> Retry always, but since that's hard to see without looking at the packet, maybe we should lift that restriction.

If we allow HRR in a Handshake packet, then the second ClientHello will probably need to be sent in a Handshake packet also.  That's annoying, but it avoids the question about a second Initial and its construction.

-- 
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/issues/1094#issuecomment-362948613

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 05 Feb 2018 02:15:03 +0000 (UTC)

> If we allow HRR in a Handshake packet, then the second ClientHello will probably need to be sent in a Handshake packet also. That's annoying, but it avoids the question about a second Initial and i…

Having seen more than one implementation crash when receiving a stateful HRR in the interops, my preference goes to prohibiting the use of them in QUIC.

-- 
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/issues/1094#issuecomment-362963600

---

From: janaiyengar <[email-masked]>
Date: Sun, 04 Feb 2018 20:50:36 -0800

> Having seen more than one implementation crash when receiving a stateful
> HRR in the interops, my preference goes to prohibiting the use of them in
> QUIC.
>

It seems to me that this is likely because the spec needs more clarity, not
because this is fundamentally bug-prone. Do you agree? If we can handle
this case by explicitly stating behavior for stateful and stateless HRRs, I
imagine that will help implementations to not crash.

-- 
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/issues/1094#issuecomment-362980979

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 05 Feb 2018 05:19:53 +0000 (UTC)

> It seems to me that this is likely because the spec needs more clarity, not because this is fundamentally bug-prone. Do you agree?

I kind of agree.

The other issue aside from documentation is that it might not be clear to a QUIC implementor how to trigger both stateful and stateless HR on a TLS stack that the person is using. Having a feature that is hard to test is a potential source of bugs.

That said, it could also be true that TLS libraries do not expose an API to reject a stateful HRR. Without the existence of such API, it is impossible to mandate all retries to be stateless.

So I wouldn't oppose if we decide to allow use of stateful retry.

-- 
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/issues/1094#issuecomment-362984365

---

From: Patrick McManus <[email-masked]>
Date: Mon, 05 Feb 2018 14:17:06 +0000 (UTC)

we might be able to specify this, but this class of issue is inherent in
having an abstracted stream 0 "just carry tls".. its very hard to know
what's going on over there.. is it hrr, is it session tickets, is it alerts?

A tighter bundling to the security layer might make this more robust.

On Mon, Feb 5, 2018 at 12:19 AM, Kazuho Oku <[email-masked]>
wrote:

> It seems to me that this is likely because the spec needs more clarity,
> not because this is fundamentally bug-prone. Do you agree?
>
> I kind of agree.
>
> The other issue aside from documentation is that it might not be clear to
> a QUIC implementor how to trigger both stateful and stateless HR on a TLS
> stack that the person is using. Having a feature that is hard to test is a
> potential source of bugs.
>
> That said, it could also be true that TLS libraries do not expose an API
> to reject a stateful HRR. Without the existence of such API, it is
> impossible to mandate all retries to be stateless.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/quicwg/base-drafts/issues/1094#issuecomment-362984365>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAP5s4vkXCPHlcWBtmIOXlOt3XuiIoQ7ks5tRo93gaJpZM4R4kvM>
> .
>

-- 
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/issues/1094#issuecomment-363096814

---

From: ianswett <[email-masked]>
Date: Mon, 05 Feb 2018 14:24:26 +0000 (UTC)

Possibly naive question: Can we get rid of the RETRY packet type and use HANDSHAKE instead?

-- 
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/issues/1094#issuecomment-363098895

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 05 Feb 2018 14:52:55 +0000 (UTC)

@ianswett I could well be wrong, but I do not think that is possible.

The Cookie extension of TLS 1.3 has too purposes:
> * Allowing the server to force the client to demonstrate reachability at their apparent network address (thus providing a measure of DoS protection). This is primarily useful for non-connection-oriented transports (see [RFC6347] for an example of this).
> * Allowing the server to offload state to the client, thus allowing it to send a HelloRetryRequest without storing any state. The server can do this by storing the hash of the ClientHello in the HelloRetryRequest cookie (protected with some suitable integrity algorithm).
> [TLS 1.3 draft 23 section 4.2.2](https://tlswg.github.io/tls13-spec/draft-ietf-tls-tls13.html#rfc.section.4.2.2)

I do not think that if the cookie is in fact stateless is distinguishable from TLS client's perspective. Therefore, we need to send a signal to the client at QUIC layer.

-- 
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/issues/1094#issuecomment-363107414

---

From: ianswett <[email-masked]>
Date: Mon, 05 Feb 2018 15:22:47 +0000 (UTC)

Thanks Kazuho, that makes sense.  Should the fact it's stateless be visible?

My impression is that the different long header packet types are more hassle than they're worth, especially if we're moving to large connection IDs.  We already got rid of the version negotiation type, which was a nice change and there's text on when to use each type in the transport draft, but it's not clear to me why they're necessary.

The model of QUIC is "Run TLS over Stream 0", but in this case it seems like we're relying on the QUIC transport to tell us how to process the TLS payload, is a bit odd.  I'm not a TLS expert, but how hard would it be to achieve a pure model of "Run TLS over Stream 0"?  Is the knowledge of stateful/statelessness in retries the only issue?

-- 
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/issues/1094#issuecomment-363116755

---

From: Martin Thomson <[email-masked]>
Date: Mon, 05 Feb 2018 21:21:21 +0000 (UTC)

It's probably a matter of what signal we want to send here.  The purpose of Retry is unclear at this point.  @kazuho is right in pointing out the dual purpose of HRR cookies, which means that it is never possible to know if the server is discarding state or merely using the cookie to verify address ownership.  

The rules for processing of Retry and Handshake are now very close, but the difference is significant: they differ in the construction of the packet number and stream 0 sequence numbers.  Retry contains a signal that the server intends to forget that part of the transport state.

If the point of using Retry is to signal to the client that the server intends to start over at the transport layer (recognizing that TLS always continues, even in the stateless case), then that suggests that using Handshake for HRR is acceptable if the server only needs a new key share or something like that.

But there is value in having a consistent rule that says HRR always goes in the Retry.  That was the assumption going in to this.  

To @mcmanus' suggestion of a stronger signal, yes, if the intent is to maintain this rule, then we need a wider API.  Frankly, I don't know how to do this in practice though.

-- 
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/issues/1094#issuecomment-363225235

---

From: janaiyengar <[email-masked]>
Date: Mon, 05 Feb 2018 22:01:30 +0000 (UTC)

Is my understanding correct that for stateful operation, the only use-case is checking client reachability? We have a mechanism in the transport for doing this: PATH_CHALLENGE/RESPONSE, which are explicitly allowed during handshake.

Is there any other reason to allow stateful HRRs? If not, I'm with Kazuho in disallowing this for QUIC entirely. (How we enforce this is another issue...)

-- 
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/issues/1094#issuecomment-363236071

---

From: Martin Thomson <[email-masked]>
Date: Mon, 05 Feb 2018 22:07:55 +0000 (UTC)

HRR is used when the client uses the wrong key share as well.

-- 
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/issues/1094#issuecomment-363237752

---

From: janaiyengar <[email-masked]>
Date: Mon, 05 Feb 2018 14:09:28 -0800

Yes, of course. I should've added that it seems reasonable to start over in that case as well.

-- 
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/issues/1094#issuecomment-363238178

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 05 Feb 2018 15:19:23 -0800

@martinthomson 
> To @mcmanus' suggestion of a stronger signal, yes, if the intent is to maintain this rule, then we need a wider API. Frankly, I don't know how to do this in practice though.

I think that something like below would work, assuming that the intent is to force use of Retry packet when the server sends HRR.

* server-side TLS API provides an option to emit stateless retry when sending HRR, and QUIC servers activate that option
  * as an example, picotls already has a boolean flag that enforces such behavior (sadly, it is called `retry_uses_cookie`, it should have been named `retry_stateless`)
* when observing a Retry packet, a QUIC client should perform stateless retry
  * this does not change
* when observing a Handshake packet, a QUIC client must confirm that the state of the TLS stack has changed to something that indicates that the handshake is complete, when the stack emits a message in response

-- 
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/issues/1094#issuecomment-363254856

---

From: Mike Bishop <[email-masked]>
Date: Mon, 05 Feb 2018 23:40:20 +0000 (UTC)

While TLS 1.3 often has the property that after the client responds to a Handshake packet, the handshake is complete, that’s not necessarily a general truth.  It might be the case that the client can emit some messages in response to a Handshake packet and still be waiting for more from the server.  Suppose, for example, that it saw the server’s CertificateRequest and emitted the Certificate/CertificateVerify, but hasn’t yet seen the server’s Finished and so hasn’t emitted its own Finished yet.  I believe that’s a possibility?

From: Kazuho Oku [mailto:[email-masked]]
Sent: Monday, February 5, 2018 3:19 PM
To: quicwg/base-drafts <[email-masked]>
Cc: Subscribed <[email-masked]>
Subject: Re: [quicwg/base-drafts] Clarification: HRR which does not perform address validation (#1094)

@martinthomson<https://github.com/martinthomson>

To @mcmanus<https://github.com/mcmanus>' suggestion of a stronger signal, yes, if the intent is to maintain this rule, then we need a wider API. Frankly, I don't know how to do this in practice though.

  *   server-side TLS API provides an option to emit stateless retry when sending HRR, and QUIC servers activate that option
     *   as an example, picotls already has a boolean flag that enforces such behavior (sadly, it is called retry_uses_cookie, it should have been named retry_stateless)
  *   when observing a Retry packet, a QUIC client should perform stateless retry
     *   this does not change
  *   when observing a Handshake packet, a QUIC client must confirm that the state of the TLS stack has changed to something that indicates that the handshake is complete, when the stack emits a message in response

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<https://github.com/quicwg/base-drafts/issues/1094#issuecomment-363254856>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AEE2hSgF22Y05OtowGSnp29fpzW5YSwMks5tR4x5gaJpZM4R4kvM>.

-- 
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/issues/1094#issuecomment-363259140

---

From: Martin Thomson <[email-masked]>
Date: Mon, 05 Feb 2018 16:00:29 -0800

@MikeBishop is right (and I edited his reply because email replies on GitHub suck).

What we would need is a signal from the cryptographic handshake implementation that it pausing the handshake.  After thinking on this some more, I might consider adding a function to NSS that allows an application to query whether the socket state can be discarded safely.  For NSS that would mean that we sent HRR (our HRR is always stateless).  That's complicated if you have a stack that might not always generate a stateless HRR, though it is made reliable if you can force HRR to be stateless (like `retry_stateless`).

Would that sort of API work for others?  This will be annoying to write up, but I can make it happen.

(@kazuho, we use a callback API, which gives the app more control, but the effect is the same.  The callback is - of course - more complicated.)

-- 
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/issues/1094#issuecomment-363262858

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 06 Feb 2018 01:44:25 +0000 (UTC)

@MikeBishop Thank you for pointing that I out. I tend to forget about client authentication.

@martinthomson 
> Would that sort of API work for others?

That would work for picotls. OTOH I am no longer sure if we need to enforce use of Retry in case of HRR, considering the fact that there are other cases of stateful handshakes that span across multiple roundtrips.

-- 
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/issues/1094#issuecomment-363282580

---

From: Christian Huitema <[email-masked]>
Date: Tue, 06 Feb 2018 02:59:45 +0000 (UTC)

@tatsuhiro-t observed that Picoquic's behavior differs from that of other servers:

    quicly: Handshake
    picoquic: Retry
    mozquic: Handshake
    ngtcp2: Handshake

This was done deliberately, because I found handling the stateful HRR quite difficult. But when Picotls issues a stateless HRR, it always appends a cookie, thus falling in the legitimate "address verification" code path.

-- 
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/issues/1094#issuecomment-363294961