Chapters

Hide chapters

Advanced Apple Debugging & Reverse Engineering

Third Edition · iOS 12 · Swift 4.2 · Xcode 10

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

Section III: Low Level

Section 3: 7 chapters
Show chapters Hide chapters

Section IV: Custom LLDB Commands

Section 4: 8 chapters
Show chapters Hide chapters

20. Code Signing
Written by Derek Selander

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

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!

Setting up

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.

mobdevim -f

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 mobdevim -h.

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!

Terminology

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.

Public/private keys

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
cat /tmp/public_cert.cer 
-----BEGIN CERTIFICATE-----
MIIFnDCCBISgAwIBAgIIFMKm2AG4HekwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...
openssl x509 -in /tmp/public_cert.cer -inform PEM -text -noout

Entitlements

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

Provisioning profiles

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.

~/Library/MobileDevice/Provisioning Profiles/
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.

WORDPRESS="/full/path/to/WordPress.app/"

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"
CERT_DATA=MIIFozCCBIu...
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 ...

Embedded executables

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.

PP_PATH=~/Downloads/Code_Signing_Example_ProvisProfile_92618.mobileprovision
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
<key>application-identifier</key>
<string>H4U46V6494.com.selander.code-signing</string>
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"
cat /tmp/ent.xml
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.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now