2  * Copyright (c) 2006-2012,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@ 
  25 // codedirectory - format and operations for code signing "code directory" structures 
  27 // A CodeDirectory is the top level object describing a particular instance 
  28 // of (static) code. It contains hashes of other objects that further describe 
  29 // parts of that code; these hashes hold the various pieces together. 
  31 // This means that if you reliably ascertain the contents of a CodeDirectory, 
  32 // you can verify the integrity of the entire code object it represents - the 
  33 // CodeDirectory can stand as a proxy for that code. 
  35 // Code signatures usually use CMS to sign the CodeDirectory to form full 
  36 // signature blobs; ad-hoc signatures simply record the interior hash of the 
  37 // CodeDirectory directly. The interior hash of the CodeDirectory is also widely 
  38 // used as concordance for a particular code instance - in essence, for 
  39 // different processes (or a process and the kernel) to "compare notes" 
  40 // to make sure they refer to the same code. 
  42 #ifndef _H_CODEDIRECTORY 
  43 #define _H_CODEDIRECTORY 
  45 #include <security_utilities/unix++.h> 
  46 #include <security_utilities/blob.h> 
  47 #include <security_utilities/cfutilities.h> 
  48 #include <security_utilities/hashing.h> 
  49 #include <Security/CSCommonPriv.h> 
  53 namespace CodeSigning 
{ 
  57 // Conventional string names for various code signature components. 
  58 // Depending on storage, these may end up as filenames, extended attribute names, etc. 
  60 #define kSecCS_CODEDIRECTORYFILE        "CodeDirectory"         // CodeDirectory 
  61 #define kSecCS_SIGNATUREFILE            "CodeSignature"         // CMS Signature 
  62 #define kSecCS_REQUIREMENTSFILE         "CodeRequirements"      // internal requirements 
  63 #define kSecCS_RESOURCEDIRFILE          "CodeResources"         // resource directory 
  64 #define kSecCS_APPLICATIONFILE          "CodeApplication"       // application-specific resource 
  65 #define kSecCS_ENTITLEMENTFILE          "CodeEntitlements"      // entitlement configuration 
  69 // Special hash slot values. In a CodeDirectory, these show up at negative slot 
  70 // indices. This enumeration is also used widely in various internal APIs, and as 
  71 // type values in embedded SuperBlobs. 
  73 // How to add a new special slot type: 
  74 //      1. Add the new name at the end of the primary or virtual slot array (below). 
  75 //      2a. For slots representing existing code pieces, follow the ball for cdInfoSlot. 
  76 //      2b. For slots representing global signature components, follow the ball for cdResourceDirSlot. 
  77 //      2c. For slots representing per-architecture signature components, follow the ball for cdEntitlementSlot. 
  78 // ("Follow the ball" -> Global search for that name and do likewise.) 
  82         // Primary slot numbers. 
  83         // These values are potentially present in the CodeDirectory hash array 
  84         // under their negative values. They are also used in APIs and SuperBlobs. 
  85         // Note that zero must not be used for these (it's page 0 of the main code array), 
  86         // and it is important to assign contiguous (very) small values for them. 
  88         cdInfoSlot 
= 1,                                         // Info.plist 
  89         cdRequirementsSlot 
= 2,                         // internal requirements 
  90         cdResourceDirSlot 
= 3,                          // resource directory 
  91         cdApplicationSlot 
= 4,                          // Application specific slot 
  92         cdEntitlementSlot 
= 5,                          // embedded entitlement configuration 
  93         // (add further primary slot numbers here) 
  95         cdSlotCount
,                                            // total number of special slots (+1 for slot 0) 
  96         cdSlotMax 
= cdSlotCount 
- 1,            // highest special slot number (as a positive number) 
  99         // Virtual slot numbers. 
 100         // These values are NOT used in the CodeDirectory hash array. They are used as 
 101         // internal API identifiers and as types in SuperBlobs. 
 102         // Zero is okay to use here; and we assign that to the CodeDirectory itself so 
 103         // it shows up first in (properly sorted) SuperBlob indices. The rest of the 
 104         // numbers is set Far Away so the primary slot set can expand safely. 
 105         // It's okay to have large gaps in these assignments. 
 107         cdCodeDirectorySlot 
= 0,                        // CodeDirectory 
 108         cdSignatureSlot 
= 0x10000,                      // CMS signature 
 109         cdIdentificationSlot
,                           // identification blob 
 110         // (add further virtual slot numbers here) 
 115 // Special hash slot attributes. 
 116 // This is a central description of attributes of each slot. 
 117 // Various places in Code Signing pick up those attributes and act accordingly. 
 120         cdComponentPerArchitecture 
= 1,                 // slot value differs for each Mach-O architecture 
 121         cdComponentIsBlob 
= 2,                                  // slot value is a Blob (need not be BlobWrapped) 
 126 // A signature with a nonzero platform identifier value, when endorsed as originated by Apple, 
 127 // identifies code as belonging to a particular operating system deliverable set. Some system 
 128 // components restrict functionality to platform binaries. The actual values are arbitrary. 
 130 typedef uint8_t PlatformIdentifier
; 
 131 static const PlatformIdentifier noPlatform 
= 0; 
 132 static const unsigned int maxPlatform 
= 255;    // stored in a uint8_t 
 136 // A CodeDirectory is a typed Blob describing the secured pieces of a program. 
 137 // This structure describes the common header and provides access to the variable-size 
 138 // elements packed after it. For help in constructing a CodeDirectory, use the nested 
 141 // At the heart of a CodeDirectory lies a packed array of hash digests. 
 142 // The array's zero-index element is at offset hashOffset, and the array covers 
 143 // elements in the range [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices 
 144 // denote pages of the main executable. Negative indices indicate "special" hashes, 
 145 // each of a different thing (see cd*Slot constants above). 
 146 // Special slots that are in range but not present are zeroed out. Unallocated special 
 147 // slots are also presumed absent; this is not an error. (Thus the range of special 
 148 // slots can be extended at will.) 
 150 // HOW TO MANAGE COMPATIBILITY: 
 151 // Each CodeDirectory has a format (compatibility) version. Two constants control 
 153 //      * currentVersion is the version used for newly created CodeDirectories. 
 154 //  * compatibilityLimit is the highest version the code will accept as compatible. 
 155 // Test for version < currentVersion to detect old formats that may need special 
 156 // handling; this is done in checkIntegrity(). The current code rejects versions 
 157 // below earliestVersion. 
 158 // Break backward compatibility by rejecting versions that are unsuitable. 
 159 // Accept currentVersion < version <= compatibilityLimit as versions newer than 
 160 // those understood by this code but engineered (by newer code) to be backward 
 161 // compatible. Reject version > compatibilityLimit as incomprehensible gibberish. 
 163 // When creating a new version, increment currentVersion. When adding new fixed fields, 
 164 // just append them; the flex fields will shift to make room. To add new flex fields, 
 165 // add a fixed field containing the new field's offset and add suitable computations 
 166 // to the Builder to place the new data (right) before the hash array. Remember to check 
 167 // for offset in-range in checkIntegrity(). Older code will then simply ignore your 
 168 // new fields on load/read. 
 169 // Add flag bits to the existing flags field to add features that step outside 
 170 // of the linear versioning stream. Leave the 'spare' fields alone unless you need 
 171 // something extraordinarily weird - they're meant to be the final escape when everything 
 173 // As you create new versions, consider moving the compatibilityLimit out to open up 
 174 // new room for backward compatibility. 
 175 // To break backward compatibility intentionally, move currentVersion beyond the 
 176 // old compatibilityLimit (and move compatibilityLimit further out). 
 178 class CodeDirectory
: public Blob
<CodeDirectory
, kSecCodeMagicCodeDirectory
> { 
 180         Endian
<uint32_t> version
;               // compatibility version 
 181         Endian
<uint32_t> flags
;                 // setup and mode flags 
 182         Endian
<uint32_t> hashOffset
;    // offset of hash slot element at index zero 
 183         Endian
<uint32_t> identOffset
;   // offset of identifier string 
 184         Endian
<uint32_t> nSpecialSlots
; // number of special hash slots 
 185         Endian
<uint32_t> nCodeSlots
;    // number of ordinary (code) hash slots 
 186         Endian
<uint32_t> codeLimit
;             // limit to main image signature range 
 187         uint8_t hashSize
;                               // size of each hash digest (bytes) 
 188         uint8_t hashType
;                               // type of hash (kSecCodeSignatureHash* constants) 
 189         uint8_t platform
;                               // platform identifier; zero if not platform binary 
 190         uint8_t pageSize
;                               // log2(page size in bytes); 0 => infinite 
 191         Endian
<uint32_t> spare2
;                // unused (must be zero) 
 192         Endian
<uint32_t> scatterOffset
; // offset of optional scatter vector (zero if absent) 
 193         Endian
<uint32_t> teamIDOffset
;  // offset of optional teamID string 
 195         // works with the version field; see comments above 
 196         static const uint32_t currentVersion 
= 0x20200;         // "version 2.2" 
 197         static const uint32_t compatibilityLimit 
= 0x2F000;     // "version 3 with wiggle room" 
 199         static const uint32_t earliestVersion 
= 0x20001;        // earliest supported version 
 200         static const uint32_t supportsScatter 
= 0x20100;        // first version to support scatter option 
 201         static const uint32_t supportsTeamID 
= 0x20200; // first version to support team ID option 
 203         void checkIntegrity() const;    // throws if inconsistent or unsupported version 
 205         typedef uint32_t HashAlgorithm
; // types of internal glue hashes 
 206         typedef int Slot
;                               // slot index (negative for special slots) 
 207         typedef unsigned int SpecialSlot
; // positive special slot index (not for code slots) 
 209         const char *identifier() const { return at
<const char>(identOffset
); } 
 210         char *identifier() { return at
<char>(identOffset
); } 
 212         // main hash array access 
 213         SpecialSlot 
maxSpecialSlot() const; 
 215         unsigned char *operator [] (Slot slot
) 
 217                 assert(slot 
>= int(-nSpecialSlots
) && slot 
< int(nCodeSlots
)); 
 218                 return at
<unsigned char>(hashOffset
) + hashSize 
* slot
; 
 221         const unsigned char *operator [] (Slot slot
) const 
 223                 assert(slot 
>= int(-nSpecialSlots
) && slot 
< int(nCodeSlots
)); 
 224                 return at
<unsigned char>(hashOffset
) + hashSize 
* slot
; 
 228         // The main page hash array can be "scattered" across the code file 
 229         // by specifying an array of Scatter elements, terminated with an 
 230         // element whose count field is zero. 
 231         // The scatter vector is optional; if absent, the hash array covers 
 232         // a single contiguous range of pages. CodeDirectory versions below 
 233         // supportsScatter never have scatter vectors (they lack the scatterOffset field). 
 236                 Endian
<uint32_t> count
;                 // number of pages; zero for sentinel (only) 
 237                 Endian
<uint32_t> base
;                  // first page number 
 238                 Endian
<uint64_t> targetOffset
;  // byte offset in target 
 239                 Endian
<uint64_t> spare
;                 // reserved (must be zero) 
 241         Scatter 
*scatterVector()        // first scatter vector element (NULL if none) 
 242                 { return (version 
>= supportsScatter 
&& scatterOffset
) ? at
<Scatter
>(scatterOffset
) : NULL
; } 
 243         const Scatter 
*scatterVector() const 
 244                 { return (version 
>= supportsScatter 
&& scatterOffset
) ? at
<const Scatter
>(scatterOffset
) : NULL
; } 
 246         const char *teamID() const { return version 
>= supportsTeamID 
&& teamIDOffset 
? at
<const char>(teamIDOffset
) : NULL
; } 
 247         char *teamID() { return version 
>= supportsTeamID 
&& teamIDOffset 
? at
<char>(teamIDOffset
) : NULL
; } 
 250         bool validateSlot(const void *data
, size_t size
, Slot slot
) const;                      // validate memory buffer against page slot 
 251         bool validateSlot(UnixPlusPlus::FileDesc fd
, size_t size
, Slot slot
) const;     // read and validate file 
 252         bool slotIsPresent(Slot slot
) const; 
 257         static DynamicHash 
*hashFor(HashAlgorithm hashType
);            // create a DynamicHash subclass for (hashType) digests 
 258         DynamicHash 
*getHash() const { return hashFor(this->hashType
); } // make one for me 
 259         CFDataRef 
cdhash() const; 
 261         std::string 
hexHash(const unsigned char *hash
) const;           // encode any canonical-type hash as a hex string 
 264         static size_t generateHash(DynamicHash 
*hash
, UnixPlusPlus::FileDesc fd
, Hashing::Byte 
*digest
, size_t limit 
= 0); // hash to count or end of file 
 265         static size_t generateHash(DynamicHash 
*hash
, const void *data
, size_t length
, Hashing::Byte 
*digest
); // hash data buffer 
 269         // Information about SpecialSlots. 
 270         // This specifies meta-data about slots themselves; 
 271         // it does not work with the contents of hash slots. 
 273         static const char *canonicalSlotName(SpecialSlot slot
); 
 274         static unsigned slotAttributes(SpecialSlot slot
); 
 275         IFDEBUG(static const char * const debugSlotName
[]); 
 279         // Canonical screening code. Requires a fully formed CodeDirectory. 
 281         std::string 
screeningCode() const; 
 289 #endif //_H_CODEDIRECTORY