]> git.saurik.com Git - apple/security.git/blob - OSX/include/security_codesigning/codedirectory.h
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / include / security_codesigning / 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
51
52 namespace Security {
53 namespace 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 //
80 enum {
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 //
119 enum {
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 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.
129 //
130 typedef uint8_t PlatformIdentifier;
131 static const PlatformIdentifier noPlatform = 0;
132 static const unsigned int maxPlatform = 255; // stored in a uint8_t
133
134
135 //
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
139 // Builder class.
140 //
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.)
149 //
150 // HOW TO MANAGE COMPATIBILITY:
151 // Each CodeDirectory has a format (compatibility) version. Two constants control
152 // versioning:
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.
162 //
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
172 // else fails.
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).
177 //
178 class CodeDirectory: public Blob<CodeDirectory, kSecCodeMagicCodeDirectory> {
179 public:
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
194
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"
198
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
202
203 void checkIntegrity() const; // throws if inconsistent or unsupported version
204
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)
208
209 const char *identifier() const { return at<const char>(identOffset); }
210 char *identifier() { return at<char>(identOffset); }
211
212 // main hash array access
213 SpecialSlot maxSpecialSlot() const;
214
215 unsigned char *operator [] (Slot slot)
216 {
217 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots));
218 return at<unsigned char>(hashOffset) + hashSize * slot;
219 }
220
221 const unsigned char *operator [] (Slot slot) const
222 {
223 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots));
224 return at<unsigned char>(hashOffset) + hashSize * slot;
225 }
226
227 //
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).
234 //
235 struct Scatter {
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)
240 };
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; }
245
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; }
248
249 public:
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;
253
254 class Builder;
255
256 public:
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;
260
261 std::string hexHash(const unsigned char *hash) const; // encode any canonical-type hash as a hex string
262
263 protected:
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
266
267 public:
268 //
269 // Information about SpecialSlots.
270 // This specifies meta-data about slots themselves;
271 // it does not work with the contents of hash slots.
272 //
273 static const char *canonicalSlotName(SpecialSlot slot);
274 static unsigned slotAttributes(SpecialSlot slot);
275 IFDEBUG(static const char * const debugSlotName[]);
276
277 public:
278 //
279 // Canonical screening code. Requires a fully formed CodeDirectory.
280 //
281 std::string screeningCode() const;
282 };
283
284
285 } // CodeSigning
286 } // Security
287
288
289 #endif //_H_CODEDIRECTORY