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