This document describes how to debug code signing entitlement problems, with specific reference to the entitlements used by the Network Extension framework.
The document was written for Xcode 7.0.
You may also want to review Technote 2415 Entitlements Troubleshooting, which is a more official take on the subject.
Check the Built Binary
The first step in debugging code signing entitlement problems is to check the actual entitlements of the binary. Xcode’s process for setting entitlements is quite complex, and it depends on various inputs, so it’s important to start by checking the output rather than looking at just the inputs.
To check the entitlements in your binary run the following command:
$ codesign -d --entitlements :- NetworkExtensionSample.app Executable=…/NetworkExtensionSample.app/NetworkExtensionSample <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" …> <plist version="1.0"> <dict> <key>application-identifier</key> <string>SKMME9E2Y8.com.example.apple-samplecode.NetworkExtensionSample</string> <key>com.apple.developer.networking.vpn.api</key> <array> <string>allow-vpn</string> </array> <key>com.apple.developer.team-identifier</key> <string>SKMME9E2Y8</string> <key>get-task-allow</key> <true/> </dict> </plist>
As you can see, this app is built with the
com.apple.developer.networking.vpn.api
set to an array of one item,
allow-vpn
.
IMPORTANT This example is for a program to test the Personal VPN feature that we introduced with the original Network Extension framework in iOS 8. The values will be different for an app using the new provider support that we added in iOS 9. Specifically:
For a provider you’d expect to see the following entitlements:
<key>com.apple.developer.networking.networkextension</key> <array> <string>packet-tunnel-provider</string> <string>app-proxy-provider</string> <string>content-filter-provider</string> </array> The array may be limited to some subset of the values shown.
For a hotspot helper you’d expect to see the following:
<key>com.apple.developer.networking.HotspotHelper</key> <true/>
Remember that, if your app has multiple executables, the main app and an extension say, you’ll have to check the entitlements on each one. Specifically, if you’re using the
com.apple.developer.networking.networkextension
entitlement it must have the same value in both your app and your extension.
Finding the Inputs
If your entitlements are wrong you have to start looking at the inputs to Xcode’s code signing entitlement machinery:
Start by looking at the build log for your executable (in Xcode, choose View > Navigators > Show Report Navigator, then select the appropriate build entry).
- Search the log for each code signing step (“Sign ***”).
- Expand that step and you’ll see an entry like this:
… Signing Identity: "iPhone Developer: Quinn Quinn (7XFU7D52S4)" Provisioning Profile: "iOSTeam Provisioning Profile: com.example.apple-samplecode.NetworkExtensionSample" (8d04addd-d7f5-4872-bd48-f6885bb67433) /usr/bin/codesign --force --sign 4735C927CF325B8BAF6E44E5EA9DE1860220A4E2 --entitlements …/NetworkExtensionSample.app.xcent …/NetworkExtensionSample.app
Note two things in this entry:
the UUID of the provisioning profile (
in this example)8d04addd-d7f5-4872-bd48-f6885bb67433
the path to the
file.xcent
These are the critical inputs to the code signing entitlement machinery and you’ll need to look at each in turn.
Exploring the Profile
Given the provisioning profile’s UUID, it’s relatively easy to find the profile: just look for it in
~/Library/MobileDevice/Provisioning Profiles/
.
$ ls -l ~/Library/MobileDevice/Provisioning\ Profiles/8d04addd-d7f5-4872-bd48-f6885bb67433.mobileprovision -rw-r--r--+ 1 quinn staff 10720 14 May 13:22 /Users/quinn/Library/MobileDevice/Provisioning Profiles/8d04addd-d7f5-4872-bd48-f6885bb67433.mobileprovision
You can use the following command to dump it:
$ security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/8d04addd-d7f5-4872-bd48-f6885bb67433.mobileprovision <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" …> <plist version="1.0"> <dict> … <key>DeveloperCertificates</key> <array> … </array> <key>Entitlements</key> <dict> <key>keychain-access-groups</key> <array> <string>SKMME9E2Y8.*</string> </array> <key>get-task-allow</key> <true/> <key>application-identifier</key> <string>SKMME9E2Y8.com.example.apple-samplecode.NetworkExtensionSample</string> <key>com.apple.developer.team-identifier</key> <string>SKMME9E2Y8</string> <key>com.apple.developer.networking.vpn.api</key> <array> <string>allow-vpn</string> </array> </dict> … <key>ProvisionedDevices</key> <array> … </array> … <key>UUID</key> <string>8d04addd-d7f5-4872-bd48-f6885bb67433</string> … </dict> </plist>
There are two things to check here:
Check that the value of the
property is the UUID you’re looking for.UUID
Check that the value of the
property makes sense.Entitlements
IMPORTANT You can think of these entitlements here as a ‘whitelist’. That is, your app is allowed to use any entitlements listed here. The values are not necessarily the exact values that will show up in the binary. For example, your final app might have lots of different entries in the
keychain-access-groups
array. Those final values also depend on the
.xcent
file.
If the entitlements in the provisioning profile are wrong, you'll have to fix that in the Certificates, Identifiers & Profiles section of the developer web site.
Exploring the Entitlements File
The
.xcent
file shown above is built from your
.entitlements
file. You should check the values in the
.xcent
file are what you expect. For example:
$ cat …/NetworkExtensionSample.app.xcent <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" …> <plist version="1.0"> <dict> <key>application-identifier</key> <string>SKMME9E2Y8.com.example.apple-samplecode.NetworkExtensionSample</string> <key>com.apple.developer.networking.vpn.api</key> <array> <string>allow-vpn</string> </array> <key>com.apple.developer.team-identifier</key> <string>SKMME9E2Y8</string> <key>get-task-allow</key> <true/> </dict> </plist>
If they’re wrong there are two potential sources of problems:
the input
file may be incorrect.entitlements
Xcode might have failed to build the
file correctly.xcent
You can check that
.entitlements
file by looking at the build log again. Look for a “Process product packaging” build step immediately above the “Sign ***” step. Expand it and you’ll see something like this:
ProcessProductPackaging … … builtin-productPackagingUtility \ …/NetworkExtensionSample.entitlements \ -entitlements -format xml \ -o …/NetworkExtensionSample.app.xcent
The second path is the path to the built
.xcent
file. The first path is the path to the
.entitlements
file that’s used to build that
.xcent
file. You should check that the path to the
.entitlements
file is correct and that the contents of that file make sense.
$ cat …/NetworkExtensionSample.entitlements <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" …> <plist version="1.0"> <dict> <key>com.apple.developer.networking.vpn.api</key> <array> <string>allow-vpn</string> </array> </dict> </plist>
If so, you can check the
.xcent
file that was built from it:
$ cat …/NetworkExtensionSample.app.xcent <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" …> <plist version="1.0"> <dict> <key>application-identifier</key> <string>SKMME9E2Y8.com.example.apple-samplecode.NetworkExtensionSample</string> <key>com.apple.developer.networking.vpn.api</key> <array> <string>allow-vpn</string> </array> <key>com.apple.developer.team-identifier</key> <string>SKMME9E2Y8</string> <key>get-task-allow</key> <true/> </dict> </plist>
If the
.entitlements
file is correct but the
.xcent
file is wrong, you can usually fix this by doing a clean build of your project.
Version History
16 Jul 2015 — First version.
16 Jul 2015 — Clarified that the
entitlement needs to be the same in both your app and your extension.com.apple.developer.networking.networkextension
16 Oct 2015 — Edited for DevForums.
Share and Enjoy
—
Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"