]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/SecRequirement.cpp
Security-59306.61.1.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / SecRequirement.cpp
1 /*
2 * Copyright (c) 2006,2011-2012,2014 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 // 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);
58 CodeSigning::Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
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);
74 CodeSigning::Required(requirementRef) =
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);
96 CodeSigning::Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text)), true))->handle();
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 #if TARGET_OS_OSX
117 CSSM_DATA certData;
118 MacOSError::check(SecCertificateGetData(anchorRef, &certData));
119 maker.anchor(0, certData.Data, certData.Length);
120 #else
121 maker.anchor(0, SecCertificateGetBytePtr(anchorRef), SecCertificateGetLength(anchorRef));
122 #endif
123 } else {
124 maker.anchor(); // canonical Apple anchor
125 }
126 CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
127
128 END_CSAPI
129 }
130
131
132 //
133 // Extract the stable binary from from a SecRequirementRef
134 //
135 OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags flags,
136 CFDataRef *data)
137 {
138 BEGIN_CSAPI
139
140 const Requirement *req = SecRequirement::required(requirementRef)->requirement();
141 checkFlags(flags);
142 CodeSigning::Required(data);
143 *data = makeCFData(*req);
144
145 END_CSAPI
146 }
147
148
149 //
150 // Generate source form for a SecRequirement (decompile/disassemble)
151 //
152 OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags flags,
153 CFStringRef *text)
154 {
155 BEGIN_CSAPI
156
157 const Requirement *req = SecRequirement::required(requirementRef)->requirement();
158 checkFlags(flags);
159 CodeSigning::Required(text);
160 *text = makeCFString(Dumper::dump(req));
161
162 END_CSAPI
163 }
164
165
166 //
167 CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info");
168 CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements");
169 CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier");
170 CFStringRef kSecRequirementKeyPackageChecksum = CFSTR("requirement:eval:package_checksum");
171 CFStringRef kSecRequirementKeyChecksumAlgorithm = CFSTR("requirement:eval:package_checksum_algorithm");
172 CFStringRef kSecRequirementKeySecureTimestamp = CFSTR("requirement:eval:secure_timestamp");
173 CFStringRef kSecRequirementKeyTeamIdentifier = CFSTR("requirement:eval:team_identifier");
174
175 OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef,
176 CFArrayRef certificateChain, CFDictionaryRef context,
177 SecCSFlags flags)
178 {
179 BEGIN_CSAPI
180
181 const Requirement *req = SecRequirement::required(requirementRef)->requirement();
182 checkFlags(flags);
183 CodeSigning::Required(certificateChain);
184
185 SecCSDigestAlgorithm checksumAlgorithm = kSecCodeSignatureNoHash;
186 if (context) {
187 CFRef<CFNumberRef> num = (CFNumberRef)CFDictionaryGetValue(context, kSecRequirementKeyChecksumAlgorithm);
188 if (num) {
189 checksumAlgorithm = (SecCSDigestAlgorithm)cfNumber<uint32_t>(num);
190 }
191 }
192
193 const char *teamID = NULL;
194 if (context && CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier)) {
195 CFStringRef str = (CFStringRef)CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier);
196 teamID = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
197 }
198
199 Requirement::Context ctx(certificateChain, // mandatory
200 context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL,
201 context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL,
202 (context && CFDictionaryGetValue(context, kSecRequirementKeyIdentifier)) ?
203 cfString(CFStringRef(CFDictionaryGetValue(context, kSecRequirementKeyIdentifier))) : "",
204 NULL, // can't specify a CodeDirectory here
205 context ? CFDataRef(CFDictionaryGetValue(context, kSecRequirementKeyPackageChecksum)) : NULL,
206 checksumAlgorithm,
207 false, // can't get forced platform this way
208 context ? CFDateRef(CFDictionaryGetValue(context, kSecRequirementKeySecureTimestamp)) : NULL,
209 teamID
210 );
211 req->validate(ctx);
212
213 END_CSAPI
214 }
215
216
217 //
218 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
219 // An empty set is allowed.
220 //
221 OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
222 CFDataRef *requirementSet)
223 {
224 BEGIN_CSAPI
225
226 checkFlags(flags);
227 if (requirements == NULL)
228 return errSecCSObjectRequired;
229 CFIndex count = CFDictionaryGetCount(requirements);
230 vector<CFNumberRef> keys_vector(count, NULL);
231 vector<SecRequirementRef> reqs_vector(count, NULL);
232 CFDictionaryGetKeysAndValues(requirements, (const void **)keys_vector.data(), (const void **)reqs_vector.data());
233 Requirements::Maker maker;
234 for (CFIndex n = 0; n < count; n++) {
235 const Requirement *req = SecRequirement::required(reqs_vector[n])->requirement();
236 maker.add(cfNumber<Requirements::Type>(keys_vector[n]), req->clone());
237 }
238 Requirements *reqset = maker.make(); // malloc'ed
239 CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset); // takes ownership of reqs
240
241 END_CSAPI
242 }
243
244
245 //
246 // Break a requirement set (given as a CFData) into its constituent requirements
247 // and return it as a CFDictionary.
248 //
249 OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
250 CFDictionaryRef *requirements)
251 {
252 BEGIN_CSAPI
253
254 checkFlags(flags);
255 if (requirementSet == NULL)
256 return errSecCSObjectRequired;
257 const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet);
258 if (!reqs->validateBlob())
259 MacOSError::throwMe(errSecCSReqInvalid);
260 CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary();
261 unsigned count = reqs->count();
262 for (unsigned n = 0; n < count; n++) {
263 CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle();
264 CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req);
265 }
266 CodeSigning::Required(requirements) = dict.yield();
267
268 END_CSAPI
269 }
270
271
272 //
273 // Generically parse a string as some kind of requirement-related source form.
274 // If properly recognized, return the result as a CF object:
275 // SecRequirementRef for a single requirement
276 // CFDataRef for a requirement set
277 //
278 OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
279 CFTypeRef *result, CFErrorRef *errors)
280 {
281 BEGIN_CSAPI
282
283 checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet);
284 if (text == NULL || result == NULL)
285 return errSecCSObjectRequired;
286 std::string s = cfString(text);
287 switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) {
288 case kSecCSParseRequirement: // single only
289 *result = (new SecRequirement(parseRequirement(s), true))->handle();
290 break;
291 case kSecCSParseRequirementSet: // single only
292 {
293 const Requirements *reqs = parseRequirements(s);
294 *result = makeCFDataMalloc(*reqs);
295 break;
296 }
297 case 0:
298 case kSecCSParseRequirement | kSecCSParseRequirementSet:
299 {
300 const BlobCore *any = parseGeneric(s);
301 if (any->is<Requirement>())
302 *result = (new SecRequirement(Requirement::specific(any), true))->handle();
303 else
304 *result = makeCFDataMalloc(*any);
305 break;
306 }
307 }
308
309 END_CSAPI_ERRORS
310 }
311
312
313 //
314 // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
315 // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
316 // A single requirement will return a single line that is NOT newline-terminated.
317 //
318 OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text)
319 {
320 BEGIN_CSAPI
321
322 checkFlags(flags);
323 if (input == NULL)
324 return errSecCSObjectRequired;
325 if (CFGetTypeID(input) == SecRequirementGetTypeID()) {
326 return SecRequirementCopyString(SecRequirementRef(input), flags, text);
327 } else if (CFGetTypeID(input) == CFDataGetTypeID()) {
328 const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input));
329 if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input))))
330 return errSecCSReqInvalid;
331 CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false));
332 } else
333 return errSecCSInvalidObjectRef;
334
335 END_CSAPI
336 }