[nanomsg] Re: end-to-end security

  • From: Drew Crawford <drew@xxxxxxxxxxxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Tue, 11 Mar 2014 15:06:27 -0500

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.

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

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.

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

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

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.

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.














> Which is why using a protocol that has already been through this — like TLS — 
> is so attractive.


On Mar 11, 2014, at 8:56 AM, Garrett D'Amore <garrett@xxxxxxxxxx> wrote:

> I have an interest in security as well, and some background.  I had been 
> contemplating a different approach, using a TLS approach.  That’s not exactly 
> end-to-end, but I had also been considering the use of “tunneling” Nanomsg 
> over Nanomsg as a way to achieve end-to-end-security, when combined with a 
> TLS-like API.
> 
> My biggest fear about trying to develop this without using TLS or another 
> well understood *protocol* is that security protocols are notoriously hard to 
> get right.  The roadside is littered with failed attempts to create new 
> security protocols, by well-meaning but less than well-trained professionals. 
>   (In particular, folks who’ve not got the training *as crypto protocols 
> people*.)  To get this right, you need something that is both designed by, 
> and audited by, people with a solid background in security.
> 
> Which is why using a protocol that has already been through this — like TLS — 
> is so attractive.
> 
> I would like to make sure that if we’re going to land new protocol support 
> (not just API!) in nanomsg, that it is one that can be reasonably implemented 
> by other parties.  (I’m in the process of implementing — from scratch — a new 
> implementation of nanomsg in “pure” Go.  I think it won’t be many more days 
> before I make my work public.)
> 
> 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.
> 
> The challenges of this is one reason why I think end-to-end might be 
> difficult in the general case.    Compared with layering on top of secure 
> transport, using a secure transport seems *lots* easier.
> 
> 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.   
> 
> Anyway, I’m happy to help review anything you do, prior to integration, but 
> I’m still pretty new around here myself. :-)
> 
> -- 
> Garrett D'Amore
> Sent with Airmail
> 
> On March 11, 2014 at 6:08:46 AM, Drew Crawford (drew@xxxxxxxxxxxxxxxxxx) 
> wrote:
> 
>> Hello folks,
>> 
>> I’ve written before to gauge the interest level on landing encryption 
>> support to nanomsg.
>> 
>> After my last post, I tentatively decided to go with a libzmq-based 
>> solution.  However, for reasons outside the scope of this list, that hasn’t 
>> gone as well as I’d liked, and I’m now thinking about nanomsg once again.
>> 
>> The problem is important enough that I actually have time to work on it, and 
>> due to time constraints I’m going to settle on some solution in the next few 
>> days.  The only open question at this point is whether I’m going to land 
>> patches in nanomsg, or whether I’m going to be doing some kind of private 
>> solution, like a private fork or wrap of some library.  I’d prefer the 
>> former if possible.
>> 
>> I’d like to make a concrete proposal for comment.  As far as I can tell, 
>> there hasn’t been further discussion on the subject of encryption since my 
>> last post.  Here is what I’m thinking on design decisions:
>> 
>> End-to-end, “well-above-transport-layer” security.  Don’t get me wrong, 
>> there is a good case for transport-layer security.  Zeromq has used it with 
>> some success.  I use it right now.  The thing is, I’ve become convinced it’s 
>> the wrong approach for **my** set of problems.
>> Zeromq's support gets poor when you move out of TCP transport.  It would be 
>> a lot of work for them to support IPC, for example, which I’m mildly 
>> interested in.  I suspect that UDP is somewhat challenging as well, which is 
>> a long-term goal.  Doing security work near the surface means it’s 
>> completely decoupled from adding new transports, which is good if you want 
>> new transports, and also good if you want security to work with them.
>> Patches to the cryptography require deep knowledge of zeromq internals, and 
>> the people with the right knowledge are often busy.  When minor features to 
>> security are needed it creates major delays.  If security sits near the 
>> surface it requires knowledge of mostly public APIs and so cryptography work 
>> can proceed without scheduling meetings with core committers to understand 
>> the obscure internal design of the day.
>> Focus on REQ/REP, and maybe DEVICE, which are the sockets I’m interested in. 
>>  The other socket types can wait until somebody is sufficiently motivated to 
>> make security work for those socket types.
>> Stick close to CurveCP where sensible, but allow for some experimentation.  
>> Maybe the user can choose from several competing security mechanisms.
>> 
>> Here are some concrete API proposals:
>> 
>> New values for nn_getsockopt, nn_setsockopt:
>> Setting/getting various public and private keys
>> Applications would rely on these values for security, so it is important 
>> that a remote attacker cannot set arbitrary socket options
>> Switching between authentication mechanisms, if several are supported, or 
>> using no authentication.
>> Reporting authentication errors.  A logical place to do this would be from 
>> nn_connect, however, my understanding is that the transport connection isn’t 
>> established at that time.  One possibility is to introduce a separate 
>> nn_authenticate function, called after nn_connect and before send/receive.  
>> Another possibility is to report errors from send/receive themselves.
>> On a socket that has opted in to security, nn_send and nn_recv encrypt, 
>> decrypt, and verify messages as appropriate. Sockets not opted in are 
>> unaffected.
>> New APIs nn_send_raw and nn_recv_raw allow unencrypted reads/writes on 
>> sockets that have opted into security
>> The entire enterprise should be documented for the forseeable future as 
>> experimental, unstable and not for use on nukes
>> 
>> Again, I’m volunteering to land all of this, pretty soonish, if this is 
>> basically sounding like a patch you want to merge.  And I am happy to 
>> collect feedback and refine some of these details as appropriate.  
>> 
>> However, I’d rather not bikeshed on this, as I have done enough bikeshedding 
>> about encryption features for message-queue projects to last many lifetimes 
>> ;)  So if this work overall isn’t feeling right for core, I am completely 
>> happy to find a place to do it that isn’t in core.  My feelings won’t be 
>> hurt.
>> 
>> Drew

Other related posts: