Fork me on GitHub

Ivan-Site.com

Signing an XPI using a VeriSign Code Signing certificate

I recently had to sign a Mozilla Firefox extension using a VeriSign Code Signing certificate. The process to receive the cert is pretty straightforward - you apply for the certificate on VeriSign's page where you input your company details and payment information. By the way, you can use "THEDEAL99" promo code to get $400 off $499 for a Microsoft© Authenticode© certificate to make the price somewhat reasonable. After your application is submitted they verify the validity of your company and the information you put in and issue you the certificate that you can use for code signing.

I exported the certificate and the private key out of the browser into a pfx file. In Internet Explorer this can be achieved by going to Tools -> Internet Options -> Content -> Certificates -> Personal tab, and clicking export, which takes you to a wizard to guide you through the export process. I was able to successfully sign and test executables using Microsoft's signing tool using the command below:

signtool.exe sign /f cert.pfx executable.exe

For XPI though, things weren't as easy. I followed this guide from Mozilla to sign the XPI using the latest compiled version of Network Security Services (NSS). The latest binaries that I found were for version 3.12.4 here. After successfully importing all the certificates and the private key into a new NSS database, I was able to sign my Mozilla extension by using the following command:

signtool.exe -d . -k {CERT_NAME} -p {CERT_PASSWORD} {XPI_DIRECTORY}

After repackaging the signed XPI it was displayed as untrusted by Firefox with a default configuration. Firefox displayed a generic "Signing could not be verified" error message with an error code of -260 as can be seen below:

Firefox Certificate Error

I also tried XPISigner, an application that simplified XPI code signing process written in Java, but got the same results. Instructions for XPISigner are here. XPISigner just needs your certificate pfx file and will take care of repackaging for you.

After investigating thoroughly, I found that the certificate signing chain looked as follows:

  • VeriSign Class 3 Public Primary Certification Authority - G5
    • VeriSign Class 3 Code Signing 2010 CA
      • (our cert)

And that the "VeriSign Class 3 Public Primary Certification Authority - G5" certificate is not trusted to "identify software makers" as can be seen in the image below:

Firefox G5 CA settings

Checking that checkbox resulted in Firefox trusting the signed XPI as expected, however we couldn't require our users to manually alter their browser configuration just to install the XPI.

After a few emails with VeriSign support, I discovered that the "VeriSign Class 3 Public Primary Certification Authority - G5" certificate is not supposed to be the root Certificate Authority, but an intermediate one. It is supposed to be signed by VeriSign's "Class 3 Public Primary Certification Authority" even though it is considered to be a root CA by all browsers including Firefox as can be seen here. The certificate chain is supposed to look like:

  • VeriSign Class 3 Public Primary Certification Authority
    • VeriSign Class 3 Public Primary Certification Authority - G5
      • VeriSign Class 3 Code Signing 2010 CA
        • (our cert)

So, now the problem was getting NSS to view the G5 certificate as an intermediate CA rather than root. For this I needed to remove the builtin G5 CA and add it as an intermediate manually. NSS does not provide any easy way to remove a builtin CA, the only documentation I found was here, requiring to manually recompile NS.

But it looked like I didn't have any other options at this point as all my other tries resulted in the signed XPI not containing the right certificate chain. I could see the list of certificates present in the XPI by getting openssl and running:

openssl pkcs7 -print_certs -inform der -in zigbert.rsa

where "zigbert.rsa" is generated by the signing tool. That list is supposed to contain all the certificates in the signing chain except for the root CA (total of 3 in my case), and I couldn't force the signing tool to do that as it never included the G5 certificate thinking that it was root.

So I got the latest version of the source of NSS (3.12.8 at the time) from here and followed the instructions to remove the builtin CA, recompile everything, and install replacing the old binaries. The guide I used for compilation is here. I did all this on a Linux box as I didn't want to deal with Cygwin on Windows, but it should definitely be possible through Cygwin as well.

Sure enough, after getting NSS compiled with the removed root CA, I was able to successfully sign the XPI and it was trusted by Firefox out of the box. Since I needed to do all of my code signing on Windows, I also exported the certificate from the modified NSS database into a pfx file and just fed it to XPISigner, which worked perfectly now!

I hope that my findings will benefit other people out there with similar problems as I spent quite a bit of time on this problem. I would also recommend Mozilla to enable the code signing bit for the "VeriSign Class 3 Public Primary Certification Authority - G5" certificate by default to eliminate these problems. I assume if the certificate is used for code signing it should have that bit set! I think VeriSign have to actually submit the request for that though.

Posted Tue 16 November 2010 by Ivan Dyedov in Linux (Cryptography, XPI, code signing, verisign, Linux)

9 comments

  • Avatar
    Mihai Danila 2012-06-13T07:56:43

    Strangely enough, after importing the intermediate version of G5 into the keystore, my signing starts working even with my old signtool. This must mean that my compiled signtool does not have G5 in it; a search for G5 in nssckbi.dll seems to confirm this (other cert names are listed in clear text in this file, but not G5).

    At least recompiling NSS was fun. :)

  • Avatar
    Mihai Danila 2012-06-13T07:53:04

    The problem is due indeed to the fact that I was using the self-signed version of the G5 certificate. After importing the one signed by the root authority instead (available at the URL linked in the second comment on this page), I was able to include it in the signature, and Firefox's "author not verified" issue went away.

    Thanks for the tip!

  • Avatar
    Mihai Danila 2012-06-13T07:14:19

    In my case, G5 seems to be self-signed. I wonder if that has something to do with it. It should be signed by VeriSign Class 3 Public Primary Certification Authority.

    Here's what I get:

    Certificate:
    Data:
    Version: 3 (0x2)
    Serial Number:
    18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a
    Signature Algorithm: PKCS #1 SHA-1 With RSA Encryption
    Issuer: "CN=VeriSign Class 3 Public Primary Certification Authority -
    G5,OU="(c) 2006 VeriSign, Inc. - For authorized use only",OU=Ver
    iSign Trust Network,O="VeriSign, Inc.",C=US"
    Validity:
    Not Before: Wed Nov 08 00:00:00 2006
    Not After : Wed Jul 16 23:59:59 2036
    Subject: "CN=VeriSign Class 3 Public Primary Certification Authority
    - G5,OU="(c) 2006 VeriSign, Inc. - For authorized use only",OU=Ve
    riSign Trust Network,O="VeriSign, Inc.",C=US"
    Subject Public Key Info:
    Public Key Algorithm: PKCS #1 RSA Encryption
    RSA Public Key:
    Modulus:
    af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b:4e:dc:
    7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57:08:a3:64:
    85:15:27:f5:f1:ad:c8:31:89:5d:22:e8:2a:aa:a6:42:
    b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe:8f:7e:07:57:ec:
    ef:43:db:66:62:15:61:cf:60:0d:a4:d8:de:f8:e0:c3:
    62:08:3d:54:13:eb:49:ca:59:54:85:26:e5:2b:8f:1b:
    9f:eb:f5:a1:91:c2:33:49:d8:43:63:6a:52:4b:d2:8f:
    e8:70:51:4d:d1:89:69:7b:c7:70:f6:b3:dc:12:74:db:
    7b:5d:4b:56:d3:96:bf:15:77:a1:b0:f4:a2:25:f2:af:
    1c:92:67:18:e5:f4:06:04:ef:90:b9:e4:00:e4:dd:3a:
    b5:19:ff:02:ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:
    ac:f2:f6:f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:
    24:19:21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:
    8d:63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95:
    ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f:9f:
    73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8:25:15
    Exponent: 65537 (0x10001)
    Signed Extensions:
    Name: Certificate Basic Constraints
    Critical: True
    Data: Is a CA with no maximum path length.

    Name: Certificate Key Usage
    Critical: True
    Usages: Certificate Signing
    CRL Signing

    Name: OID.1.3.6.1.5.5.7.1.12
    Data: Sequence {
    [1]: {
    [0]: {
    Sequence {
    Sequence {
    Sequence {
    "image/gif"
    Sequence {
    Sequence {
    Sequence {
    SHA-1
    }
    8f:e5:d3:1a:86:ac:8d:8e:6b:c3:cf:
    80:6a:d4:48:18:2c:7b:19:2e
    }
    }
    Sequence {
    "http://logo.verisign.com/vs..."
    }
    }
    }
    }
    }
    }
    }

    Name: Certificate Subject Key ID
    Data:
    7f:d3:65:a7:c2:dd:ec:bb:f0:30:09:f3:43:39:fa:02:
    af:33:31:33

    Signature Algorithm: PKCS #1 SHA-1 With RSA Encryption
    Signature:
    93:24:4a:30:5f:62:cf:d8:1a:98:2f:3d:ea:dc:99:2d:
    bd:77:f6:a5:79:22:38:ec:c4:a7:a0:78:12:ad:62:0e:
    45:70:64:c5:e7:97:66:2d:98:09:7e:5f:af:d6:cc:28:
    65:f2:01:aa:08:1a:47:de:f9:f9:7c:92:5a:08:69:20:
    0d:d9:3e:6d:6e:3c:0d:6e:d8:e6:06:91:40:18:b9:f8:
    c1:ed:df:db:41:aa:e0:96:20:c9:cd:64:15:38:81:c9:
    94:ee:a2:84:29:0b:13:6f:8e:db:0c:dd:25:02:db:a4:
    8b:19:44:d2:41:7a:05:69:4a:58:4f:60:ca:7e:82:6a:
    0b:02:aa:25:17:39:b5:db:7f:e7:84:65:2a:95:8a:bd:
    86:de:5e:81:16:83:2d:10:cc:de:fd:a8:82:2a:6d:28:
    1f:0d:0b:c4:e5:e7:1a:26:19:e1:f4:11:6f:10:b5:95:
    fc:e7:42:05:32:db:ce:9d:51:5e:28:b6:9e:85:d3:5b:
    ef:a5:7d:45:40:72:8e:b7:0e:6b:0e:06:fb:33:35:48:
    71:b8:9d:27:8b:c4:65:5f:0d:86:76:9c:44:7a:f6:95:
    5c:f6:5d:32:08:33:a4:54:b6:18:3f:68:5c:f2:42:4a:
    85:38:54:83:5f:d1:e8:2c:f2:ac:11:d6:a8:ed:63:6a
    Fingerprint (MD5):
    CB:17:E4:31:67:3E:E2:09:FE:45:57:93:F3:0A:FA:1C
    Fingerprint (SHA1):
    4E:B6:D5:78:49:9B:1C:CF:5F:58:1E:AD:56:BE:3D:9B:67:44:A5:E5

    Certificate Trust Flags:
    SSL Flags:
    Valid CA
    Email Flags:
    Valid CA
    Object Signing Flags:
    Valid CA

  • Avatar
    Mihai Danila 2012-06-13T06:28:56

    I recompiled NSS (make clean, rd /s /q mozilla dist, make nss_build_all) after stripping the G5 certificate from the relevant text file. I manually imported G5 into the store, and my signing still doesn't include it. I tried with trust flags C,C,C and c,c,c (other flags don't seem to stick), using certutil -M.

    Any ideas? Perhaps I'm not really issuing a clean make here?

    Certificate Nickname Trust Attributes
    SSL,S/MIME,JAR/XPI

    my_cert u,u,u
    VeriSign Class 3 Code Signing 2010 CA C,C,C
    VeriSign Class 3 Public Primary Certification Authority - G5 c,c,c

  • Avatar
    Khachatur 2012-05-03T23:15:36

    I'm having this same issue with signing my xpi with verisign Code signing certificate. After spending a week I finally got from another company and it worked.

  • Avatar
    Tim 2012-01-12T21:57:48

    Thanks for the article. I'm running into this exact problem. The odd part is for me it works fine on 8+, just not version 3.6.

    • Avatar
      Ivan Dyedov 2012-02-23T07:38:47

      They may have finally added the intermediate verisign certificate to Firefox in the latest versions.

  • Avatar
    Idan 2011-06-13T11:13:13

    You can obtain the intermediate certificates here:
    http://www.verisign.com/support/verisign-intermediate-ca/code-signing-intermediate/index.html

    see also:
    https://knowledge.verisign.com/support/code-signing-support/index?page=content&id=SO15698&actp=search&viewlocale=en_US&searchid=1307947823417

  • Avatar
    Ivan Dyedov 2010-12-07T09:09:46

    seems like LogMeIn is having similar issues with their VeriSign certificate as I received the same error trying to install their FireFox XPI. I had to enable the "identify software makers" bit for "Verisign Class 3 Public Primary Certification Authority" to get it to work