Posts for the month of January 2015

OpenID

Mini-rant/follow-up: It has almost been two years since I wrote about my issues interfacing with OpenID, and since I have recently been getting deprecation warnings from Google, I finally put in the work to optionally support password authentication. That will teach me to try to do the right thing.

Similar Projects to SandboxOS

When I started working on SandboxOS, I was somewhat in disbelief that nobody was doing this already. Since then, I have discovered a handful of projects with similar goals, but as far as I can tell, it is still unique enough to continue pursuing.

JavaScript Contenders

There are a handful of JavaScript-related projects with similarities.

node.js + io.js

Node.js, and by extension io.js, are essentially another runtime environment similar to those of Perl, Python, and Ruby.

node.js popularized using JavaScript outside of the web browser, especially web server-side, allowing web application to be built completely in JavaScript. But ultimately node.js and io.js compete in an already overpopulated niche.

SandboxOS is different, because it introduces a security model and an application model.

node-os

node-os is an operating system built from node.js running on a Linux kernel.

This seems to be the result of taking the package manager from node.js, npm, to its extreme and using it for managing all system files.

There is not really much comparison with SandboxOS. It is just another interesting projects in the same area.

Runtime.JS

Runtime.JS is an operating system kernel built using V8 and JavaScript.

It is an attempt at eliminating one layer of the stack commonly present in node.js applications.

SandboxOS, for better or worse, adds another layer.

Linux Container-based Contenders

I am not especially familiar with recent developments in Linux containerization. I've gather that it is a step beyond virtualization, allowing some amount of isolation without sacrificing performance.

SandboxOS different from all of them in that it attempts to make it easy to host web applications on all sorts of devices - anything where web browsers are found. While I have yet to measure the performance implications, the goal is to move toward having many more servers with many fewer (often just one?) users.

Docker / Rocket

Docker is the current dominating presence in this area. It appears to be tailored primarily toward sysadmins.

Rocket is an alternative being built for CoreOS.

Sandstorm

Sandstorm is the first project that actually concerned me that I might be stepping on somebody's toes. Their goals are very much aligned with mine, but they're taking a completely different approach, using Linux containerization. Interestingly, Sandstorm does a good job explaining why containers are great, but they don't solve enough of the problem.

They aim to make it trivial to run servers and make a better future for open source webapps, and I wish them luck.

Editing Apps

It may just be because programmers like strange loops, but being able to edit applications from an application which is itself editable is a fundamental assumption in SandboxOS.

SandboxOS targets the most devices by far.

OLPC Develop Activity

I think I first heard such a goal proposed for the One Laptop per Child project. Their Develop activity seemed to be down-prioritized pretty quickly, but it was a neat concept and it is a neat project.

Wiki OS

I'm not clear on the origins of Wiki OS, but it seems to be an attempt at reproducing a traditional desktop environment on the web on devices where Silverlight can be run, and it allows modifying applications with an interface that I would compare to Visual Basic.

Android AIDE

I encountered AIDE while in the middle at marveling at how seemingly unnecessarily difficult mobile development is made by the available toolchains. That project puts all of the tools necessary to build Android applications on-device.

Decentralization

One final theme I am watching for activity on is decentralization.

This recent article hints at future tech to decentralize web applications "like BitTorent does" without any information on how that can work.

Unhosted web applications are another trend of building web applications without a server component altogether.

Conclusion

There is a lot of activity in this area. So far, SandboxOS seems to be going in the right direction and not stepping on anybody's toes, so I'm going to charge forward with it!

SSPI WTF

This is a continuation of TLS WTF. I added SSPI / SChannel support to my list of supported TLS backends. It was not a pleasant experience, so I am taking another moment to document my grievances.

SSPI is a shining example of an API that is hard to use correctly.

  1. Microsoft documents that rather than linking against an export library, you must load security.dll dynamically and look up a symbol.
  2. To begin the TLS handshake, you call InitializeSecurityContext or AcceptSecurityContext, depending on whether you are the client or server. The credentials already know which direction we're going at this point, so this seems redundant.
  3. One argument to those functions is a pointer to a handle that is populated when the call succeeds, and a pointer to that handle must be passed back as a different argument on subsequent calls. But not before it succeeds once.
  4. InitializeSecurityContext, AcceptSecurityContext, EncryptMessage, and DecryptMessage all take arrays of input and output SecBuffer structs. After working with two other libraries that had much simpler mechanisms for passing data in and out, this just seemed wrong.
    1. Data is encrypted and decrypted in-place. While it might seem sort of clever, as though it's saving something or destroying no-longer-needed sensitive information, due to the way it works and the lack of any apparent guarantees, I found I needed an extra copy of the data anyway in order to properly restore the remaining unencrypted/decrypted bytes for the next pass.
    2. Each particular type of invocation has special requirements on the number and type of buffers it takes as input and returns as output. It's basically deliberately throwing away all parameter/type safety. Or conversely it's requiring the user to know quite a lot about the specifics of the protocol.
    3. One type of SecBuffer contents that is returned is the number of data bytes passed in that haven't been consumed. But not a pointer to the bytes like every other buffer.
  5. Shutting down a connection is bizarre. Call ApplyControlToken and then proceed as though you're starting a new handshake. I realize only now that I'm doing this incorrectly.
  6. I was pleased that I was pretty quickly able to load a PEM certificate and private key. And then it took me the better part of a day to be able to associate them with each other to be able to use them.
    1. A certificate context (container?) seems to be necessary. There is a way to get an anonymous one, but it doesn't seem to work for this purpose. I haven't found a way to get one if it exists and create it otherwise except by trying one and if it fails, trying the other.
    2. It is necessary to open a certificate store with the name "MY". What?
    3. A property "CERT_KEY_PROV_HANDLE_PROP_ID" on the certificate context looks exactly like what I would want to set to associate a key with a certificate, but it has no apparent effect. "CERT_KEY_PROV_INFO_PROP_ID" is the only one that apparently actually works, but it requires jumping through a bunch more hoops.
    4. All of this leaves some key/certificate data in some system location. I haven't found any way to avoid that.
    5. Most of the API worked with multi-byte or wide characters. One or two functions didn't.
    6. I've completely lost track of which things are opaque data types, handles, pointers to handles, or pointers to pointers to handles. It's out of control.

Again, I just hope someone stumbles on this or browser:projects/sandboxos/trunk/src/Tls.cpp, and is saved some of the hassle I went through.

I realize I am not done, but I really need to put this aside for now. Some future tasks include:

  • Support allowing individual certificates whose signing authority isn't otherwise respected (self-signed certificates).
  • Need to separate the certificate and key setup from the connection. I'm probably adding an awful amount of overhead for each connection by re-importing them each time.
  • Need to expose error messages. I've just been instrumenting the code as I go to discover what I've been doing wrong, but the actual errors are useful, so I need to make them available.
  • Need actual tests.
  • I want to be able to generate self-signed certificates on all platforms.

TLS WTF

This is my recollection of my misadventures in trying to support TLS for SandboxOS.

The Goal

I have a JavaScript runtime environment. I want it to be able to do these things:

  • Run a web server that supports HTTPS to secure or even just obfuscate my traffic.
  • Connect to web servers over HTTPS to post to Twitter and whatnot.
  • Connect to XMPP and IRC servers requiring secure connections to run chat clients and bots.

I want it to be able to do those things on Linux, OS X, and Windows, and I don't have a very high tolerance for complicated build steps or large dependencies.

Background

"I want to use SSL," I thought to myself. Apparently what I wanted is called TLS these days. I scratched my head and moved on, because this was the least of my problems.

Going in, I knew that OpenSSL had recent vulnerabilities, leading it to be forked into LibreSSL. I knew that GnuTLS was a thing. Outside of that, I did not have much knowledge about what was available.

I did some research and found that I should look into Mozilla's NSS as something that could potentially work on all the platforms I cared about. I also learned that if I wanted to support the most common libraries on each platform, I would need to look into SSPI on Windows. I also saw that node.js uses OpenSSL on all platforms.

I'm using libuv for doing all of my socket I/O, and I'm pretty happy with it. But it poses a challenge here, because these libraries tend to prefer being used as a wrapper on top of native BSD-style sockets and I didn't want TLS interfering with libuv's event loops at all. I chose to try to pass data around myself in order to avoid that scenario. It looks like NSS creates unnecessary intermediate sockets to abstract away that interface.

Getting Started: Build the Libraries

I believe it went like this:

  1. Look at Mozilla NSS (Network Security Services).
    • GPL-compatible license. Good.
    • Supports the platforms I care about. Good.
    • Get it and try to build it. They have a non-trivial custom build harness. Not a great sign, but OK.
    • Try to build it for win32/x64. Discover this note:

      Note: Building for a 64-bit environment/ABI is only supported on Unix/POSIX platforms.

    • Looked at the API a bit. It looks like it really wants to be bound to system sockets. That will incur unnecessary overhead the way I want to use it. Lame.
    • That was enough strikes for me. I wan't about to maintain my own builds of this for three platforms, and I certainly wasn't about to let this constrain me to Win32/x86, if that note was correct.
  2. Look at LibreSSL.
    • GPL-compatible license. Good.
    • It looks like the latest release is expected to be usable. Great.
    • It only builds on Windows through MinGW. Ugg.
    • By this time I had some OpenSSL code. I tried it on OS X and found that the OpenSSL system library on OS X was supported but has deprecated for some time. Crap.

I Wrote a TLS Wrapper

I resolved to support OpenSSL on Linux, the Secure Transport API on OS X, and SSPI on Windows, and all in code that could be easily extracted to use for other projects.

Currently the entirety of the public API looks like this, though I haven't yet tackled SSPI:

class Tls {
public:
    static Tls* create(const char* key, const char* certificate);
    virtual ~Tls() {}

    virtual void startAccept() = 0;
    virtual void startConnect() = 0;
    virtual void shutdown() = 0;

    enum HandshakeResult {
        kDone,
        kMore,
        kFailed,
    };
    virtual HandshakeResult handshake() = 0;

    enum ReadResult {
        kReadZero = -1,
        kReadFailed = -2,
    };
    virtual int readPlain(char* buffer, size_t bytes) = 0;
    virtual int writePlain(const char* buffer, size_t bytes) = 0;

    virtual int readEncrypted(char* buffer, size_t bytes) = 0;
    virtual int writeEncrypted(const char* buffer, size_t bytes) = 0;

    virtual void setHostname(const char* hostname) = 0;
};

Implementation Rants

I don't know where to begin.

  1. There are not enough good examples. If you are an engineer at Apple who worked on the Security framework, where did you put your ~100 line C file test case that fetches https://www.apple.com/ and fails if you try to reach the same server by a different name?
    • This was the best I could find for OpenSSL. It's alright but 12 years old.
    • This is why I haven't attempted SSPI yet. I think SSPI will be manageable, but that example is insane.
  2. Do not pretend TLS connections are BSD-style sockets. TLS is a terribly leaky abstraction. Socket calls that ought not to block might need to block so that TLS handshaking can finish. New errors can occur at every turn. A TLS session can close without the network connection going away. Stop pretending it's not a separate layer.
  3. Verify hostnames. TLS without hostname verification isn't secure. OpenSSL did not make verifying hostnames easy. The headers I have on debian jessie required me to extract the names from the certificate and do my own pattern matching to account for wildcard certificates. I had several implementations where it appeared the default verification would check names, but only testing showed that it wasn't happening. Apple made it a fair bit easier, but it still didn't happen by default.
  4. So far I have not yet found how to load my certificate and private key from PEM files on OS X without calling this private function from the Security framework:
    extern "C" SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey);
    
    All other attempts I've made at getting a SecIdentityRef from my key and certificate have failed. I could keep them in the login keychain, but I want to support PEM on all platforms for consistency.

Results

So SandboxOS does what I need for TLS for now. It took me five times longer to write than I had hoped, and doesn't support TLS on Windows yet.

It can connect to secure servers. It verifies hostnames when you do that. I can run a secure web server with it. It might be fun to support client certificates, but that is about as far as I want this to go, and that can happen later.

I'm hoping somebody searching for some of these words will stumble upon this and either show me how stupid I've been or benefit from browser:projects/sandboxos/trunk/src/Tls.cpp.

Update

I added SSPI support.