CSIT tech blog
Published in

CSIT tech blog

Demystifying iOS Code Signature

Taking apart a code signature and learning to reconstruct it

Introduction

Code Signature

Figure 1 — Overview of Code Signature
Code signing your app assures users that it's from a known source and hasn’t been modified since it was last signed. Before your app can integrate app services, be installed on a device, or be submitted to the App Store, it must be signed with a certificate issued by Apple. https://developer.apple.com/support/code-signing/
Figure 2— MachOView of Safari
hexdump -C /Applications/Safari.app/Contents/MacOS/Safari | less
Figure 3— Hexdump of Safari
Figure 4 — Mach-O Header
typedef struct __SuperBlob { 
uint32_t magic; /* magic number */
uint32_t length; /* total length of SuperBlob */
uint32_t count; /* number of index entries following */
CS_BlobIndex index[]; /* (count) entries */ /* followed by Blobs in no particular order as indicated by offsets in index */
} CS_SuperBlob;

Code Directory Blob

class CodeDirectory: public Blob<CodeDirectory, kSecCodeMagicCodeDirectory> {
public:
Endian<uint32_t> version; // compatibility version
Endian<uint32_t> flags; // setup and mode flags
Endian<uint32_t> hashOffset; // offset of hash slot element at index zero
Endian<uint32_t> identOffset; // offset of identifier string
Endian<uint32_t> nSpecialSlots; // number of special hash slots
Endian<uint32_t> nCodeSlots; // number of ordinary (code) hash slots
Endian<uint32_t> codeLimit; // limit to main image signature range
uint8_t hashSize; // size of each hash digest (bytes)
uint8_t hashType; // type of hash (kSecCodeSignatureHash* constants)
uint8_t platform; // platform identifier; zero if not platform binary
uint8_t pageSize; // log2(page size in bytes); 0 => infinite
Endian<uint32_t> spare2; // unused (must be zero)
Endian<uint32_t> scatterOffset; // offset of optional scatter vector (zero if absent)
Endian<uint32_t> teamIDOffset; // offset of optional teamID string
Endian<uint32_t> spare3; // unused (most be zero)
Endian<uint64_t> codeLimit64; // limit to main image signature range, 64 bits
Endian<uint64_t> execSegBase; // offset of executable segment
Endian<uint64_t> execSegLimit; // limit of executable segment
Endian<uint64_t> execSegFlags; // exec segment flags
Endian<uint32_t> runtime; // Runtime version encoded as an unsigned int
Endian<uint32_t> preEncryptOffset; // offset of pre-encrypt hash slots
// works with the version field; see comments above
static const uint32_t currentVersion = 0x20500; // "version 2.5"
static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room"

static const uint32_t earliestVersion = 0x20001; // earliest supported version
static const uint32_t supportsScatter = 0x20100; // first version to support scatter option
static const uint32_t supportsTeamID = 0x20200; // first version to support team ID option
static const uint32_t supportsCodeLimit64 = 0x20300; // first version to support codeLimit64
static const uint32_t supportsExecSegment = 0x20400; // first version to support exec base and limit
static const uint32_t supportsPreEncrypt = 0x20500; // first version to support pre-encrypt hashes and runtime version
...
}
Figure 5— Code Directory Structure
'flags' is used to specify option flags that can be embedded in a code signature during signing and that govern the use of the signature. https://developer.apple.com/documentation/security/seccodesignatureflag 'hashOffset' points to the start of codeSlots. Depending on the version specified, it also enables different options (scatter, teamid, codelimit64, etc.) There could be other options supported in future as the version number increases.
CSSLOT_INFOSLOT = 1, 
CSSLOT_REQUIREMENTS = 2,
CSSLOT_RESOURCEDIR = 3,
CSSLOT_APPLICATION = 4,
CSSLOT_ENTITLEMENTS = 5,
// More CSSLOT_* can be found here: https://developer.apple.com/documentation/kernel/2869934-anonymous/
pageSize = 12 == log2(page_size_bytes), hence: 
page_size_bytes = 2^12 = 0x1000
Here is the list of possible hash types (https://github.com/apple-oss-distributions/dyld/blob/main/common/CodeSigningTypes.h):CS_HASHTYPE_SHA1 = 1, 
CS_HASHTYPE_SHA256 = 2,
CS_HASHTYPE_SHA256_TRUNCATED = 3,
CS_HASHTYPE_SHA384 = 4,

Requirements Blob

codesign -d --requirements - /Applications/Safari.app/Contents/MacOS/Safari Executable=/Applications/Safari.app/Contents/MacOS/Safari designated => identifier "com.apple.Safari" and anchor apple
Figure 6— Requirements Set Structure
char *requirement_str = "<StringInRequirementLang>"; 
static SecRequirementRef requirement_ref = nil;
CFDataRef req_data;
CFStringRef req_ref = CFStringCreateWithCString(NULL, requirement_str, kCFStringEncodingUTF8);
SecRequirementCreateWithString(req_ref, kSecCSDefaultFlags, &requirement_ref);
SecRequirementCopyData((SecRequirementRef)requirement_ref, kSecCSDefaultFlags, &req_data);

Entitlements Blob

codesign -d --entitlements :- /Applications/Safari.app/Contents/MacOS/Safari
<?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>platform-application</key>
<true/>
<key>com.apple.private.skip-library-validation</key>
<true/>
<key>com.apple.private.security.no-container</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>com.apple.cfnetwork</string
<string>com.apple.safari.credit-cards</string>
<string>com.apple.safari.history</string>
<string>com.apple.ProtectedCloudStorage</string
<string>com.apple.webinspector</string>
<string>com.apple.passd</string>
<string>com.apple.sharing.safaripasswordsharing</string>
<string>com.apple.webkit.webauthn</string>
<string>lockdown-identities</string>
<string>com.apple.password-manager</string>
</array>
</dict>
</plist>
Figure 7— Entitlements Structure

Blob Wrapper (CMS) Blob

security find-identity -p codesigning Policy: Code Signing Matching identities
1) 01234567890ABCDEF01234567890ABCDEF012345 "Apple Development: yourname@email.com (0123456789)"
2) 01234567890ABCDEF01234567890ABCDEF012344 "Apple Development: yourname2@email.com (0123456788)"
2 identities found
Valid identities only
1) 01234567890ABCDEF01234567890ABCDEF012345 "Apple Development: yourname@email.com (0123456789)"
2) 01234567890ABCDEF01234567890ABCDEF012344 "Apple Development: yourname2@email.com (0123456788)"
2 identities found
Figure 8 — Code Signing Diagram
/Applications/Safari.app/Contents/MacOS/SafariBlobWrapper: CMS (RFC3852) signature (4450 bytes)
Subject: /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Code Signing Certification Authority
Issuer: /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA
Not Before: Oct 24 17:39:41 2011 GMT
Not After: Oct 24 17:39:41 2026 GMT
Subject: /C=US/O=Apple Inc./OU=Apple Software/CN=Software Signing
Issuer: /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Code Signing Certification Authority
Not Before: Oct 29 18:32:38 2020 GMT
Not After: Oct 24 17:39:41 2026 GMT
Subject: /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA
Issuer: /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA
Not Before: Apr 25 21:40:36 2006 GMT
Not After: Feb 9 21:40:36 2035 GMT
Found 5 attributes in signer_info
NID: 50 contentType (1.2.840.113549.1.9.3)
NID: 52 signingTime (1.2.840.113549.1.9.5)
signingTime: Jun 3 23:32:45 2021 GMT
NID: 51 messageDigest (1.2.840.113549.1.9.4)
NID: 0 1.2.840.113635.100.9.2 (1.2.840.113635.100.9.2)
NID: 0 1.2.840.113635.100.9.1 (1.2.840.113635.100.9.1)

Wrapping it up

// To codesign an executable with an identity/adhoc + entitlements
codesign --force -s <IDENTITY/e.g 01234567890ABCDEF01234567890ABCDEF012345 or – for adhoc signing> --entitlements <path_to_your_plist> <path_to_your_executable>
// For more information on how you can use the codesign tool
man codesign
// You can also 'strings' codesign to see the possible arg options available.
  • Code signing does ensure the identity and integrity of the executable itself, and other important data, such as entitlements and requirements, that enforces the security model of iOS.
  • Since the requirements are defined by a proprietary language and the language needs to be parsed safely, it will be interesting to dive deeper and to understand more about it.

References

--

--

We conduct applied research and develop customised digital solutions to safeguard national security. Our technical focus includes cybersecurity, data analytics, software engineering, cloud infrastructure and services. Find us at www.csit.gov.sg.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store