I had joined Directi in the mobile app development team, iOS being one of the platforms. And all the Apple code signing stuff has been my responsibility. We had launched an internal release of the mobile web app about a couple of months ago ( I want to say more on that, but this is not the time for that, so may be later) , and that was the first time I had to deal with this stuff. It wasn't all that simple, I must say. It still isn't. When we made another internal launch last week, I was still confused with the process and could not get it to work for the forst few tries. So my mentor had suggested, and I agreed, that I should make a documentation of the steps involved, so that we don't get (so much) confused next time. And here is all that I understood after much reading and experimenting with it. It may still not be complete, but I will keep updating as I gain more understanding, and with your support.
Foreword
This article is not meant to be a walkthrough on how to code sign your app in xcode. The best source for that is the iOS Development Portal's "How To" tab for every section. But even after following those steps precisely, if you are getting some errors, and are pulling your hairs off trying to figure out what you have missed out, then this article may come in handy. It will help you understand what exactly you are doing while code-signing, and it may help you troubleshoot if you get stuck somewhere.
This article assumes that you have purchased the iOS Developer Program, and know your way around the iOS Provisioning Portal (the term 'portal' will be used to refer to it throughout the article).
The following topics are listed in the order they appear in the portal. I have included some gotchas as well. Note that each topic is not independent, but they all are parts of one big plan.
Apple WWDR certificate
It is an intermediate certificate. That is, it is a trusted certificate and is used to issue all the certificates that you request from the apple. You should have this certificate in your keychain.
Although I removed it afterwords and the code signing still works, but I guess you need it at least the first time. Or I may land in trouble some day and I will make a point here then. :P
Developer Certificate
It is required to authorize a developer as an iOS app developer. Anyone can develop an iOS app and test it on a simulator, but if you plan to distribute using the Apple App Store, or even test it on a real device, you must have a valid developer certificate to sign the app.
Apple uses RSA scheme for code signing an iOS app. You sign an app using your private key, the public key for which is authorized by Apple. It confirms that you are an Apple-authorized developer and you can put your apps in your registered devices or submit to Apple App Store.
To request a developer certificate, you generate a Certificate Signing Request (CSR). This will also generate a public/private key pair. The private key resides on your machine, while the public key is uploaded with CSR for approval. Once the admin approves your request, you can download the certificate, that will contain the public key, and install it in your keychain. This certificate is what lets you sign the app with the corresponding private key.
You may have more than one developer in your team, each having a personal machine for development. Every developer must have his own developer certificate. Although, this is only required if they want to test the app on a device, since a device demands a signed app for installation.
More specifically, not every developer, but every machine requires a certificate for code signing. That is, to sign an app with a developer certificate, it must be requested from that particular machine. The xcode actually looks for a matching private key for that certificate in your keychain. So even if the certificate was not requested by you, but you happen to have the needed private key, you can still sign the app.
To have the private key doesn't necessarily mean that you have to request a certificate. The "Keychain Access" app in Mac allows you to export/import private keys easily. This also means that you can work with only one certificate shared among different machines. I like to have separate certificates though. You can see how to export a private key to other machines in the portal in Certificate->How To->Saving your Private Key and Transferring to other Systems.
Device IDs
If you want to use a device for development or testing, it must be registered in apple developer portal. A device is registered using its unique device ID (UDID). You can add upto 100 devices per developer program.
Only adding devices to the program doesn't enable you to run any app on that device. You need to associate devices with developer certificates (developers who can install an app on this device) and app IDs (the apps that are allowed to be installed). This is done through provisioning profiles. More on these coming up.
Application ID
You also have an option of naming the bundle identifier as a wild card (*) which can be used with any app your need to test on devices. I would recommend avoiding it though, as it may lead to some confusion. Do this only if you know what you are doing.
Distribution Certificate
Only team agents have the authority over distribution of the app. So only through that account, can you request and generate distribution certificate and distribution profiles.
A distribution certificate is requested the same way as any developer certificate. Note that there can only be one distribution certificate for a developer program. You can distribute multiple apps using that one certificate though. This is achieved using the multiple distribution profiles you create for every app that you want to launch.
Another point worth noting here is that since a certificate request is made from a machine, the distribution certificate will contain the public key whose private key resides on that particular machine. So even if you login with agent's account and are able to download the distribution certificate, you won't be able to sign the app since it can't find a "valid signing identity" in your keychain, unless you have already exported that key to this machine. But if you haven't, you can still fix this right there by revoking that distribution certificate and requesting a new one from that machine (you are the team agent, remember?). And you must now also reconfigure the distribution provisioning profiles and download them again to actually go ahead with the signing process, though.
Provisioning Profiles
A Development Provisioning Profile is what associates developers with the apps that they are developing, and the devices that they can use to test those apps. It is just a collection of developer certificates, device IDs and exactly one App ID. Team admins and agents have rights to create/modify/delete the development provisioning profiles.
A Distribution Provisioning Profile is required for Apple App Store distribution and also for ad-hoc distribution for testing. It contains one distribution certificate associated with your program, a profile name that you can specify, and exactly one App ID. When creating a ad-hoc profile, you can also select the devices that you are going to test the app on. The app, when signed using this profile, can only be installed on those devices. Only team agents have rights over the distribution profiles.
Now, when you download a profile to your machine, all the associated certificates also get added to your keychain. You can check that under "Certificates" category in the keychain app. But unless there is at least one certificate with the corresponding private key in your keychain, you wont be able to sign the app.
To sign an app, you need to have a provisioning profile having the same bundle identifier (or wild card). The profile must also have a valid developer certificate, as mentioned above, and also the device ID on which it needs to be tested.
Every certificate and profile has an expiry date. After that date, the app signed with this certificate will not run on the device. Also, if you modify the certificate/profile on the portal, that will not affect older certificates and they will continue to work as if nothing happened. You can even have multiple profiles in the organizer with the same name (they have different identifiers), and choose any one while signing the app.
I have also observed that if there is a profile installed on the device that associates itself with an app ID, then you may sign the app with a profile that does not contain the concerned device ID, and the app will still run on it. If you then remove the old profile, the same signing profile will not work anymore. So watch out for this gotcha. It may let you believe that you have signed the app correctly, while it doesn't work on some of the devices where it should. To avoid any confusions, you may choose to separately install the correct profile on device using "iPhone Configuration Utility" app, in addition to signing the app with a profile.
Entitlements.plist
This is not listed in the portal, but it had me confused big time. So I thought I should include it as well.
You will need this file when you are distributing your app with the ad-hoc distribution profile for testing. Why exactly do you need this file? I will just quote the answer of KennyTM on a question at stackoverflow.
Entitlements is actually a security measure of iPhoneOS. Quoted from the iPhone Development Guide:
Entitlements. These files define properties that provide your application access to iPhone OS features (such as push notifications) and secure data (such as the user’s keychain).
Publicly, the only entitlement key you could use is get-task-allow, which eventually enables the ptrace() function to be used for the app, thus enabling debugging.
But there are a lot of entitlements used privately, e.g.
- task_for_pid-allow, to allow controlling other processes (via the task_for_pid() function)
- run-unsigned-code, to allow running code from this app without signature.
The plist will be attached to and signed alongside the binary of the app — unlike Info.plist which is not signed. If the chain of trust is not broken, this acts as an entitlement of rights to some (dangerous) actions.
- com.apple.springboard.launchapplications, com.apple.springboard.wipedevice, etc.
There is one little gotcha with entitlements signing. When you write the file name in Code Signing Entities, be sure to write it only for the ad-hoc build target. I had written it as universal for all the build targets, and this gave me a 'entitlements' error when I tried to debug the app on my device.
Ad Hoc Distribution
There is one last thing I want to add. Why do we need ad-hoc distribution at all when we can distribute the app to the testers using the development profile only? This is what my mentor asked me. And I had no answer. But I found a satisfying answer here.
There's one situation in which you need an Ad Hoc profile, and that's when you want to test Push Notifications.
If you test Push Notifications on a Development Provisioning Profile, your push notifications need to be sent using the Development Push Notification Certificate for your SSL connections to Apple's sandbox APNS server.
If you want to test Push Notifications using your Production Push Notification Certificate and the live APNS servers, you'll have to deploy your app to a device using a Distribution Certificate and Ad Hoc Provisioning Profile (which includes doing the Entitlement.plist retardedness which you can ordinarily skip if you were only using Developer Provisioning Profiles).
Also note that when you deploy using an Ad Hoc profile, your device token will be different from the one you use when you're using the development profile. Also this the recommended way to test APN because there's no back end changes that need to be made between the Ad Hoc build and the final live deployment on the AppStore.
Thats all, folks. At least for now. I will keep this update if anything new comes up.
PS: After I had drafted my code, I searched for 'Understanding iOS Code Signing' on Google to check if someone else has written about it. And I found this nice blog post by Adam Eberbach. Wish I had found this a little earlier. It could save a lot of my hairs :D.
Nice to see you that you are back to blogging ! :)
ReplyDelete