2  * Copyright (c) 2008,2010,2013-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include <TargetConditionals.h> 
  25 #if TARGET_OS_EMBEDDED 
  27 #include "SecurityCommands.h" 
  29 #include <AssertMacros.h> 
  30 #include <mach-o/loader.h> 
  31 #include <mach-o/fat.h> 
  32 #include <CoreFoundation/CoreFoundation.h> 
  33 #include <Security/SecCMS.h> 
  34 #include <Security/SecPolicyPriv.h> 
  35 #include <CommonCrypto/CommonDigest.h> 
  36 #include <CommonCrypto/CommonDigestSPI.h> 
  37 #include <utilities/SecCFRelease.h> 
  40  * Magic numbers used by Code Signing 
  43         CSMAGIC_REQUIREMENT     
= 0xfade0c00,           /* single Requirement blob */ 
  44         CSMAGIC_REQUIREMENTS 
= 0xfade0c01,              /* Requirements vector (internal requirements) */ 
  45         CSMAGIC_CODEDIRECTORY 
= 0xfade0c02,             /* CodeDirectory blob */ 
  46         CSMAGIC_EMBEDDED_SIGNATURE 
= 0xfade0cc0, /* embedded form of signature data */ 
  47         CSMAGIC_DETACHED_SIGNATURE 
= 0xfade0cc1, /* multi-arch collection of embedded signatures */ 
  49         CSSLOT_CODEDIRECTORY 
= 0,                               /* slot index for CodeDirectory */ 
  54  * Structure of an embedded-signature SuperBlob 
  56 typedef struct __BlobIndex 
{ 
  57         uint32_t type
;                                  /* type of entry */ 
  58         uint32_t offset
;                                /* offset of entry */ 
  61 typedef struct __SuperBlob 
{ 
  62         uint32_t magic
;                                 /* magic number */ 
  63         uint32_t length
;                                /* total length of SuperBlob */ 
  64         uint32_t count
;                                 /* number of index entries following */ 
  65         CS_BlobIndex index
[];                   /* (count) entries */ 
  66         /* followed by Blobs in no particular order as indicated by offsets in index */ 
  71  * C form of a CodeDirectory. 
  73 typedef struct __CodeDirectory 
{ 
  74         uint32_t magic
;                                 /* magic number (CSMAGIC_CODEDIRECTORY) */ 
  75         uint32_t length
;                                /* total length of CodeDirectory blob */ 
  76         uint32_t version
;                               /* compatibility version */ 
  77         uint32_t flags
;                                 /* setup and mode flags */ 
  78         uint32_t hashOffset
;                    /* offset of hash slot element at index zero */ 
  79         uint32_t identOffset
;                   /* offset of identifier string */ 
  80         uint32_t nSpecialSlots
;                 /* number of special hash slots */ 
  81         uint32_t nCodeSlots
;                    /* number of ordinary (code) hash slots */ 
  82         uint32_t codeLimit
;                             /* limit to main image signature range */ 
  83         uint8_t hashSize
;                               /* size of each hash in bytes */ 
  84         uint8_t hashType
;                               /* type of hash (cdHashType* constants) */ 
  85         uint8_t spare1
;                                 /* unused (must be zero) */ 
  86         uint8_t pageSize
;                               /* log2(page size in bytes); 0 => infinite */ 
  87         uint32_t spare2
;                                /* unused (must be zero) */ 
  88         /* followed by dynamic content as located by offset fields above */ 
  92         //assert(page < ntohl(cd->nCodeSlots)); 
  93         //return base + ntohl(cd->hashOffset) + page * 20; 
  96 static void debug_data(uint8_t *data
, size_t length
) 
  99     for (i 
= 0; i 
< length
; i
+=16) { 
 100         fprintf(stderr
, "%p   ", (void*)(data
+i
)); 
 101         for (j 
= 0; (j 
< 16) && (j
+i 
< length
); j
++) { 
 102             uint8_t byte 
= *(uint8_t*)(data
+i
+j
); 
 103             fprintf(stderr
, "%.02x %c|", byte
, isprint(byte
) ? byte 
: '?'); 
 105         fprintf(stderr
, "\n"); 
 109 static void write_data(const char *path
, uint8_t *data
, size_t length
) 
 111     int fd 
= open(path
, O_RDWR
|O_TRUNC
|O_CREAT
, 0644); 
 113     write(fd
, data
, length
); 
 120 static void fprint_digest(FILE *file
, unsigned char *digest
, size_t length
) { 
 122     for (ix 
= 0; ix 
< length
; ++ix
) { 
 123         fprintf(file
, "%02x", digest
[ix
]); 
 127 static CFMutableDictionaryRef 
lc_code_sig(uint8_t *lc_code_signature
, size_t lc_code_signature_len
) 
 129     CFMutableDictionaryRef code_signature 
= 
 130         CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, 
 131                 &kCFTypeDictionaryKeyCallBacks
, 
 132                 &kCFTypeDictionaryValueCallBacks
); 
 133     require(code_signature
, out
); 
 135     CS_SuperBlob 
*sb 
= (CS_SuperBlob
*)lc_code_signature
; 
 136     require(ntohl(sb
->magic
) == CSMAGIC_EMBEDDED_SIGNATURE
, out
); 
 138     for (count 
= 0; count 
< ntohl(sb
->count
); count
++) { 
 139         //uint32_t type = ntohl(sb->index[count].type); 
 140         uint32_t offset 
= ntohl(sb
->index
[count
].offset
); 
 141         uint8_t *bytes 
= lc_code_signature 
+ offset
; 
 142         //fprintf(stderr, "blob[%d]: (type: 0x%.08x, offset: %p)\n", count, type, (void*)offset); 
 143         uint32_t magic 
= ntohl(*(uint32_t*)bytes
); 
 144         uint32_t length 
= ntohl(*(uint32_t*)(bytes
+4)); 
 145         //fprintf(stderr, "    magic: 0x%.08x length: %d\n", magic, length); 
 147             case 0xfade0c01: //write_data("requirements", bytes, length); 
 149             case 0xfade0c02: //write_data("codedir", bytes, length); 
 151                 const CS_CodeDirectory 
*cd 
= (const CS_CodeDirectory 
*)bytes
; 
 152                 CFDataRef codedir 
= CFDataCreate(kCFAllocatorDefault
, bytes
, length
); 
 153                 require(codedir
, out
); 
 154                 CFDictionarySetValue(code_signature
, CFSTR("CodeDirectory"), codedir
); 
 156                 require_string(ntohl(cd
->version
) >= 0x20001, out
, "incompatible version"); 
 157                 require_string(ntohl(cd
->version
) <= 0x2F000, out
, "incompatible version"); 
 158                 require_string(cd
->hashSize 
== 20, out
, "unexpected hash size"); 
 159                 require_string(cd
->hashType 
== 1, out
, "unexpected hash type"); 
 161                 uint32_t hash_offset 
= ntohl(cd
->hashOffset
); 
 162                 uint32_t entitlement_slot 
= 5; 
 164                 if (ntohl(cd
->nSpecialSlots
) >= entitlement_slot
) { 
 165                     CFDataRef message 
= CFDataCreate(kCFAllocatorDefault
, bytes
+hash_offset
-entitlement_slot
*cd
->hashSize
, cd
->hashSize
); 
 166                     require(message
, out
); 
 167                     CFDictionarySetValue(code_signature
, CFSTR("EntitlementsCDHash"), message
); 
 170                     fprintf(stderr
, "no entitlements slot yet\n"); 
 173             case 0xfade0b01:  //write_data("signed", lc_code_signature, bytes-lc_code_signature); 
 175                     CFDataRef message 
= CFDataCreate(kCFAllocatorDefault
, bytes
+8, length
-8); 
 176                     require(message
, out
); 
 177                     CFDictionarySetValue(code_signature
, CFSTR("SignedData"), message
); 
 183                 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
]; 
 184                 CCDigest(kCCDigestSHA1
, bytes
, length
, digest
); 
 186                 CFDataRef message 
= CFDataCreate(kCFAllocatorDefault
, digest
, sizeof(digest
)); 
 187                 require(message
, out
); 
 188                 CFDictionarySetValue(code_signature
, CFSTR("EntitlementsHash"), message
); 
 190                 message 
= CFDataCreate(kCFAllocatorDefault
, bytes
+8, length
-8); 
 191                 require(message
, out
); 
 192                 CFDictionarySetValue(code_signature
, CFSTR("Entitlements"), message
); 
 197                 fprintf(stderr
, "Skipping block with magic: 0x%x\n", magic
); 
 201     return code_signature
; 
 203     if (code_signature
) CFRelease(code_signature
); 
 208 open_bundle(const char * path
, const char * mode
) 
 210     char full_path
[1024] = {}; 
 211     CFStringRef path_cfstring 
= NULL
; 
 212     CFURLRef path_url 
= NULL
; 
 213     CFBundleRef bundle 
= NULL
; 
 214     CFURLRef exec 
= NULL
; 
 216     path_cfstring 
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault
, path
); 
 217     require_quiet(path_cfstring
, out
); 
 218     path_url 
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path_cfstring
, kCFURLPOSIXPathStyle
, true); 
 219     require_quiet(path_url
, out
); 
 220         bundle 
=  CFBundleCreate(kCFAllocatorDefault
, path_url
); 
 221     require_quiet(bundle
, out
); 
 222     exec 
= CFBundleCopyExecutableURL(bundle
); 
 224     require(CFURLGetFileSystemRepresentation(exec
, true, (uint8_t*)full_path
, sizeof(full_path
)), out
); 
 226     CFReleaseSafe(path_cfstring
); 
 227     CFReleaseSafe(path_url
); 
 228     CFReleaseSafe(bundle
); 
 231     return fopen(full_path
, "r"); 
 234 static CFMutableDictionaryRef 
load_code_signature(FILE *binary
, size_t slice_offset
) 
 236     bool signature_found 
= false; 
 237     CFMutableDictionaryRef result 
= NULL
; 
 238     struct load_command lc
; 
 240         require(1 == fread(&lc
, sizeof(lc
), 1, binary
), out
); 
 241         if (lc
.cmd 
== LC_CODE_SIGNATURE
) { 
 242             struct { uint32_t offset
; uint32_t size
; } sig
; 
 243             require(1 == fread(&sig
, sizeof(sig
), 1, binary
), out
); 
 244             require_noerr(fseek(binary
, slice_offset
+sig
.offset
, SEEK_SET
), out
); 
 245             size_t length 
= sig
.size
; 
 246             uint8_t *data 
= malloc(length
); 
 247             require(length 
&& data
, out
); 
 248             require(1 == fread(data
, length
, 1, binary
), out
); 
 249             signature_found 
= true; 
 250             result 
= lc_code_sig(data
, length
); 
 254         require_noerr(fseek(binary
, lc
.cmdsize
-sizeof(lc
), SEEK_CUR
), out
); 
 255     } while(lc
.cmd 
|| lc
.cmdsize
); /* count lc */ 
 257     if (!signature_found
) 
 258         fprintf(stderr
, "No LC_CODE_SIGNATURE segment found\n"); 
 262 static CF_RETURNS_RETAINED CFArrayRef 
load_code_signatures(const char *path
) 
 264     bool fully_parsed_binary 
= false; 
 265     CFMutableDictionaryRef result 
= NULL
; 
 266     CFMutableArrayRef results 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
 268     FILE *binary 
= open_bundle(path
, "r"); 
 269     if (!binary
) binary 
= fopen(path
, "r"); 
 270     require(binary
, out
); 
 272     struct mach_header header
; 
 273     require(1 == fread(&header
, sizeof(header
), 1, binary
), out
); 
 274     if ((header
.magic 
== MH_MAGIC
) || (header
.magic 
== MH_MAGIC_64
)) { 
 275         if (header
.magic 
== MH_MAGIC_64
) 
 276                 fseek(binary
, sizeof(struct mach_header_64
) - sizeof(struct mach_header
), SEEK_CUR
); 
 277         result 
= load_code_signature(binary
, 0 /*non fat*/); 
 278         require(result
, out
); 
 279         CFStringRef type 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("CPU type: (%d,%d)"), header
.cputype
, header
.cpusubtype
); 
 280         CFDictionarySetValue(result
, CFSTR("ARCH"), type
); 
 282         CFArrayAppendValue(results
, result
); 
 286         struct fat_header fat
; 
 287         require(!fseek(binary
, 0L, SEEK_SET
), out
); 
 288         require(1 == fread(&fat
, sizeof(fat
), 1, binary
), out
); 
 289         require(ntohl(fat
.magic
) == FAT_MAGIC
, out
); 
 290         uint32_t slice
, slices 
= ntohl(fat
.nfat_arch
); 
 291         struct fat_arch 
*archs 
= calloc(slices
, sizeof(struct fat_arch
)); 
 292         require(slices 
== fread(archs
, sizeof(struct fat_arch
), slices
, binary
), out
); 
 293         for (slice 
= 0; slice 
< slices
; slice
++) { 
 294             uint32_t slice_offset 
= ntohl(archs
[slice
].offset
); 
 295             require(!fseek(binary
, slice_offset
, SEEK_SET
), out
); 
 296             require(1 == fread(&header
, sizeof(header
), 1, binary
), out
); 
 297             require((header
.magic 
== MH_MAGIC
) || (header
.magic 
== MH_MAGIC_64
), out
); 
 298             if (header
.magic 
== MH_MAGIC_64
) 
 299                     fseek(binary
, sizeof(struct mach_header_64
) - sizeof(struct mach_header
), SEEK_CUR
); 
 300             result 
= load_code_signature(binary
, slice_offset
); 
 301             require(result
, out
); 
 302             CFStringRef type 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("CPU type: (%d,%d)"), header
.cputype
, header
.cpusubtype
); 
 303             CFDictionarySetValue(result
, CFSTR("ARCH"), type
); 
 305             CFArrayAppendValue(results
, result
); 
 309     fully_parsed_binary 
= true; 
 311     if (!fully_parsed_binary
) { 
 323 extern int codesign_util(int argc
, char * const *argv
) 
 325     int             result 
= 1, verbose 
= 0; 
 328     while ((ch 
= getopt(argc
, argv
, "v")) != -1) 
 336             return SHOW_USAGE_MESSAGE
; 
 344         return SHOW_USAGE_MESSAGE
; 
 346     CFArrayRef sigs 
= load_code_signatures(argv
[0]); 
 352     CFIndex i
, count 
= CFArrayGetCount(sigs
); 
 354     for (i 
= 0; i 
< count
; i
++) { 
 355         CFDictionaryRef signature 
= CFArrayGetValueAtIndex(sigs
, i
); 
 357         CFDataRef code_dir 
= CFDictionaryGetValue(signature
, CFSTR("CodeDirectory")); 
 358         const CS_CodeDirectory 
*cd 
= (CS_CodeDirectory 
*)CFDataGetBytePtr(code_dir
); 
 360         CFDataRef signed_data 
= CFDictionaryGetValue(signature
, CFSTR("SignedData")); 
 362         CFDataRef entitlements 
= CFDictionaryGetValue(signature
, CFSTR("Entitlements")); 
 363         CFDataRef entitlements_cd_hash 
= CFDictionaryGetValue(signature
, CFSTR("EntitlementsCDHash")); 
 364         CFDataRef entitlements_hash 
= CFDictionaryGetValue(signature
, CFSTR("EntitlementsHash")); 
 366         CFStringRef arch 
= CFDictionaryGetValue(signature
, CFSTR("ARCH")); 
 370         SecPolicyRef policy 
= SecPolicyCreateiPhoneApplicationSigning(); 
 373             if (SecCMSVerify(signed_data
, code_dir
, policy
, NULL
, NULL
)) { 
 374                 fprintf(stderr
, "Failed to verify signature\n"); 
 377                 fprintf(stderr
, "Signature ok\n"); 
 380             fprintf(stderr
, "Ad-hoc signed binary\n"); 
 382         if (entitlements_cd_hash
) { 
 383             if (entitlements_hash 
&& entitlements_cd_hash 
&& CFEqual(entitlements_hash
, entitlements_cd_hash
)) 
 384                 fprintf(stderr
, "Entitlements ok\n"); 
 386                 fprintf(stderr
, "Entitlements modified\n"); 
 390             fprintf(stderr
, "magic: 0x%x length: %u(%lu)\n", ntohl(cd
->magic
), ntohl(cd
->length
), CFDataGetLength(code_dir
)); 
 391             fprintf(stderr
, "code directory version/flags: 0x%x/0x%x special/code hash slots: %u/%u\n" 
 392                 "codelimit: %u hash size/type: %u/%u hash/ident offset: %u/%u\n", 
 393                 ntohl(cd
->version
), ntohl(cd
->flags
), ntohl(cd
->nSpecialSlots
), ntohl(cd
->nCodeSlots
), 
 394                 ntohl(cd
->codeLimit
), cd
->hashSize
, cd
->hashType
, ntohl(cd
->hashOffset
), ntohl(cd
->identOffset
)); 
 395             fprintf(stderr
, "ident: '%s'\n", CFDataGetBytePtr(code_dir
) + ntohl(cd
->identOffset
)); 
 398             uint8_t *hashes 
= (uint8_t *)CFDataGetBytePtr(code_dir
) + ntohl(cd
->hashOffset
); 
 399             for (ix 
= 0; ix 
< ntohl(cd
->nSpecialSlots
); ++ix
) { 
 400                 fprint_digest(stderr
, hashes
, cd
->hashSize
); 
 401                 fprintf(stderr
, "\n"); 
 402                 hashes 
+= cd
->hashSize
; 
 408                 fprintf(stderr
, "Entitlements\n%.*s", (int)CFDataGetLength(entitlements
)-8, CFDataGetBytePtr(entitlements
)+8); 
 412             if (entitlements_hash
) { 
 413                 fprintf(stderr
, "digest: "); 
 414                 fprint_digest(stderr
, (uint8_t *)CFDataGetBytePtr(entitlements_hash
), CC_SHA1_DIGEST_LENGTH
); 
 415                 fprintf(stderr
, "\n"); 
 418         CFReleaseNull(policy
); 
 428 #endif // TARGET_OS_EMBEDDED