Nice. One nit: any sane OS will provide near-perfect randomness from /dev/urandom (by restoring the last RNG state from disk), but you're bound to run into some idiotic Linux distro which doesn't; its fans will claim that you should have used /dev/random. (A quick search turns up https://dev.openwrt.org/ticket/8687, which suggests that not saving the RNG state may be more common than I'd hoped.)
A one-line comment in "Security requirements", or even an option to read from /dev/random, may be a good idea.
I tried compiling it on OpenBSD; you should probably #include <string.h> in lib/events/events_network.c for memset() as used in FD_ZERO (see OpenBSD select(2)). OpenBSD has no -lrt either, so I just removed that. It compiles and passes a quick localhost test with these changes.
I've read both stunnel and stud and 95% might ... just ... be on the high side of a reasonable estimate there. Again, I'm saying: stud <-> stunnel is not an apples-apples comparison.
The reality here, and I think you should just come out and say it, is that the rationale behind spiped is that you don't trust SSL/TLS period.
What's the deal with the per-message padding scheme here? Is this a tradeoff against rekeying?
The reality here, and I think you should just come out and say it, is that the rationale behind spiped is that you don't trust SSL/TLS period.
That's part of it, sure. But SSL/TLS also doesn't provide client authentication (unless you use client SSL keys, which is absolutely guaranteed to have security holes given that nobody ever uses them).
What's the deal with the per-message padding scheme here?
1. Makes the code much simpler and less error-prone (no need to read variable-length records from the network).
2. Cuts down on information leakage. I'm planning on using this for kivaloo, which uses variable-length records -- I don't want to expose the lengths of account names or suchlike.
Considering that a pointer mistake in code that you didn't think was security critical might allow execution of arbitrary code, aren't all code paths that might execute, security critical?
I used to use ssh tunnels for tunneling irc from irssi-proxy to my local machine (since I don't trust irssi's authentication around the proxy). This involved several steps: binding the proxy to 127.0.0.1, and then sshing in from my desktop and forwarding the ports. And, with two transport layers, my irc client would disconnect if the irc connection failed or if the ssh connection failed. This was annoying.
I eventually switched to OpenVPN. I run a server on one of my hosts, and then the other networks I control connect to that and share their networks. The result is that I can bind irssi-proxy to the 10.0.42.0 interface and then directly connect from any other machine on my network.
This ends up being much less of a pain than the other setup, scales to many more services, and lets me do cool things like ssh-ing to my phone when it's on Sprint's network and my laptop is on a cafe's network.
(Oh, and if you do this yourself, don't use anything in 10.0.0.0/16 for your internal network; VPN or otherwise. You will end up in some coffee shop that reserves the whole /16 for itself when all it needs is some random /8, and then nothing works.)
First, both SSH and OpenVPN are much more complicated than spiped, and thus more likely to have security flaws. OpenVPN as you know incorporates OpenSSL and makes use of an even greater fraction of its code than stunnel; Colin's primary goal in building spiped seems to have been avoiding the need for stunnel (or even stud).
Second, if all you're trying to do is hook one discrete component up to another, a full-on VPN isn't just overkill, it's also unnecessarily dangerous, since now you have to configure the network stacks to ensure that only the traffic you intended to allow is going to be able to get through after a minor compromise.
This is a reasonable comment, but you should read spiped before coming to a conclusion; in this one case, we're talking about (for instance) DH code from someone who writes his own blinded modexp. I don't see anything crazy in it.
I spent about five minutes poking through it and nothing stuck out... but when I stopped I contemplated how many eyeballs have done the same thing to stunnel/gnutls already.
I didn't reach any conclusion from my quick look, but was definitely put off by the "it's big so it must be insecure" view taken by the author.
Didn't know that, I'd never heard of him before (I haven't run BSD in years, and when I did it wasn't FreeBSD).
Most of the time when someone posts a "look what I just implemented in C" to HN it's, well, not great. As I mentioned I only looked for five minutes, but I looked for really basic general programming errors, low-hanging fruit kind of stuff. That's enough to effectively cull a lot of the noise that gets posted here.
His code is good - I just wonder why someone'd go to the effort (which is much higher than most other programming projects, due to the consequences of a bug) when we already have well-worn codebases for stuff /almost/ exactly like this, considering the tightrope-of-vigilance that is correctly implementing crypto protocols.
I understand now that he wants a PSK vs. stunnel/TLS's certs-on-both-ends method, but effectively it only really differs in connection setup, as TLS (the way I understand it to be generally used) does symmetric crypto for the payload data anyway (after key setup).
PS: His project is the first time I've encountered the use of gotos resulting in _cleaner_ code than without them. :)
It wasn't that much effort. Almost everything under /lib/ I had already written as part of tarsnap or kivaloo; I spent maybe 10 hours making minor tweaks and cleanups to that code (which will be useful when I next use the library code anyway) and somewhere around 40 hours figuring out the protocol and writing the spiped specific code.
Having a simple secure pipe tool will save me far more time than that, once you count things like wanting to programmatically set up encrypted pipes (for which spiped's command line and arbitrary key is much better than stunnel's configuration file and SSL certificates).
effectively it only really differs in connection setup
And connection setup is a big deal. That's where almost all the vulnerabilities happen. In SSL, you go through a complicated handshake before you can decide that the client you're talking to doesn't have the right keys; in spiped, you exchange 256-bit nonces, and then if the very next buffer you read doesn't have right right HMAC, the connection is dropped. Evil data never meets asymmetric crypto. If an attacker doesn't have the key, they can't force you to burn any significant amount of CPU time.
His kernel has many lines of source, too. How does he trust that to be secure? (As it turns out, he's the FreeBSD security guy, so that one probably would have backfired.)
Awesome work, Colin. I can think of more than a few uses for a lightweight and secure pipe forwarder. I also enjoyed reading your earlier article about keeping OpenSSL and Apache separate.
I have a question though - in the beginning of your post, you talk about STUD. Did you replace stunnel with STUD, or not just yet? Just wondering how that went.
I agree, this is very useful. Other than the advantages already noted, this is very easy to configure and you don't risk (potentially) misconfiguring your sshd in the process.
One thing this could be useful for is using a public server as a proxy to connect from a box behind a NAT to a box behind a different NAT. So you run spiped on the server and manually connect from client 1 to the server. Then you can SSH or VNC into client 1 from client 2 via the server. I wouldn't like to set this up using OpenSSH, but with spiped this seems easy.
Yes, for a sufficiently weak definition of "equivalent". spiped doesn't use OpenSSL and doesn't need to fork off separata processes for each connection, for instance.
A one-line comment in "Security requirements", or even an option to read from /dev/random, may be a good idea.
I tried compiling it on OpenBSD; you should probably #include <string.h> in lib/events/events_network.c for memset() as used in FD_ZERO (see OpenBSD select(2)). OpenBSD has no -lrt either, so I just removed that. It compiles and passes a quick localhost test with these changes.