[noise] Resumption PSKs

Trevor Perrin trevp at trevp.net
Mon Feb 26 08:21:20 PST 2018


Hi all,

We had threads last year on "resumption PSKs", i.e. PSKs derived from
a parent session that are used for a 0-RTT child handshake [1,2].

Let's finish off the design so we can write an extension spec.


Proposal:

 * Split() is modified to take a list of N "labels" (label = byte-sequence).

 * Split() is modified to return a list of N "key chains".  Each key
chain has a chaining key ck and can output a sequence of 32-byte keys
k by calculating ck,k = HKDF-Expand(ck).

 * Each key chain is initialized by taking an additional output K from
the HKDF in Split(), then setting ck = HMAC(K, label).  After all the
key chains are initialized, K is deleted.

 * To get resumption PSKs, you use a label "psk" and then get as many
resumption PSKs as you need from the resulting key chain.

 * If you want an identifier for each PSK so that the client can
specify them to the server, you use an additional label "pskid", and
the "keys" from this chain serve as identifiers for the keys from the
"psk" chain.

 * For resumption, the handshake hash "h" for the parent session must
be stored and used as prologue for the child session.

 * Alternatively, to avoid storing an extra 32 bytes, a "compressed
resumption" can be used where a compressed "resumption value" of
HASHLEN bytes r = HMAC(PSK, h) is calculated, and then "decompressed"
later as PSK',h' = HMAC-Expand(r, "decompress").  PSK' is then used as
the child's PSK, and h' is used in the child's prologue.


Notes:

 * This mechanism for deriving additional keys could be used for other
purposes (e.g. if you want keys for additional streams between client
and server).

 * This mechanism has the property that after outputing a resumption
PSK, this PSK is independent from any of the keys held by the parent
session (the PSK can't derive them, and they can't derive it).  This
gives parent and child sessions independent forward-secrecy.  This
property is not achieved in TLS 1.3.

 * The PSKs derived here are just 32-byte symmetric keys with the same
security as the parent's session keys.  They are *NOT*
collision-resistant hashes that incorporate the parent's "h".  Instead
we require the parent's handshake hash to be specified explicitly in
the prologue, either as a separate value or a compressed/decompressed
value.


This last point is a major design decision.  An alternative design
(more like TLS 1.3) would make all additional keys a HASHLEN-size hash
of K and h, and would make all PSKs a HASHLEN-sized input.

I think we should not do this, for a few reasons:

 * If the additional keys k are being used immediately (e.g. for
additional streams between client and server), we don't need the extra
cost and complexity of mixing in the transcript hash and expanding
this to HASHLEN bytes.

 * If child sessions are defined in terms of a HASHLEN-sized PSK value
that may (or may not) incorporate a parent's handshake hash, then the
parent's hash becomes an invisible but security-critical input.  It
would be easy to forget about it, and use the child handshake with a
PSK from some other source.  Thus, I think it's better to make the
parent handshake hash an *explicit* parameter.

 * Relying on "identities" hashed into "session keys" in the context
of DH-authenticated protocols is something we've avoided due to
Microsoft's KEA+ / "Extended authentication key exchange".  The
"compression" mechanism is different enough that I think this is not a
concern.

Thoughts?

Trevor

[1] https://moderncrypto.org/mail-archive/noise/2017/001212.html
[2] https://moderncrypto.org/mail-archive/noise/2017/001402.html


More information about the Noise mailing list