Subject: [TLS] 0-RTT and Anti-Replay

From: Eric Rescorla <[email-masked]>
Date: Sun, 22 Mar 2015 14:49:28 -0700

In the interim in Seattle, we had an extensive discussion of 0-RTT
anti-replay in which DKG observed that all the proposed anti-replay
mechanisms provide limited protection. The underlying problem is the
desire to present a uniform interface in which the calling application
can count on reliable delivery of the data it provides in the first
flight, thus requiring the TLS stack to retransmit it automatically.

This message describes the problem and should set us up for a
discussion about the topic in Dallas. Apologies in advance for
the length of this, but I'd like to be clear.

BACKGROUND: ANTI-REPLAY
As you'll recall, TLS ordinarily uses a server-provided random value
mixed into the keys for anti-replay. This obviously doesn't work for
0-RTT. For reference, here's a simplified description of the way that
(and the way that both QUIC and snap-start do it).

- The server keeps a list of every ClientRandom it has received
  within a given time window keyed by a server context ("orbit")
  value that loosely can be thought of as indicating the data center.

- When the server receives a new ClientHello, it checks to
  see if it has seen it before and then rejects the connection.

Now consider what happens when the server reboots and loses its
state. You don't want to reject every client 0-RTT connection so
instead what you do is you ignore the client's initial data sent in
the first flight. Since the ServerHello provides a new Random value,
any data the client sends in subsequent flights has the usual
anti-replay protection.

A SOMEWHAT CONTRIVED ATTACK
This is all fine so far, but the abstraction you probably want TLS to
supply to the application is that the data it sends in the first
flight isn't lost even in this case. In order to accomodate this, the
natural design is for the TLS stack to retransmit the plaintext in the
client's first flight as the first data it sends under the new keys.

An attacker can make use of this as follows. When the client sends
the initial first flight he captures the TCP connection and makes his
own TCP connection to the server, forwarding the first flight.

Client                        Attacker                          Server

ClientHello [+0-RTT] ------------>
"POST /buy-something" ----------->

                              ClientHello [+0-RTT] --------------->
                              "POST /buy-something" -------------->

                                                   [Processes purchase]
                                 <---------- ServerHello [accept 0-RTT]
                                                  (+ rest of handshake)

The attacker just discards the server's response and then the server
somehow forces the server to reboot (this is the hard part).

Once the server has rebooted, the attacker re-sends the client's
initial flight then just forwards data back and forth to the client.

Client                        Attacker                          Server
                              ClientHello [+0-RTT] --------------->
                              "POST /buy-something" -------------->

   <--------------------------------------  ServerHello [reject 0-RTT]
                                                 (+ rest of handshake)

Finished --------------------------------------------------------->
"Post /buy-something" -------------------------------------------->
                                                  [Processes purchase]

At this point, you've mounted a successful replay attack. Obviously
this is not that great an attack because it requires you to be able to
force a reboot and also get in under the client's timeout window.

A MORE REALISTIC ATTACK
During the interim meeting, DKG observed that you could produce the
same "I've forgotten my state" situation if you have a distributed
server. Say that the server operates in two loosely-synchronized
data centers. In that case, you can get the following situation
(shown without the attacker's intervention because of ASCII art
limitation

 Client             Attacker            Server1              Server 2

ClientHello [+0-RTT] -->
"POST /buy-something" ->

                    ClientHello [+0-RTT] -->
                    "POST /buy-something" ->

                                        [Processes
                                         purchase]

                    ClientHello [+0-RTT] ----------------------->
                    "POST /buy-something" ---------------------->

   <--------------------------------------  ServerHello [reject 0-RTT]
                                                 (+ rest of handshake)

Finished --------------------------------------------------------->
"Post /buy-something" -------------------------------------------->
                                                  [Processes purchase]

Again, the attacker will need to mess with the TCP channel, but their
ability to do so is part of our basic threat model [RFC 3552].

It's important to understand that this is a generic issue, not an
issue with TLS in particular, so it's not like there's some other
0-RTT model we can lift and put into TLS that would solve the problem.

APPROACHES
One way to address this would be to simply not provide a 0-RTT mode.
This is a charter item, so that would be sad, but obviously that's not
out of the question if we really think this is bad. The more serious
question is that there's an enormous demand for this feature (see, for
instance, the discussion at the SEMI workshop), and so if we refuse to
do a 0-RTT mode, we're giving applications the annoying choice of
accepting a RTT or inventing their own 0-RTT method.

There are a number of basic ways to address this issue, but I think
the main plausible[0] ones are:

1. Keep the server state globally consistent and also temporally
   consistent so that replays can always be detected.

2. Remove the TLS anti-replay guarantee for the data sent in the first
   flight and tell applications to only send data there that can
   tolerate being replayed.

3. Remove the TLS reliable delivery guarantee for the data sent in
   the first flight, so that the stack doesn't automatically replay it.

The first of these options (global state) is possible, but only in
some limited circumstances, namely very sophisticated operators and/or
situations where there's really only one server which has good state
management. An example of the latter is WebRTC, where the server can
have a different anti-replay context for each connection.

The other two options clearly require a separate API to handle this
special first-flight data and would require applications to handle it
separately. So, for instance, in option 2, you would have something
like:

    c = new TLSConnection(...)
    c.setReplayable0RTTData("GET /....")
    c.connect();

And in the case of option 3 you would have something like:

    c = new TLSConnection(...)
    c.setUnreliable0RTTData("GET /....")
    c.connect()
    if (c.delivered0RTTData()) {
       // Things are cool
    } else {
       // Try to figure out whether to replay or not
    }

So in the former case, the choice of replay is in the TLS
stack's hands but in the latter in the application's hands.

I would expect them to have relatively similar impacts on the wire,
namely applications would self-designate certain data as replay-safe
(e.g., HTTP GETs) and would send it in the first flight and then
either let the stack retransmit (option 2) or retransmit themselves
(option 3). This isn't that odd, since, as AGL observes, browsers
already routinely retry some HTTP requests that appear to fail even for
ordinary TLS (i.e., no HTTP response was received) so in those cases
they have already circumvented the anti-replay guarantees supplied by
TLS, but of course that's different from having TLS give up those
guarantees.

RECOMMENDATION
As I said, I think we do need to supply some sort of limited 0-RTT
functionality. Given the practical difficulty of making global state
work, I think it's a mistake to build a system which relies on
this. The remaining two options require that we relax one of TLS's
guarantees and of these, relaxing reliable delivery seems safer,
and it also makes the implementation rather easier.

Accordingly, I propose that we continue to develop 0-RTT but with the
server just dropping 0-RTT first-flight data when 0-RTT is not
possible (and of course telling the client it is doing so).  The
client application can then retransmit if it believes it is safe.
In the very limited cases where application domains can in fact
safely keep state, they can profile the use of TLS to that end
and require the endpoints to behave appropriately.

Thanks,
-Ekr

[0] One implausible approach is to treat any attempt to 0-RTT when
you have lost state as a hard-fail, but this will create a lot of
random failures, so it's not really practical.

---

From: Mohamad Badra <[email-masked]>
Date: Mon, 23 Mar 2015 02:26:58 +0400

Hi Eric,

> force a reboot and also get in under the client's timeout window.

According to draft-rescorla-tls13-new-flows-01:

   The EncryptedExtensions MUST include an ART indicator that matches
   the client's ART so that the client knows that the 0-RTT handshake
   was successful and that the client's application_data was accepted.

I wonder why the Server doesn't include an indicator in his reject
(encrypted indicator) so the client will avoid sending its request again.

(BTW, based on what a server can reject after a reboot)

Best regards
Mohamad

---

From: Eric Rescorla <[email-masked]>
Date: Sun, 22 Mar 2015 15:30:10 -0700

> (encrypted indicator) so the client will avoid sending its request again.

This would basically be option #3, namely that this data is unreliable.

Best,
-Ekr

---

From: Stephen Checkoway <[email-masked]>
Date: Sun, 22 Mar 2015 19:02:05 -0400

> and require the endpoints to behave appropriately.

None of the options makes me very happy and I'm really concerned that applications and/or implementations will mess this up and it'll lead to a vulnerability.

If we absolutely must support 0-RTT (and I believe that we do), then I agree with ekr that relaxing reliable delivery of the first-flight data is the least bad choice.

I'm not sure how in-scope API recommendations are, but I think that first flight data absolutely needs to be an explicit API call. That is, something like

    c.write(data)

SHOULD NOT send data along with the handshake. Ekr's setUnreliable0RTTData really seems like the way to go.

-- 
Stephen Checkoway

---

From: Daniel Kahn Gillmor <[email-masked]>
Date: Sun, 22 Mar 2015 18:23:57 -0500

> None of the options makes me very happy and I'm really concerned that applications and/or implementations will mess this up and it'll lead to a vulnerability.

i share this sentiment.

> If we absolutely must support 0-RTT (and I believe that we do), then I agree with ekr that relaxing reliable delivery of the first-flight data is the least bad choice.

Calling it "unreliable" in the sense that we can't guarantee that it
will get through sounds likely to mislead users.  In fact, the
"unreliability" is that we don't know whether the data was accepted and
processed by the remote server or not (particularly, in the case of a
distributed service, which the client probably can't distinguish).

So in practice, the data sent in the first flight needs to be seen as
"replayable" in some sense.  If it is rejected by the server but the
handshake continues, then the client has three options as it crafts its
1-rtt reply:

 0) send the same payload again
 1) send some different payload (with the same semantics)
 2) send some different payload with different semantics
 3) abort the connection and surface the error to the user

in cases 0 and 1, the first 0rtt payload could actually still be
processed by some other server, and the client would never know about
it.  So case 0 is strictly "replayable" (as in, the attacker can cause
the same payload to take effect twice) and case 1 is "semantically
replayable".

I'm having trouble getting my head around any cases that fall into
case 2, and case 3 is what ekr called "implausible".

so "replayable" still seems like the right way to declare this flight to
users, even though it sounds worse than "unreliable".

> SHOULD NOT send data along with the handshake. Ekr's setUnreliable0RTTData really seems like the way to go.

  c = new TLSConnection(replayableData,...)
  if c.replayableDataSucceeded :
     c.write(nextFlight)
  else:
     ....

I think there are lots of ways that developers can get burned here.
Even testing these codepaths is tricky.

     --dkg

---

From: Andrey Jivsov <[email-masked]>
Date: Sun, 22 Mar 2015 17:59:46 -0700

> state. You don't want to reject every client 0-RTT connection so

I think what you are proposing here is to treat a mismatch in 0-RTT 
parameters as "re-negotiate", similar to the SessionID-based reuse logic.

See more below.

> 0-RTT model we can lift and put into TLS that would solve the problem.

The SessionID-like fallback is a problem for a "broadcast" of the single 
"POST /buy-something" (via a replay of a captured message). Had the 
Server 2 above rejected the ClientHello [+0-RTT] which was intended for 
Server 1 (orbit1), there would be no problem.

One way to solve this is to say that the server must *fail* 0-RTT, as 
opposed to fallback to 1-RTT, if the "orbit" indicated in the 
ClientHello is not that of this server.

The only requirement here is that the server always knows its orbit. 
Servers must have different orbit IDs if they cannot handle simultaneous 
receipt of identical "POST /buy-something".

Regarding the forced server reboot. The practical issue here, it seems, 
is that it's difficult to keep the state of the global purchasing DB 
updated, so that the HTTP requests issued (replayed) simultaneously to 
servers across the globe are verified. This is less of a problem when 
TLS pins the request to the same copy of the local DB, identified by 
orbit ID.

> random failures, so it's not really practical.
...

---

From: Eric Rescorla <[email-masked]>
Date: Sun, 22 Mar 2015 20:19:14 -0700

On Sun, Mar 22, 2015 at 5:59 PM, Andrey Jivsov <[email-masked]> wrote:

> "POST /buy-something" (via a replay of a captured message). Had the Server
> 2 above rejected the ClientHello [+0-RTT] which was intended for Server 1
> (orbit1), there would be no problem.
>
> opposed to fallback to 1-RTT, if the "orbit" indicated in the ClientHello
> is not that of this server.
>

Yeah, this is what I claimed is "implausible" in my original message.

My concern here is that this basically means that implementations get
punished with random failures for any data center/routing instabilities...

-Ekr

> Regarding the forced server reboot. The practical issue here, it seems, is
> that it's difficult to keep the state of the global purchasing DB updated,
> so that the HTTP requests issued (replayed) simultaneously to servers
> across the globe are verified. This is less of a problem when TLS pins the
> request to the same copy of the local DB, identified by orbit ID.
>
>
>
>
>>
>> APPROACHES
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Martin Thomson <[email-masked]>
Date: Sun, 22 Mar 2015 20:35:34 -0700

On 22 March 2015 at 20:19, Eric Rescorla <[email-masked]> wrote:
>> opposed to fallback to 1-RTT, if the "orbit" indicated in the ClientHello is
>> not that of this server.
>
>

I don't see any way that we can support a mode that fails with
increased probability like this.  I think that the only real options
here are #2 and #3.  I'm tending toward a requirement for marking the
data as being explicitly replayable, simply because I don't think we
should leave applications with the awkward choice of deciding between
resend and something else.  Mainly because I don't know what that
something else looks like.

For HTTP, I think we can use that first flight for idempotent queries
quite easily and (at worst) the HTTP/2 connection preface.

---

From: Andrey Jivsov <[email-masked]>
Date: Sun, 22 Mar 2015 20:48:14 -0700

> quite easily and (at worst) the HTTP/2 connection preface.

I was thinking about in terms of two websites from different companies A 
and B.  They are independent and they get different orbit IDs. If A sees 
an orbit ID of B that A would never have sent, this is a replay. An 
error is appropriate on such mismatch.

Likewise, A, B can be divisions in the same company, in which case, 
again, there are different Orbit IDs and an error on mismatch.

When A and B are load-balanced, e.g. by DNS entries, then A, B are in 
the same orbit. In this case they should use the same DB.

(I probably re-defined the "orbit". In my proposal it's a persistent ID 
that survives the reboot ).

If the data center is misconfigured or a client confused the origin of 
the 0-RTT state, isn't an error appropriate? Otherwise, yes, there would 
need to be restrictions on data sent in 0-RTT.

---

From: Colm MacCárthaigh <[email-masked]>
Date: Sun, 22 Mar 2015 21:32:14 -0700

> quite easily and (at worst) the HTTP/2 connection preface.

This seems so open to error as to be untenable. Quite a lot of HTTP
based APIs are not idempotent, probably even the majority. Even where
API calls can be made idempotent in the theoretical sense, in the real
world there is often throttling and billing/metering state associated
even just with the raw number of calls made. So they are
non-idempotent by side-effect.

-- 
Colm

---

From: Colm MacCárthaigh <[email-masked]>
Date: Sun, 22 Mar 2015 22:21:02 -0700

> somehow forces the server to reboot (this is the hard part).

It's probably easier than rebooting in a real-world attack: the server
is vulnerable to state exhaustion attacks. For a primitive server, an
attacker can generate enough client randoms to exhaust the state
capabilities of the remote end. A more complicated server set-up might
use a distributed store, sharded on the client random data; but even
if they pay enough attention to use a salted hash of the client random
data for the shard key, it only changes the attack effort by a linear
factor.

> 0-RTT model we can lift and put into TLS that would solve the problem.

This probably opens a can of worms; but I think schemes that involve
an assumption of roughly synchronized time between clients and servers
can go quite a way to mitigating replay attacks too.

Also, I know it's groan-worthy: but a safe variant of 0RTT is to first
transit data opaquely, protected by a key that is only sent once the
server is authenticated. This makes optimistic execution impossible on
the server side, but it does preserve some of the benefits of network
throughput and latency.

> TLS, but of course that's different from having TLS give up those

I don't think it's a good idea to use browsers as the comparison here.
TLS is used extensively outside of browsers and many of those
applications do not retry like this, and rely on TLS as their
anti-replay mechanism.

-- 
Colm

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 00:38:05 -0500

> "Post /buy-something" -------------------------------------------->

If the client's first message had a nonce that the reject message (or
subsequent handshake) could authenticate, then this attack goes away
because the client will see that its message has been played, therefore
the client should not play it again.  Now the client application needs a
way to recover other than repeating the request!  It needs to go check
the status of whatever it wanted done (a GET, here).

Nico
--

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 23 Mar 2015 09:59:59 +0200

On Sun, Mar 22, 2015 at 05:59:46PM -0700, Andrey Jivsov wrote:
> "POST /buy-something" (via a replay of a captured message). Had the Server 2
> above rejected the ClientHello [+0-RTT] which was intended for Server 1

I think there would still be a problem: The transaction would get retried
(there might be a dialog to shift the blame on user).

I don't see a way of eliminating this "forking" attack without essentially
eliminating 0-RTT (since client doesn't prove that its exchange key was
correct until handshake is complete, and at that point you can start sending
data anyway).
 
> opposed to fallback to 1-RTT, if the "orbit" indicated in the ClientHello is

Won't help, and in general, you really don't want to fail TLS handshake
unless you know the handshake with that client can never succeed (e.g.
not supporting secure enough crypto).

> The only requirement here is that the server always knows its orbit. Servers
> must have different orbit IDs if they cannot handle simultaneous receipt of
> identical "POST /buy-something".

As noted above, you can use server that has different orbit as the second
server in attack.

Heck, in above diagram, the second server actually _rejects_ the 0RTT.
You propose additionally rejecting the connection, which will get retried.

Heck, I think the "forking" attack might actually work better in practice
with servers with different orbit IDs than with the same orbit ID, since
the latter could actually signal that replay is happening to the client.

-Ilari

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 03:33:09 -0500

> quite easily and (at worst) the HTTP/2 connection preface.

But TLS can't know what's happening at the application layer, so it had
better be the case that the 0-RTT data is clearly denoted to the app as
"had better be idempotent".  I.e., this becomes an API issue.  The name
of the method would have to be indicative of danger.

0-RTT data is acted on at great risk.  It's OK to use it for negotiation
purposes where the integrity of the negotiation will eventually be
confirmed (else the connection fails).  For things like "launch
missiles" it is a very bad idea to act on the command before
authenticating it and determining that it's not a replay.  When we don't
know the nature of the data, we must assume it can't be sent without
authentication and replay protection.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 03:47:16 -0500

> any data the client sends in subsequent flights has the usual

This is an optimization.

If the server loses its replay state then it must cause every 0-RTT
connection to become a 1-RTT connection.  There's no question of "want".

Nico
--

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 06:12:25 -0700

> data for the shard key, it only changes the attack effort by a linear

Well, Adam described at the interim why this isn't a concern: as the
"strike register" takes a higher density of entries, the window of
time over which it applies can be narrowed to limit the potential for
state exhaustion.  That simply increases the likelihood of a
rejection, not the attack.

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 23 Mar 2015 08:11:59 -0500

> connection to become a 1-RTT connection.  There's no question of "want".

Maybe I wasn't clear. When I said "reject" I meant "hard-fail" rather than
make it 1-RTT.

-Ekr

Nico

---

From: Roland Zink <[email-masked]>
Date: Mon, 23 Mar 2015 15:04:59 +0100

>    flight and tell applications to only send data there that can
The server probably can't trust the clients choice. An API on the server 
side is needed as well to check that data received on the first flight 
is acceptable.

>    the first flight, so that the stack doesn't automatically replay it.
What does happen when the stack can't deliver it? Is the user asked to 
replay? Does the software hang?

> separately. So, for instance, in option 2, you would have something
Does this mean a standard API will be specified. A separate API would 
mean that 0RTT will not be available in many cases because the replay / 
delivery guarantee requirements are unknown in some layers.

The solutions 2 and 3 seem to give the problem to the application, e.g. 
either the application doesn't (need to) care or need to implement it. 
So solution 1 seems the way to go although for non single server 
solutions this may be complicated.

Roland

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 07:12:49 -0700

On 23 March 2015 at 07:04, Roland Zink <[email-masked]> wrote:
> Does this mean a standard API will be specified.

Probably more in the form of a generic recommendation, or a
requirement on what the API needs to achieve.

---

From: Colm MacCárthaigh <[email-masked]>
Date: Mon, 23 Mar 2015 07:26:19 -0700

> rejection, not the attack.

I haven't been able to get my head around this. Doesn't that mean that
an attacker can disable 0RTT for third parties at will? it also means
that the session itself must be invalidated on a shorter duration, or
else we could just collect 0RTT data from before the time window and
replay those.

-- 
Colm

---

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 23 Mar 2015 14:40:52 +0000

> authentication and replay protection.

Therefore, 0-RTT data must:

    * Require a non-default code path to send, (explicit request
    by the client to send a 0-RTT message).

    * Require a non-default code path to *receive*.  That is,
      the server must be configured to allow receipt of such data,
      and must explicitly request to read it.  If the server issues
      a read for protected data, while expedited 0-RTT data is
      pending, the connection should be aborted by the server's
      TLS stack.  Once the server exhausts all the expedited
      data, it can switch to reading protected data.

    * The server's TLS stack must not coallesce 0-RTT expedited
      (idempotent) data with subsequent protected data.

This allows servers that receive idempotent queries to avoid the
1-RTT latency.  Something akin to DNS lookups over TLS, (I am not
specifically advocating TLS as a transport for DNS in this message).

Servers reading expedited 0-RTT data will be aware that they are
doing that, and can/should reject operations that are unsafe in
that context.

This avoids all futile attempts to add stateful replay protection
to a stateless phase protocol.  I expect such attempts are doomed
to failure.

-- 
	Viktor.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 07:42:50 -0700

On 23 March 2015 at 07:26, Colm MacCárthaigh <[email-masked]> wrote:
> an attacker can disable 0RTT for third parties at will?

To the extent that they can create connections that use 0RTT, yes.

And yes, narrowing the window means that clients need clocks that are
increasingly better synchronized to that of the server if they are to
succeed under these sorts of conditions.

---

From: Brian Sniffen <[email-masked]>
Date: Mon, 23 Mar 2015 10:00:53 -0500

> requirement on what the API needs to achieve.

APIs offering a socket model and attempting to provide a secure socket
layer shouldn't use the 0RTT path at all, then?  APIs exposing a record
or message semantics (either TLS's, or their own) can use 0RTT iff they
can guarantee idempotency of the messages in the 0RTT fragment?

-Brian

-- 
Brian Sniffen
"I reserve the right to evolve my views, and state that views I previously
 expressed may have been somewhere along the spectrum from insufficiently
 nuanced through ill-informed to dead wrong."

---

From: "Salz, Rich" <[email-masked]>
Date: Mon, 23 Mar 2015 15:06:06 +0000

> APIs offering a socket model and attempting to provide a secure socket layer
> shouldn't use the 0RTT path at all, then?

TLS_SOCKOPT_STOP_ME_IF_YOUVE_HEARD_THIS_BEFORE ?

Call me cynical, but search engines are going to force adoption of this.

--  
Senior Architect, Akamai Technologies
IM: [email-masked] Twitter: RichSalz

---

From: Roland Zink <[email-masked]>
Date: Mon, 23 Mar 2015 16:16:10 +0100

>>        (idempotent) data with subsequent protected data.
Often there is a whole software stack on top of TLS. You probably can't 
forward the requirements through the complete software stack.
>> specifically advocating TLS as a transport for DNS in this message).
Even DNS queries may have side effects, for example when it is used to 
do load balancing.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 08:18:14 -0700

On 23 March 2015 at 08:00, Brian Sniffen <[email-masked]> wrote:
> can guarantee idempotency of the messages in the 0RTT fragment

That sounds like a reasonable first approximation.  It might be that a
streamed/socket protocol can intrinsically handle the replay problem
because of the nature of the protocol, but in the generic sense, this
would be correct.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 08:20:44 -0700

> forward the requirements through the complete software stack.

If you can't then don't.  It is perhaps unfortunate, but this is going
to have a very narrow applicability.

---

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 23 Mar 2015 15:28:31 +0000

On Mon, Mar 23, 2015 at 04:16:10PM +0100, Roland Zink wrote:

> >>     * The server's TLS stack must not coalesce 0-RTT expedited

That's good.  Such software stacks will not be 0-RTT aware, and
must not see 0-RTT data.  Only stacks explicitly designed for 0-RTT
will get to play.

> Even DNS queries may have side effects, for example when it is used to do
> load balancing.

DNS "load-balancers" are really latency optimizers, they don't
actually know how much load they are directing at servers because
there is a not a 1-to-1 mapping between DNS requests and service
requests.  There should be no state changes based on the observed
DNS queries, and if even there are, nothing tragic happens.  The
intended application here would be confidentiality only.

-- 
	Viktor.

---

From: Roland Zink <[email-masked]>
Date: Mon, 23 Mar 2015 17:08:14 +0100

> must not see 0-RTT data.  Only stacks explicitly designed for 0-RTT
Seem like very limited use, but still when somebody builds something on 
top of such a stack not knowing that something special needs to be done. 
Simplest may be a HTTP library thinking GET requests are idempotent, 
which they should, and is doing 0-RTT and the server does something on 
the GET request like fire some missiles.
> intended application here would be confidentiality only.
Well DNS is only an example anyway. Assuming the server is returning A,B 
on even requests and B,A on odd requests and an attacker replays all 
requests then the server will always returning the same result to the 
real clients.

---

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 23 Mar 2015 16:22:00 +0000

On Mon, Mar 23, 2015 at 05:08:14PM +0100, Roland Zink wrote:

> Seems like very limited use,

Deliberately so, for people who know what they are doing, to support
latency sensitive idempotent requests that don't need request replay
protection.

> but still when somebody builds something on top of such a stack not knowing
> that something special needs to be done.

They lose.

    * If clients make 0-RTT requests to a stack that does not
    support these, all connection abort when the stack requests
    non-expedited data, while expedited data is pending.

    * If the stack requests expedited data without an explicit
    request from the server application to do that, it is broken.
    Vulnerability reports will be filed, everyone will run around
    patching, ...

> Simplest may be a HTTP library thinking GET requests are idempotent, which
> they should, and is doing 0-RTT and the server does something on the GET
> request like fire some missiles.

HTTP libraries have no business doing that (bring on the sky is
falling vulnerability reports, emergency patch cycles, ...).  The
application would have to explicitly signal support for such
requests, and when they arrive they'd have to be clearly tagged as
such consistent with the API that enabled their delivery.

-- 
	Viktor.

---

From: Roland Zink <[email-masked]>
Date: Mon, 23 Mar 2015 17:36:36 +0100

>      Vulnerability reports will be filed, everyone will run around
Hope you will not get many such vulnerability reports.

---

From: Colm MacCárthaigh <[email-masked]>
Date: Mon, 23 Mar 2015 09:44:16 -0700

> latency sensitive idempotent requests that don't need request replay

Should using TLS securely rely on that level of expertise? it is also
an incredible temptation to have the possibility of optimistic
execution, and just not pay any attention to the idempotent (or
reliability) issues.

Are there that many applications that are this latency sensitive that
can't use long-lived connections/sessions?

-- 
Colm

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 23 Mar 2015 18:52:01 +0200

>     non-expedited data, while expedited data is pending.

I regard that as very bad idea. The server should reject the
0-RTT data, not abort the connection, because the former can
sanely be handled by the client, the latter can't.

-Ilari

---

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 23 Mar 2015 16:59:36 +0000

> sanely be handled by the client, the latter can't.

A connection on which the initial data was lost is broken.  Signalling
such loss is simplest by dropping the connection.

In practice 0-RTT clients will talk to 0-RTT enabled servers.
Everyone else avoids the can of worms.  The 0-RTT mechanism will
support the specialized applications that need it.

--
	Viktor.

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 23 Mar 2015 19:07:33 +0200

> such loss is simplest by dropping the connection.

No, it isn't. The client will need to handle 0-RTT being lost
anyway.

And even if the client manages to guess what went wrong (if it doesn't
non-retry error is the best case), recovering from abort much more
expensive.

-Ilari

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 12:08:52 -0500

I'm missing some of the context.  Is this 0-RTT fast reconnect (a la
TCP-FO) or is this 0-RTT even for first-meet?  Regardless:

 - I don't really believe that distributed replay caches, are feasible
   without adding back a lot of the latency to be gained from having
   0-RTT.  Fast non-distributed replay caches are feasible, but from the
   discussion so far it seems like that's not interesting anyways.

   This is Kerberos experience talking.  Kerberos, you'll recall, hearts
   replay caches.  We do know how to make fast local replay caches, and
   even adaptive ones that respond to load.

 - I've made this point in the past that 0-RTT data has to be of the
   sort that is safe to use in this way, and therefore I agree strongly
   with comments made so far that this must show up in the API (client-
   and server-side) as such.

 - Idempotence isn't necessarily enough.  "Launch missiles" might be
   idempotent (e.g., world ending) or not ("accidental launch?"), but in
   the latter case a replay might then be idempotent (not accidental ->
   world ending).

 - And just in case anyone is proposing it, I object to TLS interpreting
   supposed-to-be-idempotent HTTP requests as idempotent.  As others
   have mentioned, there exist plenty of "HTTP APIs" that violate HTTP
   idempotence requirements.  Perhaps we should point and laugh, but
   ignoring them seems unwise.

 - Data to be delivered in a 0-RTT way really must be used with care.

   Any API must require that the application [developer] be aware of
   this.

FYI, I had an I-D once about combining SASL mechanism negotiation into
the TLS handshake so as to speed up LDAP, IMAP, and other SASL
applications.  There the 0-RTT data was the SASL mechanism negotiation,
and though it was used prior to handshake completion, its integrity was
also confirmed before any incorrectly-chosen SASL mechanism could yield
success and access for the attacker.  My I-D was specifically about
SASL.  Generalizing this to "any protocol" without taking care to
explain what kind of data can be used is dangerous.

Also FYI, GSS-API has ways to send/receive generic 0-RTT data with
complete handshakes, and has the same considerations that we are
describing for TLS.  The GS2 SASL mechanism uses this, again, for
negotiation purposes, not for application data, but the technique used
works for application data as well, with the caveats that we're
discussing.

The GSS case has not had a full treatment in any RFCs, but there's some
hints about it here and there.  At least GSS got the API right: the
application has to take extra steps to send and use 0-RTT data.  TLS is
much more widespread than GSS, therefore the potential harm of misuse of
0-RTT data is much higher.

Nico
--

---

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 23 Mar 2015 17:14:39 +0000

> No, it isn't. The client will need to handle 0-RTT being lost

Naturally before disconnecting, the server stack should send an
appropriate alert.  But since clients should only be configured
for 0-RTT with application protocols where the server is required
to support 0-RTT, there's no point in falling back.

I don't see 0-RTT as an "opportunistic" feature.  I see it as
support for latency-sensitive idempotent applications in which it
is always used.  Eliminating fallback to 1-RTT avoids much complexity.

-- 
	Viktor.

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 12:15:32 -0500

> execution, and just not pay any attention to the idempotent (or

In some sense this is unavoidable.

Consider channel binding.

In the SASL/GS2 framework we use the GSS channel binding data input to
deliver data beyond just proper channel binding data, but the data so
delivered is negotiation data.  (Integrity protection of that data is
delivered eventually.)

Now, TLS may not have a proper channel binding data _input_, but
developers, I'm sure, could marshall something.

Imagine a StartTLS protocol where the client sends a request (launch
missiles) and a request/offer to upgrade to TLS, with subsequent
integrity protection of the "0-RTT" data from the first request: if the
server has acted on the 0-RTT data by then, it's too late.

Therefore it seems that the issue is somewhat unavoidable even if we
exclude a 0-RTT mode in TLS, and so we should describe the associated
security considerations.

Nico
--

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 12:19:55 -0500

> Maybe I wasn't clear. When I said "reject" I meant "hard-fail" rather than

Sorry it wasn't clear to me.  Is there any reason that fallback to 1-RTT
is not feasible?

For context, I'm proposing similar fallbacks (but for other reasons) for
Kerberos (which never had such a fallback).  This has proven desirable
in the context of Kerberos, and so I suspect it will be for TLS.

Obviously I'm missing some of the TLS 0-RTT context.

Nico
--

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 23 Mar 2015 12:41:33 -0500

> Sorry it wasn't clear to me.  Is there any reason that fallback to 1-RTT

Yes. The issue is that the client has no way of knowing whether the 0-RTT
message was duplicated and processed by a separate server instance, so
when it falls back to 1-RTT, resending the initial data may be a replay.

-Ekr

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 12:47:31 -0500

> when it falls back to 1-RTT, resending the initial data may be a replay.

The server can certainly indicate what, if any 0-RTT, it received (by
sending a hash back).  If it did not receive the 0-RTT data then the
client can fail (TLS over TCP) or retransmit (DTLS over UDP or
similar).  If the server received the wrong 0-RTT data then the client
can fail and/or sound the alarms, or even retransmit if the data was
inconsequential (e.g., a SASL mechanism negotiation, which can then be
redone).

Nico
--

---

From: Patrick McManus <[email-masked]>
Date: Mon, 23 Mar 2015 12:55:15 -0500

It seems to me this is strongly analogous to how applications need to deal
with tcp fast open. And indeed, only applications strongly motivated to
need low latency embrace its complexity.

The tact with TFO is basically that any data sent with the fast open has to
be tolerant to replay.

I like the proposed refinement here, what I perceive of as #3, that the
stack does not replay it (sacrificing reliability). That seems both like
less of a footgun, and gives a chance for a little more application
flexibility on how to handle the exception.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 23 Mar 2015 11:05:47 -0700

> flexibility on how to handle the exception.

I get the sense from the discussion that people have different takes
on #2 and #3.  Do we really need to decide here?  Can we offer TLS
APIs the choice?  Some might even choose to implement both models and
kick the can even further down the road.  I don't actually see any
problem with that.

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 23 Mar 2015 13:12:57 -0500

If I can refer you back to the diagrams I provided in my e-mail, I think
you'll
see that this doesn't help. The issue is that the first time that the
client's
data is handled there is *no* feedback from the server to the client, so
nothing
that the server says is going to help.

-Ekr

---

From: Nico Williams <[email-masked]>
Date: Mon, 23 Mar 2015 14:29:36 -0500

On Mon, Mar 23, 2015 at 01:12:57PM -0500, Eric Rescorla wrote:
> If I can refer you back to the diagrams I provided in my e-mail, I
> think you'll see that this doesn't help. The issue is that the first
> time that the client's data is handled there is *no* feedback from the
> server to the client, so nothing that the server says is going to
> help.

Indeed.  If the server ever responds to the client (for that
connection), then there is feedback, but such feedback is too late, and
might never arrive (the client application times out, maybe retries).
Therefore such feedback must not be security-critical, which means that
the data sent must be more than idempotent: it must yield no meaningful
side-effects on the server-side.

Again, optimizing something like a SASL mechanism negotiation, "open
INBOX" (but not "open my-secret-design-for-xyz") -- that's fine.
Optimizing arbitrary application protocols this way is not.

This is really a security consideration, but it should come with API
design advice (since TLS lacks an abstract API).

Nico
--