Code snippets
XPI signing tutorial
Some years ago, I had to apply a digital signature to a (proprietary) Firefox XPI extension at work.
At the time (Firefox was pre-1.0 at the time), I had to dig and search to find half complete documentation.
With some extrapolation and by joining the info I gathered here and there, I managed to get a
signed XPI file. Obviously, my boss asked that I document the process for him so we could sign
new versions with less hassle, and that I did.
I figured that with time (about three years have passed), the Mozilla folks would have better
documented the process, and I sort of forgot about the sparse documentation. A couple of days ago,
a discussion on Slashdot
mentionned the still pitiful state of the Mozilla documentation regarding XPI signing. So I went
and re-dug up the documentation I could find, and made this tutorial.
I have executed all the following steps on a Fedora Core 6 installation, all with software and
libraries that come with the distro. Therefore, this tutorial currently assumes you are running
Linux. Instructions for Windows users will be provided in a future version of this tutorial.
What you need to have before beginning :
-
A PKCS#12 key/certificate (file with extension .pfx). That file should be provided to you by a
certificate authority, like Verisign or
Thawte. If you don't want a commercial certificate or can't
afford one, Ascertia can provide you with a free certificate,
but turning it into a code signing certificate requires some extra work, which I have detailed
on another page.
-
A Firefox installation (d'uh!). I have used Firefox 2.0.0.1 for this tutorial. However, I have
signed XPI extensions since Firefox 0.9, so pretty much all versions have the required tools.
Some options might have changed name, but they're all in there somewhere.
-
A compiler. Like many free software, Mozilla's
NSS
tools are distributed as source. That means you'll have to compile the code signer yourself.
-
GNU make. For some reason, Mozilla advises to not use another make program than GNU's one. Probably
has to do with some compatibility stuff.
-
The Firefox XPI extension you want to sign.
If you are running Linux, you can download this file which automates
the first few steps, greatly simplifying the process. If you use the above file, unpack it where you
want to work from and it will create a directory named XPI_signing. cd into that directory in
a console, execute the build.sh script and skip to step 5.
Step 1: In a console, create a directory named XPI_signing, and
cd into it. Then create a sub-directory named certs. This is where we'll put our certificates.
Create another subdirectory, which we'll call XPI. As you might have guessed, this is where we'll
unzip the extension to be signed.
user@host:~$ mkdir XPI_signing
user@host:~$ cd XPI_signing
user@host:~/XPI_signing$ mkdir certs XPI
Step 2: Get the Mozilla
NSS tools'
source code. The easiest way to do that is through CVS, with the following commands:
user@host:~/XPI_signing$ cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -r NSPR_4_6_4_RTM mozilla/nsprpub
user@host:~/XPI_signing$ cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -r NSS_3_11_4_RTM mozilla/dbm mozilla/security/dbm
user@host:~/XPI_signing$ cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -r NSS_3_11_4_RTM mozilla/security/coreconf mozilla/security/nss
Step 3: Build NSS. cd into the mozilla/security/nss
subdirectory and build the thing with gmake nss_build_all
user@host:~/XPI_signing$ cd mozilla/security/nss
user@host:~/XPI_signing/mozilla/security/nss$ gmake nss_build_all
Step 4: Copy the newly built signtool executable in the
XPI_signing directory.
user@host:~/XPI_signing/mozilla/security/nss$ cd ../../../
user@host:~/XPI_signing$ cp `find ./ -name signtool | grep /bin/signtool` ./
Step 5: Unzip your XPI extension in the XPI sub-directory created
on step 1. Make sure to put in that directory only the content of the XPI extension, and not
the extension itself.
user@host:~/XPI_signing$ unzip ~/MyExtension.xpi -d XPI
Step 6: Import your code signing certificate into Firefox. To do so,
launch Firefox, and open the Preferences dialog from the Edit menu. In the dialog, go to the
Advanced tab, and click on the View Certificates button to open the Certificate
Manager dialog.
In the Certificate Manager, go to the Your Certificates tab and click on the Import
button, then select your .pfx certificate file.
Notice the "Purposes" column in the last screenshot? That
column says what your certificate can do. <Unknown> means the certificate can't do much. What you
want is an "Object Signer" certificate. If your certificate has an <Unknown> purpose, read about
the Free Certificate Authority tutorial.
Step 7: We're done with Firefox for now, so head back to your console.
You'll want to copy two files from your Firefox profile directory into your certs directory. Those files
are cert8.db and key3.db. Those two files contain the certificate information you need
to sign a directory with the signtool we built and copied on step 4.
user@host:~/XPI_signing$ cp ~/.mozilla/firefox/2zue3f71.default/cert8.db ./certs/
user@host:~/XPI_signing$ cp ~/.mozilla/firefox/2zue3f71.default/key3.db ./certs/
Before signing anything, let's make sure that everything we've done so far is ok by checking if
signtool finds a code signing certificate in the database files we just copied.
user@host:~/XPI_signing$ ./signtool -d certs -L
using certificate directory: certs
S Certificates
- ------------
c.live.com
c.msn.com #2
* 10223188607c054dac3c4bf8062587cc_4dfc69f9-fbd1-48a6-8fa1-7de8c989d2f0
Thawte Time Stamping CA
Thawte Personal Basic CA
Thawte Personal Premium CA
Thawte Personal Freemail CA
- ------------
Certificates that can be used to sign objects have *'s to their left.
As it is mentionned at the end of the command output, a * by a certificate's name means the certificate
can be used to sign objects (code). If all is well, you should have at least one such certificate. If
not, something went wrong and you'll need to restart some or all of the previous steps. Don't worry if
your certificate doesn't have a nice looking name like "Thawte Personal Basic CA". Code signing
certificates can also be refered to by a long serial number, like the 10223188607… shown above.
Step 8: Now that we have confirmed we have a valid signing certificate,
we can use signtool to sign the content of the XPI directory. In the command below, replace
«certificate_id» with the name of the certificate as
we have discovered it in the previous step (10223188607… in my case).
user@host:~/XPI_signing$ ./signtool -d certs -k «certificate_id» XPI
using certificate directory: certs
Generating XPI/META-INF/manifest.mf file..
--> chrome/content/about.xul
--> chrome/content/contents.rdf
<snip>
--> chrome.manifest
--> install.rdf
Generating zigbert.sf file..
tree "XPI" signed successfully
The last line (tree "XPI" signed succesfully) indicates that the signing procedure succeeded.
Step 9: The content of the XPI directory is signed. All we need to do
now is to package it into a usable Firefox extension. While packaging an unsigned extension simply means
zipping the whole XPI directory's content into a file, that is not how it is done when dealing with
signed extensions. This last part is very simple but very badly documented, and this is why most people
fail to sign extensions. Here's the trick though. The order in which the files are included in
the zipped file matters, and the very first file that needs to be included is META-INF/zigbert.rsa.
Once this file is added to the zipped file, you can add (not replace) all the other files.
user@host:~/XPI_signing$ cd XPI
user@host:~/XPI_signing/XPI$ zip ../MyExtension.xpi META-INF/zigbert.rsa
adding: META-INF/zigbert.rsa (deflated 29%)
user@host:~/XPI_signing/XPI$ zip -r -D ../MyExtension.xpi * -x META-INF/zigbert.rsa
adding: chrome/content/about.xul (deflated 69%)
adding: chrome/content/contents.rdf (deflated 54%)
<snip>
adding: chrome.manifest (deflated 81%)
adding: install.rdf (deflated 62%)
adding: META-INF/manifest.mf (deflated 67%)
adding: META-INF/zigbert.sf (deflated 67%)
Step 10: There ya go! You should now have a signed extension on your
hands. Install your newly created extension in Firefox and gaze at the beauty of a signature.
Step 10 (b): If you have been using a free certificate authority to get
your signing certificate, make sure you are aware of the possible consequences for your users. See the
caveat section of the Free Certificate Authority tutorial.