Code Signing

| No Comments

I recently went through the process of making our applications signed which is something that’s new to┬áLeopard.

I just wanted to mention a few things that I came across and aren’t necessarily in Apple’s documentation.

Signing Frameworks

When you sign frameworks, you have to sign a specific version. So, let’s say your framework is called CSMail, you’d sign CSMail.framework/Versions/A. If you try and just sign the top level folder it will silently fail, as will CSMail.framework/Versions/Current (see “Symbolic Links” below).

Symbolic Links

Any symbolic links will be silently ignored and this extends to the path you give to the codesign command line utility. I think there’s actually a problem with symbolic links: you can add them to a Resources folder and it won’t invalidate the signature (whereas you cannot add normal files). I’ve reported this to Apple (rdar://problem/6050445).


Everything in the Resources is signed according to resource rules. You can see what the default rules are by signing something and having a look at the end of the generated CodeResources file. Here’s a bit from the default rules:


It should be clear that this means that all the .lproj folders in the Resources folder are optional which allows you to strip out unneeded localised files.

You can use your own rules if you need to; the resource rules file that you pass in to codesign is the same as the CodeResources file but with just the rules key. We needed to omit a particular file that might get installed in the Resources folder by an old version of our application when upgrading to a newer version. Using custom rules isn’t officially supported by Apple but I cannot imagine it will be broken for a while (as it would affect many Apple applications). Nevertheless, there’s no point using them unless you need to.

Helper Tools

Since helper tools should be separately signed, they shouldn’t be placed in the Resources folder, they should go in the MacOS folder if they’re simple tools or the Contents folder if they’re bundles.

When you sign helper tools (that aren’t bundles), you’re supposed to add an Info.plist to the executable although I’m not sure why you have to do it since you can specify an identifier as a parameter to codesign. Apple’s documentation shows a way to add an Info.plist file using the linker but I wrote a script that creates an object file from an Info.plist file. The advantage of doing this is that you can configure Xcode to run the script and it will properly track the dependencies whereas if you just add it as a parameter to the link command, modifying the Info.plist file will not cause things to be rebuilt. The script has the added benefit of expanding macros in the Info.plist file which we use to substitute things like the current project version.

The other issue we have is that we use the same helper tools for different variants of our main application. For example, we have iDefrag, iDefrag Lite, the demo version and a specific version for one of our customers. Each of those variants has a different bundle ID and we want to use that same bundle ID for the helper tools. Rather than have four different targets for each helper tool (we have 4 different helper tools so we’d end up with 16 different targets), I wrote a simple tool that updates the bundle ID within an embedded Info.plist file (source is here). One thing to watch out for is that it cannot increase the size of the embedded Info.plist file; you must make sure that the bundle ID only decreases in length. Also, it only works for 32 bit architectures since we have no need for 64 bit architectures at the moment.

I hope this helps someone.

Leave a comment