Signing nested app bundles
November 21, 2011

During a recent submission I came across a problem.

I got an automatically generated email back from Apple with this sort of thing in it:

Invalid Signature - the nested app bundle ECFoundation 
(Ambientweet.app/Contents/Frameworks/ECFoundation.framework)
is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. 
Refer to the Code Signing and Application Sandboxing Guide for more information.

It’s a bit annoying that the email is capable of spotting that I have one of three possible problems, but not narrowing the actual cause down for me. It’s also a bit annoying that this only runs when you’ve submitted, and not when you verify an application with Xcode.

Be that as it may… … the main point is that it looks like Apple are starting to require that all code inside your application bundle is signed. This includes any frameworks or plugins you’ve embedded, even if you didn’t actually build them.

I’m slightly mystified as to why Xcode doesn’t do this for you at the point when you submit - since it asks you for an indentity to use, and presumably does some re-signing with it at this point.

However, as luck would have it, it’s fairly easy to write a script to do what we need.

for f in "${CODESIGNING_FOLDER_PATH}/Contents/PlugIns/"*
do
    BUNDLEID=`/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$f/Contents/Info.plist"`
    codesign -f -i ${BUNDLEID} -vv -s "${CODE_SIGN_IDENTITY}" "$f"
done
 
for f in "${CODESIGNING_FOLDER_PATH}/Contents/Frameworks/"*
do
    BUNDLEID=`/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$f/Resources/Info.plist"`
    codesign -f -i ${BUNDLEID} -vv -s "${CODE_SIGN_IDENTITY}" "$f"
done

This script goes through the build app’s PlugIns and Frameworks folders and signs everything it finds. It uses the application bundle id from each framework/plugin when signing. From one reading of the signing instructions, it sounded like everything bundled in with your app has to have the same bundle id, so this might not be quite the right approach - the script might need to take the bundle id from the app, sets the bundle id of each embedded framework to it, and then signs the framework.

However, apps submitted after building with this script don’t seem to generate the warnings, so for now this one seems to do the job.

I’m running the script with a final Run Script build phase in the target for my main application. This means that the bundles and plugins inside the app will always get signed, whatever configuration I choose.

Alternatively, you could probably run it as a post-action script in the Archive part of your build scheme, so that the extra signing only gets done when you’re about to submit. Actually I think that’s probably more in line with Apple’s advice, which seems to be not to sign things until you’re actually submitting them, so as not to give legitimacy to development builds which accidentally escape into the wild. However, I’m not certain that all the environment variables that I’m using will be set at that point, so it may be that the script would need modifying. I’ll leave that bit as an exercise for the reader…