We currently allow 0-RTT with Semi-static DH, with PSK resumption, and with 
pure PSK.
Whether or not we keep all of these, it would be good to clean up the protocol 
design 
so that both the client and server have a uniform way of signaling their 
preferences.

After implementing and analyzing TLS 1.3, here are a few suggestions for 
discussion.

1) Early Data Extension

The current early-data extension is too DH-specific.
When using PSK, we now have to look at both early_data and pre_shared 
extensions.
I suggest reusing the same extension for both, with the following 
interpretation:

        struct {
          select (Role) {
              case client:
                  opaque id<1..2^16-1>;
                  opaque context<0..255>;
                  CipherSuite cipher_suite;
                  Extension extensions<0..2^16-1>;

              case server:
                 struct {};
                }
        } EarlyDataIndication;


In the semi-static DH case:
- id is the configuration id
- context is the hash of the ServerConfiguration + Server Certificate + 
CertificateRequest

In the PSK resumption case:
- id is the session ticket
- context is a *public* value unique to the derived session. For example, it 
could be defined as the session hash of the original handshake,
  or it could be derived by the client as HKDF(RMS, “early data context”)

In the pure PSK case
- id is the PSK identifier
- context is unique to the PSK and its allowed use.
  For example, it can be generated (out-of-band) as HKDF(PSK, “early data 
context”)

2) New Session Ticket

The NewSessionTicket message needs to indicate whether the server will accept 
0-RTT,
and what ciphersuites it is willing to accept (e.g. pure PSK resumption vs only 
PSK-ECDHE).

I suggest the following modification to this message:
        struct {
         uint32 ticket_lifetime;
         opaque ticket<0..2^16-1>;
         CipherSuite cipher_suites<2..2^16-2>;
         EarlyDataType early_data_type
        } NewSessionTicket;

        enum {
          no_early_data_allowed(0),
          replayable_early_data_allowed (1),
          all_early_data_allowed(2),
          (65535)
       } EarlyDataType;

The interpretation of the early_data_type field is that the server is either:
(a) unwilling to accept 0-RTT (no_early_data_allowed), 
(b) willing to accept 0-RTT, but it has no replay cache 
(replayable_early_data_allowed),
(c) willing to accept 0-RTT and has a replay cache that it uses to prevent 
replay (all_early_data_allowed)

The client’s response to this ticket message should be to store it in its
session along with the “context” (session hash or derived from RMS),
the allowed cipher suites, and the early_data_indication.

When resuming with this ticket:
- the client should not send any 0-RTT data if no_early_data_allowed
- the client should only send replayable data if replayable_early_data_allowed 
(e.g. GET requests)
- the client can send any 0-RTT data if all_early_data_allowed, trusting the 
server to do the right thing.


A note on replay
----------------------

There has been much discussion on 0-RTT replay and here’s a quick summary of my 
understanding.
We already knew that an active attacker, or a lossy network, or an overzealous 
web browser could
and would cause 0-RTT (and even 1-RTT) data to be replayed to the server. This 
can already happen
in TLS 1.2, in QUIC, and so we accepted it as a given in TLS 1.3.

The new concerns on the mailing list (and in my TRON talk which was based on a 
ProVerif model) 
are that unlike TLS 1.2:
(a) even a passive attacker could replay 0-RTT data, long after the client has 
gone away,
(b) replaying authenticated 0-RTT data can be more damaging (whether 
authenticated with client cert or with a cookie), and
(c) by replaying 0-RTT data, the attacker can obtain encrypted 0.5-RTT data 
which opens up new attack vectors.

As a result of these new concerns, I would say that TLS 1.3 should recommend 
that all servers SHOULD
implement a replay cache, and those that cannot should clearly signal this to 
the client, so that the client
can adjust its 0-RTT use case and its expectations accordingly.

A note on authenticating the 0-RTT “context”
----------------------------------------------------------

When trying to figure out how to authenticate 0-RTT DH mode in an earlier 
draft, we came upon the
design of signing the Handshake Context that consists of the ClientHello + 
additional information from the previous handshake.
This construction prevents 0-RTT authentication from unknown key share attacks.

Even if we eliminate client certificate authentication from 0-RTT, this notion 
of “context" is still useful for two reasons:
(a) the application may use TokenBinding or some such protocol to authenticate 
0-RTT data, and we need to understand what “channel binding” to provide for 
this case,
(b) in PSK resumption mode, since the handshake log does not contain much 
information that is specific to the previous connection, it would be more 
robust to add an explicit context.

If we accept the definition of “context” in the EarlyDataIndication extension, 
then we can use the hash of the ClientHello uniformly in all
0-RTT modes for deriving keys, and for deriving a channel binding for the 
application. Furthermore, we can safely introduce a PSK_ECDHE
mode where the server sends its Certificate and CertificateVerify and its 
signature is correctly bound to the PSK (via the “context” field).

Best regards,
Karthik





_______________________________________________
TLS mailing list
TLS@ietf.org
https://www.ietf.org/mailman/listinfo/tls

Reply via email to