Subject: [TLS] What does it mean to not include 0-RTT message in the handshake hash?

From: Christian Huitema <[email-masked]>
Date: Tue, 22 Dec 2015 01:49:32 +0000

The handshake hash specification in section 7.1 says:

  Where handshake_hash includes all messages up through the
  server CertificateVerify message, but not including any
  0-RTT handshake messages (the server's Finished is not
  included because the master_secret is need to compute
  the finished key).

What are the 0-RTT handshake messages that should be excluded? The diagram in 6.2.2 shows the client hello and its extensions, the optional client cert and client cert verify, and a finished message. Presumably, the handshake hash does not exclude the client hello. What is the intent there? Is the sentence meant to exclude the 0-RTT cert, cert verify and finished messages?

-- Christian Huitema

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 21 Dec 2015 18:02:46 -0800

> The handshake hash specification in section 7.1 says:

You're referring the editor's copy (WIP-11), right?

> What are the 0-RTT handshake messages that should be excluded? The diagram
> in 6.2.2 shows the client hello and its extensions, the optional client
> cert and client cert verify, and a finished message. Presumably, the
> handshake hash does not exclude the client hello. What is the intent there?
> Is the sentence meant to exclude the 0-RTT cert, cert verify and finished
> messages?
>

I was just going over this text today and realized it's kind of confusing
(and the whole "handshake_hash" abstraction is starting to be less useful
in light of the PR#316 reframing of the authentication block).

Unless I'm confused (which is possible given the time of night),
the intention, as you say, is to separate out the 0-RTT handshake
messages i.e., (cert, cert verify, finished) from the 1-RTT computations.
However,  as indicated in S 6.3.3. and 6.3.4:

- The 0-RTT Certificate Verify covers the ClientHello and Certificate
  (as well as the cached messages from the server shown in the
  table in 6.3.4)
- The 0-RTT Finished includes the above messages plus the
  CertificateVerify.

Trying to figure out the best way to clarify this text. PRs welcome :)

-Ekr

---

From: Christian Huitema <[email-masked]>
Date: Tue, 22 Dec 2015 02:25:44 +0000

> You're referring the editor's copy (WIP-11), right?

Yes.
...
> in light of the PR#316 reframing of the authentication block).

Yes, the "handshake hash" is indeed confusing. Specifying something like "all messages up to <some point>" is simple enough. But there are several such points, used at different stages. Server Hello, Server certificate verify, Server Finished, Client certificate verify, Client finished.. It would be a bit more clear to give each of them its own name.

> messages i.e., (cert, cert verify, finished) from the 1-RTT computations.

OK. That does not simplify implementations using running hashes...

> Trying to figure out the best way to clarify this text. PRs welcome :)

Yes of course...

-- Christian Huitema

---

From: Martin Thomson <[email-masked]>
Date: Tue, 22 Dec 2015 13:30:01 +1100

> OK. That does not simplify implementations using running hashes...

It does if you consider the possibility of having to drop the 0-RTT data.

---

From: Dave Garrett <[email-masked]>
Date: Mon, 21 Dec 2015 21:33:17 -0500

> Yes, the "handshake hash" is indeed confusing. Specifying something like "all messages up to <some point>" is simple enough. But there are several such points, used at different stages. Server Hell…

Along this same line, I'd suggest getting rid of "session_hash", at least as-is. Instead, just use "handshake_hash" for everything and specify what's included at each use. "Session hash" is just another term that has to be referenced, when it's just the final state of the handshake hash. The term doesn't really add anything unless every separate stage of the handshake hash was named separately (in which case, "handshake_hash_*" naming might be more clear)

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 21 Dec 2015 18:40:39 -0800

On Mon, Dec 21, 2015 at 6:33 PM, Dave Garrett <[email-masked]>
wrote:

> > Yes, the "handshake hash" is indeed confusing. Specifying something like
> "all messages up to <some point>" is simple enough. But there are several
> such points, used at different stages. Server Hello, Server certificate
> verify, Server Finished, Client certificate verify, Client finished.. It
> would be a bit more clear to give each of them its own name.
>
> Along this same line, I'd suggest getting rid of "session_hash", at least
> as-is. Instead, just use "handshake_hash" for everything and specify what's
> included at each use. "Session hash" is just another term that has to be
> referenced, when it's just the final state of the handshake hash.

I tend to agree

> The term doesn't really add anything unless every separate stage of the
> handshake hash was named separately (in which case, "handshake_hash_*"
> naming might be more clear)

Yeah, that might work.

I'm putting the final touches on draft-11 and will see what I can do to
clarify this.

Thanks
-Ekr

---

From: Christian Huitema <[email-masked]>
Date: Thu, 24 Dec 2015 20:40:26 +0000

> It does if you consider the possibility of having to drop the 0-RTT data.

That's right. In fact, it may be a good idea to add to the spec a description of a "Failed 0-RTT handshake." If I understand correctly, the following will happen:

* Server will receive the client hello, ignore the Early Data Indication extension, and proceed as in 1-RTT.
* Server will indicate that by not adding an Early Data Indication to the server hello.
* Server will receive a series of 0-RTT messages that it cannot decipher, and just drop the messages.
* Client will receive server hello, and proceed as per 1-RTT. Client API will signal that 0-RTT data was lost, application may decide to retransmit.
* Server may send client authentication requests. Client will have to repeat the authentication messages, even if it already sent them as 0-RTT.

In that scenario, the handshake hash cannot include the 0-RTT messages, since the server does not in fact receive them, and they do not contribute to the state of the connection. 

We can of course debate whether the 0-RTT messages should also not be included in the hash if the 0-RTT exchange was successful, the messages were received, and they contributed to the state of the connection. If they are not included, then the "Finished" HMAC does not offer a protection against tampering. This may open the possibility of some kind of substitution or replay attack.

The failed 0-RTT handshake scenario also has interesting consequences on the Record layer. We have a legitimate scenario in which received records cannot be decrypted. This should not trigger alarms. And the numbering scheme should be robust against these missing records.

-- Christian Huitema

---

From: Dave Garrett <[email-masked]>
Date: Thu, 24 Dec 2015 16:26:41 -0500

> The failed 0-RTT handshake scenario also has interesting consequences on the Record layer. We have a legitimate scenario in which received records cannot be decrypted. This should not trigger alarm…

Do we have anything that protects against an intermediary stripping 0RTT messages from a handshake to force a fallback?

Could we just make the handshake hash use the encrypted messages, regardless of if it can decrypt them? (maybe for all messages?)

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 24 Dec 2015 16:44:00 -0500

On Thu, Dec 24, 2015 at 3:40 PM, Christian Huitema <[email-masked]>
wrote:

> That's right. In fact, it may be a good idea to add to the spec a
> description of a "Failed 0-RTT handshake." If I understand correctly, the
> following will happen:
>
> * Client will receive server hello, and proceed as per 1-RTT. Client API
> will signal that 0-RTT data was lost, application may decide to retransmit.
> * Server may send client authentication requests. Client will have to
> repeat the authentication messages, even if it already sent them as 0-RTT.
>

This seems exactly correct.

In that scenario, the handshake hash cannot include the 0-RTT messages,
> since the server does not in fact receive them, and they do not contribute
> to the state of the connection.
>

Correct.

We can of course debate whether the 0-RTT messages should also not be
> included in the hash if the 0-RTT exchange was successful, the messages
> were received, and they contributed to the state of the connection. If they
> are not included, then the "Finished" HMAC does not offer a protection
> against tampering. This may open the possibility of some kind of
> substitution or replay attack.
>

They are included in the client's 0-RTT Finished, so as long as SS is not
compromised, you should not be able to modify them. They are not protected
against modifications if SS is compromised, whereas other messages are
covered by the server's signature.

The failed 0-RTT handshake scenario also has interesting consequences on
> the Record layer. We have a legitimate scenario in which received records
> cannot be decrypted. This should not trigger alarms. And the numbering
> scheme should be robust against these missing records.

Yes. Resetting the sequence number as proposed by Fournet et al. and
in WIP-11 makes this easier.

-Ekr

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 24 Dec 2015 16:48:58 -0500

On Thu, Dec 24, 2015 at 4:26 PM, Dave Garrett <[email-masked]>
wrote:

> > > On 22 December 2015 at 13:25, Christian Huitema <[email-masked]
> >
> > > wrote:
> Do we have anything that protects against an intermediary stripping 0RTT
> messages from a handshake to force a fallback?
>

Yes:
1. The EarlyDataIndication tells the server that some 0-RTT messages are
coming.
2. The Finished in the 0-RTT flight covers the entire handshake flight,
thus preventing
tampering with those messages.
3. The server's Finished covers the ClientHello, thus preventing tampering
with that.

-Ekr

Could we just make the handshake hash use the encrypted messages,
> regardless of if it can decrypt them? (maybe for all messages?)
>
>
> Dave
>
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Dave Garrett <[email-masked]>
Date: Thu, 24 Dec 2015 17:01:48 -0500

> 3. The server's Finished covers the ClientHello, thus preventing tampering

#1 & #3 are easily dealt with by injecting bogus 0-RTT messages that get rejected, at which point a 0RTT could be prevented and we won't get to #2.

So, the client sends a handshake with 0RTT, an intermediary strips it and replaces it with something that fills the slot, but will get rejected, the server rejects it and falls back to 1RTT, and then the client would have to accept this. This intermediary thus has the power to force any 0RTT attempt to fall back to 1RTT.

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 24 Dec 2015 17:14:17 -0500

On Thu, Dec 24, 2015 at 5:01 PM, Dave Garrett <[email-masked]>
wrote:

> #1 & #3 are easily dealt with by injecting bogus 0-RTT messages that get
> rejected, at which point a 0RTT could be prevented and we won't get to #2.
>
> So, the client sends a handshake with 0RTT, an intermediary strips it and
> replaces it with something that fills the slot, but will get rejected, the
> server rejects it and falls back to 1RTT, and then the client would have to
> accept this. This intermediary thus has the power to force any 0RTT attempt
> to fall back to 1RTT.
>

This doesn't sound correct.

1. The client sends a ClientHello with an EarlyDataIndication indicating
configuration=C
(and server key g^s) and ClientHello.key_share = x.

2. The server processes the ClientHello and determines whether 0-RTT will
be accepted
or rejected based purely on the ClientHello. I.e., it doesn't need to read
any more messages
before deciding this [0]. If it decides to accept 0-RTT then it expects the
next messages to
be 0-RTT handshake messages encrypted with SS = g^xs. If those messages
don't decrypt
properly, then it needs to fail the entire connection (fatal alert with
bad_record_mac).

3. The attacker *could* modify the ClientHello to replace C with C', which
would cause
the server to fall back to 1-RTT, but then the server's CertificateVerify
and Finished would
both be incorrect, causing the handshake to fail when the client tries to
process them.

If you still think I'm wrong here, it would help me if you provide a ladder
diagram indicating
the attack you are concerned about.

Thanks,
-Ekr

[0] Technically speaking, it should be possible to send ServerHello before
even reading
the remainder of the first flight.

---

From: Dave Garrett <[email-masked]>
Date: Thu, 24 Dec 2015 17:48:25 -0500

On Thursday, December 24, 2015 05:14:17 pm Eric Rescorla wrote:
> configuration=C (and server key g^s) and ClientHello.key_share = x.
> 
> 2. The server processes the ClientHello and determines whether 0-RTT will  be accepted
> or rejected based purely on the ClientHello. I.e., it doesn't need to read any more messages
> before deciding this [0]. If it decides to accept 0-RTT then it expects the next messages to
> be 0-RTT handshake messages encrypted with SS = g^xs. If those messages don't decrypt
> properly, then it needs to fail the entire connection (fatal alert with bad_record_mac).

This last bit stops this, yes. I would prefer the spec say this very explicitly, as right now it doesn't and all I see is a line saying:
"If any of these checks fail, the server MUST NOT respond with the extension and must discard all the remaining first flight data (thus falling back to 1-RTT)."

The current text doesn't explicitly say how to handle 0-RTT data that it thinks it should be able to decrypt but can't. After rereading things a bit I think you're correct in that the correct course of action the spec currently expects is to abort, however implementers frequently err on the side of working partially vs not at all when given any wiggle room. A clear hard "MUST abort" on failed decrypt of 0RTT data would deal with this and avoid any other possible misunderstanding. Either do or do not; no try.

> 3. The attacker *could* modify the ClientHello to replace C with C', which would cause
> the server to fall back to 1-RTT, but then the server's CertificateVerify and Finished would
> both be incorrect, causing the handshake to fail when the client tries to process them.
> 
> If you still think I'm wrong here, it would help me if you provide a ladder diagram indicating
> even reading  the remainder of the first flight.

Also, I found a typo in the early data section. The config ID was referred to by two names. PR filed. ;)

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 24 Dec 2015 20:08:25 -0500

On Thu, Dec 24, 2015 at 5:48 PM, Dave Garrett <[email-masked]>
wrote:

> This last bit stops this, yes. I would prefer the spec say this very
> explicitly, as right now it doesn't and all I see is a line saying:
> "If any of these checks fail, the server MUST NOT respond with the
> extension and must discard all the remaining first flight data (thus
> falling back to 1-RTT)."

Well, this is a general requirement any time the record MAC is bad:
See http://tlswg.github.io/tls13-spec/#rfc.section.5.2.2
"If the decryption fails, a fatal “bad_record_mac” alert MUST be generated."

> The current text doesn't explicitly say how to handle 0-RTT data that it
> thinks it should be able to decrypt but can't. After rereading things a bit
> I think you're correct in that the correct course of action the spec
> currently expects is to abort, however implementers frequently err on the
> side of working partially vs not at all when given any wiggle room. A clear
> hard "MUST abort" on failed decrypt of 0RTT data would deal with this and
> avoid any other possible misunderstanding. Either do or do not; no try.
>

If you have suggested text, I'd be happy to see a PR.

> to by two names. PR filed. ;)

Merged.

-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Fri, 25 Dec 2015 10:04:18 +0200

> If you have suggested text, I'd be happy to see a PR.

Except that when server is doing 1RTT fallback and skipping 0-RTT data,
then records that get deprotect failure (is that the proper term?) are
ignored instead of generating bad_record_mac like "normal" deprotect
failure would.

Then there's also the case where server is skipping 0-RTT data for retry
(there one can recognize end of data from content-type 23 changing back
to 22).

Then one has to ensure that configuration_id's are never reused: If
client and server disagree about server-valid configuration, the result
can easily be hard failure (instead of fallback).

One server-side trick to ensure non-reuse would be to hash the server
certificate and the configuration messages (with configuration_id being
zeroes of approriate length) using e.g. SHA-256 and then use the resulting
hash as configuration_id.

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 25 Dec 2015 09:10:33 -0500

> (there one can recognize end of data from content-type 23 changing back

Correct. These need to be special cased. And of course with DTLS you
just drop such packets rather than terminating the connectin.

However, it's worth nothing that even if the first-flight handshake data
weren't encrypted, it would still not be possible to create confusion
here because the server would still be waiting for the 0-RTT Finished
message prior to being willing to accept application data from the
client.

> can easily be hard failure (instead of fallback).

Yes, agreed. I had always assumed that configuration ids were unique.

-Ekr

---

From: Dave Garrett <[email-masked]>
Date: Sun, 27 Dec 2015 02:08:10 -0500

> If you have suggested text, I'd be happy to see a PR.

Ok, I filed PR 393 with a couple sentences to clarify that 0-RTT records aren't allowed special treatment and errors on handling MUST NOT result in a 1-RTT fall back.

Dave

---

From: Christian Huitema <[email-masked]>
Date: Mon, 28 Dec 2015 04:55:16 +0000

On Saturday, December 26, 2015 9:08 PM, Dave Garrett wrote:
> > See
> https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2ftlswg.gith
> ub.io%2ftls13-
> spec%2f%23rfc.section.5.2.2&data=01%7c01%7chuitema%40microsoft.com%7
> c57c8404a1f2f41a17f8a08d30e8c8243%7c72f988bf86f141af91ab2d7cd011db4
> 7%7c1&sdata=nTdhU1cC6yaYfKvpIG4JR1vhTgs82gFYgVLJbPYskXQ%3d
> Ok, I filed PR 393 with a couple sentences to clarify that 0-RTT records aren't
> allowed special treatment and errors on handling MUST NOT result in a 1-RTT
> fall back.

Isn't that a part where TLS and DTLS will differ a lot?

For DTLS, we have to consider the packet injection threat. It is fairly easy to send some random bytes with a fake source to a UDP destination. Such attacks should not cause the DTLS association to fail! The normal behavior ought to be to just ignore UDP packets that fail to decrypt. This would cause 0-RTT rejects to just result in dropped packets. Can we ensure that the handshake protocol is robust against that?

-- Christian Huitema

---

From: Dave Garrett <[email-masked]>
Date: Mon, 28 Dec 2015 02:32:03 -0500

> For DTLS, we have to consider the packet injection threat. It is fairly easy to send some random bytes with a fake source to a UDP destination. Such attacks should not cause the DTLS association to…

One idea might be to include a hash of all early data records' ciphertext in the "early_data" extension. This lets them stay out of the handshake hash yet still have their hash be covered by it. So long as servers verify all successfully decrypted early data records against this hash before processing them further, and abort if something is missing, then this could be done safely. More complex, though.

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 28 Dec 2015 06:46:02 -0500

On Sun, Dec 27, 2015 at 11:55 PM, Christian Huitema <[email-masked]>
wrote:

> For DTLS, we have to consider the packet injection threat. It is fairly
> easy to send some random bytes with a fake source to a UDP destination.
> Such attacks should not cause the DTLS association to fail! The normal
> behavior ought to be to just ignore UDP packets that fail to decrypt. This
> would cause 0-RTT rejects to just result in dropped packets. Can we ensure
> that the handshake protocol is robust against that?
>

We obviously need to distinguish here between handshake and application
data messages, because DTLS is intended to allow loss of application data
messages.

WRT handshake messages, as I indicated before, I believe that there is
enough information in the handshake messages to prevent removal.
Namely:

1. The ClientHello contains an indication that 0-RTT handshake messages
are coming.
2. The Client's 0-RTT Finished contains a MAC of all the Client's
0-RTT messages.
3. The Server's Finished contains a MAC of the ClientHello.

Thus, provided that the client and server in fact share a configuration
(which, again, is in the ClientHello) then the server knows at the time
of receiving the first-flight Finished that he has (or has not) received
all the client's 0-RTT Handshake messages. [0].

The more interesting question, however, is what drives the DTLS state
machine forward to ensure progress in the face of innocuous loss.
The basic DTLS design is that the receipt of the first message of the
peer's next flight indicates receipt of the entire flight. In this case,
then, the receipt of the ServerHello would indicate receipt of the
Client's 0-RTT Finished. However, this would place a requirement
that the server not *send* the ServerHello until that point, which we've
left open in WIP-11 by not hashing in the 0-RTT plaintext.

-Ekr

[0] Note, however, that the client has to rely on the server to handle this
properly. The reason

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 28 Dec 2015 23:49:15 +0200

> all the client's 0-RTT Handshake messages. [0].

Also, maybe a stupid question:

While the 0-RTT handshake parts are obviously reliably transmitted, is
the same true for the 0-RTT data part?

That is, is the server allowed to ACK the flight after having received
ClientHello/Certificate/CertificateVerify/Finished; and deal with any
0-RTT data messages should they arrive (these are not necressarily
retransmitted if lost)?

Or if the context does not support early auth, just ACK immediately
after ClientHello.

It occurs to me that data messages in DTLS 1.2 lack the fields needed
for automatic retransmission.

> left open in WIP-11 by not hashing in the 0-RTT plaintext.

I think that would be fairly easy way to deal with it (not saying that
simpler ways don't exist).

Also, on topic of DTLS 1.3... It occurs to me that naively doing it
would leave it open to "fragementation attacks" a'la IPv6.

Basically, it occurs to me that ClientHello messages SHOULD NOT be
fragmented (at TLS level, SCTP(?) or IP level fragmentation is another
kettle of fish) and if it is fragmented, the Cookie extension MUST be
in the first fragment.

The 0-RTT messages aren't so bad as those can just be dropped if
server does not want to accept right now.

Also, there's question of how to handle HelloVerifyReqest (one can't
just downgrade to DTLS 1.2!). One way:

- If it was in reply to ClientHello with EarlyData extension (at least
  with early auth?), treat it as fatal protocol_version Alert. TLS 1.2
  can't handle early data.
- If it was in reply to ClientHello without EarlyData extension, write
  the cookie into the header cookie field (not extension cookie field)
  and resend. This counts as a retry.

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 28 Dec 2015 18:59:48 -0500

> the same true for the 0-RTT data part?

No, nor for any DTLS data. The assumption is that this is handled at the
layer above.

> 0-RTT data messages should they arrive (these are not necressarily

I would anticipate that this is the correct behavior and in fact this seems
like the right behavior for TLS as well, since part of the point of 0-RTT
data is to stream it ASAP. Note that there is no explicit ACK, though.

> after ClientHello.

Yes, this is currently technicaly possible.

> kettle of fish) and if it is fragmented, the Cookie extension MUST be

Sorry, I'm not sure I am processing this. Can you explain in more detail.

>   and resend. This counts as a retry.

Yes, this seems like the right answer. I.e., You only do HVR in TLS 1.2
and as we have discussed previously, once you have sent a ServerConfig,
you have to continue to be able to do TLS 1.3, even if you forget the
config.

Best,
-Ekr

---

From: Christian Huitema <[email-masked]>
Date: Tue, 29 Dec 2015 01:27:48 +0000

From: Eric Rescorla [mailto:[email-masked]] 
Sent: Monday, December 28, 2015 1:46 AM
To: Christian Huitema <[email-masked]>
Cc: Dave Garrett <[email-masked]>; [email-masked]
Subject: Re: [TLS] What does it mean to not include 0-RTT message in the handshake hash?

On Sun, Dec 27, 2015 at 11:55 PM, Christian Huitema <[email-masked]> wrote:

-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 29 Dec 2015 09:15:07 +0200

> Sorry, I'm not sure I am processing this. Can you explain in more detail.

Basically, the server should avoid keeping any state for what it is
going to reject (because keeping such state would be pretty major
DoS vector).

And no state means no fragment reassembly and only first fragment being
parseable. And it is not only Cookie that can generate rejects, but
also KeyShare.

-Ilari