[noise] NoiseLink brainstorming

Trevor Perrin trevp at trevp.net
Sat Nov 18 12:43:35 PST 2017


Hi all,

We've talked about a protocol layer "on top" of NoiseSocket that
defines the contents of negotiation_data (and maybe also handshake
payloads).  For a working title we could call this "NoiseLink".

There's a ton of questions about how to think about this, how many
features to put in, etc.  So let's do some brainstorming!


Noise Protocol Negotiation
===========================

For a first cut, I'll suggest using protobufs version 3 (proto3).  I
think this is popular, fairly simple, has good libraries, and defines
JSON as well as binary encodings.  Deciding which subset of proto3
features to allow is another question.  Perhaps we can start defining
things and see what we use.

The main task is for the client to specify the Noise protocol it's
starting with, and alternative protocols it would allow the server to
switch to, or request retry for.  We could do something like:

message InitialNegotiationData {
    string initial_protocol = 1;
    repeated string switch_protocols = 2;
    repeated string retry_protocols = 3;
}

message ResponseNegotiationData {
    oneof {
        bool accept = 1;
        bool reject = 2;
        string switch_protocol = 3;
        string retry_protocol = 4;
    }
}

This maps to the NoiseSocket decisions (accept / switch / retry /
explicit reject) in the obvious way.  For more concise encoding, you
could replace "string" with "uint32" and define a protocol registry
(and note that "uint32" will get encoded into a single-byte "varint"
if <= 127).  Hopefully most uses won't advertise that many protocols,
so strings won't be too costly, and will make interop / debugging
easier.


Below is a JSON example transcript of "Noise Pipes" - the client is
attempting 0-RTT encryption with an IK initial message.  If the server
accepts 25519 but can't decrypt the IK, the client is willing to
support XXfallback with either AESGCM_SHA256 or ChaChaPoly_BLAKE2s.
If the server doesn't accept 25519, the client is willing to retry
with 448.

The server chooses a fallback:


InitialNegotiationData :
{
    initial_protocol : "Noise_IK_25519_AESGCM_SHA256",
    switch_protocols :
    [
        "Noise_XXfallback_25519_AESGCM_SHA256",
        "Noise_XXfallback_25519_ChaChaPoly_BLAKE2s"
    ],
    retry_protocols :
    [
        "Noise_XX_448_AESGCM_SHA256",
        "Noise_XX_448_ChaChaPoly_BLAKE2s"
    ]
}

ResponseNegotiationData :
{
    switch_protocol : "Noise_XXfallback_25519_AESGCM_SHA256"
}



Other Negotiation
==================
Besides Noise protocol, the parties might want to negotiate:
 - maximum Noise message size (if recipients have limited buffers)
 - Rekey strategy
 - Application protocol version, or server name (SNI)
 - certificate format for the server to send certificates
etc.

I'm not sure, but it might be best to view this as a request/response
exchange of fields in the handshake payloads (*not* negotiation_data).
Putting this in handshake payloads means it gets encrypted to the
maximum degree possible, and also means that it gets negotiated in the
context of whichever "final" Noise protocol the parties agree on.

So something like this:

message InitialHandshakePayload {
    uint32 max_message_size = 1;
    bool continuous_rekey = 2;
    string certificate_type = 3;
}

message ResponseHandshakePayload {
    uint32 max_message_size = 1;
    bool continuous_rekey = 2;
    bytes certificate_chain = 3;
}

There's a lot more options that could be added.  I'm not sure we'd
make all (or any!) of them part of a default NoiseLink. Perhaps we
could just list out a bunch of options that higher-level protocol
designers could choose from.


Anyways this is all very sketchy, welcome any criticisms, alternative
ideas, etc.

Trevor


More information about the Noise mailing list