]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2006-2007,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 | ||
427c49bc | 43 | class ResourceBuilder; |
e3d460c9 | 44 | class SecCodeSigner; |
427c49bc | 45 | |
b1ab9ed8 A |
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 | ||
80e23899 A |
57 | typedef std::set<OSStatus> ToleratedErrors; |
58 | ||
b1ab9ed8 A |
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 | |
80e23899 | 66 | virtual CFURLRef copyCanonicalPath() = 0; // path to whole code |
b1ab9ed8 A |
67 | virtual std::string resourcesRootPath(); // resource directory if any [none] |
68 | virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change] | |
e3d460c9 | 69 | virtual void prepareForSigning(SigningContext& context); // pre-adjust signing defaults before argument preparation [none] |
b1ab9ed8 A |
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 | |
866f8763 A |
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 | ||
b1ab9ed8 A |
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) | |
fa7225c8 | 83 | virtual CFDictionaryRef diskRepInformation(); // information from diskrep |
b1ab9ed8 | 84 | |
79b9da22 A |
85 | virtual void registerStapledTicket(); |
86 | ||
b1ab9ed8 A |
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] | |
80e23899 | 93 | |
e3d460c9 | 94 | virtual void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags); // perform strict validation |
b54c578e | 95 | virtual void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { }; // perform structural strict validation |
80e23899 A |
96 | virtual CFArrayRef allowedResourceOmissions(); // allowed (default) resource omission rules |
97 | ||
79b9da22 A |
98 | virtual bool appleInternalForcePlatform() const {return false;}; |
99 | ||
b1ab9ed8 | 100 | bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; } |
d8f41ccd | 101 | |
b1ab9ed8 | 102 | // shorthands |
b1ab9ed8 A |
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 { | |
80e23899 | 112 | Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { } |
b1ab9ed8 A |
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 | |
80e23899 | 118 | size_t size; // size of this mach-o slice |
b1ab9ed8 A |
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; | |
427c49bc | 140 | virtual SecCSFlags signingFlags() const = 0; |
e3d460c9 A |
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 | } | |
b1ab9ed8 A |
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 | ||
dbe77505 A |
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 | }; | |
b1ab9ed8 A |
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); } | |
e3d460c9 A |
213 | void codeDirectory(const CodeDirectory *cd, CodeDirectory::SpecialSlot slot) |
214 | { component(slot, CFTempData(cd->data(), cd->length())); } | |
79b9da22 A |
215 | |
216 | #if TARGET_OS_OSX | |
217 | bool getPreserveAFSC() { return mPreserveAFSC; } | |
218 | void setPreserveAFSC(bool flag) { mPreserveAFSC = flag; } | |
219 | #endif | |
220 | ||
b1ab9ed8 A |
221 | private: |
222 | Architecture mArch; | |
223 | uint32_t mAttributes; | |
79b9da22 A |
224 | #if TARGET_OS_OSX |
225 | bool mPreserveAFSC = false; // preserve AFSC compression | |
226 | #endif | |
b1ab9ed8 A |
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(); } | |
80e23899 | 256 | CFURLRef copyCanonicalPath() { return mOriginal->copyCanonicalPath(); } |
b1ab9ed8 A |
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(); } | |
866f8763 A |
262 | size_t execSegBase(const Architecture *arch) { return mOriginal->execSegBase(arch); } |
263 | size_t execSegLimit(const Architecture *arch) { return mOriginal->execSegLimit(arch); } | |
b1ab9ed8 A |
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); } | |
d8f41ccd A |
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 | ||
e3d460c9 | 277 | void strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidate(cd, tolerated, flags); } |
b54c578e | 278 | void strictValidateStructure(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags) { mOriginal->strictValidateStructure(cd, tolerated, flags); } |
d8f41ccd | 279 | CFArrayRef allowedResourceOmissions() { return mOriginal->allowedResourceOmissions(); } |
b1ab9ed8 A |
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 |