Heads up... You're reading this book for free, with parts of this chapter shown beyond this point astext.
Ah, code signing: an iOS developer’s nemesis. Code signing is hardly at the top of every iOS developer’s agenda, but a strong knowledge of how code signing works can be extremely useful for solving problems, as well as establishing yourself as a lichpin in your development team. There’s nothing more “ask-for-a-raise-worthy” than a developer who can re-sign an outdated Swift 2.2 iOS app, instead of having to fix the potentially thousands of Swift compiler errors when time is against you.
This chapter will give you a basic overview of how code signing works by having you pick apart the open-source iOS Wordpress v10.9 application found here:
You’ll explore the stages of the app’s code signature before being sent to the iTunes Connect Store. In addition, you’ll re-sign the Wordpress app so it can run on your very own iOS device!
In order to complete everything in this chapter, you’ll need a number of items. First, you’ll need a proper iOS Apple Developer account to generate Provisioning Profiles. You’ll also need a physical iOS device to install the
Wordpress iOS application.
You’ll also need to grab and install my mobdevim command, available here:
This small command line tool does a number of things, including installing applications onto the device, querying device information and grabbing console logs when connected to an iOS device. Using this tool makes it significantly easier to install an iOS app on your device and hunt for errors if the app has been incorrectly signed. You can install iOS apps in Xcode through the Devices and Simulators window, but the Xcode authors really make it a painful to do this.
Follow the instructions on the
mobdevsim repo to install the tool. Once you have
mobdevim setup, plug in your iOS device via cable and give it a test run.
This will query the device info. Provided it worked, you’ll get something similar to:
Connected to: "LOLz" (c3a8533d6dc4fa74d6748a2cd935f00e1e949af1) name LOLz UDID c3a8533d6dc4fa74d6748a2cd935f00e1e949af1 State Activated Type iPhone Version 12.0.0 Number (555) 867-5309 Region LL/A Battery 65% ... truncated ...
You can get a full list of the available commands by executing
After installing this command, and making sure you have a valid way to sign your iOS applications with a developer account, you’ll be all set up for the rest of this chapter!
To really appreciate how code signing works, you need to understand three key components: public/private keys, entitlements, and provisioning profiles. You’ll start with a breadth-first look, then dive into a depth-first look at each.
This is probably the hardest thing to understand when learning about the code signing process, since public/private keys introduce cryptography, which quickly becomes a rabbit hole of knowledge, formats, formatting, and gotchas.
security find-identity -p codesigning -v
1) 2DFE888B7BD07710444C2E4A7B9847BA8B55C220 "iPhone Developer: Derek Selander (8AW8QLCX5U)"
security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p
security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p > /tmp/public_cert.cer
-----BEGIN CERTIFICATE----- MIIFnDCCBISgAwIBAgIIFMKm2AG4HekwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 ...
openssl x509 -in /tmp/public_cert.cer -inform PEM -text -noout
Embedded in (almost) every compiled application is a set of entitlements: again, this is an XML string embedded in the application saying what an app can and can’t do. Other programs will check for permissions (or lack thereof) in the entitlements and grant or deny a request accordingly. Think of the capabilities section found in Xcode.
codesign -d --entitlements :- /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
Finally, the provisioning profiles are up for discussion. A provisioning profile includes the public x509 certificate, the list of approved devices, as well as the entitlements all embedded into one file.
ls ~/Library/MobileDevice/Provisioning\ Profiles/
PP_FILE=$(ls ~/Library/MobileDevice/Provisioning\ Profiles/*mobileprovision | head -1) security cms -D -i "$PP_FILE"
Exploring the WordPress app
Just like your typical debugging workflow on your iOS device, before an app is sent up to the Apple iTunes Connect mothership, you must compile an app with a provisioning profile. This provisioning profile is included in every pre-App Store
.app under the name embedded.mobileprovision. It’s this provisioning profile that tells iOS the application is valid and came from you.
The provisioning profile
Find the embedded.mobileprovision provisioning profile inside of the WordPress application and use the security command on it.
security cms -D -i "$WORDPRESS/embedded.mobileprovision"
echo "$CERT_DATA" | base64 -D > /tmp/wordpress_cert.cer
openssl x509 -in /tmp/wordpress_cert.cer -inform DER -text -noout
Certificate: Data: Version: 3 (0x2) Serial Number: 786948871528664923 (0xaebcdd447dc4f5b) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority Validity Not Before: Jan 17 13:26:41 2018 GMT Not After : Jan 17 13:26:41 2019 GMT Subject: UID=PZYM8XX95Q, CN=iPhone Distribution: Automattic, Inc. (PZYM8XX95Q), OU=PZYM8XX95Q, O=Automattic, Inc., C=US ... truncated ...
Provided an application contains extensions (i.e. share extension, today widgets, or others), there will be even more signed packaged bundles found in the ./Plugins directory that contain their own application identifier and embedded.mobileprovision provisioning profile.
The _CodeSignature directory
Included in a real iOS application bundle (but not in the Simulator) is a folder named _CodeSignature that includes a single file named CodeResources. This is an XML plist file which is a checksum of every non-executable file found in this directory.
cat "$WORDPRESS/_CodeSignature/CodeResources" | head -10
openssl sha1 -binary "$WORDPRESS/AboutViewController.nib" | base64
Resigning the WordPress app
Time for some codesigning fun!
(Optional) Generate a valid provisioning profile
If you don’t have a provisioning profile that met the above requirements (UDID, not expired), you’ll need to head on over to https://developer.apple.com/ and create a new one.
security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p > /tmp/public_cert.PEM
openssl x509 -in /tmp/public_cert.PEM -inform pem -noout -text | grep OU=
Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority Subject: UID=V969KV7V2B, CN=iPhone Developer: Derek Selander (8AW8QLCX5U), OU=H4U46V6494, O=Derek Selander, C=US
Copying the provisioning profile
At this point, you should have a valid provisioning profile, which you’ll use to resign the WordPress application either by creating a new provisioning profile or by using an existing provisioning profile. Assign the PP_PATH Terminal variable to the fullpath of the provisioning profile you expect to use for this experiment.
cp "$PP_PATH" "$WORDPRESS/embedded.mobileprovision"
Deleting the plugins
The WordPress application has several extension applications embedded into the main app found in the
./Plugins directory. Each of these contains a unique provisioning profile with a unique application identifier. You could sign each of these extensions itself with a unique provisioning profile, but that will get way too complicated for this demo.
Modifying the Info.plist
I hope you’ve remembered the name of the App ID of the provisioning profile! You’ll need to plug that into the Info.plist’s key CFBundleIdentifier If you don’t remember it, you can query it from the provisioning profile.
security cms -D -i "$PP_PATH" | grep application-identifier -A1
plutil -replace CFBundleIdentifier -string H4U46V6494.com.selander.code-signing "$WORDPRESS/Info.plist"
plutil -replace CFBundleDisplayName -string "Woot" "$WORDPRESS/Info.plist"
Extracting the entitlements
You’re almost there!
codesign -d --entitlements :/tmp/ent.xml "$WORDPRESS/WordPress"
security cms -D -i "$PP_PATH" > /tmp/scratch
xpath /tmp/scratch '//*[text() = "Entitlements"]/following-sibling::dict' | pbcopy
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>keychain-access-groups</key> <array> <string>H4U46V6494.*</string> </array> <key>get-task-allow</key> <true /> <key>application-identifier</key> <string>H4U46V6494.com.selander.code-signing</string> <key>com.apple.developer.team-identifier</key> <string>H4U46V6494</string> </dict> </plist>
Finally, signing the WordPress app
You now have performed all the setup. You have a valid signing identity; you have a valid provisioning profile embedded in the WordPress application at
embedded.mobileprovision; you have removed the
Plugins directory; and you have the entitlements of the new provisioning profile found at /tmp/ent.xml.
codesign -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"/Frameworks/*
codesign --entitlements /tmp/ent.xml -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"
mobdevim -i "$WORDPRESS"
Did it succeed?
Provided you have followed the steps exactly, you’ll see a new app with the WordPress logo with the name “Woot” underneath it!
mobdevim -d $WORDPRESS
(lldb) run -AppleLanguages "(es)"
Did it fail?
If the output says “success”, then you’re good to go. If not, open a new Terminal window and execute the following:
mobdevim -c | grep installd
Where to go from here?
This chapter has only scratched the surface of code signing. There is a lot more great content out there that focuses on other components to code signing.