Weave, crypto, and JavaScript

tl;dr: fa20ae35b8ac53b28dde4fc333aba21f πŸ™‚

Up until now, Mozilla’s Weave add-on has been living with an awkward implementation detail: a binary component. When I wrote Weave’s current cryptographic component back in 2008, in order to use the crypto code that’s already in Mozilla (ie, NSS) there was no choice but to write C++ code. NSS doesn’t export any scriptable interfaces at all, and its partner-in-crime (PSM) exposes only a limited set of high-level functions — none of which was useful for Weave.

The C++ code has been working fine, but has a number of serious drawbacks… A binary component has to be compiled for each supported platform (originally just Windows, Linux, Mac x86 and Mac PowerPC). That results in a bigger download, and makes it a pain to support new platforms (like 64-bit Windows, 64-bit Linux, 64-bit Mac, Maemo, Windows CE/Mobile, Android, etc). It’s also a barrier to new developers — compiling a binary component requires a build environment and XULRunner SDK, whereas hacking on most extensions requires nothing more than a text editor. Luckily the C++ code has been quite stable, so Weave was able to hack around this by including pre-compiled binaries in the Mercurial repository.

But enough is enough.

The next (trunk) version of Firefox includes JS-CTypes, a feature that allows JavaScript to interface with native code. Think of it as dlopen/dlsym for JS. By porting the WeaveCrypto component over to JavaScript + JS-CTypes, Weave is now able to talk with NSS directly, without any C++ code. It basically Just Works — adding support for Mossop’s Palm Pre port of Firefox was literally a 1-line change. Adding support for Android was a 4-line change (only because they’re tricky and put libnss3.so in a sub-directory).

I should also mention that unit tests were a HUGE help in getting the new code completed. I wrote extensive tests for the C++ version of WeaveCrypto, and once the JS-CTypes version was working with those tests I was able to make a full-up Weave sync work with the new code on the first try. Easy-peasy!

If you’re interested in seeing what this new code does, take a look at the bug and the code in the Mercurial repository. Note that the XPCOM interfaces are fairly specific to what Weave wants to do — it’s not a general-purpose JS crypto API. But it’s a huge step towards making it easier to do crypto code in JS extensions — and perhaps in the future we’ll look at making a real general-purpose crypto API for extensions; it’s certainly an interesting problem! If folks are interested in helping out with such a project, let me know.

4 thoughts on “Weave, crypto, and JavaScript”

  1. This is pretty cool! I have been toying with a pure JS client for Weave last week, based on the (abandoned?) stuff that’s in ‘weaveweb’. I’ve tried building an extension for Google Chrome with it, but it works in other browsers too: http://bitbucket.org/philikon/weaveclient-chromium/src.

    So I think it would be very cool to have a scriptable crypto API. I would even go one step further and say that it would be *awesome* to have such an API available to web scripts, not just within the chrome. Want to download an encrypted file from Dropbox? No problem! Proper cryptography for webmail clients? Yes!

  2. What are the security implications of using a JS layer of indirection as an interface to crypto services?

    It will be extremely important to ensure that no additional attack vectors (side-channel or other) are made available by a js-ctypes-based API for NSS.

    Wouldn’t it be good to get the security folks to review WeaveCrypto.js, just to make sure there are no obvious pitfalls to the approach?

  3. This is awesome – actual uses of ctypes code will serve as good documentation. It looks a little dense from the hg view, but that’s probably because of the lack of syntax highlighting. The various enum things are scary too (the compiler is free to choose the data size), but that’s a limit of C(++) and there’s not much we can do about it.

    Of course, I feel that actually extending PSM to do the things you want would be a better way (allows for non-JS consumers, more likely to be generic, keeps the security stuff to one component), but given that this already works… meh. πŸ™‚ It does seem kind of scary that one partition of the Mozilla world would be so separated from another that the answer needs to be going around them, though.

    nit: things like http://hg.mozilla.org/labs/weave/file/tip/crypto/WeaveCrypto.js#l180 are wrong, PRUint32 should be 32 bits (according to devmo, uint32_t) because the world hates us all, or something. But that’s trivially fixed πŸ™‚

Comments are closed.