Mozilla ARchive

This document describes the Mozilla ARchive (MAR) format used by the update system to deliver update packages. It is basically a series of files with an index tacked on to the end.

Details

The file structure in a nutshell is a header (HEADER), followed by a (SIGNATURES) block, followed by a list of variable length files, and finally ending with an index of the files (INDEX). The index is a list of variable length entries (INDEX_ENTRY). The signatures block is a list of variable length entries (SIGNATURE_ENTRY).

Some old MAR files will not contain the SIGNATURE block. Old parsers simply skip over these fields because they ignore everything between the MAR header and the offset given in the HEADER.OffsetToIndex field.

SIGNATURE blocks

Zero or more SIGNATURE_ENTRYs can be specified.
The signatures must be composed of all bytes of the MAR file excluding the SIGNATURE_ENTRY.Signature fields.
Each contained SIGNATURE_ENTRY.Signature must be of type SIGNATURE_ENTRY.SignatureAlgorithmID.

SIGNATURE_ENTRY.SignatureAlgorithmID

The updater will only accept the MAR file if at least one of the signatures verify.
Some versions of the updater may not apply a MAR file unless a valid signature of a particular SIGNATURE_ENTRY.SignatureAlgorithmID is included in the MAR file.

From Firefox 10-56, only RSA-PKCS1-SHA1 signatures are accepted. Bug 1105689 adds support for SHA-384 and is slated for Firefox 56.
There is no indicator in the MAR file for which operating system the MAR is for.

Byte Ordering

All fields are in big-endian format.
The signatures are in NSS / OpenSSL / big-endian order and not CryptoAPI order.
If CryptoAPI is used to check a signature, the bytes of the signature must be reversed before verifying the signature using CryptVerifySignature.

Constraints

To protect against invalid inputs the following constraints are in place:

There are at most 8 signatures.

The file size of the MAR file is at most 500MB.

No signature is more than 2048 bytes long.

Additional sections

Additional MAR file sections may be defined in the future.
If at least one additional section exists, the ADDITIONAL_SECTIONS header entry must be present.

Each additional block must be in the format described above in ADDITIONAL_SECTION_ENTRY.

The Block identifier is a value used to uniquely identify additional blocks so that they may be optionally added in any order.

Product Information Block

The product information block identifies the product and channel this MAR file applies to. It also includes the new version number to avoid downgrades.
The product and channel are combined in the MARChannelName field.

Source Code

Why not use ZIP or some other standard file format?

This question was given a fair amount of consideration. Ultimately, we decided to go with a custom file format because using libjar would have required a fair bit of hacking. Writing custom code was a simpler option, and it resulted in less code (mar_read.c is less than 300 lines of code). Moreover, the update system does not need a standard file format. The elements stored in the archive are bzip2 compressed binary diffs, generated using a variation of bsdiff. So, being able to unpack the archive file using standard tools wouldn't be very useful in and of itself.