Software Update:MAR Signing and Verification

From MozillaWiki
Jump to: navigation, search

Overview

MAR files can be signed and verified using the signmar binary. The binary should be built by default as of Firefox 40 but you can also set the configure.in option `--enable-signmar`.

Common operations

In the examples below, I'll use the NSS config directory which is included in mozilla-central's source code for running xpcshell tests.

All commands take an input MAR file, do some operation on the data, and outputs a new MAR file. Operations are non destructive to the input MAR. That is to say, none of the commands modifies the data of the input MAR in place.

Some of the common operations include:

Print detailed information on a MAR file including signatures:

 signmar -T archive.mar

Strip a MAR signature and output an un-signed mar file:

 signmar -r in.mar out.mar

Sign a MAR file which isn't already signed:

 signmar -d ./modules/libmar/tests/unit/data/ -n mycert -s in.mar out.mar

Verify a MAR file on Windows:

 signmar -D ../modules/libmar/tests/unit/data/mycert.der -v out.marr

Refresh the product information block of a MAR file:

 signmar -H some-channel-id -V 40.0a1 -i unsigned_archive_to_refresh.mar

To refresh a MAR file that is already signed, first strip its signature, refresh, then re-sign.

Multiple Signatures and signing from multiple parties

Multiple signatures per MAR file support was added for B2G originally. It may still be used in the future, but it is not used as of April 2015.

A MAR file can be signed by at most 8 different parties. The actual limit is defined in `modules/libmar/src/mar.h` with `MAX_SIGNATURES`.

To support multiple parties signing a MAR file, one party can export their MAR file's signature and send it to the 2nd party to import it into that party's already signed MAR file.

Sign a MAR file:

 signmar -d ./modules/libmar/tests/unit/data/ -n mycert -s in.mar out.mar

Extract that MAR's signature:

 signmar -n0 -X out.mar base64_encoded_sig

Note that you can pass -n1 for the 2nd signature in a file if one exists, -n2 for the 3rd, etc.

Now let's say you signed a different mar file with mycert2. You can import the mycert signature into your mar:

 signmar -n1 -I signed_input_archive.mar base64_encoded_sig changed_signed_output.mar

Verify a MAR file signed with 2 signatures:

 signmar -D0 ../modules/libmar/tests/unit/data/mycert.der -D1 ../modules/libmar/tests/unit/data/mycert2.der -v out.mar

A MAR file is only verified if all signatures are verified. That is to say if only 1 signature is verified and a MAR has 3 signatures on it, then it will not verify.

Creating an NSS db

Create an NSS db:

 mkdir foo && cd foo
 certutil -d . -N

Enter a password for your NSS db, or if you're just testing things out, then leave it blank.

Next create a certificate called mycert:

 certutil -S -d . -s "CN=My Cert" -n mycert -x -t ",,u" -g 2048

Continue typing characters until the bar is full.


Extract a DER file with your cert:

 certutil -L -d . -n mycert -r > mycert.der

Implementation

MAR signing is always done with the signmar tool using NSS. Verification happens in different ways depending on which platform you're on.

For Windows it uses the Windows Crypto API library. For OS X it uses the Security Transforms API. Everywhere else it uses NSS.

This model of not using NSS everywhere was decided early on because it wasn't wanted for an NSS bug to stop updates from working. Technically there's also a problem with us not building NSS as a static library as well making updates using NSS harder.

Where MAR verification happens

MAR verification is always done for Firefox updates in Windows. During an update operation, it happens in the updater binary, even if the Mozilla Maintenance service is used on Windows.

As of Firefox 40, MAR verification is enabled on OS X. As of Firefox 42, MAR verification is enabled on Linux.