How to Privately Code Sign Sealed iOS Apps
Code signing is a prerequisite for installing any app on a mobile iOS device.
A valid signature, which uses an Apple-issued certificate, ensures the integrity of an app and stands as proof that the app comes from a known and approved source and has not been tampered with.
By enforcing mandatory code signing, Apple ensures that no third-party app loads unsigned code resources or uses self-modifying code.
During the Appdome app Build, Build process adapters are added to the app to achieve the requested added functionality. As a result, the app’s original signature is invalidated and must be resigned to allow deploying the app on mobile devices.
Appdome allows signing an app via the Sign tab, by using any of the following methods:
- On Appdome
Allowing Appdome to take care of the entire signing process. You only need to provide the signing credentials. For details, see topic How to Sign Secured iOS Apps without Xcode.
- Private Signing
Gives you full responsibility for handling the entire signing process. For further information and in-detail instructions, see section Signing iOS Apps Locally below.
- Auto-DEV Private Signing
Allows you to sign the app without uploading the signing certificate to Appdome’s cloud service.
Appdome provides you with a script (.sh file), which runs on your trusted environment and signs the app by using your credentials (certificate and password) as input. For details, see topic How to Automate Secure iOS App Code Signing in DevOps CI/CD.
As part of the Appdome signing process of secured iOS apps, by using either Auto-dev Private Signing or Signing on Appdome, you are required to extract and upload a Provisioning Profile and an entitlement file for each executable in the app, and when using signing on Appdome, a P12 certificate and its password.
Signing iOS Apps Locally
Appdome is a mobile integration platform as a service (iPaaS) that allows users to add a wide variety of features, SDKs, and APIs to Android and iOS apps. Using a simple ‘click to add’ user interface, Appdome allows anyone to easily integrate features to any mobile app – instantly, no code or coding required.
After building an iOS app on the Appdome platform, Appdome recommends that you already sign apps on the Appdome platform.
With the click of the Sign button, the Appdome platform:
- Verifies the components of the certificate, entitlements, and provisioning profile to ensure that all of the app’s components are signed properly.
- Resolves mismatching entitlements that can occur if the provisioning profile provided does not match the entitlements within an app.
- Does not modify the iOS app in any way, as any modification would trigger a violation due to the anti-tampering protection that is automatically integrated into built apps.
For security reasons, by default, the Appdome platform does not store any credentials – namely: certificate, certificate password, or provisioning profile, used when signing apps on the platform. These credentials are permanently removed immediately after the user session is closed.
If you are required to sign iOS apps locally off the Appdome platform, you can follow the process in this KB article to sign your app.
Important Prerequisite Notes
Every time you build an app on Appdome, the final package is sealed, signed and protected automatically by ONEShield, Appdome’s app hardening (app shielding) technology. This protects the app from tampering, reverse engineering or other methods of compromise. To ensure Anti-tampering protection while signing locally, Appdome still needs to seal the app by using the provisioning profile. Hence, the private signing process requires the provisioning profile.
Furthermore, the below process will only work for applications that are developed and signed in Xcode (or any other development framework) by the same certificates, provisioning profiles, and credentials that you used for signing locally after Appdome. This is done in order to avoid mismatching entitlements that may prevent the application from installing. On the Appdome platform, you can sign any app with any certificate, because the Appdome platform resolves mismatching entitlements and performs enhanced in-depth checks.
- Appdome-GO access
- A Mac computer that runs OS X
- The certificate (with private key) in Keychain Access that was used for signing the app in Xcode before uploading the .ipa to Appdome.
For further details on creating certificates, see How to Code Sign Secured iOS Apps with a P12 Distribution Certificateere.
- Built .ipa downloaded from Appdome without signing by selecting the Private Signing option.
- The vanilla non-built app.
- A provisioning profile for each executable that requires signing.
The profile must meet the following requirements:
- The provisioning profile must be the same profile used for signing the app in Xcode before uploading the .ipa to Appdome.
- The App ID for the provisioning profile should be either a Wildcard or match the bundle ID of the executable that needs signing.
- The provisioning profile should have the entitlements that are requested by the executable.
- If the fusion or the app need AppGroups, the provisioning profile should contain them.
3 Easy Steps to Privately Sign Secured or Shielded iOS Apps
Follow these step-by-step instructions to Privately Sign Secured or Shielded iOS Apps.
- Download the secured IPA, and in the Appdome platform, perform the following steps:
- In the Sign tab, go to section How Would You Like to Sign and select Private Signing.
- Go to the Deploy tab and click Download my Built app.
- Unzip the secured IPA as well as the original IPA.
unzip <ipa_path>.ipa -d BUILT_OUTPUT_FOLDER unzip <ipa_path>.ipa -d VANILLA_OUTPUT_FOLDER
3. Sign the application executables, in the correct order.
If you have a Watchkit:
cp "<path to watchkit extension mobile provision>" BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app/PlugIns/<watchkit_name> Extension.appex/embedded.mobileprovision codesign -d --entitlements :- VANILLA_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app/PlugIns/<watchkit_extension_name>.appex/ > WATCHKIT_EXTENSION_ENTITLEMENT.plist codesign -f -s "<Name in Keychain Access>" --entitlements WATCHKIT_EXTENSION_ENTITLEMENT.plist BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app/PlugIns/<watchkit name> Extension.appex/ cp <path to watchkit mobile provision> BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app/embedded.mobileprovision codesign -d --entitlements :- VANILLA_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app > WATCHKIT_ENTITLEMENT.plist codesign -f -s "<Name in Keychain Access>" --entitlements WATCHKIT_ENTITLEMENT.plist BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Watch/<watchkit_name>.app/
If you have an app extension, for each app extension:
cp <path to app extension mobile provision> BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/PlugIns/<plugin_name>.appex/embedded.mobileprovision codesign -d --entitlements :- VANILLA_OUTPUT_FOLDER/Payload/<app_name>.app/PlugIns/<plugin_name>.appex/ > PLUGIN_ENTITLEMENT.plist codesign -f -s "<Name in Keychain Access>" --entitlements PLUGIN_ENTITLEMENT.plist BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/PlugIns/<plugin_name>.appex/
Required – To sign the Appdome library
cp <path to main app mobile provision> BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Frameworks/libloader.framework/embedded.mobileprovision echo -e "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<\0041DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n</dict>\n</plist>" > EMPTY_ENTITLEMENT.plist codesign -f -s "<Name in Keychain Access>" --entitlements EMPTY_ENTITLEMENT.plist BUILT_OUTPUT_FOLDER/Payload/<app_name>.app/Frameworks/libloader.framework/
If there are frameworks that require signing (for example, F5 Anti-Bot framework):
cp <path to main app mobile provision> FUSED_OUTPUT_FOLDER/Payload/<app_name>.app/embedded.mobileprovision codesign -f -s "<Name in Keychain Access>" --entitlements EMPTY_ENTITLEMENT.plist FUSED_OUTPUT_FOLDER/Payload/<app_name>.app/Frameworks/<framework name>.framework/
Required – To sign the main application executable:
cp <path to main app mobile provision> FUSED_OUTPUT_FOLDER/Payload/<app_name>.app/embedded.mobileprovision codesign -d --entitlements :- VANILLA_OUTPUT_FOLDER/Payload/<app_name>.app/ > MAIN_ENTITLEMENT.plist codesign -f -s "<Name in Keychain Access>" --entitlements MAIN_ENTITLEMENT.plist FUSED_OUTPUT_FOLDER/Payload/<app_name>.app/
Next, zip the IPA again
cd FUSED_OUTPUT_FOLDER && zip -qr ../<signed_ipa_name>.ipa . && cd ../
The IPA that was created after this process should not be altered in any form. Now that the app is signed, changing any file inside the zip will tamper with the iOS signing and will prevent the app from being able to be installed.
And finally, Upload your signed app to Appdome’s validation service and verify it is signed correctly.
For every framework that is not appropriately signed, follow the steps detailed in section To sign the Appdome library. This is required for frameworks that are added to your app in the fusion process; for example, F5 Anti-Bot framework.
For further details on Appdome’s app validation, see article How to Troubleshoot App Signing in Secured Android & iOS Apps.
After signing a framework, the main executable must be signed again.
Note: The main executable must be signed last, as it contains the signatures of all the frameworks and plugins.