[nanomsg] Re: end-to-end security

  • From: Drew Crawford <drew@xxxxxxxxxxxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Tue, 11 Mar 2014 16:46:32 -0500

> What’s the latency problem?  

The caffeinecrypto readme includes an extended discussion on this point, see 

> If its key negotiation (basically the SSL handshake), then your protocol is 
> going to have either the same problem, or you’re going to have weaknesses by 
> not covering all the cases that TLS does.  Strength crypto (key agreement) 
> and mutual authentication kind of play at odds with latency.  

I opened with “TLS isn’t a good fit for my problem” and your response is that 
whatever I am planning to does not address TLS usecases.  Yes.  That’s the 
*point*.  The *point* is to make different tradeoffs than TLS does.  My whole 
premise is that some applications may be satisfied to trade one thing for 
another.  If you are interested in what kinds of things people want to trade 
off and why, the links below are a good jumping off point.
> Maybe you should start with an application layer on top of nanomsg, then post 
> it.  If it makes sense, I suppose people can consider something more tightly 
> bound to nanomsg itself.  
So, that has been done, at least twice that I know of, in the past year.

Here was my approach: https://github.com/drewcrawford/caffeine-crypto, although 
in its present form it isn’t completely portable.

Also there was Pieter Hintjen’s libcuve: https://github.com/zeromq/libcurve

There are probably even more approaches that I don’t know about, but those are 
some actual, go-poke-and-prod-at-them implementations.

Just as a disclaimer, there are some issues with caffeinecrypto that I would 
want to revisit (and there are some things I would change about libcurve as 
well) so I’m not out here saying that they are bulletproof and good-to-merge as 
they sit.  What I am saying is that the general approach of doing a 
Bernstein-derived authentication handshake is solid, is deployed in stable 
software, is a proven solution for this problem, and something in this search 
space is appropriate to be merged.

These approaches are different in some details, but they are both deliberately 
not guarantee-for-guarantee TLS replacements, they are both based on real 
cryptographic work by real cryptographers, they are both used in message-queue 
systems today and they are both motivated by annoyance with TLS.

A libcurve-derived system is what eventually made it into ZeroMQ.  Whether that 
was the right move is up for debate, but I think it is notable that zeromq 
considered TLS for years and instead launched an entire project to avoid it.  
Again I’m not saying TLS is bad, I’m saying it’s bad for me, and for a lot of 
other people, and something should be done in core, and I am willing to do it.

> The problem is that there aren’t any *good* lightweight C libraries for TLS.  
> OpenSSL is kind of all there is, for better or worse.

Worth pointing out here that both of the examples I’ve linked to are 
MIT-licenseable, so there is no licensing problem with moving them to core.

> I want to see the protocol.  How will you prevent replay attacks?  What is 
> your key management scheme.  You *can’t* just blithely encrypt using a 
> pre-shared key 

I think all the “how can anyone be secure if not with TLS” type questions can 
be settled one way or another fairly quickly by consulting the two concrete 
examples I’ve linked.  Every point you’ve raised so far is addressed there.  
Whether that treatment is convincing is a different question, but from my 
keyboard, if the discussion about replay attacks etc. on neither of those 
projects is satisfactory, then no protocol can meet the burden except for TLS.

There are, of course, some actual weaknesses with Bernstein-derived 
authentication schemes.  One is that there is no chain-of-trust, so certificate 
pinning is used instead.  In my view that decision in particular is a feature, 
not a bug, but I understand that intelligent people disagree about such 
matters.  It is with that kind of issue that I appeal to “different tradeoffs 
are appropriate for different applications” type arguments.

On Mar 11, 2014, at 3:40 PM, Garrett D'Amore <garrett@xxxxxxxxxx> wrote:

> On March 11, 2014 at 1:06:32 PM, Drew Crawford (drew@xxxxxxxxxxxxxxxxxx) 
> wrote:
>> I feel the need to say, that it is not my intention to argue that my 
>> proposal is the very best proposal for everybody and should be adopted to 
>> the exclusion of every other proposal.  I think this is a place where zeromq 
>> has stumbled, by taking a very long time to study all the options and 
>> eventually producing a system pretty similar to one I suggested and landed 
>> privately ages ago.
>> My view is that there is no one-size-fits-all solution.  There are tradeoffs 
>> in security, performance, automatic-ness, etc., that make sense (or not) for 
>> different classes of applications.
>> Really, my intention is to argue that my proposal is a local maxima for a 
>> certain class of applications, and the user could choose from different 
>> side-by-side schemes that might be better for different types of 
>> applications, as the community has motivation to produce them.  Here, 
>> someone (me!) has the motivation to produce one scheme.  Some encryption is 
>> better than no encryption, and it makes the road easier, not harder, to land 
>> an alternative solution in the future.
>> At the same time I agree that there are some standards for what should be 
>> considered “merge-grade”.  Things that are obviously broken should not be 
>> considered, nor things where a better scheme already handles the case in 
>> every dimension.  But, for reasons that will become clear, I think it is 
>> much more dangerous to do nothing than to accept a competent patch that is 
>> limited in scope.
>>> Which is why using a protocol that has already been through this — like TLS 
>>> — is so attractive.
>> I concede that TLS is both safer and quite a lot simpler than implementing 
>> what I’m proposing.  However for reasons you can find on my post to this 
>> list several months ago, it’s not a good fit for my class of applications 
>> (there’s a latency problem).  I support a TLS-based scheme if someone is 
>> volunteering to write one side-by-side but at the moment I don’t have a use 
>> case for it.
> What’s the latency problem?  If its key negotiation (basically the SSL 
> handshake), then your protocol is going to have either the same problem, or 
> you’re going to have weaknesses by not covering all the cases that TLS does.  
> Strength crypto (key agreement) and mutual authentication kind of play at 
> odds with latency.  That said, if you can separate the assymmetric key 
> negotiation from the  symmetric encryption data path, then once the 
> connection is established you’re golden.  TLS already does that if you reuse 
> the connection.  If you don’t reuse, you’re hosed.
>>>  Compared with layering on top of secure transport, using a secure 
>>> transport seems *lots* easier.
>> It is most certainly easier, for things like TLS and for certain network 
>> topologies.  However, the easy solution is not a good fit for my usecase.  
>> I’ve described the architecture problems in zeromq’s transport-layer 
>> solution that impede meaningful work getting done by new contributors, and 
>> nanomsg will inherit some of those problems. Transport layer also 
>> complicates the multihop case, which is very important for my set of 
>> problems.  None of this is to say that transport-layer is bad all the time; 
>> I would not oppose such a scheme.  It’s mostly that I do not particularly 
>> want to tackle these problems, while there is in the alternative a solution 
>> that fits my situation better.
> It sounds to me like you might have an application specification problem.  
> Maybe you should start with an application layer on top of nanomsg, then post 
> it.  If it makes sense, I suppose people can consider something more tightly 
> bound to nanomsg itself.  
> For me, I’d like to see a protocol level description of what you’re talking 
> about.  I want to ensure that the *protocol* is sound, and secure.  While I 
> don’t necessarily consider myself fully qualified as a reviewer there, I do 
> consider myself *more* qualified than myriads of fools that I’ve seen try to 
> implement cryptography/security naively.  I expect I can spot some of the 
> more gaping holes (replay attacks, man-in-the-middle weaknesses, etc.)
>> Really though, the situation is this.  I’ve volunteered to land an 
>> end-to-end scheme soon even though it is hard.  To my knowledge, nobody has 
>> volunteered to land a transport scheme in any timeframe even though it is 
>> easy.  I suggest, given these facts, that it does not really matter whether 
>> some solution is easy or hard.  What matters is what patches can be written 
>> and what patches can be merged.
> I’m planning on implementing TLS in my Go library, on top of nanomsg.  I’ll 
> probably wind up adding it to a fork of nanomsg itself as well.  However the 
> crosslinkage between OpenSSL (GnuTLS is out due to licensing) is possibly 
> going to preclude it from being mainstream.  The problem is that there aren’t 
> any *good* lightweight C libraries for TLS.  OpenSSL is kind of all there is, 
> for better or worse.  And I don’t feel like implementing TLS by hand myself. 
> :-)
>> So far, an end-to-end scheme can be written, and it is an open question 
>> whether or not it can be merged.  You are saying that a transport scheme can 
>> be merged, but I have not yet seen any evidence that one will be written.  
> Its not hard to write one.  nanomsg has a pretty good abstraction layer.  As 
> I said, I’m implementing nanomsg’s SP protocols in Go, and once I do, adding 
> TLS support should be a matter of at most an hour or so.  Its more effort in 
> C because you have to deal with OpenSSL *cough*, but that shouldn’t deter a 
> serious effort given need.  Probably instead of an hour or two its more like 
> a day or two.  I expect the Go implementation of what I’m talking is more 
> than a few days away, but also less than a month, from being ready for folks 
> to start looking at and playing with.  It will be wire compatible with 
> nanomsg, but will add tls and websocket (both ws and wss) transports 
> (experimental).
>> And again to emphasize, these two paths are not necessarily mutually 
>> exclusive—there is also the possibility of both schemes, or of no scheme at 
>> all.  The latter is I think the worst of all worlds, and I am concerned that 
>> nanomsg will follow zeromq’s lead in that regard.
> Of course.  But you can of course implement end-to-end security in your 
> application.  At some level, if you’re concerned, that’s the cleanest 
> solution.  But it does require that *you* know what you’re doing.  If you 
> don’t… well then your stuff wouldn’t be appropriate merging either.
> I’d like to see something merged; I recall about 2 years ago a colleague of 
> mine wanted to implement his own cryptographic layer on top of pub/sub 
> sockets (zmq, before zmq added SSL).  It was swiss cheese full of holes.  I 
> tried to convince him to skip it, and just use IPsec instead. Ultimately 
> that’s what we did, although I had to rip out all his crummy attempts at 
> crypto security.  It cost me a lot of extra time, and wasted energy trying to 
> get him to understand that “encryption != security”.
> It would have been better to have a solid implementation that folks like him 
> could just *use*, instead of having everyone invent their own shoddy security 
> layers.
>>> I would also like to make sure that any new protocol support is designed in 
>>> a way that makes it possible to support the other protocol topologies (bus, 
>>> pub/sub, etc.)  I think that’s a bit non-trivial, as you then are talking 
>>> about multicast topologies.
>> I have thought about the pub/sub problem in a little bit of depth.  The 
>> problem is that there is quite a cornucopia of different solutions:
>> Pre-sharing a session key
>> Time-based or N-many-messages-based key rotation
>> Bootstrapping keys from a REQ/REP key server
>> Exploit subscriptions / unsubscription commands to rotate keys
>> Just encrypting the message N times
>> Each of these schemes has pros and cons and might make sense for a 
>> particular class of applications.  There is no one-size-fits-all solution.
>> I am confident that someone with sufficient real-world motivation to tackle 
>> the pub/sub problem would find one of these ideas compelling for their use 
>> case, or be able to generate better ones.  However I think it would be 
>> unwise to make decisions for PUB/SUB without someone who has a real use-case 
>> at the table making comments.  I also think it is unwise to delay a solution 
>> for REQ/REP until the question of what other sockets will do has been sorted 
>> out, particularly if nobody with a clear need for securing those sockets has 
>> in several months inserted themselves into the conversation to describe 
>> their needs.
> I think it would be unwise to build into the core a solution that only works 
> for REQ/REP.  I’d rather see this properly designed, than something cobbled 
> together that won’t support the main patterns.   As I indicated, the one case 
> I’ve seen for this in the real world was actually PUB/SUB, and it was badly 
> botched by the person who tried to solve it.
> Using a PKI, the problem of PUB/SUB is much more easily solveable, although 
> it only addresses the security of the transport itself, and not end-end 
> authentication. 
>> The trouble with waiting for consensus for other use cases is that you never 
>> really get all the people in the room at the same time.  When you turn away 
>> a concrete REQ/REP proposal due to lack of addressing PUB/SUB, that 
>> user/contributor finds some other way to solve his problem and doesn’t 
>> become a user.  And then perhaps a sufficiently-motivated PUB/SUB user does 
>> finally appear, but by then the REQ/REP implementor has moved on, so the 
>> PUBSUB proposal is now rejected due to lack of REQ/REP, and around and 
>> around it goes.  And this is basically the story of how libzmq went without 
>> any encryption at all for 3 major releases, although there was plenty of 
>> bikeshedding throughout.
> I’m not talking about bikeshedding.  Indeed, most commenters probably aren’t 
> qualified to judge a security protocol.  But I am saying that it would be 
> *insane* to add a security layer to nanomsg without a review of the protocol 
> itself, ideally from qualified security experts.   Adding a busted security 
> layer to nanomsg would IMO be far worse than adding none at all.  (I cite WEP 
> as an example here.)
> If you want to push something quickly and can’t wait for such a review, I 
> think you should proceed with application layer work.
>> They finally converged on a solution, but the fact that I am here 
>> volunteering to write patches for nanomsg is evidence that even after 
>> thinking about it for 3 years they did not come up with something that works 
>> for everybody.  And I am convinced that waiting for a solution that pleases 
>> everybody is waiting for Godot.  No such solution will ever present itself, 
>> because it does not exist.
>>> You’d also have to figure out some questions such as — devices — if you’re 
>>> going to route requests, you need to be able to look at least at the 
>>> envelope.  That requires that at least envelopes are unencrypted.   
>> What I am proposing is more-or-less applying the encryption immediately 
>> after the call to nn_send, to nn_send’s argument.  So this doesn’t touch 
>> anything below that layer.  Specifically, it wouldn’t encrypt the envelope.
> I want to see the protocol.  How will you prevent replay attacks?  What is 
> your key management scheme.  You *can’t* just blithely encrypt using a 
> pre-shared key and be secure.  You may gain *secrecy*, but that is *all* you 
> will gain.
>       - Garrett

Other related posts: