]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/SecStaticCode.cpp
e56d188c0d4a53ffdaae59c52a0cdab86dedf28a
[apple/libsecurity_codesigning.git] / lib / SecStaticCode.cpp
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 // SecStaticCode - API frame for SecStaticCode objects
26 //
27 #include "cs.h"
28 #include "StaticCode.h"
29 #include <security_utilities/cfmunge.h>
30 #include <fcntl.h>
31
32 using namespace CodeSigning;
33
34
35 //
36 // CF-standard type code function
37 //
38 CFTypeID SecStaticCodeGetTypeID(void)
39 {
40 BEGIN_CSAPI
41 return gCFObjects().StaticCode.typeID;
42 END_CSAPI1(_kCFRuntimeNotATypeID)
43 }
44
45
46 //
47 // Create an StaticCode directly from disk path.
48 //
49 OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCodeRef)
50 {
51 BEGIN_CSAPI
52
53 checkFlags(flags);
54 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str())))->handle();
55
56 END_CSAPI
57 }
58
59 const CFStringRef kSecCodeAttributeArchitecture = CFSTR("architecture");
60 const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture");
61 const CFStringRef kSecCodeAttributeBundleVersion = CFSTR("bundleversion");
62
63 OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
64 SecStaticCodeRef *staticCodeRef)
65 {
66 BEGIN_CSAPI
67
68 checkFlags(flags);
69 DiskRep::Context ctx;
70 std::string version; // holds memory placed into ctx
71 if (attributes) {
72 std::string archName;
73 int archNumber, subarchNumber;
74 if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) {
75 ctx.arch = Architecture(archName.c_str());
76 } else if (cfscan(attributes, "{%O=%d,%O=%d}",
77 kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber))
78 ctx.arch = Architecture(archNumber, subarchNumber);
79 else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber))
80 ctx.arch = Architecture(archNumber);
81 if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version))
82 ctx.version = version.c_str();
83 }
84
85 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx)))->handle();
86
87 END_CSAPI
88 }
89
90
91 //
92 // Check static validity of a StaticCode
93 //
94 static void validate(SecStaticCode *code, const SecRequirement *req, SecCSFlags flags)
95 {
96 try {
97 code->validateDirectory();
98 if (!(flags & kSecCSDoNotValidateExecutable))
99 code->validateExecutable();
100 if (!(flags & kSecCSDoNotValidateResources))
101 code->validateResources();
102 if (req)
103 code->validateRequirement(req->requirement(), errSecCSReqFailed);
104 } catch (CSError &err) {
105 if (Universal *fat = code->diskRep()->mainExecutableImage()) // Mach-O
106 if (MachO *mach = fat->architecture()) {
107 err.augment(kSecCFErrorArchitecture, CFTempString(mach->architecture().displayName()));
108 delete mach;
109 }
110 throw;
111 } catch (const MacOSError &err) {
112 // add architecture information if we can get it
113 if (Universal *fat = code->diskRep()->mainExecutableImage())
114 if (MachO *mach = fat->architecture()) {
115 CFTempString arch(mach->architecture().displayName());
116 delete mach;
117 CSError::throwMe(err.error, kSecCFErrorArchitecture, arch);
118 }
119 // else just pass it on
120 throw;
121 }
122 }
123
124 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
125 SecRequirementRef requirementRef)
126 {
127 return SecStaticCodeCheckValidityWithErrors(staticCodeRef, flags, requirementRef, NULL);
128 }
129
130 OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
131 SecRequirementRef requirementRef, CFErrorRef *errors)
132 {
133 BEGIN_CSAPI
134
135 checkFlags(flags,
136 kSecCSCheckAllArchitectures
137 | kSecCSDoNotValidateExecutable
138 | kSecCSDoNotValidateResources
139 | kSecCSConsiderExpiration);
140
141 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
142 const SecRequirement *req = SecRequirement::optional(requirementRef);
143 DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
144 if (flags & kSecCSCheckAllArchitectures) {
145 SecStaticCode::AllArchitectures archs(code);
146 while (SecPointer<SecStaticCode> scode = archs())
147 validate(scode, req, flags);
148 } else
149 validate(code, req, flags);
150
151 END_CSAPI_ERRORS
152 }
153
154
155 //
156 // ====================================================================================
157 //
158 // The following API functions are called SecCode* but accept both SecCodeRef and
159 // SecStaticCodeRef arguments, operating on the implied SecStaticCodeRef as appropriate.
160 // Hence they're here, rather than in SecCode.cpp.
161 //
162
163
164 //
165 // Retrieve location information for an StaticCode.
166 //
167 OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURLRef *path)
168 {
169 BEGIN_CSAPI
170
171 checkFlags(flags);
172 SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
173 CodeSigning::Required(path) = staticCode->canonicalPath();
174
175 END_CSAPI
176 }
177
178
179 //
180 // Fetch or make up a designated requirement
181 //
182 OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
183 SecRequirementRef *requirementRef)
184 {
185 BEGIN_CSAPI
186
187 checkFlags(flags);
188 const Requirement *req =
189 SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement();
190 CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle();
191
192 END_CSAPI
193 }
194
195
196 //
197 // Fetch a particular internal requirement, if present
198 //
199 OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
200 SecCSFlags flags, SecRequirementRef *requirementRef)
201 {
202 BEGIN_CSAPI
203
204 checkFlags(flags);
205 const Requirement *req =
206 SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
207 CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
208
209 END_CSAPI
210 }
211
212
213 //
214 // Record for future use a detached code signature.
215 //
216 OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signature,
217 SecCSFlags flags)
218 {
219 BEGIN_CSAPI
220
221 checkFlags(flags);
222 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
223
224 if (signature)
225 CFRetain(signature); // own a reference...
226 code->detachedSignature(signature); // ... and pass it to the code
227 code->resetValidity();
228
229 END_CSAPI
230 }
231
232
233 //
234 // Attach a code signature to a kernel memory mapping for page-in validation.
235 //
236 OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags)
237 {
238 BEGIN_CSAPI
239
240 checkFlags(flags);
241 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
242 if (const CodeDirectory *cd = code->codeDirectory(false)) {
243 fsignatures args = { code->diskRep()->signingBase(), (void *)cd, cd->length() };
244 UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args));
245 } else
246 MacOSError::throwMe(errSecCSUnsigned);
247
248 END_CSAPI
249 }