Signing an XPI

Note: These instructions are outdated. For an extension to work in Firefox it must be signed by Mozilla, not by yourself. See Signing and distributing your add-on.
Note: These instructions are for how to test with a self-signed certificate. See Signing an extension for a practical guide.

Introduction

This article describes how to sign your own Firefox extensions with a code-signing certificate on a Windows platform. It was developed from the linux article So you want to sign your XPI package? by MozDev Group's Pete Collins.

This article is a mirror of the original, with minor reformatting, some new info and all links updated in March 2010.

Get network security services

1. Download the latest Network Security Services (NSS) package from the Mozilla FTP site at https://ftp.mozilla.org/pub/mozilla.or.../nss/releases/. For Windows, you'll want the nss-3.11.4.zip package in the NSS_3_11_4_RTM/msvc6.0/WINNT5.0_OPT.OBJ/ folder - it is by 2010 the only one with the right binaries.

2. Extract the contents of the archive file to a local folder. In my case it's C:\Apps\nss-3.11.4\

Get Netscape Portable Runtime

1. Download the latest Netscape Portable Runtime from the Mozilla FTP site: http://ftp.mozilla.org/pub/mozilla.org/nspr/releases/. For Windows you'll want the nspr-4.6.zip package in the v4.6/WINNT5.0_OPT.OBJ/ folder.

2. Extract the contents of the archive file to a local folder. In my case it's C:\Apps\nspr-4.6\

Add path

Add the NSS tools bin/ and lib/, and the NSPR lib/ directories to the system path. You can either set this permanently via Control Panel->System Properties->Advanced->Environment Variables->System Variables or do it each time you run the tools from the command-line (preferably using a batch file). Windows contains its own version of some of these files (e.g. certutil.exe) in the system directory (\Windows\system32\) so ensure the new paths are first in the PATH search list.

C:\> set PATH=C:\Apps\nss-3.11.4\bin\;C:\Apps\nss-3.11.4\lib\;C:\Apps\nspr-4.6\lib\;%PATH%

An easier way is to copy everything from your new directories C:\Apps\nss-3.11.4\ and C:\Apps\nspr-4.6\ including sub directories to the same directory - fx C:\Apps\CodeSigning\ - and then run every command from that.

Initialize the certificate database

Decide which folder to create the certificate database in. Use this command to create it (note the trailing dot is required).

C:\Projects\CodeSigning\> certutil -N -d .

The dot will cause the database to be created in the current directory.

You will be prompted for the NSS Certificate database password - don't forget it!

C:\Projects\CodeSigning\> certutil -N -d .
Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.

Enter new password:
Re-enter password:

Create a test certificate

Create a test certificate, using the -p option to set a password for the new certificate

C:\Projects\CodeSigning\> signtool -G myTestCert -d . -p"password"
using certificate directory: .

WARNING: Performing this operation while the browser is running could cause
corruption of your security databases. If the browser is currently running,
you should exit the browser before continuing this operation. Enter
"y" to continue, or anything else to abort: y


Enter certificate information.  All fields are optional. Acceptable
characters are numbers, letters, spaces, and apostrophes.
certificate common name: XPI Test
organization: TJworld
organization unit: Software
state or province: Nottingham
country (must be exactly 2 characters): GB
username: tj
email address: certificates@lan.tjworld.net
generated public/private key pair
certificate request generated
certificate has been signed
certificate "myTestCert" added to database
Exported certificate to x509.raw and x509.cacert.

x509.cacert will be used to sign your XPI package. Check that it exists on the file system and in the certificate database:

C:\Projects\CodeSigning\> dir x509*

14/12/2005  15:13             1,031 x509.cacert
14/12/2005  15:13               798 x509.raw

C:\Projects\CodeSigning\> certutil -d . -L
myTestCert                                                   u,u,Cu

Prepare XPI file for signing

Create a new folder just for signing, copy your existing XPI into it, unzip* it (maintaining paths), delete the XPI and return to the certificate-database folder.

*Assumes you have a zip utility available on your system path. This example is using the CygWin bin/zip.exe tool. You can use a graphical Zip tool provided it manages the internal sub-directory structure properly. An alternative is to use WinRar.

The 7-Zip tool doesn't work when creating Mozilla XPI signed archives because it sorts the directory entries alphabetically, and Mozilla requires the first entry to be META-INF/zigbert.rsa.
C:\Projects\CodeSigning\> md signed

C:\Projects\CodeSigning\> copy C:\Projects\fsb\fsb.xpi signed
        1 file(s) copied.

C:\Projects\CodeSigning\> cd signed

C:\Projects\CodeSigning\signed> unzip fsb.xpi
Archive:  fsb.xpi
   creating: chrome/
  inflating: chrome.manifest
  inflating: chrome/fsb.jar
  inflating: install.rdf

C:\Projects\CodeSigning\signed> del fsb.xpi

C:\Projects\CodeSigning\signed> cd ..

Sign XPI

C:\Projects\CodeSigning\> signtool -d . -k myTestCert -p "password" signed/
using certificate directory: .
Generating signed//META-INF/manifest.mf file..
--> chrome/fsb.jar
--> chrome.manifest
--> install.rdf
Generating zigbert.sf file..
tree "signed/" signed successfully

Re-package XPI

Change to the signed/ folder, create a new zip with the META-INF/zigbert.rsa file listed first, then add the remaining files.

C:\Projects\Certs\> cd signed

C:\Projects\CodeSigning\signed\> zip fsb.xpi META-INF/zigbert.rsa
  adding: META-INF/zigbert.rsa (deflated 35%)

C:\Projects\CodeSigning\signed> zip -r -D fsb.xpi * -x META-INF/zigbert.rsa
  adding: META-INF/manifest.mf (deflated 37%)
  adding: META-INF/zigbert.sf (deflated 40%)
  adding: chrome/fsb.jar (deflated 74%)
  adding: chrome.manifest (deflated 69%)
  adding: install.rdf (deflated 62%)

Test your certificate

To test your certificate, install it into your browser, and attempt to load the signed extension by following these steps:

1. Temporarily install the Test Certificate Authority into your Mozilla browser

Rename the x509.cacert file generated earlier to x509.cert

Import it into Mozilla Firefox as a Software Developer Certificate Authority.

Don't forget to delete the certificate from Mozilla Firefox once you've finished testing

Firefox 1.5: From the Tools menu choose Options->Advanced->Security->View Certificates->Authorities

Firefox 1.0: From the Tools menu choose Options->Advanced->Certificates->Manage Certificates->Authorities

Press the Import button.

Navigate to the folder containing x509.cert and choose it.

In the Downloading Certificate dialog, tick Trust this CA to identify software developers. and press the View button if you wish to examine the certificate more closely.

Press the OK button and you'll see your new certificate in the list of Authorities.

2. Attempt to install the signed extension

Either drag and drop or browse to and download the signed XPI. When the Mozilla Firefox Software Installation dialog appears the organisation name of the certificate will appear where Firefox usually displays unsigned.

image

Obtaining a valid software developer code-signing certificate

Warning: Currently Firefox expects XPI files to be signed with certificates that conform to the older Object Signing convention, rather than the newer Code Signing convention. This means that Firefox will refuse to install code signed via an intermediate certificate authority such as Certum Level I unless the user installs that intermediate CA certificate into Firefox first. Installing the intermediate CA certificate causes Firefox to mark the intermediate Code Signing CA certificate as a valid Object Signing CA certificate, which makes it all work. bug 321156 has been filed to request a way to obviate the installation of intermediate Code Signing CA certs into Firefox.

Now you know it all works, you need to add a real software developer's certificate to the NSS certificate database, and use that to sign the XPI. There are several issuers of software developer certificates, with the three key differentials: availability, cost and identity verification.

Many issuers will not provide a software developer certificate to individuals (how ridiculous) so you may have to search hard to find one that will, and who also has a CA root Authority installed in Mozilla Firefox. Without the certificate-issuers CA root certificate Mozilla Firefox will not confirm the validity of your certificate to users who want to install your extension. Ideally you want a certificate that has a root CA installed in all major platforms (Microsoft Windows, Sun Java, Mozilla/Netscape Firefox/Navigator, Opera) so you only use one certificate for signing all your software, no matter which platform it is for.

The cheapest universally supported (Mozilla, Java, Microsoft) certificate seems to be the Comodo Instant-SSL offering. You can get a free certificate for open-source developers from Unizeto Certum, in 2010 it is a Certum Level III CA.

Here are some current issuers:

  • Comodo Instant-SSL Code Signing
  • Digi-Sign Digi-Code
  • GeoTrust Code Signing
  • Thawte Code Signing (owned by Verisign)
  • Unizeto Certum Code-signing (free certificates for open-source authors)
  • Verisign Code Signing

You will need to apply for a Code Signing Certificate and satisfy the Issuer's identity verification procedures. They will then issue a signed certificate. When you receive the signed certificate it must be imported into the certificate database.

Your browser will generate a new private key and Code Signing Request (CSR) in the background without you necessarily realising it. The CSR will be uploaded to the Issuer. Later, you must use the same browser when installing the new certificate because the key and certificate pair must be together.

Hint: When applying for a certificate ensure that the Organisation (O) contains your name and not the Issuer's default text, because this is what is displayed to users.

For this guide I applied for a free certificate from Unizeto Certum. After completing the application process where I entered my details into the online application, I received an automated email requesting documentary evidence of my ID in the form of a photo-ID or similar. I have hi-resolution scanned images of my passport and drivers license for these situations so I placed them on my web-server temporarily in a hidden location and emailed Unizeto Certum with the details and location of the files. Within a few hours I received a confirmation email from a human accepting the ID images and giving me a hyperlink to the certifcate download area.

Install the certificate into Mozilla Firefox (which goes with the private key created earlier), and copy/paste the displayed certificate text into a new file called C:\Projects\CodeSigning\Certum Code Signing.cer.

Installing real certificate

There are two steps required to install the new certificate in the Code Signing NSS certificate database.

 1. Install the Issuer's Certificate Authority Root
 2. Install your key and certificate

The root CA establishes the trust of your certificate. Many issuer's have multiple root CAs for different levels of trust. find out which one was used for your certificate and download it. You can view the details of your certificate in Mozilla Firefox and get this information from the Issued By Common Name (Unizeto Certum's free certificate CA is Certum Level III CA).

Download the Root CA and any intermediate certificates used to sign your certificate from the Issuer; their web site will have a link somewhere to their root CAs and public certificates. (Certum public key page). I downloaded the Certum Root CA and Certum Level III CA Digital ID for web and SSL/TLS Servers, copied the text and saved them to the files C:\Projects\CodeSigning\Certum Root CA.cer and C:\Projects\CodeSigning\Certum Level III CA.cer.

Open a command prompt (ensure the paths to the NSS tools are set as described above) in the CodeSigning folder, install the Issuer CA certificates, and check they have been added correctly.

C:\Projects\CodeSigning> certutil -A -n "Certum Root CA" -t "TC,TC,TC" -d . -i "Certum Root CA.cer"

C:\Projects\CodeSigning> certutil -A -n "Certum Level III CA" -t "c,c,C" -d . -i "Certum Level III CA.cer"

C:\Projects\CodeSigning> certutil -L -d .
myTestCert                                                   u,u,Cu
Certum Root CA                                               CT,C,C
Certum Level III CA                                          CT,C,C

The name given to the newly issued certificate in the Mozilla Firefox keystore is not the easiest key alias in the world to remember, so I've added an additional step here that lets you rename it (its not just a simple rename operation, unfortunately).

To find the name, in Mozilla Firefox navigate to the Certificate Manager (described in Step 11), choose Your Certificates, select the new certificate, press View, choose Details and look at the first entry in the Certificate Fields tree-view.

My Unizeto Certum certificate is named "TJ's Unizeto Sp. z o.o. ID" but I want it to be called "Code Signing (Certum)".

The trick is to install the certificate (without the key) first and give your chosen nickname at that point. When the key/certificate pair is imported from Mozilla Firefox afterwards, the private key will be added but the certificate name will remain the same.

C:\Projects\CodeSigning> certutil -A -n "Code Signing (Certum)" -t "u,u,u" -d . -i "Certum Code Signing.cer"

C:\Projects\CodeSigning> certutil -L -d .
myTestCert                                                   u,u,Cu
Certum Root CA                                               CT,C,C
Certum Level III CA                                          CT,C,C
Code Signing (Certum)                                        ,,

C:\Projects\CodeSigning> signtool -l -d .
using certificate directory: .

Object signing certificates
---------------------------------------
myTestCert
    Issued by: myTestCert (XPI Test)
    Expires: Tue Mar 14, 2006
Code Signing (Certum)
    Issued by: Certum Level III CA (Certum Level III CA)
    Expires: Tue Mar 14, 2006
---------------------------------------
For a list including CA's, use "signtool -L"

Now you must export the new key/certificate pair from the Mozilla Firefox certificate database and into the NSS certificate database.

The hardest part is locating Mozilla's key database. It consists of two files named key3.db and cert8.db. They usually live in the Mozilla Firefox user profile folder. I found mine in C:\Documents and Settings\TJ\Application Data\Mozilla\Firefox\Profiles\xxxxxxxx.default\ where xxxxxxxx is a random string of characters.

This procedure assumes you installed the new certificate into Mozilla Firefox

Here's the commands required to export it to a file, import it to the Code Signing database, and verify the signing attributes (u,u,u). Ensure you use the nickname of your certificate in place of mine, and the directory where your Mozilla Firefox key database files are:

C:\Projects\CodeSigning> pk12util -o "Certum Code Signing.pkcs12" -n "TJ's Unizeto Sp. z o.o. ID" -d "C:\Documents and Settings\TJ\Application Data\Mozilla\Firefox\Profiles\xxxxxxxx.default"
Enter password for PKCS12 file:
Re-enter password:
pk12util: PKCS12 EXPORT SUCCESSFUL

C:\Projects\CodeSigning> pk12util -i "Certum Code Signing.pkcs12" -d .
Enter Password or Pin for "NSS Certificate DB":
Enter password for PKCS12 file:
pk12util: PKCS12 IMPORT SUCCESSFUL

C:\Projects\CodeSigning> certutil -L -d .
myTestCert                                                   u,u,Cu
Certum Root CA                                               CT,C,C
Certum Level III CA                                          c,c,C
Code Signing (Certum)                                        u,u,u

You should notice that the existing certificate has been updated.

Sign extension with real certificate

This is a repeat of the earlier steps using the real certificate's details. Here's the output on a test directory:

C:\Projects\CodeSigning>signtool -d . -k "Code Signing (Certum)" -p ******* test
using certificate directory: .
Generating test/META-INF/manifest.mf file..
--> test.txt
Generating zigbert.sf file..
tree "test" signed successfully

Incorporating signing into your build process

You may want to incorporate these steps into your existing build process. I have a build.bat file that automates the creation of the jar and xpi files. This example is using the CygWin bin/zip.exe tool.

build.bat is placed in the extension's root folder. E.g.

/dev/fsb/build.bat /dev/fsb/install.rdf /dev/fsb/chrome.manifest /dev/fsb/chrome/ /dev/fsb/chrome/content/ /dev/fsb/chrome/locale/ /dev/fsb/chrome/skin/

Here it is with the code-signing steps included:

@echo off
set x=%cd%

echo Building %x%.xpi ...
echo Started at %DATE% %TIME% > %x%\build.log

md build\chrome

cd chrome

zip  -r -0 "%x%.jar" * >> %x%\build.log

move "%x%.jar" ..\build\chrome >> %x%\build.log

cd ..

copy install.rdf build >> %x%\build.log

copy chrome.manifest build >>%x%\build.log

signtool.exe -d C:\Projects\CodeSigning -k "Code Signing (Certum)" -p "password" build/ >> %x%\build.log

cd build

zip "%x%.xpi" META-INF/zigbert.rsa >> %x%\build.log

zip -r -D "%x%.xpi" * -x META-INF/zigbert.rsa >> %x%\build.log

rem copy "%x%.xpi" ..\..\..\http\fsb.xpi >> %x%\build.log

move "%x%.xpi" ..\ >> %x%\build.log

cd ..

rd build /s/q

echo Done.

Make sure to replace password with your NSS Certificate database password.

Alternatives to NSS/signtool

There are several alternatives to using signtool that might suit your needs better, however please note that these alternatives are unofficial third party products.

References