[noise] Additional 0-RTT modes

Trevor Perrin trevp at trevp.net
Tue Aug 1 12:28:41 PDT 2017


Noise currently supports 0-RTT encryption based on the server's static
public key.

We've talked about adding support for 0-RTT based on:
 * A short-lived server public key, like QUIC or MinimaLT
 * A PSK, like TLS

I'd like to write a spec for these soon, based on the following ideas.
Any feedback is welcome, particularly if you doesn't like this
direction:


Short-lived static plus offline signing key
---------------------------------------------
Noise currently supports 2 types of DH keys:
 * Long-lived key = Noise static (s)
 * One-time key = Noise ephemeral (e)

A short-lived key would offer better forward secrecy for 0-RTT data.
A short-lived key would seem to be a 3rd type, and we've thought about
whether this would be a "semi-static", "semi-ephemeral", or something
else.

One option for "something else" is to allow short-lived static keys
which are signed by a long-term key held by the server.  The
signatures and statics could be published, allowing 0-RTT initial
connections as well as resumptions.  The signing key would be
"offline", meaning it is not used interactively during the handshake.
This would allow existing Noise patterns (NK, XK, IK) to be used for
0-RTT, without modification.

There's a couple downsides, but I think they're tolerable:

 * For 1-RTT handshakes (like XX), the client would have to verify an
additional signature, instead of authenticating the long-term key
directly.  (We could consider authenticating the signing key directly,
either via an XX+sig pattern or by using something like XEdDSA that
allows signing keys to also be DH keys.  But it's probably easiest and
most consistent to just authenticate the short-lived static).

 * For 0-RTT handshakes, the client would have to be careful to bind
the "OSK" public key into the prologue, to prevent identity
misbinding/unknown key-share cases where a malicious OSK signs someone
else's static.


PSK resumption
---------------
TLS 1.3 will offer 0-RTT resumption via something like our NN+psk0.
In some cases, PSK resumption has advantages compared to short-lived
statics:

 * If the server is storing PSKs and deleting them immediately on
receiving 0-RTT data, then forward secrecy is improved vs short-lived
keys.  (However, this benefit is not achieved if the server is storing
PSKs inside session tickets which are encrypted with short-lived
keys).

 * If the client doesn't have a static key and is authenticating with
some other means (e.g. a password) inside the connection, then
resuming the connection could allow a more secure authenticated 0-RTT
(However, this benefit is not achieved if the client is authenticating
by sending something like an HTTP cookie inside the 0-RTT encryption).

PSK for 0-RTT also has disadvantages.  A big one is that it can only
be used for resumption, not initial connections.  Another disadvantage
is that authentication of the other party with a PSK uses a secret
value instead of a public key, so could be forged if the local PSK is
compromised ("key compromise impersonation").

In any case, we can provide a PSK option by deriving resumption PSKs
from an initial connection.  To give a general framework for deriving
extra keys, we can do something like:

EK = 3rd output from Split().HKDF()
CK_PSK, PSK_0 = HKDF(EK, "PSK")
CK_PSK, PSK_1 = HKDF(CK_PSK, "")
CK_PSK, PSK_2 = HKDF(CK_SK, "")

We could also use the third output from each HKDF as a label for the
PSK, so any number of resumption PSKs and labels can be derived
without client-server communication.

The client can then send the PSK label inside something like
NoiseSocket negotiation_data, and use resumption patterns like
NN+psk0, KK+psk0, XK+psk0, etc.


Trevor


More information about the Noise mailing list