My goal is to perform something similar to How to get access to iOS Developer Certificate from code: verify that my library is not used in a re-packaged IPA. The answer there suggests to parse the embedded.mobileprovision
file to see information about the certificates and provisioning profile.
In the embedded.mobileprovision
file, I can find a long embedded plist, and the XML I see there has two relevant fields:
<?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>AppIDName</key>
…
<key>application-identifier</key>
<string>ABCDEFGHIJ.com.example.ObjCExample</string>
…
<key>UUID</key>
<string>00000000-0000-0000-0000-000000000000</string>
…
<key>Version</key>
<integer>1</integer>
</dict>
</plist>
(for obvious reasons I replaced the true DEVELOPMENT_TEAM ID with ABCDEFGHIJ
and the UUID with zeros).
There is also a list array of long <data>
entries under the key DeveloperCertificates
, but I have no idea how I can use this data. For example, I don't know if I can consistently choose one of these certificates. But I don't see the signing certificate ID in this file, and also I don't have a reliable procedure to parse the embedded.mobileprovision
file.
Still, this may be enough for my purposes, but I have another, more robust approach. I can parse the mach_header
of my binary, following the example by Dave DeLong and based on an earlier answer by Cédric Luthi. The format of LC_CODE_SIGNATURE
seems to be better documented than that of the embedded.mobileprovision
file.
Specifically, the EMBEDDED_ENTITLEMENTS
blob (magic 0xfade7171
) contains a short plain-text plist:
<?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>application-identifier</key>
<string>ABCDEFGHIJ.com.example.ObjCExample</string>
<key>com.apple.developer.team-identifier</key>
<string>ABCDEFGHIJ</string>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>ABCDEFGHIJ.com.example.ObjCExample</string>
</array>
</dict>
</plist>
So far so good, but I am not sure how the same XML will look for an app that comes from the AppStore. For example, there is the new EMBEDDED_ENTITLEMENTS_DER
blob (0xfade7172
) which seems to hole the same plist, but in binary format (is there an example that shows how this should be parsed?).
Also, I see the signing certificate ID Apple Development: alexcohn@mycompany.com (KLMNOPQRST)
in REQUIREMENTS
blob (magic 0xfade0c01
), and by following the flow of a go package, I can find this ID in my executable programmatically.
Which certificate ID will be more reliable for my purposes?
The requirements are simple:
- this ID should change when the app is resigned, even if it is not resigned for the App Store.
- this ID should be present in both debug builds and release builds (these may be different IDs).
- this ID should be stable, i.e. it should not change when the developer rebuilds the app, or switches the build machine, or new devices are added to the adHoc provisioning profile.
- this ID should be easy to find (like the signing certificate is visible in the keychain app).