2 * Copyright (c) 2006-2007 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>
33 using namespace CodeSigning
;
37 // CF-standard type code function
39 CFTypeID
SecStaticCodeGetTypeID(void)
42 return gCFObjects().StaticCode
.typeID
;
43 END_CSAPI1(_kCFRuntimeNotATypeID
)
48 // Create an StaticCode directly from disk path.
50 OSStatus
SecStaticCodeCreateWithPath(CFURLRef path
, SecCSFlags flags
, SecStaticCodeRef
*staticCodeRef
)
55 CodeSigning::Required(staticCodeRef
) = (new SecStaticCode(DiskRep::bestGuess(cfString(path
).c_str())))->handle();
60 const CFStringRef kSecCodeAttributeArchitecture
= CFSTR("architecture");
61 const CFStringRef kSecCodeAttributeSubarchitecture
=CFSTR("subarchitecture");
62 const CFStringRef kSecCodeAttributeBundleVersion
= CFSTR("bundleversion");
64 OSStatus
SecStaticCodeCreateWithPathAndAttributes(CFURLRef path
, SecCSFlags flags
, CFDictionaryRef attributes
,
65 SecStaticCodeRef
*staticCodeRef
)
71 std::string version
; // holds memory placed into ctx
74 int archNumber
, subarchNumber
;
75 if (cfscan(attributes
, "{%O=%s}", kSecCodeAttributeArchitecture
, &archName
)) {
76 ctx
.arch
= Architecture(archName
.c_str());
77 } else if (cfscan(attributes
, "{%O=%d,%O=%d}",
78 kSecCodeAttributeArchitecture
, &archNumber
, kSecCodeAttributeSubarchitecture
, &subarchNumber
))
79 ctx
.arch
= Architecture(archNumber
, subarchNumber
);
80 else if (cfscan(attributes
, "{%O=%d}", kSecCodeAttributeArchitecture
, &archNumber
))
81 ctx
.arch
= Architecture(archNumber
);
82 if (cfscan(attributes
, "{%O=%s}", kSecCodeAttributeBundleVersion
, &version
))
83 ctx
.version
= version
.c_str();
86 CodeSigning::Required(staticCodeRef
) = (new SecStaticCode(DiskRep::bestGuess(cfString(path
).c_str(), &ctx
)))->handle();
93 // Check static validity of a StaticCode
95 static void validate(SecStaticCode
*code
, const SecRequirement
*req
, SecCSFlags flags
);
96 static void validateNested(string location
, const SecRequirement
*req
, SecCSFlags flags
, string exclude
= "/");
98 static void validate(SecStaticCode
*code
, const SecRequirement
*req
, SecCSFlags flags
)
101 code
->validateNonResourceComponents(); // also validates the CodeDirectory
102 if (!(flags
& kSecCSDoNotValidateExecutable
))
103 code
->validateExecutable();
104 if (!(flags
& kSecCSDoNotValidateResources
))
105 code
->validateResources();
107 code
->validateRequirement(req
->requirement(), errSecCSReqFailed
);
108 if (flags
& kSecCSCheckNestedCode
)
109 if (CFURLRef baseUrl
= code
->resourceBase()) {
110 // CFBundle has no orderly enumerator of these things, so this is somewhat ad-hoc.
111 // (It should be augmented by information in ResourceDirectory.)
112 string base
= cfString(baseUrl
) + "/";
113 validateNested(base
+ "Frameworks", req
, flags
);
114 validateNested(base
+ "SharedFrameworks", req
, flags
);
115 validateNested(base
+ "PlugIns", req
, flags
);
116 validateNested(base
+ "Plug-ins", req
, flags
);
117 validateNested(base
+ "XPCServices", req
, flags
);
118 validateNested(base
+ "MacOS", req
, flags
, code
->mainExecutablePath()); // helpers
120 } catch (CSError
&err
) {
121 if (Universal
*fat
= code
->diskRep()->mainExecutableImage()) // Mach-O
122 if (MachO
*mach
= fat
->architecture()) {
123 err
.augment(kSecCFErrorArchitecture
, CFTempString(mach
->architecture().displayName()));
127 } catch (const MacOSError
&err
) {
128 // add architecture information if we can get it
129 if (Universal
*fat
= code
->diskRep()->mainExecutableImage())
130 if (MachO
*mach
= fat
->architecture()) {
131 CFTempString
arch(mach
->architecture().displayName());
133 CSError::throwMe(err
.error
, kSecCFErrorArchitecture
, arch
);
135 // else just pass it on
140 static void validateNested(string location
, const SecRequirement
*req
, SecCSFlags flags
, string exclude
)
142 DIR *dir
= opendir(location
.c_str());
144 if (errno
== ENOENT
) // nothing there (okay)
146 UnixError::throwMe();
148 while (struct dirent
*dp
= readdir(dir
)) {
149 switch (dp
->d_type
) {
157 if (dp
->d_name
[0] == '.')
159 string path
= location
+ "/" + dp
->d_name
;
160 if (path
== exclude
) // main executable; skip
163 SecPointer
<SecStaticCode
> code
= new SecStaticCode(DiskRep::bestGuess(path
));
164 validate(code
, req
, flags
);
165 } catch (CSError
&err
) {
166 err
.augment(kSecCFErrorPath
, CFTempURL(path
));
174 OSStatus
SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
175 SecRequirementRef requirementRef
)
177 return SecStaticCodeCheckValidityWithErrors(staticCodeRef
, flags
, requirementRef
, NULL
);
180 OSStatus
SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
181 SecRequirementRef requirementRef
, CFErrorRef
*errors
)
186 kSecCSCheckAllArchitectures
187 | kSecCSDoNotValidateExecutable
188 | kSecCSDoNotValidateResources
189 | kSecCSConsiderExpiration
190 | kSecCSEnforceRevocationChecks
191 | kSecCSCheckNestedCode
);
193 SecPointer
<SecStaticCode
> code
= SecStaticCode::requiredStatic(staticCodeRef
);
194 const SecRequirement
*req
= SecRequirement::optional(requirementRef
);
195 DTRACK(CODESIGN_EVAL_STATIC
, code
, (char*)code
->mainExecutablePath().c_str());
196 if (flags
& kSecCSCheckAllArchitectures
) {
197 SecStaticCode::AllArchitectures
archs(code
);
198 while (SecPointer
<SecStaticCode
> scode
= archs())
199 validate(scode
, req
, flags
);
201 validate(code
, req
, flags
);
208 // ====================================================================================
210 // The following API functions are called SecCode* but accept both SecCodeRef and
211 // SecStaticCodeRef arguments, operating on the implied SecStaticCodeRef as appropriate.
212 // Hence they're here, rather than in SecCode.cpp.
217 // Retrieve location information for an StaticCode.
219 OSStatus
SecCodeCopyPath(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
, CFURLRef
*path
)
224 SecPointer
<SecStaticCode
> staticCode
= SecStaticCode::requiredStatic(staticCodeRef
);
225 CodeSigning::Required(path
) = staticCode
->canonicalPath();
232 // Fetch or make up a designated requirement
234 OSStatus
SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef
, SecCSFlags flags
,
235 SecRequirementRef
*requirementRef
)
240 const Requirement
*req
=
241 SecStaticCode::requiredStatic(staticCodeRef
)->designatedRequirement();
242 CodeSigning::Required(requirementRef
) = (new SecRequirement(req
))->handle();
249 // Fetch a particular internal requirement, if present
251 OSStatus
SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef
, SecRequirementType type
,
252 SecCSFlags flags
, SecRequirementRef
*requirementRef
)
257 const Requirement
*req
=
258 SecStaticCode::requiredStatic(staticCodeRef
)->internalRequirement(type
);
259 CodeSigning::Required(requirementRef
) = req
? (new SecRequirement(req
))->handle() : NULL
;
266 // Record for future use a detached code signature.
268 OSStatus
SecCodeSetDetachedSignature(SecStaticCodeRef codeRef
, CFDataRef signature
,
274 SecPointer
<SecStaticCode
> code
= SecStaticCode::requiredStatic(codeRef
);
277 CFRetain(signature
); // own a reference...
278 code
->detachedSignature(signature
); // ... and pass it to the code
279 code
->resetValidity();
286 // Attach a code signature to a kernel memory mapping for page-in validation.
288 OSStatus
SecCodeMapMemory(SecStaticCodeRef codeRef
, SecCSFlags flags
)
293 SecPointer
<SecStaticCode
> code
= SecStaticCode::requiredStatic(codeRef
);
294 if (const CodeDirectory
*cd
= code
->codeDirectory(false)) {
295 fsignatures args
= { code
->diskRep()->signingBase(), (void *)cd
, cd
->length() };
296 UnixError::check(::fcntl(code
->diskRep()->fd(), F_ADDSIGS
, &args
));
298 MacOSError::throwMe(errSecCSUnsigned
);