Software Update:MAR

From MozillaWiki
Revision as of 23:47, 22 November 2011 by Bbondy (talk | contribs)
Jump to navigation Jump to search

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).


HEADER

 4 bytes : MARID - "MAR1"
 4 bytes : OffsetToIndex - offset to INDEX in bytes relative to the start of MAR file
 8 bytes : FileSize - size in bytes of the entire MAR file

SIGNATURES

 4 bytes : NumSignatures - Number of signatures
 NumSignatures SIGNATURE_ENTRY elements

SIGNATURE_ENTRY

 4 bytes : SignatureAlgorithmID - ID representing the type of signature algorithm.
 4 bytes : SignatureSize - Size in bytes of the signature that follows
 N bytes : Signature - The signature of type SIGNATURE_ENTRY.SignatureAlgorithmID and size N = SIGNATURE_ENTRY.SignatureSize bytes

INDEX

 4 bytes : IndexSize - Size of INDEX in bytes
 variable number of INDEX_ENTRY elements

INDEX_ENTRY

 4 bytes : OffsetToContent - Offset in bytes relative to start of the MAR file
 4 bytes : ContentSize - Size in bytes of the content
 4 bytes : Flags - File permission bits (in standard unix-style format).
 M bytes : FileName - File name (byte array)
 1 byte  : null terminator

Some old MAR files will not contain the SIGNATURE block nor the HEADER.FileSize field. 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. The contained SIGNATURE_ENTRY.signature must be of type SIGNATURE_ENTRY.SignatureAlgorithmID.

SIGNATURE_ENTRY.SignatureAlgorithmID

 1: RSA-PKCS1-SHA1 (2048 bits / 256 bytes)

The updater will only accept the MAR file if at least one of the signatures verifies. 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.

As of Firefox 10, only RSA-PKCS1-SHA1 signatures are accepted. 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.

Additional sections

Additional MAR file sections may defined in the future. These sections must follow directly after the SIGNATURES section.

Source Code

The source code can be found under modules/libmar.

See bug 296303 and bug 699700

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.