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