diskrep.h
  1  /*
  2   * Copyright (c) 2006-2007,2011-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  // diskrep - disk representations of code
 26  //
 27  #ifndef _H_DISKREP
 28  #define _H_DISKREP
 29  
 30  #include "cs.h"
 31  #include "codedirectory.h"
 32  #include "cdbuilder.h"
 33  #include "requirement.h"
 34  #include "resources.h"
 35  #include <security_utilities/macho++.h>		// for class Architecture
 36  #include <security_utilities/refcount.h>
 37  #include <security_utilities/superblob.h>
 38  #include <CoreFoundation/CFData.h>
 39  
 40  namespace Security {
 41  namespace CodeSigning {
 42  
 43  class ResourceBuilder;
 44  class SecCodeSigner;
 45  
 46  
 47  //
 48  // DiskRep is an abstract interface to code somewhere located by
 49  // a file system path. It presents the ability to read and write
 50  // Code Signing-related information about such code without exposing
 51  // the details of the storage locations or formats.
 52  //
 53  class DiskRep : public RefCount {
 54  public:
 55  	class SigningContext;
 56  	
 57  	typedef std::set<OSStatus> ToleratedErrors;
 58  	
 59  public:
 60  	DiskRep();
 61  	virtual ~DiskRep();
 62  	virtual DiskRep *base();
 63  	virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component
 64  	virtual CFDataRef identification() = 0;					// binary lookup identifier
 65  	virtual std::string mainExecutablePath() = 0;			// path to main executable
 66  	virtual CFURLRef copyCanonicalPath() = 0;					// path to whole code
 67  	virtual std::string resourcesRootPath();				// resource directory if any [none]
 68  	virtual void adjustResources(ResourceBuilder &builder);	// adjust resource rule set [no change]
 69  	virtual void prepareForSigning(SigningContext& context); // pre-adjust signing defaults before argument preparation [none]
 70  	virtual Universal *mainExecutableImage();				// Mach-O image if Mach-O based [null]
 71  	virtual size_t signingBase();							// start offset of signed area in main executable [zero]
 72  	virtual size_t signingLimit() = 0;						// size of signed area in main executable
 73  
 74  	// The executable segment, if present, denotes which part of the image can be mapped
 75  	// into a virtual address space as executable. Not all platforms check this.
 76  	virtual size_t execSegBase(const Architecture *arch);			// start offset of executable segment in main executable [zero]
 77  	virtual size_t execSegLimit(const Architecture *arch) = 0;		// size of executable segment in main executable
 78  
 79  	virtual std::string format() = 0;						// human-readable type string
 80  	virtual CFArrayRef modifiedFiles();						// list of files modified by signing [main execcutable only]
 81  	virtual UnixPlusPlus::FileDesc &fd() = 0;				// a cached file descriptor for main executable file
 82  	virtual void flush();									// flush caches (refetch as needed)
 83      virtual CFDictionaryRef copyDiskRepInformation();		// information from diskrep
 84  
 85  	virtual void registerStapledTicket();
 86  
 87  	// default values for signing operations
 88  	virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier
 89  	virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none]
 90  	virtual const Requirements *defaultRequirements(const Architecture *arch,
 91  		const SigningContext &ctx);							// default internal requirements [none]
 92  	virtual size_t pageSize(const SigningContext &ctx);		// default main executable page size [infinite, i.e. no paging]
 93  
 94  	virtual void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags); // perform strict validation
 95  	virtual void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { }; // perform structural strict validation
 96  	virtual CFArrayRef allowedResourceOmissions();			// allowed (default) resource omission rules
 97  
 98  	virtual bool appleInternalForcePlatform() const {return false;};
 99  
100  	bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; }
101  
102  	// shorthands
103  	CFDataRef signature()		{ return component(cdSignatureSlot); }
104  
105  public:
106  	class Writer;
107  	virtual Writer *writer();								// Writer factory
108  
109  public:
110  	// optional information that might be used to create a suitable DiskRep. All optional
111  	struct Context {
112  		Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { }
113  		Architecture arch;			// explicit architecture (choose amongst universal variants)
114  		const char *version;		// bundle version (string)
115  		off_t offset;				// explicit file offset
116  		bool fileOnly;				// only consider single-file representations (no bundles etc.)
117  		const void *inMemory;		// consider using in-memory copy at this address
118  		size_t size;				// size of this mach-o slice
119  	};
120  
121  	static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path
122  	static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly
123  	static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only
124  
125  	// versions using std::string paths (merely a convenience)
126  	static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL)
127  		{ return bestGuess(path.c_str(), ctx); }
128  	static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); }
129  	static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); }
130  
131  public:
132  	// see DiskRep::Writer docs for why this is here
133  	class SigningContext {
134  	protected:
135  		SigningContext() { }
136  
137  	public:
138  		virtual std::string sdkPath(const std::string &path) const = 0;
139  		virtual bool isAdhoc() const = 0;
140  		virtual SecCSFlags signingFlags() const = 0;
141  
142  		virtual const CodeDirectory::HashAlgorithms &digestAlgorithms() const = 0;
143  		virtual void setDigestAlgorithms(CodeDirectory::HashAlgorithms types) = 0;
144  		
145  		void setDigestAlgorithm(CodeDirectory::HashAlgorithm type)
146  		{
147  			CodeDirectory::HashAlgorithms types;
148  			types.insert(type);
149  			setDigestAlgorithms(types);
150  		}
151  	};
152  
153  protected:
154  	// canonically derive a suggested signing identifier from some string
155  	static std::string canonicalIdentifier(const std::string &name);
156  	
157  public:
158  	static const size_t segmentedPageSize = 4096;	// default page size for system-paged signatures
159  	static const size_t monolithicPageSize = 0;		// default page size for non-Mach-O executables
160  };
161  
162  /*
163   * Editable Disk Reps allow editing of their existing code signature.
164   * Specifically, they allow for individual components to be replaced,
165   * while preserving all other components.
166   * Lots of restrictions apply, e.g. machO signatures' superblobs may
167   * not change in size, and components covered by the code directory
168   * cannot be replaced without adjusting the code directory.
169   * Replacing or adding CMS blobs (having reserved enough size in the
170   * superblob beforehand) is the original reason this trait exists.
171   */
172  class EditableDiskRep {
173  public:
174  	typedef std::map<CodeDirectory::Slot, CFCopyRef<CFDataRef>> RawComponentMap;
175  	
176  	/* Return all components in raw form.
177  	 * Signature editing will add all the components obtained hereby
178  	 * back to their specific slots, though some of them may have
179  	 * been replaced in the map.
180  	 */
181  	virtual RawComponentMap createRawComponents() = 0;
182  };
183  
184  //
185  // Write-access objects.
186  // At this layer they are quite abstract, carrying just the functionality needed
187  // for the signing machinery to place data wherever it should go. Each DiskRep subclass
188  // that supports writing signing data to a place inside the code needs to implement
189  // a subclass of Writer and return an instance in the DiskRep::writer() method when asked.
190  //
191  // The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code,
192  // which is handled as a special case. This means that not all Writer subclass objects were made
193  // by DiskRep::writer, and it is unwise to assume so.
194  //
195  // Note that the methods that provide defaults for signing operations are in DiskRep rather
196  // than here. That's because writers abstract data *sending*, and are virtual on management
197  // of stored data, while DiskRep is virtual on the existing code object, which is where
198  // we get our defaults from.
199  //
200  class DiskRep::Writer : public RefCount {
201  public:
202  	Writer(uint32_t attrs = 0);
203  	virtual ~Writer();
204  	virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0;
205  	virtual uint32_t attributes() const;
206  	virtual void addDiscretionary(CodeDirectory::Builder &builder);
207  	virtual void remove();
208  	virtual void flush();
209  
210  	bool attribute(uint32_t attr) const		{ return mAttributes & attr; }
211  	
212  	void signature(CFDataRef data)			{ component(cdSignatureSlot, data); }
213  	void codeDirectory(const CodeDirectory *cd, CodeDirectory::SpecialSlot slot)
214  		{ component(slot, CFTempData(cd->data(), cd->length())); }
215  
216  #if TARGET_OS_OSX
217  	bool getPreserveAFSC()					{ return mPreserveAFSC; }
218  	void setPreserveAFSC(bool flag)			{ mPreserveAFSC = flag; }
219  #endif
220  
221  private:
222  	Architecture mArch;
223  	uint32_t mAttributes;
224  #if TARGET_OS_OSX
225  	bool mPreserveAFSC = false; // preserve AFSC compression
226  #endif
227  };
228  
229  //
230  // Writer attributes. Defaults should be off-bits.
231  //
232  enum {
233  	writerLastResort = 0x0001,			// prefers not to store attributes itself
234  	writerNoGlobal = 0x0002,			// has only per-architecture storage
235  };
236  
237  
238  //
239  // A prefix DiskRep that filters (only) signature-dependent behavior and passes
240  // all code-dependent behavior off to an underlying (different) DiskRep.
241  // FilterRep subclasses are typically "stacked" on top of their base DiskRep, and
242  // then used in their place.
243  //
244  class FilterRep : public DiskRep {
245  public:
246  	FilterRep(DiskRep *orig) : mOriginal(orig) { }
247  	
248  	DiskRep *base()							{ return mOriginal; }
249  	
250  	// things that look at signature components are filtered
251  	CFDataRef component(CodeDirectory::SpecialSlot slot) = 0;
252  
253  	// the rest of the virtual behavior devolves on the original DiskRep
254  	CFDataRef identification()				{ return mOriginal->identification(); }
255  	std::string mainExecutablePath()		{ return mOriginal->mainExecutablePath(); }
256  	CFURLRef copyCanonicalPath()			{ return mOriginal->copyCanonicalPath(); }
257  	std::string resourcesRootPath()			{ return mOriginal->resourcesRootPath(); }
258  	void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); }
259  	Universal *mainExecutableImage()		{ return mOriginal->mainExecutableImage(); }
260  	size_t signingBase()					{ return mOriginal->signingBase(); }
261  	size_t signingLimit()					{ return mOriginal->signingLimit(); }
262  	size_t execSegBase(const Architecture *arch)					{ return mOriginal->execSegBase(arch); }
263  	size_t execSegLimit(const Architecture *arch)					{ return mOriginal->execSegLimit(arch); }
264  	std::string format()					{ return mOriginal->format(); }
265  	CFArrayRef modifiedFiles()				{ return mOriginal->modifiedFiles(); }
266  	UnixPlusPlus::FileDesc &fd()			{ return mOriginal->fd(); }
267  	void flush()							{ return mOriginal->flush(); }
268  	
269  	std::string recommendedIdentifier(const SigningContext &ctx)
270  		{ return mOriginal->recommendedIdentifier(ctx); }
271  	CFDictionaryRef defaultResourceRules(const SigningContext &ctx)
272  		{ return mOriginal->defaultResourceRules(ctx); }
273  	const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx)
274  		{ return mOriginal->defaultRequirements(arch, ctx); }
275  	size_t pageSize(const SigningContext &ctx) { return mOriginal->pageSize(ctx); }
276  
277  	void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidate(cd, tolerated, flags); }
278  	void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidateStructure(cd, tolerated, flags); }
279  	CFArrayRef allowedResourceOmissions() { return mOriginal->allowedResourceOmissions(); }
280  
281  private:
282  	RefPointer<DiskRep> mOriginal;			// underlying representation
283  };
284  
285  
286  } // end namespace CodeSigning
287  } // end namespace Security
288  
289  #endif // !_H_DISKREP