Public Key Cryptography in Mozilla extensions

In some cases it is desired to encrypt communication. Assuming X.509 certificates at hand, it is quite simple to prepare messages according to Cryptographic Message Syntax (CMS) in extensions using built-in XPCOM features. But how this works is not yet documented on MDN and also the rest of the web is not telling much about it.

Encryption in existing extensions

It seems that encryption hadn’t been a big topic for extension developers so far. Maybe this is because often only the channel to a (web) server should be secured and therefore TLS can be used.

Besides Weave, which now is better known as Firefox Sync, and DOMCrypt, an extension which provides encryption and signing to websites in Firefox via the property window.mozCipher, I found nothing that goes in this direction. DOMCrypt is mainly developed by David Dahl whose work serves as the basis for the development of an W3C standard draft for web cryptography and who was great help for me with getting along in NSS with js-ctypes.

The js-ctypes way

DOMCrypt reuses and extends code from Weave for crypto operations. They make use of the Network Security Services (NSS) library via js-ctypes as, unfortunately, most of its functionality is either not exposed via XPCOM or it is not documented how to use it – this is where I’m currently digging around. Js-ctypes is a way to load native C/C++ libraries like NSS and call exported functions directly.

Reasons against

A downside of this approach is that you have to map and convert the data exchanged with the native code on your own – there simply is no char * in JS. For struct types it is important to obey the size of their fields in memory at least if you want to access them and not only push references around.

Additionally, according to kaie in #security on Mozilla’s IRC,  you can’t be sure that NSS’s initialization succeeded when you start calling it this way. For access through XPCOM you certainly could. As one does not know which assumptions were made for the proper use of some function by simply looking at its declaration, this approach could have unforeseeable security deficiencies as well (i.e. you should make sure to check that if you want to go this way).

The „hidden“ XPCOM way

Because of the high effort to get things running (its nevertheless possible) and the inconvenient interaction scheme with js-ctypes, I was glad that kaie indicated that there are some XPCOM interfaces in security/manager which could help me out. As there is no documentation for them yet, he suggested to look at Thunderbird’s S/MIME implementation to understand how to use them.

How it works

1. Fetch certificates

First of all you need a base64-encoded DER representation of the certificate you want to use for encryption. Either you can get it from a *.pem file or if it is imported in the certificate database you can retrieve it from there.

  1. // certFile holds the contents of a *.pem file as a string
  2. var b64DERCert = certFile.substring(certFile.indexOf("-----BEGIN CERTIFICATE-----")
  3.                                       + ("-----BEGIN CERTIFICATE-----").length + 1);
  4. b64DERCert =
  5.          b64DERCert.substring(0, b64DERCert.indexOf("-----END CERTIFICATE-----")-1);
  6. b64DERCert = pubDERCert.replace(/\n/g, "");
  1. // get cert DB and look up desired cert by its nickname
  2. var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
  3. var cert = certDB.findCertByNickname(null, "Foobar");
  4. // getRawDER will set len.value and assign it rawDER.length
  5. var len = new Object();
  6. // rawDER is an array of integers which represent char values
  7. var rawDER = cert.getRawDER(len);
  8. // let the chars be converted and base64 encoded
  9. var b64DERCert = buildBase64DER(rawDER);
  10.  
  11. function buildBase64DER(chars){
  12.     var result = "";
  13.     for (i=0; i < chars.length; i++)
  14.         result += String.fromCharCode(chars[i]);
  15.     return btoa(result);
  16. }

2. Encrypting and decrypting messages

Encrypting messages afterwards takes you three lines if you know how to use nsICMSSecureMessage:

  1. var secMsg =
  2.          Cc["@mozilla.org/nsCMSSecureMessage;1"].createInstance(Ci.nsICMSSecureMessage);
  3. var msg = "Let there be PKC in JS";
  4. // cmsMsg afterwards holds a base64 encoded message in CMS ready to ship
  5. var cmsMsg = secMsg.sendMessage(msg, b64DERCert);

For decryption the private key of the receiver must be present in the cryptographic module. This can be done by importing the appropriate *.p12 file in the certificate manager, otherwise an exception will be thrown by the following code:

  1. var secMsg =
  2.          Cc["@mozilla.org/nsCMSSecureMessage;1"].createInstance(Ci.nsICMSSecureMessage);
  3. // msg afterwards is the restored string
  4. var msg = secMsg.receiveMessage(enc)

Own certificates

If you want to create authentic certificates yourself, e.g. for testing purposes, you can follow this great tutorial on Flat Mountain which explains how to create your own CA and issue certificates for users.

Wanted: Signing

What is still missing is a way to sign messages which is as simple as the encryption described above. If someone has an idea of how to achieve that please drop me a comment.

Comments (5)

JoshMärz 12th, 2014 at 19:37

I realize this is ridiculously old, but it looks like you can just use crypto.signText(„text to sign“, „ask“) to sign text. Are you still using this?

Also. thank you for this post. I was getting nowhere finding how to do the pki stuff in an add on.

jonasMärz 12th, 2014 at 19:49

Thanks for the hint but no, I’m not using this anymore. It was part of a project I did as a research assistant back then when I was at University.

JoshMärz 13th, 2014 at 16:14

Did you find other good methods for signing messages in an add on.

And, seriously, thank you for this post. I had searched for quite a while before finding this method. Was getting very frustrated.

jonasMärz 21st, 2014 at 22:27

No, if I remember correctly, I didn’t dig further into this. Encryption was the main focus and signing more a nice-to-have at that stage.
And, you’re welcome – recording stuff that was tedious to find out was my reason to start this blog.

AlfSeptember 4th, 2014 at 20:39

Damn Mozilla:
https://bugzilla.mozilla.org/show_bug.cgi?id=611752

Leave a comment

Your comment

(required)