[nanomsg] Re: nanomsg status and encryption

  • From: Drew Crawford <drew@xxxxxxxxxxxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Sun, 15 Dec 2013 22:03:04 -0600

> 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.

Let me be a lot more specific about my requirements.  I wasn’t sure how tedious 
to be in my first email.

I am largely interested in a traditional client/server architecture and 
providing TLS-like guarantees (confidentiality, integrity, identity).  There 
are a couple of places where my requirements depart from TLS (for example chain 
of trust—I deliberately don’t want this), and this and a handful of other 
issues precludes using TLS as such.  

In my case, I am mostly interested in single-hop connections, because 
performance requirements cast doubt on the multihop case independently of any 
encryption requirement.  So the distinction between “hop-to-hop” and 
“end-to-end” encryption is largely an academic one for my application, although 
I believe an end-to-end scheme would as a practical matter make it more 
difficult to wind up with accidental or unintended participants in the 
topology, and, potentially, may be more useful to others where the distinction 
is non-academic.  But, if there is some compelling reason to do one or the 
other, I am up for implementing either one, potentially.  

> 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.

I want to probe a bit at specifically what you mean by “REQ/REP is stateless,” 
because I haven’t groked what exactly you are saying.

Do you mean that this is the current implementation?
Do you mean that this is the current implementation, and that it is a design 
goal that REQ/REP should remain stateless?
Do you mean that implementing an alternate transport protocol, API-compatible 
with Req/Rep but with the change of being stateful under the hood, is a bad 
and/or foolish idea?
Do you mean that an application that uses Req/Rep as the transport layer of a 
stateful protocol (consider imap-over-nanomsg, or ftp-over-nanomsg for example) 
is doing something bad?

The reason I’m probing here is that trying to secure a “stateless” transport 
layer with TLS-ish guarantees seems like a fundamentally intractable problem.  
Just as a simple example, a stateless scheme cannot thwart a replay attack by 
definition, because there is no state by which an oracle could determine that 
some REQ is a replay from earlier.  So, at least from the perspective of 
applications where preventing replay attacks is important (and I am in that 
set), any proposal that starts with “consider a stateless protocol” is a 
non-starter.  Assuming, of course, I have grasped what you mean by “stateless”.

If there is some deep-seated ideological objection to stateful transports that 
will prevent any work along that line from getting merged in I suppose I can 
maintain an incompatible fork that solves my problems and not trouble everybody 
else with my requirements about replay attacks.  However if that is the way the 
wind is blowing, given my experience with maintaining an incompatible fork of 
zeromq, it may make more sense for me to keep doing that instead of embarking 
on my second incompatible fork of a messaging system.

> and 
> that way lies the risk of rolling our own crypto. That has real, large risks 
> of doing it very very wrong. 

It’s probably worth having a discussion here about where the line on “too 
dangerous to merge in” is.  My hope is/was that, on an alpha-stage project, 
there is some flexibility for living dangerously.  By this I don’t mean taking 
on risk for no reason—I mean taking on a calculated risk for plausible reasons, 
but obviously those words mean different things to everybody.

Having a broader discussion on where the line is on acceptable risk for merging 
in crypto would probably shed some light on how compatible my patches would be 
with nanomsg as a whole.

> 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).


I think you have successfully distilled the single major reason that prevents 
zeromq from making any progress on crypto.  There is no solution that works for 
everybody, and holding out for that solution means you pass up “ok” solutions 
in the meantime.  The road to crypto starts with a solution that works for just 
one or two people, and then is extended to encompass the requirements of more 
users.

As such a person, I’m trying to figure out which way the wind is blowing as far 
as merging a “solves my problem” solution upstream.  If there’s a desire to 
hold out for a much broader solution than mine, or there’s a lot of concern 
about “dangerous" crypto, or if there’s a deep anti-stateful culture, all 
things that have come up so far, those might be clues that I should figure out 
some other way to go.  That’s what I’m trying to figure out.

Drew

On Dec 15, 2013, at 3:07 PM, Alex Elsayed <eternaleye@xxxxxxxxx> wrote:

> 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: