If you are doing iOS development, you might ask yourself why did Apple make the whole process of signing an app putting it on the app store so bloody complicated and confusing?
You might know all the right steps you have to do to make everything work, but you have no idea what you are doing. That was me some weeks ago. For me in order to understand how something works, it helps to know why it has to be like this.
But before we get into the whys let us look at what it is and isn’t.
At first I thought a provisioning profile was for signing your applications so that iOS would know it was safe to run. Turns out I got it exactly opposite of what it is.
What it is
A provisioning profile is NOT for signing applications. It is a plist (xml format) which is installed on your iOS device. During development applications are signed with the private key in Code Signing Identity (specified in target build settings. Remember from previous post that code signing identity is a private public key pair). When the iOS kernel encounters a signed app, it checks with the installed provisioning profiles whether:
- Has the app been signed with a private key, which has a corresponding certificate (public key) in one of the provisioning profiles?
- Is the ID of the app in the provisiong profile?
- Are we on a device listed in the provisoning profile containing said certificate and app id?
If all of these criteria are fullfilled we can run the application.
Provisioning profiles can be used to run apps in different ways:
- Run on device thru xCode (iOS Team Provisioning Profile)
- Ad Hoc distribution
- App Store
- Enterprise build for In-House distribution
The provisioning profile is a PKCS#7 signed plist, signed by Apple. Apple works as the Certificate Authority (CA). Look at my previous post on cryptography if Certificate Authoritydoesn’t make sense to you. A plist is a dictionary in XML form. Under the key
DeveloperCertificates the developer certificate is stored in base64 encoding.
<key>DeveloperCertificates</key> <array> <data> MIIFeTCCBGGgAwIBA... </data> </array>
Copy data into a file with ending
.pem like this:
-----BEGIN CERTIFICATE----- MIIFeTCCBGGgAwIBA... -----END CERTIFICATE-----
To the developer certificate stored in a file on PEM format (Privacy Enhanched Email). Inspect content of certificate with:
$ openssl x509 -text -in mycertificate.pem
iOS use this certificate to verify that code has been signed by an appropriate developer. If the application has not been signed with a private key associated with one of the certificates under
DeveloperCertificates in the provisioning profile then the app can not run. And just to repeat from earlier: The private key and certificate together makes a so called Code Signing Identity.
Why do we need a provisiong profile?
So back to our original question. Can’t we just sign the apps? Why go through these extra hoops with the provisiong profile?
The reason is that Apple does not want us to be able to distribute the signed apps to any device. That would allow us to circumvent the appstore and Apple’s verification that the app is safe for anybody to use. So Apple wants us to restrict the number of devices we can place our apps on and which apps we can place there.
That is what the provisiong profile is for. We make updates to it through a web interface so Apple can sign it and we can download it. Because it is signed by Apple, iOS can trust it’s content.
How to find out which developers are included in a provisioning profile
Apple will list this on its developer portal. But you can also figure this out yourself.
Typically a team provisioning profile contains a list of certificates for every developer.
In this example we have extracted the XML part from the provisioning profile and stored in a file named
xpath will not work, because it can not deal with the binary data prefix in the provisioning profile.
#!/bin/sh for (( i = 1; i <= 16; i++ )); do rm cert.pem echo -----BEGIN CERTIFICATE----- > cert.pem xpath teamprovisioning.plist plist/dict/array/data[$i] | tail -n 34 | head -n 33 >> cert.pem echo -----END CERTIFICATE----- >> cert.pem openssl x509 -text -in cert.pem | ack Subject done
Where in xCode are provisioning profiles configured?
Follow these steps to find which provisioning profile a given target is using.
- Select blue icon representing your project in project navigator (folder icon on left most side).
- Select your target from the leftmost dropdown menu in view of your selected project icon.
- Click Build Settings tab.
- Scroll down to the Code Signing header
- Here you can see both Code Signing Identify andProvisioning Profile
Your code signing identity will have to have its corresponding certificate in the selected provisioning profile. Remember code signing identity is both public and private key while the certificate stored in the provisioning profileonly contains the public key.
Getting info about how an app has been signed
Apple Root CA, has signed Apple Worldwide Developer Relations Certification Authority which has signed certificateiPhone Distribution: REAKTOR AS, which has been used to actually sign the executable.
This is valid because the certificate signing chain is no longer than three links.
$ codesign -dvvv Systemspill.app Executable=/Users/erikengheim/Library/Developer/Xcode/DerivedData/Systemspill-cadtzgsdfjkesuaazsbldkfdgbua/Build/Products/Debug-iphoneos/Systemspill.app/Systemspill Identifier=no.knowit.systemspill Format=bundle with Mach-O universal (armv7 (12:11)) CodeDirectory v=20100 size=8950 flags=0x0(none) hashes=439+5 location=embedded Hash type=sha1 size=20 CDHash=2ee0c12f668b02980e95eb2232944569cd8669bb Signature size=4299 Authority=iPhone Distribution: REAKTOR AS Authority=Apple Worldwide Developer Relations Certification Authority Authority=Apple Root CA Signed Time=18. sep. 2013 10:46:08 Info.plist entries=31 Sealed Resources rules=3 files=391 Internal requirements count=1 size=172
This is how the app might look when signed locally. When placed on the appstore the certificate used to sign the executable will be from Apple. So the 3 Authority lines will look like this:
Authority=Apple iPhone OS Application Signing Authority=Apple iPhone Certification Authority Authority=Apple Root CA
I verified this by copying the
.ipa package for dragonbox, changed suffix to
.zip and unpacked it. Then I ran:
codesign -dvvv DragonBox+\ 1.1.1/Payload/DragonBoxPlus.app/DragonBoxPlus