1/* 2 * Copyright (c) 2006-2010 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 SHA-1 hash of the 37// CodeDirectory directly. The SHA-1 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 51 52namespace Security { 53namespace CodeSigning { 54 55 56// 57// Conventional string names for various code signature components. 58// Depending on storage, these may end up as filenames, extended attribute names, etc. 59// 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 66 67 68// 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. 72// 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.) 79// 80enum { 81 // 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. 87 // 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) 94 95 cdSlotCount, // total number of special slots (+1 for slot 0) 96 cdSlotMax = cdSlotCount - 1, // highest special slot number (as a positive number) 97 98 // 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. 106 // 107 cdCodeDirectorySlot = 0, // CodeDirectory 108 cdSignatureSlot = 0x10000, // CMS signature 109 cdIdentificationSlot, // identification blob 110 // (add further virtual slot numbers here) 111}; 112 113 114// 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. 118// 119enum { 120 cdComponentPerArchitecture = 1, // slot value differs for each Mach-O architecture 121 cdComponentIsBlob = 2, // slot value is a Blob (need not be BlobWrapped) 122}; 123 124 125// 126// A CodeDirectory is a typed Blob describing the secured pieces of a program. 127// This structure describes the common header and provides access to the variable-size 128// elements packed after it. For help in constructing a CodeDirectory, use the nested 129// Builder class. 130// 131// At the heart of a CodeDirectory lies a packed array of hash digests. 132// The array's zero-index element is at offset hashOffset, and the array covers 133// elements in the range [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices 134// denote pages of the main executable. Negative indices indicate "special" hashes, 135// each of a different thing (see cd*Slot constants above). 136// Special slots that are in range but not present are zeroed out. Unallocated special 137// slots are also presumed absent; this is not an error. (Thus the range of special 138// slots can be extended at will.) 139// 140// HOW TO MANAGE COMPATIBILITY: 141// Each CodeDirectory has a format (compatibility) version. Two constants control 142// versioning: 143// * currentVersion is the version used for newly created CodeDirectories. 144// * compatibilityLimit is the highest version the code will accept as compatible. 145// Test for version < currentVersion to detect old formats that may need special 146// handling; this is done in checkIntegrity(). The current code rejects versions 147// below earliestVersion. 148// Break backward compatibility by rejecting versions that are unsuitable. 149// Accept currentVersion < version <= compatibilityLimit as versions newer than 150// those understood by this code but engineered (by newer code) to be backward 151// compatible. Reject version > compatibilityLimit as incomprehensible gibberish. 152// 153// When creating a new version, increment currentVersion. When adding new fixed fields, 154// just append them; the flex fields will shift to make room. To add new flex fields, 155// add a fixed field containing the new field's offset and add suitable computations 156// to the Builder to place the new data (right) before the hash array. Remember to check 157// for offset in-range in checkIntegrity(). Older code will then simply ignore your 158// new fields on load/read. 159// Add flag bits to the existing flags field to add features that step outside 160// of the linear versioning stream. Leave the 'spare' fields alone unless you need 161// something extraordinarily weird - they're meant to be the final escape when everything 162// else fails. 163// As you create new versions, consider moving the compatibilityLimit out to open up 164// new room for backward compatibility. 165// To break backward compatibility intentionally, move currentVersion beyond the 166// old compatibilityLimit (and move compatibilityLimit further out). 167// 168class CodeDirectory: public Blob<CodeDirectory, kSecCodeMagicCodeDirectory> { 169public: 170 Endian<uint32_t> version; // compatibility version 171 Endian<uint32_t> flags; // setup and mode flags 172 Endian<uint32_t> hashOffset; // offset of hash slot element at index zero 173 Endian<uint32_t> identOffset; // offset of identifier string 174 Endian<uint32_t> nSpecialSlots; // number of special hash slots 175 Endian<uint32_t> nCodeSlots; // number of ordinary (code) hash slots 176 Endian<uint32_t> codeLimit; // limit to main image signature range 177 uint8_t hashSize; // size of each hash digest (bytes) 178 uint8_t hashType; // type of hash (kSecCodeSignatureHash* constants) 179 uint8_t spare1; // unused (must be zero) 180 uint8_t pageSize; // log2(page size in bytes); 0 => infinite 181 Endian<uint32_t> spare2; // unused (must be zero) 182 Endian<uint32_t> scatterOffset; // offset of optional scatter vector (zero if absent) 183 Endian<uint32_t> teamIDOffset; // offset of optional teamID string 184 185 // works with the version field; see comments above 186 static const uint32_t currentVersion = 0x20200; // "version 2.2" 187 static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room" 188 189 static const uint32_t earliestVersion = 0x20001; // earliest supported version 190 static const uint32_t supportsScatter = 0x20100; // first version to support scatter option 191 static const uint32_t supportsTeamID = 0x20200; // first version to support team ID option 192 193 void checkIntegrity() const; // throws if inconsistent or unsupported version 194 195 typedef uint32_t HashAlgorithm; // types of internal glue hashes 196 typedef int Slot; // slot index (negative for special slots) 197 typedef unsigned int SpecialSlot; // positive special slot index (not for code slots) 198 199 const char *identifier() const { return at<const char>(identOffset); } 200 char *identifier() { return at<char>(identOffset); } 201 202 // main hash array access 203 SpecialSlot maxSpecialSlot() const; 204 205 unsigned char *operator [] (Slot slot) 206 { 207 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots)); 208 return at<unsigned char>(hashOffset) + hashSize * slot; 209 } 210 211 const unsigned char *operator [] (Slot slot) const 212 { 213 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots)); 214 return at<unsigned char>(hashOffset) + hashSize * slot; 215 } 216 217 // 218 // The main page hash array can be "scattered" across the code file 219 // by specifying an array of Scatter elements, terminated with an 220 // element whose count field is zero. 221 // The scatter vector is optional; if absent, the hash array covers 222 // a single contiguous range of pages. CodeDirectory versions below 223 // supportsScatter never have scatter vectors (they lack the scatterOffset field). 224 // 225 struct Scatter { 226 Endian<uint32_t> count; // number of pages; zero for sentinel (only) 227 Endian<uint32_t> base; // first page number 228 Endian<uint64_t> targetOffset; // byte offset in target 229 Endian<uint64_t> spare; // reserved (must be zero) 230 }; 231 Scatter *scatterVector() // first scatter vector element (NULL if none) 232 { return (version >= supportsScatter && scatterOffset) ? at<Scatter>(scatterOffset) : NULL; } 233 const Scatter *scatterVector() const 234 { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; } 235 236 const char *teamID() const { return version >= supportsTeamID && teamIDOffset ? at<const char>(teamIDOffset) : NULL; } 237 char *teamID() { return version >= supportsTeamID && teamIDOffset ? at<char>(teamIDOffset) : NULL; } 238 239public: 240 bool validateSlot(const void *data, size_t size, Slot slot) const; // validate memory buffer against page slot 241 bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const; // read and validate file 242 bool slotIsPresent(Slot slot) const; 243 244 class Builder; 245 246public: 247 static DynamicHash *hashFor(HashAlgorithm hashType); // create a DynamicHash subclass for (hashType) digests 248 DynamicHash *getHash() const { return hashFor(this->hashType); } // make one for me 249 250 std::string hexHash(const unsigned char *hash) const; // encode any canonical-type hash as a hex string 251 252protected: 253 static size_t generateHash(DynamicHash *hash, UnixPlusPlus::FileDesc fd, Hashing::Byte *digest, size_t limit = 0); // hash to count or end of file 254 static size_t generateHash(DynamicHash *hash, const void *data, size_t length, Hashing::Byte *digest); // hash data buffer 255 256public: 257 // 258 // Information about SpecialSlots. 259 // This specifies meta-data about slots themselves; 260 // it does not work with the contents of hash slots. 261 // 262 static const char *canonicalSlotName(SpecialSlot slot); 263 static unsigned slotAttributes(SpecialSlot slot); 264 IFDEBUG(static const char * const debugSlotName[]); 265 266public: 267 // 268 // Canonical screening code. Requires a fully formed CodeDirectory. 269 // 270 std::string screeningCode() const; 271}; 272 273 274} // CodeSigning 275} // Security 276 277 278#endif //_H_CODEDIRECTORY 279