IPA signing
Check an IPA’s Code Signature and Signing Certificate
Verify an IPA's code signature, identify who signed it, and compare the signed app with its embedded provisioning authorization.
Inspecting an IPA must answer three separate questions:
- Does the code signature cryptographically verify?
- Who—or which Apple Developer team—signed the app?
- Does the embedded provisioning authorization match the intended app, device, entitlements, and distribution workflow?
A green answer to one question does not automatically answer the other two. A valid signature can belong to the wrong team or accompany an incompatible profile. A profile can list the target device while the signed bundle is damaged. And signature validity does not establish that an unknown artifact is trustworthy.
Preserve provenance and checksum first
Before extraction, record where the IPA came from, who authorized inspection, its intended distribution method, filename, version/build if known, and a checksum:
shasum -a 256 ClientBuild.ipa
mkdir ClientBuild-unpacked
unzip -q ClientBuild.ipa -d ClientBuild-unpacked
APP_PATH=$(find ClientBuild-unpacked/Payload \
-maxdepth 1 -name '*.app' -print -quit)
Keep the original IPA unchanged. Extraction for inspection does not alter it; editing files inside the app and repackaging them invalidates the existing signature.
If provenance is unknown, preserve the file as untrusted evidence. Do not install it, re-sign it, or treat a successful codesign result as proof that the software is safe or authorized by the app owner.
Question 1: does the main app signature verify?
Display the signature and run a strict verification against the extracted main app:
codesign --display --verbose=4 "$APP_PATH" 2>&1
codesign --verify --strict --verbose=4 "$APP_PATH"
The display output can expose the code-signing identifier, signature format, authority chain, team identifier, and sealed-resource context. Verification checks whether the bundle currently satisfies its code-signing requirements on the inspection Mac.
A nonzero verification result is evidence of a signing or artifact-integrity problem. Preserve the complete output and checksum before changing anything. Possible causes include modified signed content, damaged packaging, an incomplete signing pass, or a nested-code inconsistency.
Local verification is necessary evidence, not a guarantee of successful installation on every iPhone. iOS still evaluates distribution method, profile authorization, entitlements, device eligibility, platform compatibility, and other device-side requirements.
Question 2: who signed the app?
Read the main bundle identity and signed entitlements alongside the verbose signature output:
plutil -extract CFBundleIdentifier raw \
-o - "$APP_PATH/Info.plist"
codesign --display --entitlements :- "$APP_PATH" \
> /tmp/app-entitlements.plist 2>/dev/null
plutil -p /tmp/app-entitlements.plist
Record:
- the app’s
CFBundleIdentifier; - the code-signing identifier;
Authorityentries or signing-certificate identity shown bycodesign;- the team identifier;
- the signed
application-identifierwhere present; and - the actual signed entitlement claims.
Do not infer ownership from a certificate common name alone. Compare team, application identifier, certificate identity, bundle identifier, and the app owner’s release records. A certificate can be cryptographically valid yet belong to a team that does not own the intended App ID.
Question 3: does the embedded profile authorize this app?
For an app with embedded.mobileprovision, decode the exact embedded profile:
security cms -D \
-i "$APP_PATH/embedded.mobileprovision" \
-o /tmp/client-profile.plist
plutil -extract Name raw -o - /tmp/client-profile.plist
plutil -extract UUID raw -o - /tmp/client-profile.plist
plutil -extract ExpirationDate raw -o - /tmp/client-profile.plist
plutil -extract TeamIdentifier xml1 -o - /tmp/client-profile.plist
plutil -extract Entitlements.application-identifier raw \
-o - /tmp/client-profile.plist
plutil -extract DeveloperCertificates xml1 \
-o /tmp/profile-certificates.plist \
/tmp/client-profile.plist
Apple describes DeveloperCertificates as the profile’s authorization for who may sign covered code. The app’s signing certificate must be represented in that authorization, and the signing machine needs the matching private key when producing a new artifact. The profile also constrains app identity, validity, device location where applicable, and entitlement claims.
Compare the app and profile as one authorization set:
- signed team versus profile team context;
CFBundleIdentifierand signed application identifier versus profile application identifier;- signing certificate versus
DeveloperCertificates; - app entitlements versus the profile’s allowed entitlements;
- current time versus
ExpirationDate; and - target UDID versus
ProvisionedDevicesfor device-bound Development or Ad Hoc profiles.
Inspect a Provisioning Profile Inside an IPA owns the field-by-field profile evidence workflow. Profile and Signing Certificate Mismatch owns exact certificate/profile disagreement. Bundle ID and Profile Mismatch owns identity and entitlement mismatch.
Inspect nested signed code explicitly
The main app can verify while a nested extension, framework, or app is inconsistent. Enumerate nested code instead of assuming the outer result proves every component:
find "$APP_PATH" -type d \
\( -name '*.appex' \
-o -name '*.framework' \
-o -name '*.app' \) -print
For each signed component, run a deliberate inspection:
codesign --display --verbose=4 "PATH_TO_COMPONENT" 2>&1
codesign --verify --strict --verbose=4 "PATH_TO_COMPONENT"
codesign --display --entitlements :- "PATH_TO_COMPONENT" 2>/dev/null
For each nested .appex or .app carrying its own provisioning profile, repeat the security cms and profile comparison. A framework normally participates in code signing but does not use an iOS device-list profile in the same way as an app extension.
Record each component’s bundle identifier, signing team, authority, entitlements, verification result, and profile context where present. A main-app success does not prove a notification extension, widget, App Clip, embedded framework, or nested app was signed and sealed correctly.
Be careful with --deep
Do not use --deep as a generic signing repair method. Apple Developer Technical Support explicitly warns against deep signing because complex bundles should be signed as deliberate code items in the correct inside-out order.
For verification, a recursive --deep check can be a supplemental scan, but it is not a substitute for identifying and inspecting each nested signed component. It can tell you that something under the outer bundle fails without producing the release evidence needed to understand each target’s bundle ID, entitlements, certificate, and profile.
Never combine --deep, --force, and a signing identity as an experimental “fix” on the only copy of an IPA. Preserve the original and use an authorized workflow that understands the bundle structure.
What signature verification proves—and does not prove
A successful codesign --verify result proves that the inspected code currently satisfies the local code-signing verification requested by that command. It does not prove:
- the signing team is the intended app owner;
- the artifact came from a trusted source;
- the embedded profile authorizes the certificate;
- the bundle ID and entitlements match the profile;
- the target device appears in a device-bound profile;
- the profile or certificate is current for the intended workflow;
- the delivered file has the same checksum as the inspected file; or
- installation will succeed on the target iOS version and device.
Conversely, a recognizable profile name or target UDID does not prove the code signature is intact.
Decision table
| Evidence | Next action |
|---|---|
| Signature invalid | Preserve the IPA, checksum, and command output. Investigate modification, packaging, nested code, or signing-chain failure before any repair. |
| Signature valid; target device absent | Treat it as a profile/device authorization problem. Verify the exact embedded profile and produce a replacement artifact. |
| Signature valid; certificate and profile disagree | Follow the certificate/profile diagnostic. Select or regenerate compatible signing inputs, then rebuild or authorizedly re-sign. |
| Signature valid; authorization appears correct; install still fails | Preserve the artifact and move to installation, integrity, delivery, OS compatibility, or device-state diagnostics. |
| Artifact provenance unknown | Do not install or trust it merely because the signature verifies. Establish app-owner authorization and source first. |
For an integrity-specific device alert, continue with App Integrity Could Not Be Verified. For a generic installation failure, use Unable to Install App. If the owner authorizes a replacement and the inputs are compatible, How to Re-sign an IPA Safely explains when re-signing is appropriate and when rebuilding is safer.
Close the release-evidence loop
After a rebuild or authorized re-sign:
- checksum the replacement IPA;
- extract it into a new directory;
- verify the main app and every nested signed component;
- compare the embedded profile, team, App ID, certificate, entitlements, expiry, and devices;
- install the exact checksummed artifact on a representative intended device; and
- replace the delivery object without leaving the old IPA behind the same ambiguous link.
Run the browser-local iOS Distribution Checklist before client handoff. Do not upload Apple credentials, P8/P12 files, private keys, or untrusted IPAs to a public diagnostic service.
Related next steps
- How to Re-sign an IPA Safely →
- Inspect a Provisioning Profile Inside an IPA →
- Fix a Provisioning Profile and Signing Certificate Mismatch →
- Fix “Integrity Could Not Be Verified” on iPhone →
- Fix a Bundle ID and Provisioning Profile Mismatch →
- Unable to Install App on iPhone →
- tools ios distribution checklist →