]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/SecStaticCode.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / SecStaticCode.cpp
1 /*
2 * Copyright (c) 2006-2007,2011-2015 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 // SecStaticCode - API frame for SecStaticCode objects
26 //
27 #include "cs.h"
28 #include "StaticCode.h"
29 #include <security_utilities/cfmunge.h>
30 #include <security_utilities/logging.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33
34 using namespace CodeSigning;
35
36
37 //
38 // CF-standard type code function
39 //
40 CFTypeID SecStaticCodeGetTypeID(void)
41 {
42 BEGIN_CSAPI
43 return gCFObjects().StaticCode.typeID;
44 END_CSAPI1(_kCFRuntimeNotATypeID)
45 }
46
47
48 //
49 // Create an StaticCode directly from disk path.
50 //
51 OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
52 {
53 BEGIN_CSAPI
54
55 checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
56 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str()), flags))->handle();
57
58 END_CSAPI
59 }
60
61 const CFStringRef kSecCodeAttributeArchitecture = CFSTR("architecture");
62 const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture");
63 const CFStringRef kSecCodeAttributeBundleVersion = CFSTR("bundleversion");
64 const CFStringRef kSecCodeAttributeUniversalFileOffset = CFSTR("UniversalFileOffset");
65
66 OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
67 SecStaticCodeRef *staticCodeRef)
68 {
69 BEGIN_CSAPI
70
71 checkFlags(flags, kSecCSForceOnlineNotarizationCheck);
72 DiskRep::Context ctx;
73 std::string version; // holds memory placed into ctx
74 if (attributes) {
75 std::string archName;
76 int archNumber, subarchNumber, offset;
77 if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeUniversalFileOffset, &offset)) {
78 ctx.offset = offset;
79 } else if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) {
80 ctx.arch = Architecture(archName.c_str());
81 } else if (cfscan(attributes, "{%O=%d,%O=%d}",
82 kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber))
83 ctx.arch = Architecture(archNumber, subarchNumber);
84 else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber))
85 ctx.arch = Architecture(archNumber);
86 if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version))
87 ctx.version = version.c_str();
88 }
89
90 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx), flags))->handle();
91
92 END_CSAPI
93 }
94
95
96 //
97 // Check static validity of a StaticCode
98 //
99 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
100 SecRequirementRef requirementRef)
101 {
102 return SecStaticCodeCheckValidityWithErrors(staticCodeRef, flags, requirementRef, NULL);
103 }
104
105 OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
106 SecRequirementRef requirementRef, CFErrorRef *errors)
107 {
108 BEGIN_CSAPI
109
110 checkFlags(flags,
111 kSecCSReportProgress
112 | kSecCSCheckAllArchitectures
113 | kSecCSDoNotValidateExecutable
114 | kSecCSDoNotValidateResources
115 | kSecCSConsiderExpiration
116 | kSecCSEnforceRevocationChecks
117 | kSecCSNoNetworkAccess
118 | kSecCSCheckNestedCode
119 | kSecCSStrictValidate
120 | kSecCSStrictValidateStructure
121 | kSecCSRestrictSidebandData
122 | kSecCSCheckGatekeeperArchitectures
123 | kSecCSRestrictSymlinks
124 | kSecCSRestrictToAppLike
125 | kSecCSUseSoftwareSigningCert
126 | kSecCSValidatePEH
127 | kSecCSSingleThreaded
128 | kSecCSApplyEmbeddedPolicy
129 | kSecCSSkipRootVolumeExceptions
130 | kSecCSSkipXattrFiles
131 );
132
133 if (errors)
134 flags |= kSecCSFullReport; // internal-use flag
135
136 #if !TARGET_OS_OSX
137 flags |= kSecCSApplyEmbeddedPolicy;
138 #endif
139
140 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
141 code->setValidationFlags(flags);
142 const SecRequirement *req = SecRequirement::optional(requirementRef);
143 DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
144 code->staticValidate(flags, req);
145
146 // Everything checked out correctly but we need to make sure that when
147 // we validated the code directory, we trusted the signer. We defer this
148 // until now because the caller may still trust the signer via a
149 // provisioning profile so if we prematurely throw an error when validating
150 // the directory, we potentially skip resource validation even though the
151 // caller will go on to trust the signature
152 // <rdar://problem/6075501> Applications that are validated against a provisioning profile do not have their resources checked
153 if ((flags & kSecCSApplyEmbeddedPolicy) && code->trustedSigningCertChain() == false) {
154 return CSError::cfError(errors, errSecCSSignatureUntrusted);
155 }
156
157
158 END_CSAPI_ERRORS
159 }
160
161
162 //
163 // ====================================================================================
164 //
165 // The following API functions are called SecCode* but accept both SecCodeRef and
166 // SecStaticCodeRef arguments, operating on the implied SecStaticCodeRef as appropriate.
167 // Hence they're here, rather than in SecCode.cpp.
168 //
169
170
171 //
172 // Retrieve location information for an StaticCode.
173 //
174 OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURLRef *path)
175 {
176 BEGIN_CSAPI
177
178 checkFlags(flags);
179 SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
180 CodeSigning::Required(path) = staticCode->copyCanonicalPath();
181
182 END_CSAPI
183 }
184
185
186 //
187 // Fetch or make up a designated requirement
188 //
189 OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
190 SecRequirementRef *requirementRef)
191 {
192 BEGIN_CSAPI
193
194 checkFlags(flags);
195 const Requirement *req =
196 SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement();
197 CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle();
198
199 END_CSAPI
200 }
201
202
203 //
204 // Fetch a particular internal requirement, if present
205 //
206 OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
207 SecCSFlags flags, SecRequirementRef *requirementRef)
208 {
209 BEGIN_CSAPI
210
211 checkFlags(flags);
212 const Requirement *req =
213 SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
214 CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
215
216 END_CSAPI
217 }
218
219
220 //
221 // Record for future use a detached code signature.
222 //
223 OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signature,
224 SecCSFlags flags)
225 {
226 BEGIN_CSAPI
227
228 checkFlags(flags);
229 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
230
231 code->detachedSignature(signature); // ... and pass it to the code
232 code->resetValidity();
233
234 END_CSAPI
235 }
236
237
238 //
239 // Attach a code signature to a kernel memory mapping for page-in validation.
240 //
241 OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags)
242 {
243 BEGIN_CSAPI
244
245 checkFlags(flags);
246 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
247 if (const CodeDirectory *cd = code->codeDirectory(false)) {
248 if (code->isDetached()) {
249 // Detached signatures need to attach their code directory from memory.
250 fsignatures args = { static_cast<off_t>(code->diskRep()->signingBase()), (void *)cd, cd->length() };
251 UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args));
252 } else {
253 // All other signatures can simply point to the signature in the main executable.
254 Universal *execImage = code->diskRep()->mainExecutableImage();
255 if (execImage == NULL) {
256 MacOSError::throwMe(errSecCSNoMainExecutable);
257 }
258
259 unique_ptr<MachO> arch(execImage->architecture());
260 if (arch.get() == NULL) {
261 MacOSError::throwMe(errSecCSNoMainExecutable);
262 }
263
264 size_t signatureOffset = arch->signingOffset();
265 size_t signatureLength = arch->signingLength();
266 if (signatureOffset == 0) {
267 MacOSError::throwMe(errSecCSUnsigned);
268 }
269
270 fsignatures args = {
271 static_cast<off_t>(code->diskRep()->signingBase()),
272 (void *)signatureOffset,
273 signatureLength,
274 };
275 UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDFILESIGS, &args));
276 }
277 } else {
278 MacOSError::throwMe(errSecCSUnsigned);
279 }
280
281 END_CSAPI
282 }
283
284
285 //
286 // Attach a callback block to a code object
287 //
288 OSStatus SecStaticCodeSetCallback(SecStaticCodeRef codeRef, SecCSFlags flags, SecCodeCallback *old, SecCodeCallback monitor)
289 {
290 BEGIN_CSAPI
291
292 checkFlags(flags);
293 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
294 if (old)
295 *old = code->monitor();
296 code->setMonitor(monitor);
297
298 END_CSAPI
299 }
300
301
302 OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef, CFDictionaryRef conditions)
303 {
304 BEGIN_CSAPI
305
306 checkFlags(0);
307 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
308 code->setValidationModifiers(conditions);
309
310 END_CSAPI
311 }
312
313
314 //
315 // Set cancellation flag on a static code object.
316 //
317 OSStatus SecStaticCodeCancelValidation(SecStaticCodeRef codeRef, SecCSFlags flags)
318 {
319 BEGIN_CSAPI
320
321 checkFlags(0);
322 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
323 code->cancelValidation();
324
325 END_CSAPI
326 }
327
328
329 //
330 // Retrieve a component object for a special slot directly.
331 //
332 CFDataRef SecCodeCopyComponent(SecCodeRef codeRef, int slot, CFDataRef hash)
333 {
334 BEGIN_CSAPI
335
336 SecStaticCode* code = SecStaticCode::requiredStatic(codeRef);
337 return code->copyComponent(slot, hash);
338
339 END_CSAPI1(NULL)
340 }
341
342
343 //
344 // Validate a single plain file's resource seal against a memory copy.
345 // This will fail for any other file type (symlink, directory, nested code, etc. etc.)
346 //
347 OSStatus SecCodeValidateFileResource(SecStaticCodeRef codeRef, CFStringRef relativePath, CFDataRef fileData, SecCSFlags flags)
348 {
349 BEGIN_CSAPI
350
351 checkFlags(0);
352 if (fileData == NULL)
353 MacOSError::throwMe(errSecCSObjectRequired);
354 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
355 code->validatePlainMemoryResource(cfString(relativePath), fileData, flags);
356
357 END_CSAPI
358
359 }