Subject: [TLS] Interaction between cookies and middlebox compat mode

From: Matt Caswell <[email-masked]>
Date: Wed, 27 Dec 2017 19:17:20 +0000

Consider the scenario where a server is operating statelessly (i.e.
using the cookie extension) and a client is operating in middlebox
compat mode.

In that case the client sends an initial ClientHello and receives a
ServerHello(HRR) back with a cookie in it. Before it sends its second
ClientHello it first sends a dummy CCS.

>From the server perspective it is operating statelessly so until it gets
a ClientHello with a valid cookie in it, any message it receives is
considered the "first" one. Therefore, because the server has forgotten
about the initial interaction with the client, the first message it sees
is a CCS.

Draft-22 says this:

  "An implementation may receive an unencrypted record of type
   change_cipher_spec consisting of the single byte value 0x01 at any
   time during the handshake and MUST simply drop it without further
   processing."

Does "any time during the handshake" include the very first message it
receives? If so then this has implications for servers that accept
connections from TLSv1.2 (and below) clients (regardless of whether the
server is stateless or not), i.e. an incoming connection that starts
with a CCS and then goes on to negotiate TLSv1.2 would be accepted which
seems odd.

If it doesn't mean that then a stateless server will receive a CCS as
the first message and not know how to handle it.

Maybe there are different rules for handling CCS for stateless servers?
Or perhaps middlebox compat mode should never be used in a scenario
where a stateless server is being used (e.g. QUIC). Either way it seems
that some clarification of the wording would help.

Matt

---

From: Eric Rescorla <[email-masked]>
Date: Wed, 27 Dec 2017 11:33:33 -0800

> the first message and not know how to handle it.

The way that NSS handles this is to remember that the CCS was received
and then if it turns out that you negotiate TLS 1.2, you throw an error in
that case. With that said, in most of the cases where you are stateless,
you're probably going to want to ignore bogus records anyway, which would
include unexpected CCS.

-Ekr

> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Matt Caswell <[email-masked]>
Date: Thu, 28 Dec 2017 08:54:45 +0000

On 27/12/17 19:33, Eric Rescorla wrote:
> 
> 
> On Wed, Dec 27, 2017 at 11:17 AM, Matt Caswell <[email-masked]
> <mailto:[email-masked]>> wrote:
> 

So, do you believe that the correct interpretation of "any time during
the handshake" includes the first message? I think it would be helpful
to be more explicit in the text if that is the case, i.e. identify the
first point in the handshake and the last point in the handshake where
CCS is valid. There probably should also be some words about how servers
implementing older TLS versions should handle a CCS that comes first.

However, I'm concerned about the added complexity of interpreting things
that way. Suddenly a CCS arriving is no longer handled by just dropping
it and forgetting it - you now have to store state about that and
remember it later on in the process in other TLS versions. The CCS
workaround was supposed to be a simple no-op to implement and it no
longer appears that way in this interpretation.

Matt

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 28 Dec 2017 04:28:32 -0800

On Thu, Dec 28, 2017 at 12:54 AM, Matt Caswell <[email-masked]> wrote:

> the handshake" includes the first message?

Yes, this is how we have interpreted it

> I think it would be helpful

I could add those.

> longer appears that way in this interpretation.

Well, it seems like the issue here is you want the client to send CH1, CCS,
CH2
so we need the server to accept that. Am I missing something?

-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Thu, 28 Dec 2017 14:54:31 +0200

> longer appears that way in this interpretation.

To me it seems like if you are doing a stateless retry, you can not
fail the handshake if you receive CCS between the two CHs. In fact,
more generally you can not fail the handshake if you receive arbitrary
junk between the two CHs (as long as the junk does not mess framing
of the later CH).

Here "can not fail" does not mean requirement on implementation, it
is fundamential constraint due to stateless implementation (because
failing would require keeping state!).

I think there should be note about this in the specification (that
stateless implementations need to ignore arbitrary junk records and
messages before the ClientHello message).

However, this causes problems if the junk contains any handshke
messages that are fragmented. Especially so if the underlying
transport not reliable. This is the same problem as why fragmenting
ClientHello is a bad idea.

-Ilari

---

From: Matt Caswell <[email-masked]>
Date: Thu, 28 Dec 2017 16:12:52 +0000

On 28/12/17 12:28, Eric Rescorla wrote:
> Well, it seems like the issue here is you want the client to send CH1,
> CCS, CH2

The point is a stateless server will not know about CH1 at the point
that it receives CCS. Actually, as Ilari points out, there could be any
junk (including partial records) arriving between CH1 and CH2. So this
feels more like a special case for stateless servers.

In other words I would prefer to say that a CCS that arrives first is
not allowed. That simplifies the general case and requires no special
coding for servers implementing older versions of TLS. However, we add
additional words around what stateless servers do with "junk" they
receive that doesn't look like a ClientHello (i.e. they ditch it). That
"junk" would include a CCS. That seems like a much cleaner solution.

Matt

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 28 Dec 2017 09:42:27 -0800

On Thu, Dec 28, 2017 at 8:12 AM, Matt Caswell <[email-masked]> wrote:

> that it receives CCS.

Well, sort of.

Specifically, there are three valid things that a server (whether stateless
or stateful) can receive:

- CH1 [I.e. a CH without a cookie]
- CH2 [i.e., a CH with a cookie]
- CCS

It should respond to any other message with an alert and abort the
handshake.
A stateful server should also tear down the transport connection, so that
subsequent
messages are considered an error. This obviously isn't an option for a
stateless server,
so, yes, a stateless server might in principle receive arbitrary amounts of
junk
before CH1 or between CH1 and CH2, and it would still survive, albeit by
sending alerts.

> Actually, as Ilari points out, there could be any
> coding for servers implementing older versions of TLS.

This issue only seems to arise for people who are both doing TLS 1.3 and
TLS 1.2 *and* doing stateless implementations, which is kind of an odd
configuration because a number of the conditions in TLS 1.3 that involve
HRR (and thus can be stateless). It doesn't arise for QUIC (because no
TLS 1.2) and mostly doesn't arise for DTLS (if you reject all kinds of
junk).  Or am I wrong?

However, we add
> "junk" would include a CCS. That seems like a much cleaner solution.

I'm not enthusiastic about this, as it entails not alerting in cases of
clear
protocol error.

-Ekr

---

From: Matt Caswell <[email-masked]>
Date: Thu, 28 Dec 2017 17:51:28 +0000

On 28/12/17 17:42, Eric Rescorla wrote:
> 
> 
> On Thu, Dec 28, 2017 at 8:12 AM, Matt Caswell <[email-masked]
> A stateful server should also tear down the transport connection, so
> that subsequent
> so, yes, a stateless server might in principle receive arbitrary amounts
> of junk

Correct, although technically the wording of draft-22 (in your
interpretation) *requires* that a server receiving a CCS first MUST
ignore it - even though that should never happen except in the weird
scenario above. That is why I prefer to say that a CCS arriving first is
always an error for the general case.

Matt

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 28 Dec 2017 09:55:18 -0800

> always an error for the general case.

Well, you can receive a CCS first any time you're stateless. What's unusual
is having to subsequently reject it if you are stateless and *then*
negotiate
1.2. My point is that this doesn't seem like a very big hardship for the
reasons
above.

-Ekr

---

From: Matt Caswell <[email-masked]>
Date: Thu, 28 Dec 2017 18:02:42 +0000

On 28/12/17 17:55, Eric Rescorla wrote:
> 
> On Thu, Dec 28, 2017 at 9:51 AM, Matt Caswell <[email-masked]
>     > On Thu, Dec 28, 2017 at 8:12 AM, Matt Caswell <[email-masked] <mailto:[email-masked]>
>     > <mailto:[email-masked] <mailto:[email-masked]>>> wrote:
>     >
>     >
>     >
>     >     >     I think it would be helpful
>     >     >     to be more explicit in the text if that is the case,
>     i.e. identify the
>     >     >     first point in the handshake and the last point in the
>     handshake where
>     >     >     CCS is valid. There probably should also be some words
>     about how servers
>     >     >     implementing older TLS versions should handle a CCS that
>     comes first.
>     >     >
>     >     >
>     >     > I could add those.
>     >     >
>     >     >
>     >     >     However, I'm concerned about the added complexity of
>     interpreting things
>     >     >     that way. Suddenly a CCS arriving is no longer handled
>     by just dropping
>     >     >     it and forgetting it - you now have to store state about
>     that and
>     >     >     remember it later on in the process in other TLS
>     versions. The CCS
>     >     >     workaround was supposed to be a simple no-op to
>     implement and it no
>     >     >     longer appears that way in this interpretation.
>     >     >
>     >     >
>     >     > Well, it seems like the issue here is you want the client to
>     send CH1,
>     >     > CCS, CH2
>     >     > so we need the server to accept that. Am I missing something?
>     >

I must be missing your point. According to the spec as it stands even
with a stateful server I MUST ignore a CCS that comes first. Since this
is a stateful server it may end up negotiating TLSv1.2 - which requires
us to abort the handshake if the CCS comes first. No sensible
implementation will ever send a CCS first in this scenario, so why am I
required by the spec to ignore it and implement the extra complexity in
TLSv1.2 handling?

In reality I wouldn't bother to implement this which would make me
technically non-compliant. I would prefer it if the wording were fixed
to not require this.

Matt

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 28 Dec 2017 10:06:46 -0800

On Thu, Dec 28, 2017 at 10:02 AM, Matt Caswell <[email-masked]> wrote:

> <mailto:[email-masked]>

OK, I understand your point now, I think it's fine to reject this case as
long as
you properly handle things in the stateless case. If you want to submit a
PR,
I will take a look.

-Ekr

---

From: Matt Caswell <[email-masked]>
Date: Fri, 29 Dec 2017 10:54:41 +0000

On 28/12/17 18:06, Eric Rescorla wrote:
> OK, I understand your point now, I think it's fine to reject this case
> as long as
> you properly handle things in the stateless case. If you want to submit
> a PR,
> I will take a look.

https://github.com/tlswg/tls13-spec/pull/1129

Matt

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 30 Dec 2017 13:07:54 +0200

> feels more like a special case for stateless servers.

Stateless servers also have the problem of dealing with nasty things
like fragmented ClientHello messages (yuck) or other initial fragmented
messages (which should not happen outside attacks).

And unlike DTLS where one can detect subsequent fragments of message,
this is not possible in TLS. And since one can not commit state for
each connection, the mitigations are much more limited.

I suppose one way of handing things is to send a fatal-level 
unexpected_message alert (of course without tearing connection down,
since there is nothing to tear down) in response to any handshake
record that does not start with 0x01 byte unless there is pending
reassembly state or connection state.

The reassembly states would be limited in number (possibly to 0)
and and size to avoid DoS. What alert to use if the message is too
large to reassemble (if there are 0 reassembly states, any message
is too big to reassemble)?

Lower-layer reassembly might be possibility. That doesn't allow
ClientHello messages larger than 16kB, but that would be give
considerably more freedom with Post-Quantum key exchanges than
<1232 bytes one gets with single packets[1]. I think QUIC does
not support any kind of reassembly of Client Hello.

[1] NIST PQC Round1 has only 3 candidates (LAKE, Round2 and SIKE) that
have triple digits public key sizes at "level 3 security" below 800
bytes (in fact, all three are somewhere between 500 and 600 bytes).

Those are pretty aggressive (or slow in case of SIKE), and the sizes
might grow quite a bit as new attacks are discovered.

With 3kB space for public keys, there would be considerably more
candidates (and space for parameter adjustments). These include
even ~20 year old schemes like NTRU (which is one of the candidates).

-Ilari