iOS Code Signing & Provisioning

First we create a CSR

While creating CSR, the public/private key pair is generated under the hood.

The public key is attached to your CSR

The private key is kept inside your local machine.

It’s not a good idea to generating CSR from multiple macOS as they key pair generated on one mac cannot be present on other mac. Good to use one mac to generate CSR until we create the certificate in P12 format.

To generate a CSR from the command line run:

openssl genrsa -out mykey.key 2048
openssl req -new -key mykey.key -out CertificateSigningRequest.certSigningRequest -subj "/emailAddress=yourAddress@example.com, CN=Your Name Dev Key, C=GB"

This will create CertificateSigningRequest.certSigningRequest

To see some basic info of what’s in the certificate run this

openssl asn1parse -i -in CertificateSigningRequest.certSigningRequest

or for a textual representation

openssl req -text -noout -in CertificateSigningRequest.certSigningRequest

Second we create a Certificate

Upload your CSR to Apple download the .cer file, this is your certificate

Basically, the certificate has all the data that we have provided during creating certificate signing request, Apple then adds some signer data like Authority, expiry date etc. The whole certificate has the signature attached to it.

you can see certificate details with this command:

openssl x509 -in ios_development.cer -inform DER -text -noout

we also need private key attached to the certificate to code signing the apps. This is where we need the certificate in the P12 format to back it up with the private key

PKCS#12

In Cryptography, PKCS#12 a.k.a Public Key Cryptography Standard is the standard used to store private keys with public key certificates protected with the password.

In our case in the iOS Development certificate, we can export the certificate from keychain into the Personal Information Exchange a.k.a p12 format

or from the command line using:

openssl x509 -in XXXXX.cer -inform DER -out mycert.pem -outform PEM
openssl pkcs12 -export -inkey my.key -in mycert.pem -out mycert.p12

You can find details about the p12 using

openssl pkcs12 -info -in mycert.p12

Provisioning Profiles

Provisioning profiles are a combination of multiple things:

App ID

Creation Date

Platform

Developer Certificates

Entitlements

Expiration Date

Provisioning Profile Name

Provisioned Devices

*Team Identifier *

*Team Name *

Version

Team ID

The Team ID is a unique identifier for a team. It can be found under the Apple Developer Portal under the Membership tab. It should be kept secret.

You can also find your team ID in the form of “iPhone Developer: Team Name (YOUR_TEAM_ID)” by running this:

security find-identity -v -p codesigning

Bundle Identifier

This is unique identifier for your app in reverse domain notation (EX: com.domain.appname). This needs to be set up in iTunes Connect and included in the app plist file.

App Identifier

The App ID is a combination of your Team ID and your Bundle Identifier. It identifies one or more apps.

Lets say your Team ID is *A1B2C3D4E5 *and your Bundle ID is *com.domainname.appname *then your App ID would be:

A1B2C3D4E5.com.domainname.appname

You can also use an asterisk to identify multiple apps like so:

A1B2C3D4E5.com.domainname.*

Device ID

Your Device ID is your device’s UDID, which is a 40 character combination of letters and numbers.

You can find your Device’s UDID by following this guide:

https://www.macworld.co.uk/how-to/iphone/how-find-out-your-iphone-or-ipad-udid-3530239/

or you can type this to get the UDID of all connected devices:

instruments -s devices

Entitlements and Sandbox

Entitlements specify what system resources the app can use. They can be defined in the capabilities section. The will be stored in a plist file with extension .entitlements

Check here for an in depth discussion:

https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AboutEntitlements.html

You can check an apps entitlements by running this command

codesign -d --entitlements :- /Users/shashi/Library/Developer/Xcode/DerivedData/iOSCodeSigning-gakpslthucwluoakkipsycrwhnze/Build/Products/Debug-iphones/iOSCodeSigning.app

To check the entitlements of a .ipa file

* Change the extension to zip
* Expand the zip file which will produce a Payload folder with a .app file
* Use the codesign tool

codesign -d --entitlements :- "Payload/YourApp.app"

For an in depth discussion of the App Sandbox check here:

https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html#//apple_ref/doc/uid/TP40011183

Provisioning Profiles Creation

After we create the profile on the Apple Developer Portal, download and install it. We should be able to find it here:

~/Library/MobileDevices/Provisioning Profiles

Provisioning Profiles have a .mobileprovision extension. They are stored using Cryptographic Message Syntax. To view them we can do this:

cd ~/Library/MobileDevice/Provisioning\ Profiles/
security cms -D -i xxxxxxxx_your_pp_id.mobileprovision

Code Signing

For the Apple documentation look here:

https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005929-CH1-SW1

To code sign an app from the command line we can do this:

codesign -s "iPhone Developer: Shalom Friss (MY_TEAMID)" ~/Library/Developer/Xcode/DerivedData/iOSCodeSigning-gakpslthucwluoakkipsycrwhnze/Build/Products/Debug-iphonesimulator/iOSCodeSigning.app/

There are three main stages to code signing

Seal

Digital Signature

Code Requirement

Seal

Codesign generates a seal by hashing every part of the code. A verifier then goes through the code and double checks the hashes. The hashes look like this:

<key>Frameworks/libswiftos.dylib</key>
<dict>
    <key>hash</key>
    <data>
    dyKltMCMbq+pYDVJBtY78y7BuP0=
    </data>
    <key>hash2</key>
    <data>
    6DxNIVZgqWfOeWfedGQ1+wOnIuA7vQlU+gVA0WhCiRw=
    </data>
</dict>

This is great as long as the hashes aren’t altered. To make sure they are not, codesign uses a digital signature.

Digital Signature

To create the digital signature, codesign encrypts the hashes using the user’s private key, which are stored in the app along with the signer’s certificate. We can verify the signature on the command line using:

codesign -v --verbose=5 ~/Library/Developer/Xcode/DerivedData/iOSCodeSigning-gakpslthucwluoakkipsycrwhnze/Build/Products/Debug-iphonesimulator/iOSCodeSigning.app/

Any change in the code will invalidate the hash. The signature of the code is stored in the app binary, while the signatures of frameworks, bundles, tools and other code are stored in the bundle in CodeSignature/CodeResources

Code Requirements

Code requirements are rules used to ealuate the code. The complete language details can be found here.

https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html#//apple_ref/doc/uid/TP40005929-CH5-SW1****

For example, you could require that any plugins only come from Apple.

Code requirements can be specified to be part of the code signature, which are called internal requirements.

Details

To print out the details of the code signing run this:

codesign -d --verbose iOSCodeSigning.app/

NOTES

* Archives created with xcodebuild are signed with a development certificate at first

* When we specify the distribution method, the archive is re-signed with the distribution certificate

This means if you are using automatic signing on Continuous Integration servers then you must have development as well as distribution certificate on CI server.

Apple’s guide to manual signing

https://help.apple.com/xcode/mac/current/#/dev1bf96f17e****

Re-Signing an App

1.) Find the .ips file

2.) Unzip and remove the code signature:

unzip -q old.ipa
rm -rf Payload/*.app/_CodeSignature

3.) Replace the old provisioning profile with the new one

cp new_provisining_profile.mobileprovision Payload/*.app/embedded.mobileprovision

4.) Generate entitlements using the old entitlements

cd Payload/
codesign -d --entitlements - *.app > entitlements.plist
cd ..
mv Payload/entitlements.plist entitlements.plist

5.) Force sign the app with the new entitlements and certificate

/usr/bin/codesign -f -s "Your_certificate_in Keychain" '--entitlements' 'entitlements.plist'  Payload/*.app

6.) Zip the .ipa

zip -qr resigned.ipa Payload

References

https://medium.com/xcblog/ios-code-signing-tutorial-series-814b22eba507

https://help.apple.com/deployment/ios/#/apda0e3426d7