Subject: Re: [TLS] Application layer interactions and API guidance

From: Watson Ladd <[email-masked]>
Date: Fri, 7 Oct 2016 13:41:14 -0700

On Fri, Sep 23, 2016 at 10:47 PM, Ilari Liusvaara
<[email-masked]> wrote:
> On Fri, Sep 23, 2016 at 04:08:38PM -0700, Watson Ladd wrote:
>> Dear all,
>> We've got API guidance and application layer interactions on the TODO
>> list, and both of these are important and don't show up yet. I can't
>> credibly commit to taking a big stab at them, but hopefully this email
>> is detailed enough that it serves as a starting point.
>>
>> The problems with the application layer interaction center around
>> 0-RTT and client post-authentication. 0-RTT data is replayable, and
>> furthermore does not authenticate SNI or other extensions that might
>> affect its interpretation at the server. I smell possible bugs where
>> extension data isn't properly treated with 0-RTT vs. 1-RTT fallback:
>> the current draft probably should include something like "any
>> extensions which influence the interpretation of this data must be the
>> same".
>
> In composing my list of extensions to pay attention when doing 0-RTT
> (SNI and ALPN), I considered matters like:
>
> - Does this seem like it would affect 0-RTT interpretation.
> - What are the TLS 1.2 rules on it?
> - Is it even meaningful with PSK?
> - Is it just low-level connection control?
>
> ALPN was included because it definitely affects 0-RTT interpretation
> (even against TLS 1.2 rules) and SNI because of TLS 1.2 rules (SNI
> was later removed from the list).

Are we sure this is safe to remove? It probably depends on higher
layer protocol semantics.

I would suggest that we make 0-RTT per application layer support: each
application needs to opt in to 0-RTT, and we should ensure each higher
level protocol is aware of the interactions and writes a description
of what to do for each extension. Yes, this is hideous and a ton of
work. I'm not convinced there is a safe alternative.

>
> There might be future extensions that do have an effect on 0-RTT
> (some proposed extensions to Token Binding perhaps?). And it is of
> course theoretically possible that TLS stack implements some extension
> in a very odd way.
>
>> The difference between received 0-RTT data and other data doesn't
>> necessarily line up with connection state while processing, as the TLS
>> stack could have transitioned to normal 1-RTT operation while 0-RTT
>> data is still sitting around waiting to be processed.  This is really
>> an API problem, but can also be caused by application layer choices:
>> if the 0-RTT data can't be cleanly parsed, and some leaks into 1-RTT,
>> life gets a bit weird.
>
> Is "life gets a bit weird" an euphemism for "there will likely be
> security issues here"? :-)
>
> Also, it is very likely that 0-RTT would need its own read API, because
> it is pretty unlikely that existing API could be safely retrofitted
> or even purpose-built unified API be designed that isn't just asking
> for security problems via mixing 0-RTT and 1-RTT data.

Yes. In particular I think the TLS state machine transitions need to
be ordered with respect to the arrival and sending of data. The
challenge for a multithreaded program (yes, some programs have
multiple threads sending and receiving at once) is making this make
sense, or even a single-threaded program where the TLS stack can
change state at times not visible to the sending thread. Maybe there
is some slop here, like 0-RTT can become 1-RTT on send, but this
raises all sorts of problems for receiving. I think we need to require
separation in the API.

>
>
> It gets even more fun in DTLS, where 0-RTT packets can be reordered
> after Client Finished, so more 0-RTT data arrives when the connection
> has already transitioned to 1-RTT.
>
> Perhaps the last one could be solved by requiring the library to
> discard any such packets and not pass them forward.

This is the sanest solution I can think of. When DTLS 1.3 is produced
it should be noted.

>
>
>> Post-handshake auth is an ugly one for both. It can complete
>> asynchronously with respect to data exchange, which is not what the
>> desired semantics usually are. Generally we want each request to have
>> a single authentication context. Designing APIs to handle this is
>> hard, and applications will have to be aware of how TLS authentication
>> works to have rules for it. Add in the ability to stream data in both
>> directions, and life gets interesting. I'm really not sure what this
>> should look like.
>
> At least you must have client and server agree on authentication
> context of every given request. If they don't, vulernabilities WILL
> result.
>
> And then there have been multiple CVEs due to applications using
> wrong authentication context in some situation.
>
> (This is the reason one needs to be especially careful when combining
> dynamic client certificates with HTTP/2... Basically, it can not be
> done safely without coordination on application layer).
>
> One likely wants application protocol to be able to specify part of
> or the entiere request context and to extract that part in the other
> end when requesting a certificate selection. This is to allow putting
> part of coordination data into the request itself. However, this is not
> sufficient for e.g. HTTP/2 signaling, so more needs to be exchanged at
> application layer.
>
> E.g. HTTP/2 would want to signal which stream triggered the client
> certificate request, in order to enable the client to not be completely
> dumb in certificate selection.
>
> And then upon completion of the authentication (either successful or
> explicitly rejected), signal the application with the new certificate
> chain and the context the request had.

This is going to require major changes to APIs and to the HTTP/2
layer. It also interacts with token binding, whee! My question then
becomes one of what we actually need: can we assume that leakage
between authentication contexts over a single session is safe because
all contexts represent the same principal, by restricting the usages,
or is this overly restrictive?

When we have multiple requests and replies in flight and the
authentication state changes, things get nasty. If we think of TLS as
sending a stream of events including authentication changes to the
application, this fits the semantics of the TLS draft as I understand
them to be, but does not necessarily fit what application protocols
want. There might be a semantic mismatch here requiring reworking of
one or another part.

Sincerely,
Watson

> -Ilari

-- 
"Man is born free, but everywhere he is in chains".
--Rousseau.

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 8 Oct 2016 01:00:28 +0300

> raises all sorts of problems for receiving. I think we need to require

0-RTT can't be allowed to become 1-RTT on send (unless it is auto-
retransmit, which needs to be disableable, as sometimes that just plain
won't work).

This impiles that the application always needs to explicitly signal
the end of 0-RTT data, even just to abort sending it.

> or is this overly restrictive?

Yes, it is going to reuqire such changes.

And you absolutely can not assume that all contexts present the same
principal.

And as I said, in multiplexed protocol like HTTP/2, you need application-
level coordination on top. TLS just can't do that.

> want. There might be a semantic mismatch here requiring reworking of

Also, some applications presumably want the events done synchronously,
so they don't move with data reads.

Basically, post-handshake auth is heckuva nasty problem.

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 7 Oct 2016 15:04:14 -0700

> retransmit, which needs to be disableable, as sometimes that just plain

Can you explain why that is?

-Ekr

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

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 8 Oct 2016 17:22:47 +0300

> Can you explain why that is?

E.g. what they are planning to do with 0-RTT Token Binding in HTTP.
The client puts in a signature into 0-RTT data. If the server rejects
the 0-RTT and the client retransmits, the signature will still be
there but is different.

Also, if 0-RTT data can silently shift to 1-RTT, it would mean the
server-side model would be to concatenate 0-RTT and 1-RTT data, which
I thought we already established is quite dangerous.

-Ilari

---

From: Watson Ladd <[email-masked]>
Date: Sat, 8 Oct 2016 07:25:47 -0700

> Can you explain why that is?

Grammar problems.

Let's say you have an context-free parseable protocol, and you want to
insert the restriction that there is a 0-RTT set of allowed constructions
and an 1-RTT allowed set that is bigger. The most obvious way to do this is
to treat the transition as a token that comes between the top-level
productions of each set of allowable things: so I send you a bunch of 0-RTT
allowed bits, then switch, then a bunch of 1-RTT allowed bits.

If the sending stack can insert that transition anywhere the grammar
explodes.

One could try to handle this by some nasty "did we switch before now"
construction to delay the transition. But you still need to switch how you
are reading.

---

From: Eric Rescorla <[email-masked]>
Date: Sat, 8 Oct 2016 09:22:40 -0700

> If the sending stack can insert that transition anywhere the grammar
In the APIs people have been designing, 0-RTT can become 1-RTT but not the
other way around.
Specifically:

- There is an option to allow 0-RTT writing
- With that option on, SSL_Write() succeeds in both 0-RTT and 1-RTT modes.
- There is a callback that tells you when you have gone from 0-RTT to 1-RTT.

-Ekr

-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 8 Oct 2016 20:06:05 +0300

> - There is a callback that tells you when you have gone from 0-RTT to 1-RTT.

I really hope I misunderstood what you wrote...

I understood it as: The TLS client library notifies the application
that it has transitioned on its own, without instruction from client
application from sending 0-RTT data to server to sending 1-RTT data
to the server???

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Sat, 8 Oct 2016 10:13:07 -0700

> application from sending 0-RTT data to server to sending 1-RTT data

Approximately.

It's a little more subtle than that b/c individual SSL_Write() calls don't
cross boundaries, so at any
given time you can interrogate what state you're in, but it's really not
practical for the client
app to tell the stack what state to be in, because the stack responds to
receiving the server's
Finished by sending end_of_early_data and then its own Finished, so it's
not like you can
keep it on sending 0-RTT at that point, though of course if you had two
APIs, you could
generate an error when the client tried to use the wrong one.

Can you elaborate on your concern here?

-Ekr

---

From: Nick Harper <[email-masked]>
Date: Sat, 8 Oct 2016 10:13:55 -0700

In my proposed 0-RTT Token Binding draft (
https://tools.ietf.org/html/draft-nharper-0-rtt-token-binding-01), the
signature is the same in 0-RTT data as in 1-RTT data, assuming the server
didn't reject early data. The thought here is that a client's write API
might look like "please send this data, and I'm fine with it being sent
0-RTT", so the Token Binding code doesn't have to know if its message was
sent before or after handshake completion. If early data is rejected, then
the application data has to change, but this isn't something limited to
Token Binding. A server cold reject early data and also change ALPN from
what the client expected, requiring the client to send different data.

I think it's fine from an API perspective for data sent 0-RTT to also be
sent 1-RTT so long as early data is accepted.

On Saturday, October 8, 2016, Ilari Liusvaara <[email-masked]>
wrote:

> > On Fri, Oct 7, 2016 at 3:00 PM, Ilari Liusvaara <
> [email-masked] <javascript:;>>
> > wrote:
> >
> > > > <[email-masked] <javascript:;>> wrote:
> > > > >
> [email-masked] <javascript:;>

---

From: David Benjamin <[email-masked]>
Date: Sat, 08 Oct 2016 17:32:09 +0000

To add to that, in out-of-order transports, whether a message was sent over
0-RTT or not may not even be very well-defined. If QUIC originally sent
data over 0-RTT but had to retransmit it after the full connection
parameters are available, I believe it will use those.

Even in an in-order transport, imagine if I have a very long replayable
request in HTTP/2 (maybe it's a PUT and comes with a request body, or maybe
it has too many headers). I start sending that one over 0-RTT. While I'm in
the middle of sending that, I get back a ServerHello (w/ early_data)
through Finished. I either need to complete the handshake and switch to
1-RTT mid-request or wait for the long request to complete before finishing
the handshake or sending any non-replayable ones, though they may be higher
priority. (They probably are if they don't come with as giant of response
bodies...) The former is by far the more attractive option.

Or perhaps I hit max_early_data_size (
https://github.com/tlswg/tls13-spec/pull/674) and thus can't send more
0-RTT data anyway.

In HTTP/2 you have the additional amusement that, due to HPACK, your 0-RTT
data probably has an effect on the 1-RTT data even if requests are all or
nothing.

I don't think we can make the receiver aware of the 0-RTT / 1-RTT boundary
sanely. In my mind, the decision whether to send something 0-RTT or wait
until 1-RTT is primarily the sender's business. If the sender wanted to, it
could make the data replayable anyway by just replaying it. On the
receiver's side, yeah, you concatenate the streams. That's why the server
must decline 0-RTT if any negotiated parameter (ALPN, etc.) changes.

David

On Sat, Oct 8, 2016 at 1:14 PM Nick Harper <[email-masked]> wrote:

-Ilari

---

From: Watson Ladd <[email-masked]>
Date: Mon, 10 Oct 2016 13:49:11 -0700

On Sat, Oct 8, 2016 at 10:32 AM, David Benjamin <[email-masked]> wrote:
> 0-RTT or not may not even be very well-defined. If QUIC originally sent data
> over 0-RTT but had to retransmit it after the full connection parameters are
> available, I believe it will use those.
>
> the middle of sending that, I get back a ServerHello (w/ early_data) through
> Finished. I either need to complete the handshake and switch to 1-RTT
> mid-request or wait for the long request to complete before finishing the
> handshake or sending any non-replayable ones, though they may be higher
> Or perhaps I hit max_early_data_size
> (https://github.com/tlswg/tls13-spec/pull/674) and thus can't send more
> 0-RTT data anyway.
>

The problem is with poorly-behaved senders and attackers resending
0-RTT data. Receivers should be able to ensure side-effectfull
operations are not carried out by 0-RTT data. Making 0-RTT silent in
APIs transforms an interoperability issue into a silent security
issue. This is not a good idea.

>> In my proposed 0-RTT Token Binding draft
>> (https://tools.ietf.org/html/draft-nharper-0-rtt-token-binding-01), the

---

From: Kyle Rose <[email-masked]>
Date: Mon, 10 Oct 2016 13:57:27 -0700

> issue. This is not a good idea.

+1.

FWIW, Patrick McManus made a pretty eloquent and convincing case in Berlin
that the web is substantially broken without retry logic in the browsers,
that naturally make application-level replay mitigation a necessity. But I
don't think (nor do I think he claimed) that the same is true of all
protocols or systems that might use TLS. So while 0-RTT-obliviousness may
be okay for browsers in particular given the other constraints under which
they operate, it is probably not good to bake that into the API for the
general case.

Kyle

---

From: Martin Thomson <[email-masked]>
Date: Tue, 11 Oct 2016 17:27:23 +1100

On 11 October 2016 at 07:57, Kyle Rose <[email-masked]> wrote:
> protocols or systems that might use TLS. So while 0-RTT-obliviousness may be
> okay for browsers in particular given the other constraints under which they
> operate, it is probably not good to bake that into the API for the general
> case.

The 0-RTT API in NSS allows a server to detect this transition.  The
problem that I think David was referring to is that the specific
instant of the transition is lost when the multiple layers of stack
that sit on top of TLS get involved.

If an HTTP client sends a request that relies on HPACK state that was
established during 0-RTT, is it a 0-RTT request?  I'm going to go with
probably not.

If an HTTP client sends the first octets of a message in 0-RTT but
completes the request after the handshake completes, is it 0-RTT?  I
suspect that this again is not a concern.

I agree that we should make it clear that 0-RTT data needs to be
treated specially.  I would like to see someone propose some text
rather than read more vague emails on the subject.

---

From: Kyle Rose <[email-masked]>
Date: Tue, 11 Oct 2016 21:41:55 -0400

> that sit on top of TLS get involved.

To David's second paragraph, if we eventually authenticate the early data
as strongly as 1-RTT data, then there is no problem with long requests.
I.e., if the client starts a long PUT request that doesn't finish until
after the handshake is done, then the connection could be broken by the
server stack mid-request if it is able to figure out that the early data
was replayed. It appears this will be the case because the handshake
context for 0-RTT includes the ClientHello, which includes the early data,
so the client {Finished} will cover it. (Not clear on the value of 0-RTT to
long PUT requests, but you provide a more likely example below.)

> established during 0-RTT, is it a 0-RTT request?  I'm going to go with

For the above reason, the HPACK state should be strongly authenticated by
this point, at which point it's no longer 0-RTT data.

Since the authentication status of early data may vary over the course of
the connection from "unknown/possibly replayed" to either "replayed" or
"authentic", maybe we should classify it by its status at the time we go to
use it. Which suggests the following terrible API for the server:

read(max) will return either a string of fully-authenticated data up to max
bytes, or EAGAIN if none is available (with possibly some side-band
mechanism for indicating that data of unknown authenticity is available)

read_sketchy(max) will return possibly-sketchy data up to max bytes, or 0
if there is no more such data (at which point the caller should switch to
regular read), or EAGAIN if the entire ClientHello hasn't yet been received.

If the server doesn't care about early data, or waits long enough for the
handshake to complete, all data will have been elevated to authentic or the
connection broken, depending on what happened with client {Finished}.

On the client side, one option is for the early data to be specified prior
to or alongside handshake initiation, with some indication by the stack of
whether it was written or not. (I suggest all-or-none.) This precludes
question on the part of the client as to which data might have been sent
0-RTT and which must have been sent 1-RTT.

One of the nice things about the above API is that a simple server wanting
to process early data ASAP can do the same thing every time:

poll for read
try:
  r = read_sketchy()
  if r: do_something_with_early_data(r)
catch EAGAIN: noop
try:
  r = read()
  if r: do_something(r)
  else: terminate_connection
catch EAGAIN: noop

Another nice thing is that at the moment you receive a single byte from
read() you know a priori that every byte of early data you processed was
authentic.

Do we want to support the case in which 0-RTT failure means the client can
send entirely different data? If so, then the above isn't general enough,
but the client API could offer an option to say "don't resend this data if
0-RTT fails" with some flag set on this condition or (for event systems) a
callback registered to do something more interesting.

The above API also doesn't support the case in which the server wants to
treat 0-RTT data entirely different from 1-RTT data, which would suggest a
side-band/two channel API. Is this interesting to anyone? I'm not sure I
can see any use for purposely ignoring post-hoc authentication of early
data.

Kyle

---

From: Ilari Liusvaara <[email-masked]>
Date: Wed, 12 Oct 2016 11:11:45 +0300

> long PUT requests, but you provide a more likely example below.)

I have actually seen one service where partially received PUT requests
had "side effects". Fortunately, not a replay problem in that case,
since application would reject replays anyway.

> regular read), or EAGAIN if the entire ClientHello hasn't yet been received.

For when 0-RTT has become boring enough for me to implement, I would
think the server-side interface I put in would be something like the
following:

- ServerSession::getReplayable0RttReader(alp_list) -> ZRttReader
- ZRttReader::getAlpn() -> String
- ZRttReader::dataAvailable() -> size
- ZRttReader implements Read

If there is no replayable 0RTT reader given when ClientHello is
received, or if the ALP of the 0-RTT does not match any in alp_list,
the 0-RTT is rejected. Otherwise it is accepted and the data stream is
received via the ZRttReader. Then regular 1-RTT data will be returned by
the usual Read interface of ServerSession.

> connection broken, depending on what happened with client {Finished}.

In the interface above, not caring about 0-RTT gets 0-RTT rejected. And
waiting just causes the connection to freeze up.
 
> 0-RTT and which must have been sent 1-RTT.

The interface I envision has client write all the 0-RTT data and
explicitly signal the end of data, with a callback if server rejects,
so the application can abort the flight early (the stack just black-
holes the data after error).

And of course some critical thingy in which normally blocks 0-RTT
sending has name suggestive of replayability.

The reason for waiting for application to ACK the 0-RTT error is that
the thing is MT-safe, so one has to prepare for races..
 
> read() you know a priori that every byte of early data you processed was

Well, one always knows that for any received data, one who sent it
possesses the PSK secret and it can't be tampered with without the
PSK secret.

However, receiving any 1-RTT data after 0-RTT data does not imply that
the 0-RTT data was not replayed!
 
> callback registered to do something more interesting.

There's the case where ALP mismatches (and unfortunately, due to how
ALPN and 0-RTT interact, mismatches can happen in cases other than
just that 0-RTT is fundamentially impossible).

In that case, the data is obviously different. Then there are also
things like the planned 0-RTT tokbind, where the data sent on 0-RTT
failure is different from the original data.

> can see any use for purposely ignoring post-hoc authentication of early

I regard post-hoc authentication as quite dangerous. At least in
some applications it is a deadly security mistake.

-Ilari

---

From: Kyle Rose <[email-masked]>
Date: Wed, 12 Oct 2016 11:54:59 -0400

> the usual Read interface of ServerSession.

Ok, I see where you're going with this. I'm not sure whether I would put
the ALP filtering logic in the API or do something more like:

early_data = get_early_data()
is_early_data_good = <application inspects the early data>
start_server_handshake(reject_early_data = !is_early_data_good)

This allows the server to decide whether or not to reject early data on any
basis, not just ALP. But maybe a shortcut is good for the common case.

> holes the data after error).

Agreed on that, with s/a callback/some client application signaling
appropriate to the language or development model involved/.

> the thing is MT-safe, so one has to prepare for races..

I'm frankly skeptical of the utility of (most) thread safety at the socket
level. (Safety against crashes, yes; safety against arbitrary interleaving
of stream data, no.) IMO, semantic guarantees around multiplexing belong in
a higher layer. Otherwise, the API must impose additional constraints
(e.g., max write size) that apply across the board, even to applications
that will never write from multiple threads, and must require the stack
provide additional guarantees (e.g., all-or-none writes) that the developer
has to know about.

Given how much TLS libraries try to look like Berkeley sockets to
applications, you'll probably see fewer usage errors if that multiplexing
logic is implemented at the application layer with an upward-facing
interface that either looks nothing like sockets or that presents distinct
logical sockets for distinct streams, intended for use by one thread at a
time, multiplexed over the same connection.

> possesses the PSK secret and it can't be tampered with without the

Absolutely. But is it an authentic part of *this* connection? That's what
the client {Finished} tells you, later.

> the 0-RTT data was not replayed!

I think I may have been imprecise. By "received" I mean "received by the
application", i.e., "delivered by the stack". By the time the stack
delivers one byte of 1-RTT data to the application, we know:

(1) Client {Finished} has been received by the server
(2) which authenticates ClientHello
(3) which incorporates early_data
(4) Client {Finished} is protected by client_handshake_traffic_secret
(5) which incorporates ServerHello
(6) which incorporates the server random
(7) which means that secret is fresh (i.e., not subject to replay)

By this point in the connection, there is proof that early_data has not
been replayed. The application doesn't necessarily know this when the early
data is first delivered, but it can find out later, which may be all that

> failure is different from the original data.

Agreed that this is a perfect example.

Since the early_data has to be received by the stack and be authenticated
as a single chunk as part of the ClientHello, an API that returns it as a
monolithic blob (like get_early_data, as above) solves the problem of
associating requests/tokens to channel bindings. If some middleware wants
to offer a stream interface to this buffer because that's the idiom for the
particular language, that probably makes sense, but I suspect the low-level
interface for a C implementation will be something more like "Here's a
pointer and a length; go nuts."

> some applications it is a deadly security mistake.

How so? There's certainly some danger in mixing the two data streams for
applications that really care about the state of forward secrecy for each
byte. But I'm having a tough time understanding why finding out later that
"No, that early_data was in fact not replayed" is a bad thing. IANAC:
genuinely curious here.

Kyle

---

From: Ilari Liusvaara <[email-masked]>
Date: Wed, 12 Oct 2016 20:02:37 +0300

> basis, not just ALP. But maybe a shortcut is good for the common case.

You need ALP if multiple are supported, since some applications might
support 0-RTT and some not.

Also, TLS 1.3 0-RTT assumes that 0-RTT transport is all-or-none.
 
> provide additional guarantees (e.g., all-or-none writes) that the developer

That was actually mostly artifact of the programming language (easiest
to make things that aren't thread-locked fully thread-safe, even if
there is an intermediate step).
 
> time, multiplexed over the same connection.

Well, this lib looks nothing like Berkeley sockets. :-)
 
> some applications want. Clearly not all, as you point out:

This is actually only useful if the application can cancel out effects
of 0-RTT if handshake fails... Which tends to be fraught with peril to
implement.

Because the transport delay from client starting sending CH to server
first receiving first byte past some point is the same if the data
before the point is sent as 0-RTT or 1-RTT!

And the dominant component in transport delay tends to be round-trip
delay.

> pointer and a length; go nuts."

The 0-RTT data is not part of ClientHello. It is sent in streaming
manner (with handshake blocking if it hans't been completely sent by
the time ServerFinished is received.

ClientFinished does _not_ MAC 0-RTT data, even in case of successful
transport.

Also, the tokbind case would require interface that lets the application
get to the connection in state where ClientHello has been sent but no
0-RTT data yet, since some of the parameters in 0-RTT data do actually
depend on the exact ClientHello sent.

> "No, that early_data was in fact not replayed" is a bad thing. IANAC:

Well, I was referring to the general problem that finding out that 'the
peer is X' and applying it to the data sent in the same TLS connection
before that point can result in very nasty surprises.

And also, receiving 1-RTT data does not imply that the 0-RTT data
itself was not replayed (just that any replay it is of didn't
complete, assuming PSK keys are secret).

-Ilari

---

From: Kyle Rose <[email-masked]>
Date: Wed, 12 Oct 2016 13:51:25 -0400

> of 0-RTT if handshake fails... Which tends to be fraught with peril to

Absolutely, but it doesn't seem like it would be any more perilous than the
danger of accepting 0-RTT data in the first place: at worst you process the
same replayed data, and at best you process less replayed data. (Unless
there's a perverse incentive problem created by providing a half-measure.)

> ClientFinished does _not_ MAC 0-RTT data, even in case of successful

There's my confusion. I misinterpreted both the Zero-RTT diagram and the
table of handshake contexts under "Authentication Messages", specifically
"ClientHello ... later of EncryptedExtensions/CertificateRequest". I'm
guessing I should be looking at the 0-RTT row only? I.e., if 0-RTT is
accepted, is the second Finished message from the client ("{Finished}") the
same message encrypted differently (using the handshake traffic secret)?

Is there a succinct explanation for the design choices around what is and
is not included in the handshake context? Being spread out over a year and
a half of mailing list messages makes it hard to track. :-) I'm concerned
that an on-path adversary that can slice-and-dice connections along MAC
context lines will be able to create mischief, so I'd like to be able to
convince myself that this isn't the case.

> complete, assuming PSK keys are secret).

Yeah, I get that now. It seems like a missed opportunity to detect mischief
after the fact, and could make for some interesting vulnerabilities for
stateful protocols. E.g., if your early data is "cd /tmp" and your 1-RTT
data is "rm -rf *", but the adversary is able to swap out the early data
for a replayed "cd ~". That one is probably too obvious of an example to
happen in real life, but imagine some developer who maintains his or her
own tlstunnel hearing about 0-RTT and implementing early data for arbitrary
applications using that tunnel wrapper because "reduced latency!": if early
data were later authenticated, it would limit the scope of vulnerability to
only those things that could fit in that first flight. But because it can't
catch every possible replay-based attack, maybe such a measure would
provide only a false sense of security. Sigh. I have no desire to re-ignite
arguments from a year ago.

Kyle

---

From: Ilari Liusvaara <[email-masked]>
Date: Wed, 12 Oct 2016 21:03:37 +0300

> there's a perverse incentive problem created by providing a half-measure.)

If all 0-RTT data is idempotent (including after replay delay!), sure.

However, if it isn't idempotent, you could get issues...
 
> same message encrypted differently (using the handshake traffic secret)?

No, there is no difference in ClientFinished in case of 0-RTT accept or
reject (other than the contents of the CH and EE hashed in).
 
> convince myself that this isn't the case.

The thing that protects the 0-RTT data from substitution is the record
protection MACs that are made using key derived from the PSK secret. So
if the PSK secret is unknown, the key for 0-RTT can't be derived, and
as consequence, 0-RTT data can't be altered (there's end-of-data marker
too, preventing truncation).

And basically, ServerFinished MAC covers everything up to that point,
and ClientFinished MAC covers the entiere handshake (0-RTT data not
included).

> arguments from a year ago.
 
You can't swap out 0-RTT data (without PSK keys). One can only create
new connection attempts (that fail!) with the same 0-RTT data (and the
same ClientHello) before or after the real connection (if any, it
could be supressed, in which case you would get only failed handshakes
with 0-RTT data).

-Ilari

---

From: Kyle Rose <[email-masked]>
Date: Wed, 12 Oct 2016 15:55:49 -0400

> reject (other than the contents of the CH and EE hashed in).

Still confused. :-)

In the message flow for 0-RTT, there are two Finished messages sent from
client to server. One is sent right after CH, and is protected by the
client_early_traffic_secret: (Finished). The other is sent after the server
sends its Finished, and this is protected by the handshake_traffic_secret:
{Finished}.

In the table under "Authentication Messages", there are four rows, one for
each Mode: 0-RTT, 1-RTT (Server), 1-RTT (Client), and Post-Handshake.

Which handshake context is used for the (Finished) message and which is
used for the {Finished} message?

> too, preventing truncation).

Altered is one thing, and I agree that is prevented; I'm talking about
substitution.

> and ClientFinished MAC covers the entiere handshake (0-RTT data not

So client Finished doesn't protect 0-RTT data, but...

> could be supressed, in which case you would get only failed handshakes

This is exactly what I'm trying to understand. What specifically prevents
this swapping? I.e., what ties the 0-RTT data sent on a particular
connection to the rest of that connection, such that replacing that 0-RTT
data with 0-RTT data from a previous successful connection will cause a
failure?

Kyle

---

From: Eric Rescorla <[email-masked]>
Date: Wed, 12 Oct 2016 12:57:02 -0700

On Wed, Oct 12, 2016 at 12:55 PM, Kyle Rose <[email-masked]> wrote:

> On Wed, Oct 12, 2016 at 2:03 PM, Ilari Liusvaara <[email-masked]
> > wrote:
>

The 0-RTT traffic key incorporates the ClientHello.Random which is tied
into the full handshake.

-Ekr

---

From: Kyle Rose <[email-masked]>
Date: Wed, 12 Oct 2016 16:12:34 -0400

> The 0-RTT traffic key incorporates the ClientHello.Random which is tied

Ok, so for the replayed early data to be accepted, an adversary would also
have to swap out CH.Random and the (Finished) message, which would alter
the server Finished message, resulting in a handshake failure. I think that
resolves my concern. Thanks.

Kyle

---

From: Watson Ladd <[email-masked]>
Date: Fri, 14 Oct 2016 17:50:00 -0700

> rather than read more vague emails on the subject.

See https://github.com/tlswg/tls13-spec/pull/694. This is for API
guidance rather than applications, and definitely needs expansion. I
don't think we can say anything about HTTP without more details.