A fork/clone of the subversion xar repository from http://xar.googlecode.com/svn/ that includes several enhancements and bug fixes including very basic command line signature support (master branch). See the xar project page for more information.
After building an xar tool with signature support, an xar archive (including Apple’s .pkg flat-file format) can be signed.
To verify that the xar tool has signature support try this:
xar --versionThe output should be:
xar 1.6.1If the version number is less than 1.6.1 then your version of the xar tool is too old to use these instructions (and also has various bugs).
A signing certificate in DER (binary) format together with its signing key in PEM (ASCII) format will be needed to sign an xar archive file.
Additionally, if your signing certificate was not signed directly by the root certificate, you should also have available any intermediate certificates (again in DER format) in the certificate chain between your signing certificate and the root certificate — you do not need any signing keys for these intermediate certificates.
For example, suppose you had this certificate chain:
root.crt | Some root certificate that has already been pre-installed by the OS/browser vendor and is therefore implicitly trusted |
toporg.crt | The top-level certificate for some organization (typically obtained by paying a certificate authority to sign it) that has been signed by root.crt |
intorg.crt | An intermediate certificate for some organization (perhaps for a developer division within that organization) that has been signed by toporg.crt |
leaf.crt | A leaf signing certificate for which you have the signing key (typically obtained by paying the owner of the certificate that signed it) that has been signed by intorg.crt |
This certificate chain is only an example. Real certificate chains may contain a different number of certificates than shown here using either more certificates or fewer certificates in the chain.
When the recipient of a signed xar archive attempts to verify the signature, all certificates in the chain must be available. The leaf signing certificate will always be present in the xar archive and any trusted root certificates will always be present on the machine doing the verification.
However, the recipient has no means to obtain any certificates in between the leaf signing certificate and the trusted root certificate; without them the signature verification will always fail. It’s possible the recipient has already seen the intermediate certificates and stashed them away, but this behavior cannot be depended on.
In the example certificate chain above, the toporg.crt certificate and the intorg.crt certificate are the intermediate certificates.
To guarantee a successful signature verification, all intermediate certificates must always be included in the xar archive. It’s good form to go ahead and include the root certificate as well so that if the recipient does not already have it (and therefore it’s not trusted), at least its full information can be displayed to help make an informed choice about whether or not to trust it.
These example signing commands are written for an sh-compatible shell and also require the openssl command to be available.
To successfully sign an xar file using the commands in this section, the xar archive must use SHA-1 checksum hashes (the default) and the leaf signing certificate must use the SHA-1 with RSA Encryption (aka sha1WithRSAEncryption — see RFC 3447 section A.2) signature algorithm for signatures (see here for instructions on checking a certificate’s signature algorithm).
Given the sample certificate chain above with DER (binary) versions of the four certificates available in the files root.der, toporg.der, intorg.der and leaf.der and the private key for leaf.der available in PEM (ASCII) format in the file key.pem the following steps will sign an archive.xar file.
The characteristics of the signing key (bit length, algorithm, etc.) determine the size of the signatures it generates. In order to sign an xar archive, the correct amount of space must be reserved for the signature so we must determine length of signatures produced by the signing key.
: | openssl dgst -sign key.pem -binary | wc -c > siglen.txt
The above command is used to automate the signing process by storing the signature length in bytes (as an ASCII number) into the file siglen.txt. However, the same thing can be accomplished by hand with only the openssl command by first creating a file named empty.txt that’s empty (a single blank line is fine too). Then using
openssl dgst -sign key.pem -binary -out sig.dat < empty.txt
and looking at the size in bytes of the generated sig.dat file which gives the number of bytes to reserve for the signature.
xar --sign -f archive.xar --digestinfo-to-sign digestinfo.dat \ --sig-size `cat siglen.txt` \ --cert-loc leaf.der --cert-loc intorg.der \ --cert-loc toporg.der --cert-loc root.derIt’s important that the --cert-loc options list the certificates in the certificate chain in bottom-up order (i.e. from leaf signing certificate to root). Only the first --cert-loc option is required (which must be the signing certificate), but if the signing certificate is not a self-signed root certificate, the rest of the certificates in the certificate chain should be included as well or the recipient of the xar archive may not be able to verify the signature.
If a siglen.txt file was not created in the previous step, replace the “`cat siglen.txt`” part of the above command with the number of bytes to reserve for the signature as determined by hand in the previous step.
If the archive already has a signature use --replace-sign instead of --sign to rip out the old signature and replace it.
Archive creation can be combined with this step by adding a -c option and a list of files to add to the archive.
Despite the name, the --sign option does not create a signature, it only reserves space for one so that it can be injected later.
openssl rsautl -sign -inkey key.pem -in digestinfo.dat -out signature.dat
For the curious, the digestinfo.dat created in the previous step consists of the DigestInfo prefix for an SHA-1 digest (see RFC 3447 section 9.2 and scroll down to the "Notes." and in note "1." the value for the SHA-1 DigestInfo prefix is given) followed by the actual SHA-1 hash (20 bytes) of the xar file’s table of contents.
xar --inject-sig signature.dat -f archive.xar
Until this step is performed, the archive is not signed. Even though the --sign option was used in a previous step, all that did was reserve the space (specified with the --sig-size option) so that the actual signature could be injected later (in this step) with the --inject-sig option.
rm -f signature.dat digestinfo.dat siglen.txt sig.dat
Steps 2–4 must be repeated whenever the content of the xar archive changes. Omitting any of these steps will produce an xar archive with an invalid signature.
Before signing an xar archive, the archive itself needs to be created.
By default, when creating an xar archive, the xar command includes all kinds information about the files it contains including the owner user id, owner user name, group id, group name, inode number, device number, extended attributes and so on.
Some recipient software can be confused by some of this extra information and do you really want to include things like the inode number, owner user name etc. for files you distribute? Especially since some of that information (owner user name for example) might assist someone in compromising your computer.
To get extremely fine-grained control over which properties are stored for each file in the xar archive, the --prop-include or --prop-exclude options can be used.
Specifying all those --prop-include or --prop-exclude options can get tedious. The simpler solution is to use the --distribution option which just keeps the file name and file mode.
For example, if you have this directory structure:
foo.ext/ foo.ext/dir1/ foo.ext/dir1/d1file1.txt foo.ext/dir1/d1file2.txt foo.ext/dir2/ foo.ext/dir2/d2file1.txt foo.ext/file1.txtand you would like to create a maximally compressed xar archive of foo.ext/ named foo.ext.xar that omits all the extra xar information that would be included by default, you can use this command:
xar -czf foo.ext.xar --compression-args=9 --distribution foo.ext
The default compression level is embedded in the xar library and is set to high compression by default, but adding the --compression-args=9 option ensures the highest compression level is used.
Given a signed xar file named signed.xar the contained certificates may be extracted using this command sequence:
mkdir certs xar -f signed.xar --extract-certs certs
The certificates are extracted in DER (binary) format and are named with a “cert” prefix and a two-digit suffix and placed in the specified directory (in this case certs). The leaf signing certificate is always named “cert00”.
If the example certificate chain was used to sign the signed.xar file and all four certificates were passed to the xar command using --cert-loc options, then the --extract-certs option would produce four files. “cert00” would correspond to “leaf.crt”, “cert01” would correspond to “intorg.crt”, “cert02” would correspond to “toporg.crt”, and “cert03” would correspond to “root.crt”.
You may have a private key for your certificate available in a .p12 (aka PKCS#12) format file. (The OS X Keychain Access application can export private keys in the .p12 format.)
To convert a private key file named my_private_key.p12 in PKCS#12 format to a standard RSA Private Key PEM format key.pem file use this sequence of commands:
openssl pkcs12 -in my_private_key.p12 -nodes | openssl rsa -out key.pem
Trying to be clever and omitting the trailing “openssl rsa -out key.pem” command leaves extra stuff in the output file and fails to produce an RSA Private Key format output file so the resulting key file may not actually work to sign the archive.
You may have a certificate for your private key contained in the same .p12 (aka PKCS#12) format file that the private key is in. (The OS X Keychain Access application can export private keys together with their certificates in the .p12 format if both are selected for export at the same time.)
To extract the certificate contained within a private key file named my_private_key.p12 in PKCS#12 format to a standard X509 DER certificate format cert.der file use this sequence of commands:
openssl pkcs12 -in my_private_key.p12 -nodes | openssl x509 -outform der -out cert.der
Trying to be clever and omitting the trailing “openssl rsa -out key.pem” command leaves extra stuff in the output file and fails to produce an X509 certificate DER format output file so the resulting certificate file would not actually be usable with the --cert-loc xar option.
Not all .p12 files contain certificates. If there’s no certificate in the file the above command sequence will produce an error.
If you have a certificate in PEM format (you can tell because you can open the file in your favorite text editor and one of the first lines of the file will be “-----BEGIN CERTIFICATE-----”) named cert.pem you can easily convert it to a DER format cert.der file like so:
openssl x509 -in cert.pem -outform der -out cert.der
To do the reverse you would use the command
openssl x509 -inform der -in cert.der -out cert.pem
but PEM format certificates are not helpful in creating signed xar archives.
(The OS X Keychain Access application can export certificates in both DER [shown as .cer] and PEM formats.)
Given a DER format certificate file named cert.der the following command will produce a text description of it:
openssl x509 -inform der -in cert.der -noout -text
Given a PEM format certificate file named cert.pem the following command will produce a text description of it:
openssl x509 -inform pem -in cert.pem -noout -text
To check the signature algorithm of a certificate file, simply generate the text description and look for “Signature Algorithm:” in the output.
A “Signature Algorithm:” value of “sha1WithRSAEncryption” is required to use the xar signing instructions included in this document.
Apple’s Safari browser supports browser extensions starting with Safari version 5. These extensions are packaged as signed xar archives using gzip compression named with a .safariextz extension.
There has been a lot of interest in using the xar command line interface to sign .safariextz files.
It may be possible to do this provided the version of xar is 1.6.1 or later and the full certificate chain (including the root certificate) is embedded using the --cert-loc options. The full certificate chain may be extracted from a .safariextz file that has already been signed using Safari’s Extension Builder with the intended signing key (see here). It may also be helpful to create the XAR archive using the --distribution option or possibly the --prop-exclude ea option although this is probably not strictly necessary.
Remember that only a single name.safariextension directory should be added to a .safariextz archive (the name part doesn’t matter, only the .safariextension suffix) and it must be at the top level of the archive.
Please note that Safari seems to be hard-coded to require all extensions to be signed by a certificate whose certificate chain leads up to an Apple root certificate. A normal code signing certificate simply will not produce loadable extensions. Furthermore, Safari Extension Signing certificates must have additional options set as described in Apple’s Certification Practice Statement. So don’t even think about trying it without a real Apple-issued Safari extension signing certificate.
You may be able to obtain one of these signing certificates for free from here.
Note that as of OS X 10.8 (and 10.7.5), the phrase “identified developers” seems to be a euphemism for signed by an Apple-issued certificate that’s part of a certificate chain that leads to an Apple root certificate so these signed extensions would appear to qualify.
Visit the xar project page (source code etc.) at http://mackyle.github.io/xar.