Before I got my first job as an iOS Developer I did not know much about code signing and provisioning profiles. As a member of Apple’s free developer program I mostly used the simulator and occasionally ran my app on my device. Whenever I would run into problems I would rely on Xcode to fix them for me. But after a while I quickly found out that it usually is better to solve the problem yourself instead of relying on Xcode. To gain a better understanding of what I was actually doing I did some research on code signing and provisioning profiles and I wrote it down as a reference to myself and everyone else who is interested in it.
What is code signing?
Code signing is the process of digitally signing executables to confirm the software author and to guarantee that the code has not been altered or corrupted since it was signed. In iOS all code needs to be signed with a certificate that is issued by Apple. This makes Apple the only one who can decide if your app is allowed to run on a device or not. The only exception to this is when a device is jailbroken.
In short this is how it works:
- You register as a developer with the Apple WorldWide Developer Program.
- Apple verifies your identity and then issues a certificate with which we can sign our apps and submit them for distribution to the App Store.
- When your app is finished your app will be reviewed by Apple. During this process Apple checks if your app performs as expected and adheres to their guidelines.
- When your app passes the review process Apple re-signs the app with their security certificate which means it can run on any iOS device and is ready to be published in the App Store.
What is a provisioning profile?
As you can imagine Apple needed to come up with a way to manage all of the above. This is where provisioning profiles come into play. A provisioning profile is a collection of different components that the operating system needs to decide if an app should be allowed to run on a particular device or not. A provisioning profile allows us to test and debug our apps on our devices and distribute our app to beta testers or the app store. Provisioning profiles contain a lot of metadata and its four most important components are:
- The App ID
- A signing certificate issued by Apple
- List of devices (UDID) that the app is allowed to run on
- Special entitlements the app is allowed to use like (e.g. push notifications or health kit)
1. App ID
iOS identifies our applications through the App Bundle ID. It is very important that the App Bundle ID always matches the App ID in the provisioning profile. The App bundle ID has a couple of restrictions:
- Reverse DNS Format e.g. com.companyName.appName
- Can only contain alpha-numeric characters, hyphens (-) or periods (.)
- Special characters (like $, !, @, etc) are not allowed
Before I will talk about certificates, I will briefly touch on a subject called public-key cryptography which plays an important role in code signing. As a self-taught developer this was quite a new subject for me, but if you already know what this is then feel free to skip this part.
Public key cryptography, or asymmetric cryptography is a cryptography system that uses a pair of keys. That is a public key paired with a private key which is only known to the owner. With the public key you can authenticate that a message originated with a holder of the paired private key, or you can encrypt a message with the public key to ensure that the holder of the paired private key can decrypt it.
For example when you send a message over HTTP you can digitally sign this request to authenticate that the message was send by you, and has not been changed along the way. You do this by sending the message + the message encrypted by the private key. When the receiver receives the message he or she hashes the message with the public key and then compares it with the hash from the encrypted message. If they are the same then he or she knows for sure that the message comes from you and has not been changed by someone in the middle.
As I said earlier certificates play an important role in public key cryptography. They are issued by a certificate authority which is a trusted entity that issues digital certificates that verify a digital entity’s identity on the internet. They contain a lot of metadata like the owner’s name, the expiration date etc. iOS maintains a list of trusted CA root certificates to verify that a CA has issued and signed. Apple signs its developer certificates with a root certificate issued by the Apple WorldWide Developer Relations CA.
With a distribution certificate Apple uniquely identifies you as a developer or publisher of an app. The private key is used to sign the application. There are two types of signing certificates. First we have the developer certificate which allows for constant redeployment to our test device and debugging in Xcode. Production certificates are used for production builds (App Store) or QA builds that get distributed through e.g. Testflight. It is through this certificate that Apple identifies you as an App Store publisher or test distributor. Therefore it can only be used with a provisioning profile for production.
After the app is compiled it is signed with the private key of your distribution certificate. The private key must match the public key of the certificate in the provisioning profile. This tells Apple that you are the one who compiled the app, and not someone pretending to be you. Of course if the pair is invalid the app wont be installed and executed.
UDID, short for Unique Device Identifier, uniquely identifies an app on your device. Don’t confuse this with UUID which stands for Universally Unique Identifier and identifies an app on a device. A provisioning profile contains a list of UDID’s of the devices on which the app is allowed to run. Whenever an App is signed with Apple’s security certificate it can be published in the app store and installed on any device.
Because iOS applications are sand-boxed they can not directly interact with system services. Entitlements are permissions or capabilities for when an app needs to interact with system services like push notifications. They specify what to allow and what to deny your application. It is important that the entitlements in your app always match those in your provisioning profile.
I hope that you enjoyed this article and now understand enough about provisioning profiles to work with them and fix any issues that occur while using them. Because even though they can be very frustrating to work with, they are very important for keeping the iOS platform secure.