codedirectory.h
1 /* 2 * Copyright (c) 2006-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 // 25 // codedirectory - format and operations for code signing "code directory" structures 26 // 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. 30 // 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. 34 // 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. 41 // 42 #ifndef _H_CODEDIRECTORY 43 #define _H_CODEDIRECTORY 44 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> 50 #include <set> 51 52 53 namespace Security { 54 namespace CodeSigning { 55 56 57 // 58 // Conventional string names for various code signature components. 59 // Depending on storage, these may end up as filenames, extended attribute names, etc. 60 // 61 #define kSecCS_CODEDIRECTORYFILE "CodeDirectory" // CodeDirectory 62 #define kSecCS_SIGNATUREFILE "CodeSignature" // CMS Signature 63 #define kSecCS_REQUIREMENTSFILE "CodeRequirements" // internal requirements 64 #define kSecCS_RESOURCEDIRFILE "CodeResources" // resource directory 65 #define kSecCS_ENTITLEMENTFILE "CodeEntitlements" // entitlement configuration 66 #define kSecCS_REPSPECIFICFILE "CodeRepSpecific" // DiskRep-specific use slot 67 #define kSecCS_TOPDIRECTORYFILE "CodeTopDirectory" // Top-level directory list 68 #define kSecCS_ENTITLEMENTDERFILE "CodeEntitlementDER" // DER entitlement representation 69 70 // 71 // Special hash slot values. In a CodeDirectory, these show up at negative slot 72 // indices. This enumeration is also used widely in various internal APIs, and as 73 // type values in embedded SuperBlobs. 74 // 75 // How to add a new special slot type: 76 // 1. Add the new name at the end of the primary or virtual slot array (below). 77 // 2a. For slots representing existing code pieces, follow the ball for cdInfoSlot. 78 // 2b. For slots representing global signature components, follow the ball for cdResourceDirSlot. 79 // 2c. For slots representing per-architecture signature components, follow the ball for cdEntitlementSlot. 80 // ("Follow the ball" -> Global search for that name and do likewise.) 81 // 82 enum { 83 // 84 // Primary slot numbers. 85 // These values are potentially present in the CodeDirectory hash array 86 // under their negative values. They are also used in APIs and SuperBlobs. 87 // Note that zero must not be used for these (it's page 0 of the main code array), 88 // and it is important to assign contiguous (very) small values for them. 89 // 90 cdInfoSlot = 1, // Info.plist 91 cdRequirementsSlot = 2, // internal requirements 92 cdResourceDirSlot = 3, // resource directory 93 cdTopDirectorySlot = 4, // Application specific slot 94 cdEntitlementSlot = 5, // embedded entitlement configuration 95 cdRepSpecificSlot = 6, // for use by disk rep 96 cdEntitlementDERSlot = 7, // DER representation of entitlements 97 // (add further primary slot numbers here) 98 99 cdSlotCount, // total number of special slots (+1 for slot 0) 100 cdSlotMax = cdSlotCount - 1, // highest special slot number (as a positive number) 101 102 // 103 // Virtual slot numbers. 104 // These values are NOT used in the CodeDirectory hash array. They are used as 105 // internal API identifiers and as types in SuperBlobs. 106 // Zero is okay to use here; and we assign that to the CodeDirectory itself so 107 // it shows up first in (properly sorted) SuperBlob indices. The rest of the 108 // numbers is set Far Away so the primary slot set can expand safely. 109 // It's okay to have large gaps in these assignments. 110 // 111 cdCodeDirectorySlot = 0, // CodeDirectory 112 cdAlternateCodeDirectorySlots = 0x1000, // alternate CodeDirectory array 113 cdAlternateCodeDirectoryLimit = 0x1005, // 5+1 hashes should be enough for everyone... 114 cdSignatureSlot = 0x10000, // CMS signature 115 cdIdentificationSlot, // identification blob (detached signatures only) 116 cdTicketSlot, // ticket embedded in signature (DMG only) 117 // (add further virtual slot numbers here) 118 }; 119 120 121 // 122 // Special hash slot attributes. 123 // This is a central description of attributes of each slot. 124 // Various places in Code Signing pick up those attributes and act accordingly. 125 // 126 enum { 127 cdComponentPerArchitecture = 1, // slot value differs for each Mach-O architecture 128 cdComponentIsBlob = 2, // slot value is a Blob (need not be BlobWrapped) 129 }; 130 131 132 // 133 // A signature with a nonzero platform identifier value, when endorsed as originated by Apple, 134 // identifies code as belonging to a particular operating system deliverable set. Some system 135 // components restrict functionality to platform binaries. The actual values are arbitrary. 136 // 137 typedef uint8_t PlatformIdentifier; 138 static const PlatformIdentifier noPlatform = 0; 139 static const unsigned int maxPlatform = 255; // stored in a uint8_t 140 141 142 // 143 // A CodeDirectory is a typed Blob describing the secured pieces of a program. 144 // This structure describes the common header and provides access to the variable-size 145 // elements packed after it. For help in constructing a CodeDirectory, use the nested 146 // Builder class. 147 // 148 // At the heart of a CodeDirectory lies a packed array of hash digests. 149 // The array's zero-index element is at offset hashOffset, and the array covers 150 // elements in the range [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices 151 // denote pages of the main executable. Negative indices indicate "special" hashes, 152 // each of a different thing (see cd*Slot constants above). 153 // Special slots that are in range but not present are zeroed out. Unallocated special 154 // slots are also presumed absent; this is not an error. (Thus the range of special 155 // slots can be extended at will.) 156 // 157 // HOW TO MANAGE COMPATIBILITY: 158 // Each CodeDirectory has a format (compatibility) version. Two constants control 159 // versioning: 160 // * currentVersion is the version used for newly created CodeDirectories. 161 // * compatibilityLimit is the highest version the code will accept as compatible. 162 // Test for version < currentVersion to detect old formats that may need special 163 // handling; this is done in checkIntegrity(). The current code rejects versions 164 // below earliestVersion. 165 // Break backward compatibility by rejecting versions that are unsuitable. 166 // Accept currentVersion < version <= compatibilityLimit as versions newer than 167 // those understood by this code but engineered (by newer code) to be backward 168 // compatible. Reject version > compatibilityLimit as incomprehensible gibberish. 169 // 170 // When creating a new version, increment currentVersion. When adding new fixed fields, 171 // just append them; the flex fields will shift to make room. To add new flex fields, 172 // add a fixed field containing the new field's offset and add suitable computations 173 // to the Builder to place the new data (right) before the hash array. Remember to check 174 // for offset in-range in checkIntegrity(). Older code will then simply ignore your 175 // new fields on load/read. 176 // Add flag bits to the existing flags field to add features that step outside 177 // of the linear versioning stream. Leave the 'spare' fields alone unless you need 178 // something extraordinarily weird - they're meant to be the final escape when everything 179 // else fails. 180 // As you create new versions, consider moving the compatibilityLimit out to open up 181 // new room for backward compatibility. 182 // To break backward compatibility intentionally, move currentVersion beyond the 183 // old compatibilityLimit (and move compatibilityLimit further out). 184 // 185 class CodeDirectory: public Blob<CodeDirectory, kSecCodeMagicCodeDirectory> { 186 public: 187 Endian<uint32_t> version; // compatibility version 188 Endian<uint32_t> flags; // setup and mode flags 189 Endian<uint32_t> hashOffset; // offset of hash slot element at index zero 190 Endian<uint32_t> identOffset; // offset of identifier string 191 Endian<uint32_t> nSpecialSlots; // number of special hash slots 192 Endian<uint32_t> nCodeSlots; // number of ordinary (code) hash slots 193 Endian<uint32_t> codeLimit; // limit to main image signature range 194 uint8_t hashSize; // size of each hash digest (bytes) 195 uint8_t hashType; // type of hash (kSecCodeSignatureHash* constants) 196 uint8_t platform; // platform identifier; zero if not platform binary 197 uint8_t pageSize; // log2(page size in bytes); 0 => infinite 198 Endian<uint32_t> spare2; // unused (must be zero) 199 Endian<uint32_t> scatterOffset; // offset of optional scatter vector (zero if absent) 200 Endian<uint32_t> teamIDOffset; // offset of optional teamID string 201 Endian<uint32_t> spare3; // unused (most be zero) 202 Endian<uint64_t> codeLimit64; // limit to main image signature range, 64 bits 203 Endian<uint64_t> execSegBase; // offset of executable segment 204 Endian<uint64_t> execSegLimit; // limit of executable segment 205 Endian<uint64_t> execSegFlags; // exec segment flags 206 207 Endian<uint32_t> runtime; // Runtime version encoded as an unsigned int 208 Endian<uint32_t> preEncryptOffset; // offset of pre-encrypt hash slots 209 210 // works with the version field; see comments above 211 static const uint32_t currentVersion = 0x20500; // "version 2.5" 212 static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room" 213 214 static const uint32_t earliestVersion = 0x20001; // earliest supported version 215 static const uint32_t supportsScatter = 0x20100; // first version to support scatter option 216 static const uint32_t supportsTeamID = 0x20200; // first version to support team ID option 217 static const uint32_t supportsCodeLimit64 = 0x20300; // first version to support codeLimit64 218 static const uint32_t supportsExecSegment = 0x20400; // first version to support exec base and limit 219 static const uint32_t supportsPreEncrypt = 0x20500; // first version to support pre-encrypt hashes and runtime version 220 221 void checkIntegrity() const; // throws if inconsistent or unsupported version 222 223 typedef uint32_t HashAlgorithm; // types of internal glue hashes 224 typedef std::set<HashAlgorithm> HashAlgorithms; 225 typedef int Slot; // slot index (negative for special slots) 226 typedef unsigned int SpecialSlot; // positive special slot index (not for code slots) 227 228 const char *identifier() const { return at<const char>(identOffset); } 229 char *identifier() { return at<char>(identOffset); } 230 231 size_t signingLimit() const 232 { return (version >= supportsCodeLimit64 && codeLimit64) ? size_t(codeLimit64) : size_t(codeLimit); } 233 234 // main hash array access 235 SpecialSlot maxSpecialSlot() const; 236 237 unsigned char *getSlotMutable (Slot slot, bool preEncrypt) 238 { 239 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots)); 240 241 if (preEncrypt) { 242 if (version >= supportsPreEncrypt && preEncryptOffset != 0) { 243 assert(slot >= 0); 244 return at<unsigned char>(preEncryptOffset) + hashSize * slot; 245 } else { 246 return NULL; 247 } 248 } else { 249 return at<unsigned char>(hashOffset) + hashSize * slot; 250 } 251 } 252 253 const unsigned char *getSlot (Slot slot, bool preEncrypt) const 254 { 255 CodeDirectory *cd = const_cast<CodeDirectory *>(this); 256 return const_cast<const unsigned char *>(cd->getSlotMutable(slot, preEncrypt)); 257 } 258 259 // 260 // The main page hash array can be "scattered" across the code file 261 // by specifying an array of Scatter elements, terminated with an 262 // element whose count field is zero. 263 // The scatter vector is optional; if absent, the hash array covers 264 // a single contiguous range of pages. CodeDirectory versions below 265 // supportsScatter never have scatter vectors (they lack the scatterOffset field). 266 // 267 struct Scatter { 268 Endian<uint32_t> count; // number of pages; zero for sentinel (only) 269 Endian<uint32_t> base; // first page number 270 Endian<uint64_t> targetOffset; // byte offset in target 271 Endian<uint64_t> spare; // reserved (must be zero) 272 }; 273 Scatter *scatterVector() // first scatter vector element (NULL if none) 274 { return (version >= supportsScatter && scatterOffset) ? at<Scatter>(scatterOffset) : NULL; } 275 const Scatter *scatterVector() const 276 { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; } 277 278 const char *teamID() const { return version >= supportsTeamID && teamIDOffset ? at<const char>(teamIDOffset) : NULL; } 279 char *teamID() { return version >= supportsTeamID && teamIDOffset ? at<char>(teamIDOffset) : NULL; } 280 281 uint64_t execSegmentBase() const { return (version >= supportsExecSegment) ? execSegBase.get() : 0; } 282 uint64_t execSegmentLimit() const { return (version >= supportsExecSegment) ? execSegLimit.get() : 0; } 283 uint64_t execSegmentFlags() const { return (version >= supportsExecSegment) ? execSegFlags.get() : 0; } 284 285 const unsigned char *preEncryptHashes() const { return getSlot(0, true); } 286 287 uint32_t runtimeVersion() const {return (version >= supportsPreEncrypt) ? runtime.get() : 0; } 288 289 public: 290 bool validateSlot(const void *data, size_t size, Slot slot, bool preEncrypted) const; // validate memory buffer against page slot 291 bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot, bool preEncrypted) const; // read and validate file 292 bool slotIsPresent(Slot slot) const; 293 294 class Builder; 295 296 public: 297 static DynamicHash *hashFor(HashAlgorithm hashType); // create a DynamicHash subclass for (hashType) digests 298 DynamicHash *getHash() const { return hashFor(this->hashType); } // make one for me 299 CFDataRef cdhash(bool truncate = true) const; 300 301 static void multipleHashFileData(UnixPlusPlus::FileDesc fd, size_t limit, HashAlgorithms types, void (^action)(HashAlgorithm type, DynamicHash* hasher)); 302 bool verifyMemoryContent(CFDataRef data, const Byte* digest) const; 303 304 static bool viableHash(HashAlgorithm type); 305 static HashAlgorithm bestHashOf(const HashAlgorithms& types); 306 307 std::string hexHash(const unsigned char *hash) const; // encode any canonical-type hash as a hex string 308 309 protected: 310 static size_t generateHash(DynamicHash *hash, UnixPlusPlus::FileDesc fd, Hashing::Byte *digest, size_t limit = 0); // hash to count or end of file 311 static size_t generateHash(DynamicHash *hash, const void *data, size_t length, Hashing::Byte *digest); // hash data buffer 312 313 public: 314 // 315 // Information about SpecialSlots. 316 // This specifies meta-data about slots themselves; 317 // it does not work with the contents of hash slots. 318 // 319 static const char *canonicalSlotName(SpecialSlot slot); 320 static unsigned slotAttributes(SpecialSlot slot); 321 IFDEBUG(static const char * const debugSlotName[]); 322 323 public: 324 // 325 // Canonical screening code. Requires a fully formed CodeDirectory. 326 // 327 std::string screeningCode() const; 328 }; 329 330 331 } // CodeSigning 332 } // Security 333 334 335 #endif //_H_CODEDIRECTORY