Any developer who has worked on apps for Apple’s Mac or iOS platforms has undoubtedly run up against confounding issues with code signing. Some issue may be rooted in the behavior of the codesign tool itself, while others have to do with Xcode’s valiant but sometimes confounding attempt to mask all the complexity of code signing in its build settings. On top of that, there are myriad ways in which one can introduce subtle abnormalities over time, by allowing certificates and private keys to outstay their welcome in one’s keychain, or by neglecting to transfer them to another machine which will now be used for development.
When code signing works, it just works. And when it doesn’t? I hope you didn’t have anything planned for the rest of the week.
One vexing issue arises when Apple’s “timestamp service” is not available for whatever reason. Perhaps you’re hacking on an airplane without internet access, or as is commonly the case, Apple’s servers are taking an unplanned siesta. I’m sure you’ll recognize the problem by the tell-tale error that appears in Xcode, just before you would otherwise expect a build to succeed:
% codesign MyApp.app MyApp.app: The timestamp service is not available.
The purpose of the timestamp server is to provide authenticated timestamps to the codesign tool, so that it can embed along with its code signature a future-proof confirmation of the date the code was signed. What purpose could this serve? For example, if a piece of software was found to have a critical bug that compromised the security of users, but was fixed as of January 1, 2014, Apple and other consumers of the code could consider the timestamp of that vendor’s code while evaluating how much to trust it. In practice, I don’t think code signature timestamps are being put to much use on Mac OS X, but I can see the reasoning for them and they seem like a pretty good idea. I don’t mind supporting them as long as it isn’t too much of a hassle. (Update: See the comment below from Václav SlavÁk about the more fundamental purpose of timestamps tying a code signature’s date to the era of the certificate that was used to sign it).
In the event that the timestamp server cannot be reached for whatever reason, codesign simply fails. This is probably a good idea, because if it’s important for signed code to also contain a timestamp, you wouldn’t want to accidentally ship a major release of your app without it. But because the timestamp server can be unavailable for a variety of reasons, some of them common, we need some simple solution for continuing with the the day-to-day building of our apps without ever being bothered by the pesky timestamp service issue.
Lucky for us, such a solution exists in the form of a codesign command-line flag: “–timestamp”. Ordinarily this flag is used to specify the URL of a timestamp server, if you choose to use one other than the Apple default. But a special value none indicates that timestamping of the signed code should be disabled altogether. Let’s see, when could we care less about the timestamping of code? For example, when we’re on an airplane or iterating on debugging builds in Xcode, in the privacy of our own offices and homes.
In short, save yourself a lot of headaches by configuring your projects such that code signing does not consult the timestamp server unless you are building a release build. You can add the option directly to the “Other Code-Signing Flags” section of your build settings, configured to only affect Debug builds. In my case, I employ a variety of cascading Xcode configuration files, upon which all of my projects and targets are based. By changing the value in the configuration file, I’m assured that all my apps will be helped with one fell swoop. This comes straight out of my “RS-Project-Debug.xcconfig” file:
// For Debug builds, we don't require timestamping because // Apple's server may be down or we may be off-network OTHER_CODE_SIGN_FLAGS = --timestamp=none
Now any build configuration that inherits the configuration will default to not consulting the timestamp server. My Debug build configurations inherit this setting, my Release builds do not. There is always the small chance that a Release build will be caught up by a misbehaving Apple timestamp server, but whenever I’m hacking on an airplane or iterating on debug builds in my office, code signing occurs without any risk of being stopped by this pesky error.