1/*
2 * Copyright (c) 2006-2007 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
40namespace Security {
41namespace CodeSigning {
42
43class ResourceBuilder;
44
45
46//
47// DiskRep is an abstract interface to code somewhere located by
48// a file system path. It presents the ability to read and write
49// Code Signing-related information about such code without exposing
50// the details of the storage locations or formats.
51//
52class DiskRep : public RefCount {
53public:
54	class SigningContext;
55
56	typedef std::set<OSStatus> ToleratedErrors;
57
58public:
59	DiskRep();
60	virtual ~DiskRep();
61	virtual DiskRep *base();
62	virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component
63	virtual CFDataRef identification() = 0;					// binary lookup identifier
64	virtual std::string mainExecutablePath() = 0;			// path to main executable
65	virtual CFURLRef copyCanonicalPath() = 0;					// path to whole code
66	virtual std::string resourcesRootPath();				// resource directory if any [none]
67	virtual void adjustResources(ResourceBuilder &builder);	// adjust resource rule set [no change]
68	virtual Universal *mainExecutableImage();				// Mach-O image if Mach-O based [null]
69	virtual size_t signingBase();							// start offset of signed area in main executable [zero]
70	virtual size_t signingLimit() = 0;						// size of signed area in main executable
71	virtual std::string format() = 0;						// human-readable type string
72	virtual CFArrayRef modifiedFiles();						// list of files modified by signing [main execcutable only]
73	virtual UnixPlusPlus::FileDesc &fd() = 0;				// a cached file descriptor for main executable file
74	virtual void flush();									// flush caches (refetch as needed)
75
76	// default values for signing operations
77	virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier
78	virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none]
79	virtual const Requirements *defaultRequirements(const Architecture *arch,
80		const SigningContext &ctx);							// default internal requirements [none]
81	virtual size_t pageSize(const SigningContext &ctx);		// default main executable page size [infinite, i.e. no paging]
82
83	virtual void strictValidate(const ToleratedErrors& tolerated); // perform strict validation
84	virtual CFArrayRef allowedResourceOmissions();			// allowed (default) resource omission rules
85
86	bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; }
87
88	// shorthands
89	CFDataRef codeDirectory()	{ return component(cdCodeDirectorySlot); }
90	CFDataRef signature()		{ return component(cdSignatureSlot); }
91
92public:
93	class Writer;
94	virtual Writer *writer();								// Writer factory
95
96public:
97	// optional information that might be used to create a suitable DiskRep. All optional
98	struct Context {
99		Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { }
100		Architecture arch;			// explicit architecture (choose amongst universal variants)
101		const char *version;		// bundle version (string)
102		off_t offset;				// explicit file offset
103		bool fileOnly;				// only consider single-file representations (no bundles etc.)
104		const void *inMemory;		// consider using in-memory copy at this address
105		size_t size;				// size of this mach-o slice
106	};
107
108	static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path
109	static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly
110	static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only
111
112	// versions using std::string paths (merely a convenience)
113	static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL)
114		{ return bestGuess(path.c_str(), ctx); }
115	static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); }
116	static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); }
117
118public:
119	// see DiskRep::Writer docs for why this is here
120	class SigningContext {
121	protected:
122		SigningContext() { }
123
124	public:
125		virtual std::string sdkPath(const std::string &path) const = 0;
126		virtual bool isAdhoc() const = 0;
127		virtual SecCSFlags signingFlags() const = 0;
128	};
129
130protected:
131	// canonically derive a suggested signing identifier from some string
132	static std::string canonicalIdentifier(const std::string &name);
133
134public:
135	static const size_t segmentedPageSize = 4096;	// default page size for system-paged signatures
136	static const size_t monolithicPageSize = 0;		// default page size for non-Mach-O executables
137};
138
139
140//
141// Write-access objects.
142// At this layer they are quite abstract, carrying just the functionality needed
143// for the signing machinery to place data wherever it should go. Each DiskRep subclass
144// that supports writing signing data to a place inside the code needs to implement
145// a subclass of Writer and return an instance in the DiskRep::writer() method when asked.
146//
147// The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code,
148// which is handled as a special case. This means that not all Writer subclass objects were made
149// by DiskRep::writer, and it is unwise to assume so.
150//
151// Note that the methods that provide defaults for signing operations are in DiskRep rather
152// than here. That's because writers abstract data *sending*, and are virtual on management
153// of stored data, while DiskRep is virtual on the existing code object, which is where
154// we get our defaults from.
155//
156class DiskRep::Writer : public RefCount {
157public:
158	Writer(uint32_t attrs = 0);
159	virtual ~Writer();
160	virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0;
161	virtual uint32_t attributes() const;
162	virtual void addDiscretionary(CodeDirectory::Builder &builder);
163	virtual void remove();
164	virtual void flush();
165
166	bool attribute(uint32_t attr) const		{ return mAttributes & attr; }
167
168	void signature(CFDataRef data)			{ component(cdSignatureSlot, data); }
169	void codeDirectory(const CodeDirectory *cd)
170		{ component(cdCodeDirectorySlot, CFTempData(cd->data(), cd->length())); }
171
172private:
173	Architecture mArch;
174	uint32_t mAttributes;
175};
176
177//
178// Writer attributes. Defaults should be off-bits.
179//
180enum {
181	writerLastResort = 0x0001,			// prefers not to store attributes itself
182	writerNoGlobal = 0x0002,			// has only per-architecture storage
183};
184
185
186//
187// A prefix DiskRep that filters (only) signature-dependent behavior and passes
188// all code-dependent behavior off to an underlying (different) DiskRep.
189// FilterRep subclasses are typically "stacked" on top of their base DiskRep, and
190// then used in their place.
191//
192class FilterRep : public DiskRep {
193public:
194	FilterRep(DiskRep *orig) : mOriginal(orig) { }
195
196	DiskRep *base()							{ return mOriginal; }
197
198	// things that look at signature components are filtered
199	CFDataRef component(CodeDirectory::SpecialSlot slot) = 0;
200
201	// the rest of the virtual behavior devolves on the original DiskRep
202	CFDataRef identification()				{ return mOriginal->identification(); }
203	std::string mainExecutablePath()		{ return mOriginal->mainExecutablePath(); }
204	CFURLRef copyCanonicalPath()			{ return mOriginal->copyCanonicalPath(); }
205	std::string resourcesRootPath()			{ return mOriginal->resourcesRootPath(); }
206	void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); }
207	Universal *mainExecutableImage()		{ return mOriginal->mainExecutableImage(); }
208	size_t signingBase()					{ return mOriginal->signingBase(); }
209	size_t signingLimit()					{ return mOriginal->signingLimit(); }
210	std::string format()					{ return mOriginal->format(); }
211	CFArrayRef modifiedFiles()				{ return mOriginal->modifiedFiles(); }
212	UnixPlusPlus::FileDesc &fd()			{ return mOriginal->fd(); }
213	void flush()							{ return mOriginal->flush(); }
214
215	std::string recommendedIdentifier(const SigningContext &ctx)
216		{ return mOriginal->recommendedIdentifier(ctx); }
217	CFDictionaryRef defaultResourceRules(const SigningContext &ctx)
218		{ return mOriginal->defaultResourceRules(ctx); }
219
220private:
221	RefPointer<DiskRep> mOriginal;			// underlying representation
222};
223
224
225} // end namespace CodeSigning
226} // end namespace Security
227
228#endif // !_H_DISKREP
229