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