[nanomsg] Re: nanomsg status and encryption

  • From: Alex Elsayed <eternaleye@xxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Sun, 15 Dec 2013 13:07:32 -0800

Drew Crawford wrote:

> Hey folks, I know this has been asked before, but it seems it’s been 7
> months, so maybe it’s time for a new one :)
> 
<snip>
>
> Also, I have some encryption requirements.  I’m no stranger to
> implementing this, having designed something that worked “well enough for
> me" for zeromq.  As far as trying to move that work upstream goes, there
> were two real problems.  One was that everybody says “encryption” and
> wants something different, and solving my problem (mostly securing and
> authenticating 1:1 REQ/REP sockets) didn’t necessarily solve other
> people’s problems.  In my view there is no one-size-fits-all solution. 
> There are some better and worse ones, but nothing that works for
> everybody, and if you hold out for that solution you get nothing, and thus
> is the state of zeromq.

Yeah, there really are a lot of different things 'encryption' can mean (and 
some things people think it means when it doesn't).

First of all, we need to distinguish between the three purposes cryptography 
is used for: identity, confidentiality, and integrity. 'Encryption' is 
_properly_ only used to refer to things that provide confidentiality.

Second, we need to distinguish _what_ we are trying to prove about 
ourselves(identification)/keep secret(confidentiality)/prevent tampering 
with(integrity), and who we are trying to prevent from interfering.

For instance, if we want to make sure that node A is a valid participant of 
topology B and that communications within the topology cannot be 
eavesdropped by anything outside it, that's best solved by node-to-node/hop-
to-hop security along the lines of TLS, or possibly tcpcrypt + 
authentication. (Have the topology name in the SubjectAltName of the per-
node certificate or some similar approach).

This is probably not _too_ hard to implement (warning: W.A.G. in progress), 
and can be used (with configuration) to ensure that only trusted nodes 
participate, and thus content is only seen in unencrypted form by trusted 
nodes.

This would be implemented per-transport - inproc:// probably doesn't really 
need it, ipc:// can do it as long as we're using SOCK_STREAM because 
generally TLS APIs allow you to plug in another socket, tcp:// is obvious, 
etc - I'd actually suggest using a notation like tcp+tls:// instead of a new 
tls:// transport, to allow for the ipc+tls:// case (or if something replaces 
tls someday). I will also note that authentication and/or key exchange for 
multicast is a very hard problem indeed, and we'll want to think about that 
going forward if we ever want to implement a multicast transport like zmq 
had.

On the other hand, if we want to make sure that data passing through 
untrusted nodes is still confidential and has not been tampered with (i.e. 
end-to-end security), we need to do something on a per-topology basis, and 
that way lies the risk of rolling our own crypto. That has real, large risks 
of doing it very very wrong. It's also going to be very difficult. For 
instance, REQ/REP is stateless - any such system that is implemented on 
_top_ of REQ/REP cannot require a round trip to handshake, it needs to be 
single-pass.

You might be able to get away with something like OpenPGP for REQ/REP - it's 
one-pass stateless message sending, although you need to know the 
recipient's public key. However, that could come from the configuration 
service. If you bootstrap it via a pre-loaded key for the conf service, 
you'd have a well-rooted trust path (you would need to provide some id to 
look up your key by for the _return_ path though). However, that provides no 
forward secrecy - if someone managed to store all of your old REQs in 
encrypted form and then yoinked the node's private key, they could go back 
and decrypt them all at any later time.

It's things like that which convince me that even if we _can_ do end-to-end, 
I think that at least _some_ users will need both hop-to-hop (which would 
prevent anyone other than a trusted node from participating in the 
topology/saving those old messages) and end-to-end (to guarantee that the 
node replying to you is the one you meant to ask).

> The other issue is that there was no real obvious way to inject
> authentication/decryption modules into the zeromq codebase.  (That stuff
> minimally requires a handshake before any packets are sent, for example,
> so it’s not just as simple as running a function on packets as they enter
> the queue).  As a result I just did something at the application level,
> which is impossible to upstream.  My thinking is that in nanomsg I could
> perhaps implement encryption as a protocol or transport…maybe… and get it
> merged in.  Thoughts?

Eh, a handshake may not be necessary (depending on the layer, and possibly 
in the universal sense) - if the right parameters are known ahead of time, 
you can do some cool things with no handshake at all. (However, any suite 
providing perfect forward secrecy _does_ require a round trip to the best of 
my knowledge, which is certainly a possible issue).

Also, if what you're doing at the application level expects a REQ/REP to 
keep state between requests, that's a violation of the spirit of REQ/REP 
IIUC.

tl;dr: I think implementing something that is either an option to the lower-
layer transport or another state machine between transport and the SP 
framing is a good thing to do in the near term, but doing anything end-to-
end will require lots of very careful thought and consulting people 
considerably better at cryptography than myself.



Other related posts: