]>
Commit | Line | Data |
---|---|---|
7d31e928 A |
1 | /* |
2 | * Copyright (c) 2006 Apple Computer, 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 | // SecRequirement - API frame for SecRequirement objects | |
26 | // | |
27 | #include "cs.h" | |
28 | #include "Requirements.h" | |
29 | #include "reqparser.h" | |
30 | #include "reqmaker.h" | |
31 | #include "reqdumper.h" | |
32 | #include <Security/SecCertificate.h> | |
33 | #include <security_utilities/cfutilities.h> | |
34 | ||
35 | using namespace CodeSigning; | |
36 | ||
37 | ||
38 | // | |
39 | // CF-standard type code function | |
40 | // | |
41 | CFTypeID SecRequirementGetTypeID(void) | |
42 | { | |
43 | BEGIN_CSAPI | |
44 | return gCFObjects().Requirement.typeID; | |
45 | END_CSAPI1(_kCFRuntimeNotATypeID) | |
46 | } | |
47 | ||
48 | ||
49 | // | |
50 | // Create a Requirement from data | |
51 | // | |
52 | OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags, | |
53 | SecRequirementRef *requirementRef) | |
54 | { | |
55 | BEGIN_CSAPI | |
56 | ||
57 | checkFlags(flags); | |
f60086fc | 58 | CodeSigning::Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle(); |
7d31e928 A |
59 | |
60 | END_CSAPI | |
61 | } | |
62 | ||
63 | ||
64 | // | |
65 | // Create a Requirement from data in a file | |
66 | // | |
67 | OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags, | |
68 | SecRequirementRef *requirementRef) | |
69 | { | |
70 | BEGIN_CSAPI | |
71 | ||
72 | checkFlags(flags); | |
73 | CFRef<CFDataRef> data = cfLoadFile(resource); | |
f60086fc | 74 | CodeSigning::Required(requirementRef) = |
7d31e928 A |
75 | (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle(); |
76 | ||
77 | END_CSAPI | |
78 | } | |
79 | ||
80 | ||
81 | // | |
82 | // Create a Requirement from source text (compiling it) | |
83 | // | |
84 | OSStatus SecRequirementCreateWithString(CFStringRef text, SecCSFlags flags, | |
85 | SecRequirementRef *requirementRef) | |
86 | { | |
87 | return SecRequirementCreateWithStringAndErrors(text, flags, NULL, requirementRef); | |
88 | } | |
89 | ||
90 | OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags flags, | |
91 | CFErrorRef *errors, SecRequirementRef *requirementRef) | |
92 | { | |
93 | BEGIN_CSAPI | |
94 | ||
95 | checkFlags(flags); | |
f60086fc | 96 | CodeSigning::Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text)), true))->handle(); |
7d31e928 A |
97 | |
98 | END_CSAPI_ERRORS | |
99 | } | |
100 | ||
101 | ||
102 | // | |
103 | // Create a Requirement group. | |
104 | // This is the canonical point where "application group" is defined. | |
105 | // | |
106 | OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchorRef, | |
107 | SecCSFlags flags, SecRequirementRef *requirementRef) | |
108 | { | |
109 | BEGIN_CSAPI | |
110 | ||
111 | checkFlags(flags); | |
112 | Requirement::Maker maker; | |
113 | maker.put(opAnd); // both of... | |
114 | maker.infoKey("Application-Group", cfString(groupName)); | |
115 | if (anchorRef) { | |
116 | CSSM_DATA certData; | |
117 | MacOSError::check(SecCertificateGetData(anchorRef, &certData)); | |
118 | maker.anchor(0, certData.Data, certData.Length); | |
119 | } else { | |
120 | maker.anchor(); // canonical Apple anchor | |
121 | } | |
f60086fc | 122 | CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle(); |
2e2533ba | 123 | |
7d31e928 A |
124 | END_CSAPI |
125 | } | |
126 | ||
127 | ||
128 | // | |
129 | // Extract the stable binary from from a SecRequirementRef | |
130 | // | |
131 | OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags flags, | |
132 | CFDataRef *data) | |
133 | { | |
134 | BEGIN_CSAPI | |
135 | ||
136 | const Requirement *req = SecRequirement::required(requirementRef)->requirement(); | |
137 | checkFlags(flags); | |
f60086fc | 138 | CodeSigning::Required(data); |
7d31e928 A |
139 | *data = makeCFData(*req); |
140 | ||
141 | END_CSAPI | |
142 | } | |
143 | ||
144 | ||
145 | // | |
146 | // Generate source form for a SecRequirement (decompile/disassemble) | |
147 | // | |
148 | OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags flags, | |
149 | CFStringRef *text) | |
150 | { | |
151 | BEGIN_CSAPI | |
152 | ||
153 | const Requirement *req = SecRequirement::required(requirementRef)->requirement(); | |
154 | checkFlags(flags); | |
f60086fc | 155 | CodeSigning::Required(text); |
7d31e928 A |
156 | *text = makeCFString(Dumper::dump(req)); |
157 | ||
158 | END_CSAPI | |
159 | } | |
160 | ||
d1c1ab47 | 161 | |
f60086fc A |
162 | // |
163 | CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info"); | |
164 | CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements"); | |
62e4ed3d | 165 | CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier"); |
f60086fc A |
166 | |
167 | OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef, | |
168 | CFArrayRef certificateChain, CFDictionaryRef context, | |
169 | SecCSFlags flags) | |
170 | { | |
171 | BEGIN_CSAPI | |
172 | ||
173 | const Requirement *req = SecRequirement::required(requirementRef)->requirement(); | |
174 | checkFlags(flags); | |
175 | CodeSigning::Required(certificateChain); | |
176 | ||
177 | Requirement::Context ctx(certificateChain, // mandatory | |
178 | context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL, | |
179 | context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL, | |
62e4ed3d A |
180 | (context && CFDictionaryGetValue(context, kSecRequirementKeyIdentifier)) ? |
181 | cfString(CFStringRef(CFDictionaryGetValue(context, kSecRequirementKeyIdentifier))) : "", | |
f60086fc A |
182 | NULL // can't specify a CodeDirectory here |
183 | ); | |
184 | req->validate(ctx); | |
185 | ||
186 | END_CSAPI | |
187 | } | |
188 | ||
189 | ||
d1c1ab47 A |
190 | // |
191 | // Assemble a requirement set (as a CFData) from a dictionary of requirement objects. | |
192 | // An empty set is allowed. | |
193 | // | |
194 | OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags, | |
195 | CFDataRef *requirementSet) | |
196 | { | |
197 | BEGIN_CSAPI | |
198 | ||
199 | checkFlags(flags); | |
200 | if (requirements == NULL) | |
201 | return errSecCSObjectRequired; | |
202 | CFIndex count = CFDictionaryGetCount(requirements); | |
203 | CFNumberRef keys[count]; | |
204 | SecRequirementRef reqs[count]; | |
205 | CFDictionaryGetKeysAndValues(requirements, (const void **)keys, (const void **)reqs); | |
206 | Requirements::Maker maker; | |
207 | for (CFIndex n = 0; n < count; n++) { | |
208 | const Requirement *req = SecRequirement::required(reqs[n])->requirement(); | |
209 | maker.add(cfNumber<Requirements::Type>(keys[n]), req->clone()); | |
210 | } | |
211 | Requirements *reqset = maker.make(); // malloc'ed | |
f60086fc | 212 | CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset); // takes ownership of reqs |
d1c1ab47 A |
213 | |
214 | END_CSAPI | |
215 | } | |
216 | ||
217 | ||
218 | // | |
219 | // Break a requirement set (given as a CFData) into its constituent requirements | |
220 | // and return it as a CFDictionary. | |
221 | // | |
222 | OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags, | |
223 | CFDictionaryRef *requirements) | |
224 | { | |
225 | BEGIN_CSAPI | |
226 | ||
227 | checkFlags(flags); | |
228 | if (requirementSet == NULL) | |
229 | return errSecCSObjectRequired; | |
230 | const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet); | |
231 | CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary(); | |
232 | unsigned count = reqs->count(); | |
233 | for (unsigned n = 0; n < count; n++) { | |
234 | CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle(); | |
235 | CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req); | |
236 | } | |
f60086fc | 237 | CodeSigning::Required(requirements) = dict.yield(); |
d1c1ab47 A |
238 | |
239 | END_CSAPI | |
240 | } | |
241 | ||
242 | ||
243 | // | |
244 | // Generically parse a string as some kind of requirement-related source form. | |
245 | // If properly recognized, return the result as a CF object: | |
246 | // SecRequirementRef for a single requirement | |
247 | // CFDataRef for a requirement set | |
248 | // | |
249 | OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags, | |
250 | CFTypeRef *result, CFErrorRef *errors) | |
251 | { | |
252 | BEGIN_CSAPI | |
253 | ||
254 | checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet); | |
255 | if (text == NULL || result == NULL) | |
256 | return errSecCSObjectRequired; | |
257 | std::string s = cfString(text); | |
258 | switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) { | |
259 | case kSecCSParseRequirement: // single only | |
260 | *result = (new SecRequirement(parseRequirement(s), true))->handle(); | |
261 | break; | |
262 | case kSecCSParseRequirementSet: // single only | |
263 | { | |
264 | const Requirements *reqs = parseRequirements(s); | |
265 | *result = makeCFDataMalloc(*reqs); | |
266 | break; | |
267 | } | |
268 | case 0: | |
269 | case kSecCSParseRequirement | kSecCSParseRequirementSet: | |
270 | { | |
271 | const BlobCore *any = parseGeneric(s); | |
272 | if (any->is<Requirement>()) | |
273 | *result = (new SecRequirement(Requirement::specific(any), true))->handle(); | |
274 | else | |
275 | *result = makeCFDataMalloc(*any); | |
276 | break; | |
277 | } | |
278 | } | |
279 | ||
280 | END_CSAPI_ERRORS | |
281 | } | |
282 | ||
283 | ||
284 | // | |
285 | // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text. | |
286 | // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty. | |
287 | // A single requirement will return a single line that is NOT newline-terminated. | |
288 | // | |
289 | OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text) | |
290 | { | |
291 | BEGIN_CSAPI | |
292 | ||
293 | checkFlags(flags); | |
294 | if (input == NULL) | |
295 | return errSecCSObjectRequired; | |
296 | if (CFGetTypeID(input) == SecRequirementGetTypeID()) { | |
297 | return SecRequirementCopyString(SecRequirementRef(input), flags, text); | |
298 | } else if (CFGetTypeID(input) == CFDataGetTypeID()) { | |
299 | const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input)); | |
300 | if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input)))) | |
301 | return errSecCSReqInvalid; | |
f60086fc | 302 | CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false)); |
d1c1ab47 A |
303 | } else |
304 | return errSecCSInvalidObjectRef; | |
305 | ||
306 | END_CSAPI | |
307 | } |