2 * Copyright (c) 2006-2007,2011-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // SecStaticCode - API frame for SecStaticCode objects
28 #include "StaticCode.h"
29 #include <security_utilities/cfmunge.h>
30 #include <security_utilities/logging.h>
34 using namespace CodeSigning
;
38 // CF-standard type code function
40 CFTypeID
SecStaticCodeGetTypeID(void)
43 return gCFObjects().StaticCode
.typeID
;
44 END_CSAPI1(_kCFRuntimeNotATypeID
)
49 // Create an StaticCode directly from disk path.
51 OSStatus
SecStaticCodeCreateWithPath(CFURLRef path
, SecCSFlags flags
, SecStaticCodeRef
*staticCodeRef
)
55 checkFlags(flags
, kSecCSForceOnlineNotarizationCheck
);
56 CodeSigning::Required(staticCodeRef
) = (new SecStaticCode(DiskRep::bestGuess(cfString(path
).c_str()), flags
))->handle();
61 const CFStringRef kSecCodeAttributeArchitecture
= CFSTR("architecture");
62 const CFStringRef kSecCodeAttributeSubarchitecture
=CFSTR("subarchitecture");
63 const CFStringRef kSecCodeAttributeBundleVersion
= CFSTR("bundleversion");
64 const CFStringRef kSecCodeAttributeUniversalFileOffset
= CFSTR("UniversalFileOffset");
66 OSStatus
SecStaticCodeCreateWithPathAndAttributes(CFURLRef path
, SecCSFlags flags
, CFDictionaryRef attributes
,
67 SecStaticCodeRef
*staticCodeRef
)
71 checkFlags(flags
, kSecCSForceOnlineNotarizationCheck
);
73 std::string version
; // holds memory placed into ctx
76 int archNumber
, subarchNumber
, offset
;
77 if (cfscan(attributes
, "{%O=%d}", kSecCodeAttributeUniversalFileOffset
, &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();
90 CodeSigning::Required(staticCodeRef
) = (new SecStaticCode(DiskRep::bestGuess(cfString(path
).c_str(), &ctx
), flags
))->handle();
97 // Check static validity of a StaticCode
99 OSStatus
SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
100 SecRequirementRef requirementRef
)
102 return SecStaticCodeCheckValidityWithErrors(staticCodeRef
, flags
, requirementRef
, NULL
);
105 OSStatus
SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
106 SecRequirementRef requirementRef
, CFErrorRef
*errors
)
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
127 | kSecCSSingleThreaded
128 | kSecCSApplyEmbeddedPolicy
129 | kSecCSSkipRootVolumeExceptions
130 | kSecCSSkipXattrFiles
134 flags
|= kSecCSFullReport
; // internal-use flag
137 flags
|= kSecCSApplyEmbeddedPolicy
;
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
);
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
);
163 // ====================================================================================
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.
172 // Retrieve location information for an StaticCode.
174 OSStatus
SecCodeCopyPath(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
, CFURLRef
*path
)
179 SecPointer
<SecStaticCode
> staticCode
= SecStaticCode::requiredStatic(staticCodeRef
);
180 CodeSigning::Required(path
) = staticCode
->copyCanonicalPath();
187 // Fetch or make up a designated requirement
189 OSStatus
SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
190 SecRequirementRef
*requirementRef
)
195 const Requirement
*req
=
196 SecStaticCode::requiredStatic(staticCodeRef
)->designatedRequirement();
197 CodeSigning::Required(requirementRef
) = (new SecRequirement(req
))->handle();
204 // Fetch a particular internal requirement, if present
206 OSStatus
SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef
, SecRequirementType type
,
207 SecCSFlags flags
, SecRequirementRef
*requirementRef
)
212 const Requirement
*req
=
213 SecStaticCode::requiredStatic(staticCodeRef
)->internalRequirement(type
);
214 CodeSigning::Required(requirementRef
) = req
? (new SecRequirement(req
))->handle() : NULL
;
221 // Record for future use a detached code signature.
223 OSStatus
SecCodeSetDetachedSignature(SecStaticCodeRef codeRef
, CFDataRef signature
,
229 SecPointer
<SecStaticCode
> code
= SecStaticCode::requiredStatic(codeRef
);
231 code
->detachedSignature(signature
); // ... and pass it to the code
232 code
->resetValidity();
239 // Attach a code signature to a kernel memory mapping for page-in validation.
241 OSStatus
SecCodeMapMemory(SecStaticCodeRef codeRef
, SecCSFlags 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
));
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
);
259 unique_ptr
<MachO
> arch(execImage
->architecture());
260 if (arch
.get() == NULL
) {
261 MacOSError::throwMe(errSecCSNoMainExecutable
);
264 size_t signatureOffset
= arch
->signingOffset();
265 size_t signatureLength
= arch
->signingLength();
266 if (signatureOffset
== 0) {
267 MacOSError::throwMe(errSecCSUnsigned
);
271 static_cast<off_t
>(code
->diskRep()->signingBase()),
272 (void *)signatureOffset
,
275 UnixError::check(::fcntl(code
->diskRep()->fd(), F_ADDFILESIGS
, &args
));
278 MacOSError::throwMe(errSecCSUnsigned
);
286 // Attach a callback block to a code object
288 OSStatus
SecStaticCodeSetCallback(SecStaticCodeRef codeRef
, SecCSFlags flags
, SecCodeCallback
*old
, SecCodeCallback monitor
)
293 SecStaticCode
*code
= SecStaticCode::requiredStatic(codeRef
);
295 *old
= code
->monitor();
296 code
->setMonitor(monitor
);
302 OSStatus
SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef
, CFDictionaryRef conditions
)
307 SecStaticCode
*code
= SecStaticCode::requiredStatic(codeRef
);
308 code
->setValidationModifiers(conditions
);
315 // Set cancellation flag on a static code object.
317 OSStatus
SecStaticCodeCancelValidation(SecStaticCodeRef codeRef
, SecCSFlags flags
)
322 SecStaticCode
*code
= SecStaticCode::requiredStatic(codeRef
);
323 code
->cancelValidation();
330 // Retrieve a component object for a special slot directly.
332 CFDataRef
SecCodeCopyComponent(SecCodeRef codeRef
, int slot
, CFDataRef hash
)
336 SecStaticCode
* code
= SecStaticCode::requiredStatic(codeRef
);
337 return code
->copyComponent(slot
, hash
);
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.)
347 OSStatus
SecCodeValidateFileResource(SecStaticCodeRef codeRef
, CFStringRef relativePath
, CFDataRef fileData
, SecCSFlags flags
)
352 if (fileData
== NULL
)
353 MacOSError::throwMe(errSecCSObjectRequired
);
354 SecStaticCode
*code
= SecStaticCode::requiredStatic(codeRef
);
355 code
->validatePlainMemoryResource(cfString(relativePath
), fileData
, flags
);