[noise] Alice and Bob (was Re: NoiseSocket and "reversed" protocols)

Trevor Perrin trevp at trevp.net
Thu Nov 9 11:34:53 PST 2017


On Thu, Nov 9, 2017 at 3:05 PM, David Wong <davidwong.crypto at gmail.com> wrote:
>>> However, some situations might require "branching" (negotiating
>>> protocol versions or crypto choices; 0-RTT fallback).
>
> Isn't "crypto choices" something we want to avoid?

Yes!  I think runtime complexity should be avoided if possible
(parsing, negotiation, etc).

But some is a necessary evil (protocols and crypto choices will evolve
over time; 0-RTT will sometimes fail; there are situations where
agility makes sense).

So composing simple/linear Noise protocols into compound/branching
protocols is probably something we have to deal with.


> agl posted about
> this in what he calls "crypto agility" (this might have been discussed
> on the list before but I missed that :D)

Yeah that's a great essay:
https://www.imperialviolet.org/2016/05/16/agility.html

My take is that he advocates "extensibility" (being able to deploy
changes over time without breaking old implementations), but not
"agility" (having lots of options at a single point in time).

So I see extensibility as a mechanism, and agility as a philosophy of
using that mechanism.

I think we're all in opposition to the "kitchen-sink" agility of 1990s
protocols, but I can think of cases where limited agility makes sense:
 * A server supporting AESGCM for clients with HW acceleration or
ChaChaPoly for clients without.
 * A server supporting 448+Kyber for more powerful clients and 25519
for constrained devices.

Regardless, I think the "extensibility" mechanism needed for "agility"
is the same mechanism needed to support protocol changes over time
(e.g. migrating from older to newer crypto), so it's the mechanism we
need to tackle.  We can leave questions of "agility philosophy" for
higher-level designers using the mechanism.


>>> In a "compound protocol", it's not clear how to handle the roles of
>>> "initiator" and "responder".  For example, if the client initiates a
>>> connection to the server and sends an IK message that the server can't
>>> decrypt, the server will be "initiating" the XXfallback.  But since
>>> initiator-sent messages are notated with right-pointing arrows,
>>> reading IK and XXfallback back-to-back would be confusing if we didn't
>>> do something to prevent the client<->server message direction from
>>> flipping.
>
> Why not just have the server send some "retry-with-protocol-X"
> message, which will make the client re-start a new handshake with a
> different pattern.
> This is what TLS 1.3 does at the moment, the server sends a hello
> retry request if it's not satisfied with the client hello, and the
> handshake basically restarts. It's a penalty but it keeps things
> simple and easy to analyze.

A "retry request" is not a great alternative to IK/XXfallback ("Noise
Pipes"), since it adds a whole round-trip in the case that the server
fails to decrypt the 0-RTT data.

It's also *not* how TLS 1.3 always handles this - a TLS 1.3 server
that fails to decrypt the 0-RTT data can transition into a full
handshake using the client ephemeral (if it is present), just like
XXfallback.

If the server rejects the client ephemeral (because the server prefers
448 over 25519, for example), then a "retry request" is a simple way
to handle this, and this is what's in TLS 1.3 and the current
NoiseSocket spec.

While that's simple, it's a bit inefficient to use the server's
response solely for a "retry request".  If the server is willing to
send an ephemeral and identity public key in the clear, then we can
get more out of the server's response.

This is why I'm comparing NX/retry-request/NX with NX/IN.  Here are
the patterns (IN is presented with Bob as initiator):

NX(rs):
    -> e
    <- e, ee, s, es

IN(s):
    <- e, s
    -> e, ee, es


Here are transcripts of the "compound protocols" where the server
rejects the first ephemeral.  With the retry-request, Alice needs 2
round-trips before sending encrypted data, but with NX/IN she only
needs 1:

NX / retry / NX:
 -> e [25519]
 <- retry request
 -> e [448]
 <- e, ee, s, es

NX/IN:
 -> e [25519]
 <- e, s [448]
 -> e, ee, es

There's certainly an argument that "retry-request" is better - it's
simpler, this is a perhaps a rare case, and the security properties of
the NX/IN initial encryption are subtly weaker.

However I think the NX/IN combination is reasonable, so we should have
a language for describing this (and perhaps other cases like it).  And
I think being able to talk about (and compose) Alice-initiated and
Bob-initiated patterns might get us there.

Trevor


More information about the Noise mailing list