iOS Code Signing: Under The Hood

Ray Wenderlich

This is a guest post by Adam Eberbach, a mod on the forums and a full-time iOS developer in Melbourne, Australia for Intunity, a local consultancy.

Learn all about how Code Signing works!

Learn all about how Code Signing works!

Many beginner iOS developers cringe when they think about bundle identifiers, provisioning profiles, App IDs, or certificate signing requests. It’s a lot of new and confusing terminology coming all at once, and it’s easy to make a mistake during the process and be unsure where to turn.

That’s where this article comes in! Here we will demystify the various terms related to iOS code signing and explain step by step how everything fits together. When you’re through reading this article, you should have a much better understanding on how things work, and be ready to apply the knowledge when building apps to run on devices.

This article assumes that you are a member the iOS Developer Program and have a basic familiarity with Xcode and iOS development. If you are completely new to iOS development, you might want to check out some of the other tutorials on this site first.

Allright, so let’s dig into iOS code signing and see how it works!

Why Should I Care?

The main reason you should care about how code signing works is that you need to use it to run apps on real devices, whether it be your own, those of clients, or for customers on the App Store!

If you don’t use code signing, you will only be able to run your code on a simulator or a jailbroken device – and if you want to reach a wide audience, that’s simply not enough.

And just as important, to properly test your code you really need a physical device. The simulator does an excellent job for an initial level of testing, but there are three main reasons you need to test on an actual device before you ship:

  • A physical device is usually slower
  • A physical device has far less memory
  • There are some APIs that work only on a physical device

Let’s go through each of these in detail.

A physical device is usually slower

The simulator uses the full power of your Mac processor, while a physical device has far less capability. As such, it’s important to run on an actual device to make sure that your app will perform the way you want it to.

For example, make a new View-based application in Xcode, and put the following code in your view controller’s viewDidLoad:

int count = 200000;
NSMutableArray * array = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count; ++i) {
    [array addObject:[NSString stringWithFormat:@"%d", i]];
}

If you run this on your simulator, the app will start up within a second or two, but if you try running this on your device it will take considerably longer (around 7 seconds on an iPhone 3GS). If you were testing only on the simulator, you might not realize the performance problem.

A physical device has far less memory

Similarly, the simulator uses all of the memory available on your Mac, while the memory available for your app is quite limited on physical devices.

This is especially important for games (so listen up Cocos2D fans!), which usually include a large number of images, and hence are quite memory intensive. On older devices, there’s an upper limit of 24MB of textures that can be loaded at a time, which would be just enough to fit 3 1024×1024 8-bit textures, so it’s quite easy to exhaust!

Update: As Stuart from the forums points out, newer devices have a unified memory architecture, which gives you a lot more storage for textures. For more details check out his full comment!

Exhausting memory is something you don’t want to happen in iOS apps, because if you use up too much memory the OS will shut down your app, which appears to users as if your app crashed.

So when you’re testing memory load and usage, you really need to use a physical device, as you’re won’t see as many issues on the simulator.

There are some APIs that work only on a physical device

The final reason why you need to test on an actual device is that sometimes you just have to!

For example, most of the In-App Purchase API works only on a physical device, and you can’t use some Instruments, like Core Animation, on the simulator because it requires hardware.

In summation, it is absolutely true to say that you haven’t really tested until you have tested on the device!

Why Shouldn’t I Care?

Sometimes you might wish you could just ignore all of this, because it can be complicated. And sometimes you can, because later versions of Xcode are making it easier to handle all of this for you behind the scenes, by choosing options such as “use this device for development.”

If you haven’t seen this already, open the XCode 4 organizer, select devices and then right-click on “Developer Profile” you get this menu. It will take you to instructions on how to do most of what this article discusses automatically.

Automatic provisioning with Xcode 4

True – you can sign into your developer account and automatically provision apps to run on your device. Now if this worked perfectly every time this article would not have been necessary, but equipped with the knowledge of what might have gone wrong when or if it does, you’re set. And as a developer you want to know how things work anyway.

On almost every project I know a client is going to want a build on their device. I get the UDIDs up front, I make sure I can provision for that device with a bare project template and at the end of every sprint I aim to be able to build and pass on that build without wasting a day on working out which bit of the provisioning process I got wrong. It’s a lot easier to get all your ducks in a row when a clean build only takes seconds.

So the answer – there’s no good reason why you shouldn’t have a basic understanding of how things work. Read on.

Public and Private Keys, Oh My!

Before we continue with the explanation of how things work, let’s briefly explain public and private keys.

There are two different types of cryptography: symmetric cryptography, and asymmetric cryptography.

With symmetric cryptography, there’s only one key. So if you have a secret key and encrypt a message with it, only a person who knows the secret key can decrypt it.

In asymmetric cryptography, there are two keys – a public key (which can be known by everyone) and a private key (which is kept secret to you).

One of the nice things about asymmetric cryptography is that you can use to prove a message came from you. If you encrypt something with your secret private key and someone can decrypt the message with your public key to get something that makes sense, they know that you, being the only person who knows the private key, created the message.

In other words, it is “signed”. And this is the basic technique behind code signing apps in iOS!

This is all you really need to know about code signing to understand how things work at a high level for the rest of this article. But if you’re curious to learn more, Wikipedia and RSA Labs have articles that explain this concept in much more detail. And if you really get interested in how it works read Bruce Schneier.

Code Signing Objects

There are a lot of objects related to Code Signing – Provisioning Profiles, App IDs, UDIDs, and more. In this section we’ll go through what each of these mean, one by one.

I’ve also put together a diagram using the Core Data model editor to help show the relationships between the objects, shown below. Refer back to this as we go through each object, so you can understand how they all fit together. This diagram is for development profiles – for Distribution it is very slightly different, and that will be covered in a future article.

Objects related to Code Signing

Without further ado, let’s discuss these in more detail, starting with a more about private keys!

Private Key

In Mac OS X keys are managed through an app called Keychain Access found in Applications\Utilities. Go ahead and run it now – you might see a private key and a public key with your name attached similar to the following:

Keychain Access showing public/private keys

Notice that the private key shows certificates that it has been used to sign – in this case the developer certificate.

If you don’t have any keys listed here yet don’t worry, Keychain Access will create one for you the first time you request a certificate (which we’ll talk about later).

The keys that are listed here (or that will be listed here soon) are the foundation of all your provisioning and code signing abilities. Without them, you can’t sign your code or release your apps to the App Store!

If you lose them you have to start the whole process again – your certificates will not work any more, your provisioning profiles will generate only errors, you will waste a lot of time – so keep them safe.

So if you haven’t already, export these now by going to File\Export Items, and saving them to a safe place. I suggest using a small thumb drive that you can put in a safe place and use for nothing else. You also might consider syncing to Mobile Me if you have an account.

Have Multiple Keys?

If you have created accounts on several Macs without knowing about this key pair then you likely have several. This can be a problem because the certificate you generate on one machine will not be usable for code signing on a machine that does not have that private key. Forgetting this is a great way to waste hours and get angry…

You could propagate all your keys to all your machines but I prefer to maintain just one. I like to have just one key pair for everything and I have been able to delete extra keys, in fact all keys, with no bad effect – the worst thing that happened to me was I had to sign in to a couple of websites again.

If you choose to keep just one pair of keys you should name them so your one true key is easier to track – by default they are all named the same. To rename you have to double-click them in Keychain Access, type a new name and close the dialog.

UDID

A UDID is a unique identifier for each physical device. So your iPhone is guaranteed to have a different UDID than your iPad, for example. It is usually displayed as a 40-character hexadecimal string.

When you want to get code on a device through means other that the app store or enterprise distribution (wait for part 2 of this article series) this is the way you identify each device that your code is signed to run on. So if you want to install an app you make on a device, you need to know that device’s UDID!

But how can you find a device’s UDID? There are several ways.

First, when a device is connected to your PC you can find the UDID in the Xcode Organizer window as shown below:

How to see your device's UDID in XCode Organizer

Second, you can see the UIDID in iTunes clicking the serial number displayed in the Summary screen – useful to know when you have someone who wants your app on their device but does not have Xcode.

How to find a device's UDID in iTunes

Third and finally, I’ve found the easiest method to get a client or customer to send you their UDID is to have them download an app called Ad Hoc Helper on the App Store.

Ad Hoc Helper is a simple app that on startup begins an email that includes the device’s UDID, and the client or customer can send the email to you so you have it – with no typos!

Certificates

The certificate, whether your personal developer certificate or the grandly-named “Apple Worldwide Developer Relations Certification Authority Certificate”, are bundles of data that represent trust. They are the guarantee that you, the named developer, built this code, that you are a member of the developer program, and that Apple have issued you with a certificate to do so.

To get a certificate, you need to generate a Certificate Signing Request with Keychain Access and send it to Apple. As mentioned earlier, this will create a public/private key for you if you don’t have one already. Apple will then verify the information, and create a certificate for you.

App ID

When you create a project in Xcode 4, you are asked for a Product Name and Company Identifier. For the product name, you usually give a shortened version of your app (such as myapp), and for the company identifier you usually give a unique string for your company (reverse DNS notation works well, such as com.mycompanyname).

These combine to form the Bundle Identifier, found in the “-Info.plist” file in your project, as you can see below:

Finding the Bundle Identifier in your Info.plist

An App ID is simply this same Bundle identifier here, along with a prefix of random characters. It looks something like “ESCSR39CF9.com.AwesomeAppCo.Alabasteroids” forming a unique identifier for your application.

(I’m not actually writing a masonry-based space shooter right now so feel free to steal the name.)

For every app you release, you need to register your App ID in the iTunes Developer Center as shown in the screenshot below, and it needs to match what you have set in your Info.plist.

Provisioning Profile

When put together all these objects combine so that:

  • this unique app (App ID)
  • can run on this restricted set of devices (UDIDs)
  • with trust based on the signing by a developer (Certificate).

And the combination of these three pieces of info is called a provisioning profile!

A provisioning profile accompanies the device either by being copied into Xcode or iTunes and from there onto the device, or by being part of a “.ipa” archive containing both app and profile.

You can make a Provisioning Profile in the iOS Provisioning Portal, as shown in the screenshot below:

Creating a Provisioning Profile in the iOS Provisioning Portal

When setting one up, you have to do the following:

  • You need to give the profile a name, which is the name you will see in the Xcode Organizer, Build Settings and other places.
  • You need to select all the certificates that will be able to build using this provisioning profile – if working in a team there is no harm in selecting everyone.
  • You need to select the App ID, which needs to match what is set up in your Info.plist.
  • Finally, you need to specify which UDIDs this profile applies to. Generally I select all the devices for which I have UDIDs, I have sometimes wished I had more UDIDs in a profile but never less.

Signing for personal use

So you have an app you’re ready to test, you are signed up for the Apple iOS member program and you’re looking at the Provisioning Portal. Now you know the objects involved and how everything fits together, things get easy.

  1. Check your public/private key pair, name them for future peace of mind. (warning sign: more than one pair…)
  2. Create your developer certificate using Keychain Access to generate a certificate request. Download the certificate and double click to install. Verify that you see it in your keychain.
  3. Download the Apple Worldwide Developer Relations Certification Authority Certificate. Double click to install it, verify that you see it in your keychain.
  4. Check your project’s Bundle ID and go and create an App ID for your app through the Provisioning Portal. The Bundle ID must match.
  5. Get all the UDIDs for the devices you want to build for added to your devices list in the Provisioning Portal. These must match. Cut and paste of these 40-digit strings is highly recommended, too easy to make mistakes otherwise.
  6. Create a Provisioning Profile specifying the certificates, the app ID and the UDIDs you want this profile to support.
  7. Download, then drag the profile into Xcode’s Organizer window, under the Library section for Provisioning Profiles.

That’s it!

You should now be able to choose to sign projects and run them on your device. In the Target’s (not the Project’s!) Build Settings, scroll down to the Code Signing section. Start with the Debug scheme for now. It is easier, especially if working in a team, to select “iPhone Developer” in the Automatic Profile Selector and see your certificate selected automatically. That way your “best” current certificate is selected – if someone on your team checks out the project5 their profile will be selected for them. It’s the same idea as the new “Latest iOS” setting when selecting Base SDK, one less trivial thing to update.

When you have done this you should see Xcode show something like the picture. Xcode has correctly identified the Provisioning Profile based on the App ID and certificate. If you connect your device to the Mac now, select the device and Debug build in the build selection pulldown and build, Xcode will install the provisioning profile and start to run your app on the device.

Congratulations – there’s nothing much harder about iOS programming than getting through this step. Every other aspect of provisioning builds on this result, and you are now equipped to test the way apps must be tested, and you will soon be able to build and submit to the store.

Where To Go From Here?

For more information on iOS code signing, check out the great documentation available on the iOS Provisioning Portal.

Also, stay tuned for the exciting conclusion to this two-part article series, where I’ll cover signing and provisioning for distribution, and using Archives in Xcode 4 to make the whole process easy. For certain values of “easy”.

If you have gotten stuck somewhere in the process of code signing, or have tips and tricks for other developers, feel free to join the forum discussion below!

This is a guest post by Adam Eberbach, a mod on the forums and a full-time iOS developer in Melbourne, Australia for Intunity, a local consultancy.

Ray Wenderlich

Ray is part of a great team - the raywenderlich.com team, a group of over 100 developers and editors from across the world. He and the rest of the team are passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

Other Items of Interest

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 19 total!

Swift Team

... 16 total!

iOS Team

... 32 total!

Android Team

... 17 total!

macOS Team

... 13 total!

Apple Game Frameworks Team

... 12 total!

Unity Team

... 10 total!

Articles Team

... 10 total!

Resident Authors Team

... 10 total!