Mac OS X Application Code Signing
Developer — 11 Feb 2008 11:29 — 1453 days ago

This article is about digitally signing executable code and converting the required public/private key and X.509 certificate material between different formats using the OpenSSL toolkit. It adds to the information in my earlier article “Converting Microsoft .pvk Private Keys to Java Keystore”. If this kind of stuff makes your eyes glaze over, you might want to skip this one :-)

Benefits of Signing Applications on Mac OS X

The latest version 10.5 (Leopard) of Mac OS X adds the ability to digitally sign executable code. I wanted to do that with one of our Mac OS X applications, the image uploader for our snapmania Online Photo Manager.

Right now, the main user-visible benefit of signed applications is that accessing objects in the user’s Keychain no longer triggers this confirmation dialog after a new version of the application is installed:

Mac OS X Keychain access confirmation dialog after application update

I recently added Sparkle-based auto-updating to this application and the update user experience is now really smooth except for this Keychain dialog. Getting rid of it by digitally signing the application promises even less mental friction for the user.

Preparing the Certificate

The Apple developer tool used to sign an application is the codesign command line utility (check out its man page for details). In order to sign an application with it, you need a code signing certificate from a certificate authority trusted by the system. As noted in my earlier article, we already have such a certificate in the format used by Microsoft’s tools. Our provider in this case is the Thawte Code Signing CA and they are in Mac OS X’s list of trusted CAs.

codesign expects the certificate and associated private key in your keychain. The way to get them in there is by packaging them up in a PKCS#12 container file which Keychain can import. I’ll use the Swiss Army Knife of cryptography, the openssl command line tool, to do the conversion.

I had already converted the private key from Microsoft’s .pvk format into openssl RSA PEM format for the Java conversion the last time around. Let’s take a look:

$ openssl rsa -text < futurelab-codesign.privkey.rsa.pem 
Enter pass phrase:
Private-Key: (2048 bit)
... fancy prime number ...

I didn’t have to convert the certificate for Java the last time because the Java tools can import Microsoft .spc (Software Publisher Certificate) files directly. It turns out that .spc files are PKCS#7 containers, so I can take a look at it with openssl’s pkcs7 command:

$ openssl pkcs7 -inform der -text -print_certs < futurelab-codesign.spc

I am checking out two things, namely if the certificate is still within its validity period and if the X.509 extensions for code signing are present:

Subject: C=CH, ST=ZH, L=Winterthur, O=futureLAB AG, OU=ENGINEERING, CN=futureLAB AG
Issuer: C=ZA, O=Thawte Consulting (Pty) Ltd., CN=Thawte Code Signing CA

Validity
    Not Before: Nov 14 00:00:00 2007 GMT
    Not After : Nov 25 23:59:59 2008 GMT

...

X509v3 extensions:
    X509v3 Extended Key Usage: 
        Code Signing, Microsoft Commercial Code Signing

    Netscape Cert Type: 
        Object Signing

In our case there are several certificates in the .spc file because it’s a “certificate chain” which includes the certificates of the intermediate subjects in the trust hierarchy. The one whose Subject: refers to our orgainzation is the actual code signing certificate we are going to use.

Now that I know that the certificate is valid, I can convert the entire certificate chain to a text file with a series of X.509 PEM format certificates:

openssl pkcs7 -inform der -print_certs \
< futurelab-codesigning.spc \
> futurelab-codesigning.cert.pem

With the private key and certificate data converted I can merge them into the PKCS#12 container:

openssl pkcs12 -export -inkey futurelab-codesign.privkey.rsa.pem \
-in futurelab-codesign.cert.pem  \
-out futurelab-codesign.p12

Enter pass phrase for futurelab-codesign.privkey.rsa.pem:
Enter Export Password:
Verifying - Enter Export Password:

The “pass phrase” is what protects the contents of the RSA key input file, enter what you used when you created that file. The “Export Password” is something which you can choose freely here, it protects the private key in the PKCS#12 container.

Double-clicking the resulting .p12 file opens it in Keychain which will prompt for the export password used in the previous step. The imported certificate should look like this:

Imported Code Signing Certificate in Apple Keychain

And again, it should have the code sign extension flags set:

Code Signing Certificate x509 extension flags in Apple Keychain

Signing the Application

Signing the application with codesign is straightforward:

$ codesign -s 'futureLAB AG' Uploader.app

Verifying the signature:

$ codesign --verbose -v Uploader.app
Uploader.app: valid on disk

I automated this in Xcode with an additional “Run Script” build phase that uses the variables $TARGET_BUILD_DIR and $WRAPPER_NAME:

codesign run script phase in Xcode

The “Transition Notes” in Apple’s “Leopard Code Signing Release Notes” explain that the first update to a signed application version will trigger the Keychain dialog one last time:

Existing keychain items that allow access to a prior (unsigned) version of your application or tool will trigger a confirmation dialog when the system first encounters an updated signed version of your code. Upon user consent, the ACL is then rewritten to add access to your application gated by its code signature. No further dialogs should appear for that item afterwards, ever (unless you stop signing your updates). New items created by or for a signed application automatically have this benefit.

Resources


Powered By blojsom