Overview
Code signing is a critical security mechanism in iOS that ensures:
- Authenticity: The app comes from a known, trusted source
- Integrity: The app hasn’t been modified since it was signed
- Authorization: The app has permission to run on the device
Every iOS app must be code-signed to execute on a device, whether it’s for development, ad-hoc distribution, or App Store release.
Modifying any part of a signed app bundle invalidates the signature, preventing the app from launching.
Code Signature Components
iOS code signatures consist of several interconnected components:
Digital Certificate
An Apple-issued certificate that identifies the developer or organization.
Provisioning Profile
A file containing entitlements, certificates, and device IDs (for non-App Store builds).
Entitlements
Permissions and capabilities the app is allowed to use.
Code Signature Blob
Cryptographic hashes of all executable code and resources.
┌─────────────────────────────────────────┐
│ iOS App Bundle │
├─────────────────────────────────────────┤
│ MyApp (Mach-O) │
│ ├─ LC_CODE_SIGNATURE → CodeDirectory │ ← Hashes of code
│ └─ Signature │ ← Cryptographic signature
├─────────────────────────────────────────┤
│ _CodeSignature/CodeResources │ ← Hashes of all resources
├─────────────────────────────────────────┤
│ embedded.mobileprovision │ ← Entitlements & certificates
├─────────────────────────────────────────┤
│ Info.plist, Assets, Frameworks, etc. │
└─────────────────────────────────────────┘
Certificate Types
Apple issues different types of certificates for different purposes:
Development
Distribution
Enterprise
iOS App Development
- Used for debugging and testing on registered devices
- Limited to 100 devices per account per year
- Requires device UDIDs in provisioning profile
- Cannot be distributed outside registered devices
# Verify development certificate
security find-identity -v -p codesigning
iOS DistributionTwo types:Ad Hoc: For internal testing and distribution
- Limited to 100 devices
- Requires device UDIDs
- No App Store submission
App Store: For App Store submission
- No device restrictions
- Must go through App Review
- Encrypted by Apple
Apple Developer Enterprise Program
- For internal distribution within an organization
- No device limit
- Requires D-U-N-S number and legal entity verification
- Not for public distribution
- Subject to revocation if misused
Enterprise certificates are often abused for unauthorized distribution and are monitored closely by Apple.
Code Signature Structure
The code signature is embedded in the Mach-O binary’s __LINKEDIT segment and referenced by the LC_CODE_SIGNATURE load command.
CodeDirectory
The CodeDirectory contains:
SHA-1 or SHA-256 hashes of every page (4KB) of executable code.# View code hashes
codesign -d -vvvv MyApp 2>&1 | grep "CandidateCDHash"
These hashes ensure the executable code hasn’t been modified.
Hashes of special data like:
- Info.plist (slot -1)
- Requirements (slot -2)
- Resource directory (slot -3)
- Entitlements (slot -5)
- DER entitlements (slot -7)
# Extract and view special slots
codesign -d --entitlements :- MyApp
The unique bundle identifier for the application.codesign -d -r- MyApp
# Output: identifier "com.company.appname"
Code signature flags indicating properties like:
adhoc: Signed locally without certificate
hard: Kill process if signature is invalid
runtime: Hardened runtime enabled
library-validation: Only load Apple or same-team-signed libraries
codesign -d -vvvv MyApp 2>&1 | grep "CodeDirectory"
CodeResources
The _CodeSignature/CodeResources file is an XML plist containing SHA hashes of all files in the app bundle:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Assets.car</key>
<data>5oqY8JG9h8...</data> ← SHA-1 hash
<key>Info.plist</key>
<data>7kPl2QW3x9...</data>
</dict>
<key>files2</key>
<dict>
<key>Assets.car</key>
<dict>
<key>hash2</key>
<data>9mKp4RT7y2...</data> ← SHA-256 hash
</dict>
</dict>
</dict>
</plist>
The presence of both files (SHA-1) and files2 (SHA-256) ensures compatibility with older iOS versions.
Provisioning Profiles
Provisioning profiles connect certificates, app IDs, entitlements, and devices.
Profile Structure
A .mobileprovision file is a CMS (Cryptographic Message Syntax) signed plist:
# Extract plist from provisioning profile
security cms -D -i embedded.mobileprovision > profile.plist
Key Profile Properties
AppIDName
Human-readable app ID name
ApplicationIdentifierPrefix
Team ID prefix for the app identifier
DeveloperCertificates
Array of DER-encoded certificates allowed to sign the app
Entitlements
Dictionary of entitlements granted to the app
ProvisionedDevices
Array of device UDIDs (development/ad-hoc only)
ExpirationDate
When the provisioning profile expires
TeamIdentifier
The developer team ID
UUID
Unique identifier for this profile
Profile Example
<dict>
<key>AppIDName</key>
<string>My Application</string>
<key>ApplicationIdentifierPrefix</key>
<array>
<string>A1B2C3D4E5</string>
</array>
<key>DeveloperCertificates</key>
<array>
<data>MIIFmTCCBIG...</data>
</array>
<key>Entitlements</key>
<dict>
<key>application-identifier</key>
<string>A1B2C3D4E5.com.company.appname</string>
<key>get-task-allow</key>
<true/>
</dict>
<key>ExpirationDate</key>
<date>2026-12-31T23:59:59Z</date>
<key>ProvisionedDevices</key>
<array>
<string>00008030-001234567890001E</string>
</array>
</dict>
Verification Process
When iOS launches an app, it verifies the code signature in multiple steps:
Certificate Chain Validation
Verify the signing certificate chains to a trusted Apple root certificate.# View certificate chain
codesign -dv --verbose=4 MyApp 2>&1 | grep "Authority"
Provisioning Profile Check
For non-App Store apps:
- Check profile hasn’t expired
- Verify device UDID is in profile (dev/ad-hoc)
- Ensure certificate in profile matches signing certificate
Code Hash Verification
Verify hashes of all code pages match those in CodeDirectory.# Verify signature
codesign -v -vvvv MyApp
# Output: MyApp: valid on disk
# Output: MyApp: satisfies its Designated Requirement
Resource Verification
Verify hashes of all resources match CodeResources file.
Entitlements Validation
Ensure requested entitlements are granted in provisioning profile and not security-critical without proper authorization.
Verification happens both at launch time and continuously during execution. If a memory page is modified, the kernel will detect the hash mismatch.
Inspecting Code Signatures
Using codesign
# Display basic signature info
codesign -dv MyApp
# Output:
Executable=/path/to/MyApp
Identifier=com.company.appname
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20500 size=12345 flags=0x0(none) hashes=123+5 location=embedded
# Advanced code signature analysis
jtool2 --sig MyApp
# Display CodeDirectory
jtool2 --sig --ent MyApp
# Extract embedded provisioning profile
jtool2 --prov MyApp
Using security command
# Extract provisioning profile
security cms -D -i embedded.mobileprovision
# Verify certificate
security verify-cert -c certificate.cer
# List available signing identities
security find-identity -v -p codesigning
Re-signing Applications
Re-signing apps requires:
- A valid certificate and provisioning profile
- All embedded frameworks must also be re-signed
- Original entitlements must be compatible with your profile
Re-signing Steps
Extract entitlements
codesign -d --entitlements entitlements.xml OriginalApp
Sign embedded frameworks
codesign -f -s "iPhone Developer: Name (ID)" \
MyApp.app/Frameworks/Framework.framework
Replace provisioning profile
cp new.mobileprovision MyApp.app/embedded.mobileprovision
Sign the app bundle
codesign -f -s "iPhone Developer: Name (ID)" \
--entitlements entitlements.xml \
MyApp.app
Verify the signature
codesign -v -vvvv MyApp.app
ios-app-signer
GUI tool for macOS to re-sign IPA files with drag-and-drop interface.
zsign
Command-line tool for re-signing IPAs without Xcode or macOS.
ldid
Lightweight tool for ad-hoc signing (jailbreak environments).
Xcode (xcodebuild)
Official Apple tool for signing during build process.
Security Implications
Bypassing Code Signing
Jailbreak
Developer Mode (iOS 16+)
Kernel Exploits
On jailbroken devices:
- Code signature verification is disabled
- Apps can be modified and run without valid signatures
- Unsigned binaries can execute
- Common on older iOS versions and security research devices
iOS 16+ introduced Developer Mode:
- Must be explicitly enabled in Settings
- Allows side-loading of development apps
- Still requires valid development certificate
- Provides security warnings to users
Kernel-level exploits can:
- Disable AMFI (Apple Mobile File Integrity)
- Patch code signature checks
- Used in jailbreaking and security research
- Quickly patched by Apple
Detecting Tampering
Apps can implement runtime integrity checks:
// Check if running with valid signature
func isCodeSigningValid() -> Bool {
var status = SecStaticCodeCheckValidityWithErrors(
code,
SecCSFlags(rawValue: kSecCSCheckAllArchitectures),
nil,
nil
)
return status == errSecSuccess
}
// Detect debugger attachment (get-task-allow)
func isDebuggerAttached() -> Bool {
var info = kinfo_proc()
var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
var size = MemoryLayout<kinfo_proc>.stride
sysctl(&mib, 4, &info, &size, nil, 0)
return (info.kp_proc.p_flag & P_TRACED) != 0
}
Practical Examples
Example 1: Analyzing Example IPA Signatures
# Extract IPA
unzip ~/workspace/source/ObfuscatedAppExamples/NoTampering.ipa -d /tmp/notamper/
cd /tmp/notamper/Payload/*.app/
# Check code signature
codesign -dv NoTampering
# Extract entitlements
codesign -d --entitlements :- NoTampering
# Verify signature validity
codesign -v -vvvv NoTampering
# Check provisioning profile
security cms -D -i embedded.mobileprovision | plutil -p -
Example 2: Comparing Debug vs Release Signatures
# Debug build typically has:
# - get-task-allow entitlement (allows debugging)
# - Development certificate
# - Device UDIDs in profile
# Release build has:
# - No get-task-allow
# - Distribution certificate
# - No device restrictions (App Store)
Next Steps
Entitlements
Learn about app permissions and capabilities.
Mach-O Format
Understand where signatures are stored in binaries.
IPA Files
Learn how to extract and inspect signed apps.
Runtime Analysis
Analyze apps at runtime despite code signing.