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 an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is 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.

User Comments

26 Comments

[ 1 , 2 ]
  • Adam, this is the best article on this that I've found yet. I still don't understand it the way I would like to, but you've helped me more than anybody so far. I've been thinking about why I've had so much trouble getting comfortable with this material, and I think I've gotten a handle on it: for an article on this subject to work 100% for me, it needs to be organized not in terms of principles or steps that a developer needs to take (though, of course, it needs to contain those things), but in terms of what an iOS device does when it's running an app, why it does that, and what can go wrong (and what error message you see, if any, when that thing goes wrong). Then, for each piece of data that's involved in this, tracking it back to its source, explaining what tools and procedures are involved (and why it works that way instead of some other way that might be simpler). I'm going to try to put together this kind of explanation for my own reference. Email me if you'd like to see what (if anything) I come up with. And, of course, thank you. Stephen Malinowski (it's easy to track down my email address from my name)
    musanim
  • Thanks a lot!

    Code signing is one of the most intricate process in the way of iOS dev. This tutorial helps a lot to understand the jargon and the necessity of each step.

    I am actually waiting for the next episode of this tutorial on distribution, as I am struck with one of my finished app. In Xcode 4, archive validates successfully but after submission to store, status changes to 'Invalid Binary'.

    Really looking forward for the next in this series...
    satishmavuri
  • Thanks guys - yes I have to do the second part. But in brief - do experiment with Xcode's Archive build method. Basically it does everything for you. Once you have filled in all the information on iTunes Connect, Xcode will handle the submission and most of the time it just works. If it doesn't work chances are Xcode is incorrectly copying third party libraries or headers into the target and you can fix that in the "TARGETS" build settings, under build phases.
    aeberbach
  • Thanks for this well written clarification how this mysterious things work. Saved my day.
    jonasahlgren
  • Thank you for the tutorial. I'm new to iOS programming, but still.. I have a free app in the iTunes store. Yesterday I wrote a simple app for some friends which took half an hour to code, and then several hours of pain before it would install on their devices. I came away feeling that I still don't understand the various certificates, keys, etc. The tutorial here helped. Still.. I am having trouble connecting the conceptual framework of public/private keys, profiles, etc to the actual confusing xcode build settings and warnings/errors. So... here are some questions:

    In my keychain I have two private keys, one for development and one for distribution. Is this normal, acceptable, or something I should try to fix?

    In the places where I can select an identity for signing, it appears that I am selecting a profile to sign with, right? But signing must be using my private key, which can't be in the profile. Is the profile used at all for signing, like maybe added to the bundle before signing, or does it just tell which private key to use?

    Which target settings are related or affect the signing process? I think it's the following:
    Summary -> Identifier
    Info -> Bundle identifier
    Info -> Bundle name
    Build Settings -> Code Signing Identity -> why are there two settings i.e. Release and then below it "any iOS SDK" ???
    Build Settings -> Packaging -> does the name of the plist file have to match anything?

    And what about the plist file? Is it just "Bundle identifier" that is relevant?

    (Easy question) Where are ${PRODUCT_NAME} and ${TARGET_NAME} set?

    When archiving for beta testing, I get "warning: Application failed codesign verification. The signature was invalid, or it was not signed with an iPhone Distribution Certificate. (-19011)". However, if I continue and make the ipa file, my beta testers can install and run it. What can be happening? I spent multiple hours trying to "fix" this by selecting different signing options, making new profiles, etc.

    After archiving, in the organizer I click "Share" and then I have the option of signing the ipa (or not). What's going on here? Didn't I already sign in the archive step? What is the correct entry for this step?

    Help in understanding the install process:
    To install, my friends need to drag both the ipa and the profile into iTunes. Is iTunes just blocking improperly signed code from being installed, or is the ipa somehow encrypted and cannot be run without the profile (and correct UDID)? Assuming the former, how does iTunes tell? Here's my hypothesis: The profile must be signed by Apple, which can be checked using Apples public key. The profile must then contain my public key, and the list of UDIDs. So.. if the device is in the list of UDIDs, and iTunes verifies that the ipa was signed using the private key corresponding to the public key in the profile, then iTunes allows the app to be installed. (Or it's the device doing this checking). Is this roughly correct, or am I way off the mark?

    I appreciate any help. I just found this site and look forward to checking out the other tutorials.
    Kurt
    txkurt
  • Any idea when we might be seeing part 2?
    brucehobbs
  • brucehobbs wrote:Any idea when we might be seeing part 2?


    +1 for part 2 ...
    beezlebug
  • Very useful article. You shed some light on teamwork. One step further?

    A small team of trainee developers (team A) has developed and tested an app (using TestFlight etc) and are ready to submit to iTunes to appear alongside apps from an established developer (team B). I am registered as admin on both teams using my Apple ID. In the Apple documentation (iOS Developer Library, Developing for the App Store)
    http://developer.apple.com/library/ios/ ... tTeam.html there is a useful diagram (Figure 2-5 Overview of the iOS development provisioning process) that shows under Team Admin a "List of authorized signing certificates". Any ideas where this list can be found? And updated? In the portal or in someones Xcode?

    For team B there is one certificate listed in the Distribution tab and the related keys are remote with the established developer. If I make a request via KeyChain Assistant then there is no button at team B provisioning portal to upload the request. Is this an Apple problem or have I misunderstood the role of team members. Do we all share the one certificate and it's keys (that's not teamwork!) or can we create certificates for different apps? I don't want to mess with the other apps of team B.

    Maybe this is a question for Apple (I have already sent a query via support) but as I'm sure more developers work in networked teams I would much appreciate your experienced advice.

    Thanks in advance,

    Kit Miles
    kitm
  • Thank you for your article. I got struked at one place see if you can help me out....

    I am having following configuration.
    MacBook with OS X version 10.8.5
    XCode Version 5.0.2 (5A3005)

    Aim: Want to test iOS App with Instrument, for memory leak.

    Problem: After building and running the profiler, I select Memory Leak option from Instrument Template and click on Profile button.
    It gives following error message:
    Target failed to run : Permission to debug com.tcs.mobility.cep was denied. The app must be signed with a development identity (e.g. iOS Developer).
    Tejendra
  • Excellent breakdown from Apple to Human :)

    My question is, I want to verify that the UDID (via a provisioning profile) was properly provisioned in the IPA that I get from the Build Master. Our builds are done offshore, and I have to work with the client to install on his device. There were multiple "promises" that it was built correctly and failed. I cannot rely on what is in the portal since I cannot verify that the Build Master has generated, downloaded, installed and built it correctly. Our credibility is shot, so I don't want to try again without examining the IPA and finding the client's UDID. Is that possible? I have tried to dump the binary and search for the UDID as a binary pattern.
    mobibob
  • kylie.wilson76
[ 1 , 2 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Non-Gaming!

    Loading ... Loading ...

Last week's winner: How To Make a Tower Defense Game with Swift.

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in December: The Great CALayer Tour

Sign Up - December

Our Books

Our Team

Tutorial Team

  • Jean-Pierre Distler
  • Tony Dahbura

... 59 total!

Update Team

  • Zouhair Mahieddine

... 14 total!

Editorial Team

... 22 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

... 4 total!