]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/codedirectory.h
0f99dd116c2b5a687b9138716fefe5a63f0a703f
[apple/libsecurity_codesigning.git] / lib / codedirectory.h
1 /*
2 * Copyright (c) 2006 Apple Computer, 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 a contiguous binary blob containing a two-tiered
28 // hash of (much of) the contents of a real StaticCode object.
29 // It consists of a header followed by an array of hash vector elements.
30 //
31 // This structure is meant to be self-describing, binary stable, and endian independent.
32 //
33 #ifndef _H_CODEDIRECTORY
34 #define _H_CODEDIRECTORY
35
36 #include <security_utilities/unix++.h>
37 #include <security_utilities/blob.h>
38 #include <security_utilities/cfutilities.h>
39 #include <security_utilities/hashing.h>
40
41
42 namespace Security {
43 namespace CodeSigning {
44
45
46 //
47 // Types of hashes supported.
48 // Actually, right now, only SHA1 is really supported.
49 //
50 enum {
51 cdHashTypeSHA1 = 1,
52 cdHashTypeSHA256 = 2,
53
54 cdHashTypeDefault = cdHashTypeSHA1
55 };
56
57
58 //
59 // Conventional string names for various code signature components.
60 // Depending on storage, these may end up as filenames, extended attribute names, etc.
61 //
62 #define kSecCS_CODEDIRECTORYFILE "CodeDirectory" // CodeDirectory
63 #define kSecCS_SIGNATUREFILE "CodeSignature" // CMS Signature
64 #define kSecCS_REQUIREMENTSFILE "CodeRequirements" // internal requirements
65 #define kSecCS_RESOURCEDIRFILE "CodeResources" // resource directory
66 #define kSecCS_APPLICATIONFILE "CodeApplication" // application-specific resource
67 #define kSecCS_ENTITLEMENTFILE "CodeEntitlements" // entitlement configuration (just in case)
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 slot code:
76 // 1. Add the new name into the primary or virtual slot array at the end (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's good 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 cdApplicationSlot = 4, // Application specific slot
94 cdEntitlementSlot = 5, // embedded entitlement configuration
95 // (add further primary slot numbers here)
96
97 cdSlotCount, // total number of special slots (+1 for slot 0)
98 cdSlotMax = cdSlotCount - 1, // highest special slot number (as a positive number)
99
100 //
101 // Virtual slot numbers.
102 // These values are NOT used in the CodeDirectory hash array. The are used as
103 // internal API identifiers and as types in SuperBlobs.
104 // Zero is okay to use here; and we assign that to the CodeDirectory itself so
105 // it shows up first in (properly sorted) SuperBlob indices. The rest of the
106 // numbers is set Far Away so the primary slot set can expand safely.
107 // It's okay to have gaps in these assignments.
108 //
109 cdCodeDirectorySlot = 0, // CodeDirectory
110 cdSignatureSlot = 0x10000, // CMS signature
111 cdIdentificationSlot, // identification blob
112 // (add further virtual slot numbers here)
113 };
114
115
116 //
117 // Special hash slot attributes.
118 // This is a central description of attributes of each slot.
119 // Various places in Code Signing pick up those attributes and act accordingly.
120 //
121 enum {
122 cdComponentPerArchitecture = 1, // slot value differs for each Mach-O architecture
123 cdComponentIsBlob = 2, // slot value is a Blob (need not be BlobWrapped)
124 };
125
126
127 //
128 // A CodeDirectory is a typed Blob describing the secured pieces of a program.
129 // This structure describes the common header and provides access to the variable-size
130 // elements packed after it. For help in constructing a CodeDirectory, use the nested
131 // Builder class.
132 //
133 // The hashes are stored as an array of digests. The array covers the range
134 // [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices denote pages of the main
135 // executable. Negative indices indicate "special" hashes, each of a different thing
136 // (see cd*Slot constants above). Special slots that are in range but not present
137 // are zeroed out. Unallocated special slots are also presumed absent; this is not
138 // an error. (Thus the range of special 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. The current code rejects those; add backward cases to checkValidity().
147 // Break backward compatibility by rejecting versions that are unsuitable.
148 // Accept currentVersion < version <= compatibilityLimit as versions newer than
149 // those understood by this code but engineered (by newer code) to be backward
150 // compatible. Reject version > compatibilityLimit as incomprehensible gibberish.
151 //
152 // When creating a new version, increment currentVersion. When adding new fixed fields,
153 // just append them; the flex fields will shift to make room. To add new flex fields,
154 // add a fixed field containing the new field's offset and add suitable computations
155 // to the Builder to place the new data (right) before the hash array. Remember to check
156 // for offset in-range in checkIntegrity(). Older code will then simply ignore your
157 // new fields on load/read.
158 // Add flag bits to the existing flags field to add features that step outside
159 // of the linear versioning stream. Leave the 'spare' fields alone unless you need
160 // something extraordinarily weird - they're meant to be the final escape when everything
161 // else fails.
162 // As you create new versions, consider moving the compatibilityLimit out to open up
163 // new room for backward compatibility.
164 // To break backward compatibility intentionally, move currentVersion beyond the
165 // old compatibilityLimit (and move compatibilityLimit further out).
166 //
167 class CodeDirectory: public Blob<CodeDirectory, 0xfade0c02> {
168 typedef SHA1 Hash;
169 public:
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 in bytes
178 uint8_t hashType; // type of hash (cdHashType* 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
183
184 // works with the version field; see comments above
185 static const uint32_t currentVersion = 0x20100; // "version 2.1"
186 static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room"
187
188 static const uint32_t earliestVersion = 0x20001; // earliest supported version
189 static const uint32_t supportsScatter = 0x20100; // first version to support scatter option
190
191 void checkIntegrity() const; // throws if inconsistent or unsupported version
192
193 typedef int Slot; // slot index (negative for special slots)
194 typedef unsigned int SpecialSlot; // positive special slot index (not for code slots)
195
196 const char *identifier() const { return at<const char>(identOffset); }
197 char *identifier() { return at<char>(identOffset); }
198
199 unsigned char *operator [] (Slot slot)
200 {
201 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots));
202 return at<unsigned char>(hashOffset) + hashSize * slot;
203 }
204
205 const unsigned char *operator [] (Slot slot) const
206 {
207 assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots));
208 return at<unsigned char>(hashOffset) + hashSize * slot;
209 }
210
211 struct Scatter {
212 Endian<uint32_t> count; // number of pages; zero for sentinel (only)
213 Endian<uint32_t> base; // first page number
214 Endian<uint64_t> targetOffset; // offset in target
215 Endian<uint64_t> spare; // reserved
216 };
217 Scatter *scatterVector() // first scatter vector element (NULL if none)
218 { return (version >= supportsScatter && scatterOffset) ? at<Scatter>(scatterOffset) : NULL; }
219 const Scatter *scatterVector() const
220 { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; }
221
222 public:
223 bool validateSlot(const void *data, size_t size, Slot slot) const;
224 bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const;
225 bool slotIsPresent(Slot slot) const;
226
227 class Builder;
228
229 protected:
230 static size_t hash(UnixPlusPlus::FileDesc fd, Hash::Byte *digest, size_t limit = 0);
231 static size_t hash(const void *data, size_t length, Hash::Byte *digest);
232
233 public:
234 //
235 // Information about SpecialSlots
236 //
237 static const char *canonicalSlotName(SpecialSlot slot);
238 static unsigned slotAttributes(SpecialSlot slot);
239 IFDEBUG(static const char * const debugSlotName[]);
240 };
241
242
243 } // CodeSigning
244 } // Security
245
246
247 #endif //_H_CODEDIRECTORY