2 * Copyright (c) 2006,2011-2012,2014 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 // SecRequirement - API frame for SecRequirement objects
28 #include "Requirements.h"
29 #include "reqparser.h"
31 #include "reqdumper.h"
32 #include <Security/SecCertificate.h>
33 #include <security_utilities/cfutilities.h>
35 using namespace CodeSigning
;
39 // CF-standard type code function
41 CFTypeID
SecRequirementGetTypeID(void)
44 return gCFObjects().Requirement
.typeID
;
45 END_CSAPI1(_kCFRuntimeNotATypeID
)
50 // Create a Requirement from data
52 OSStatus
SecRequirementCreateWithData(CFDataRef data
, SecCSFlags flags
,
53 SecRequirementRef
*requirementRef
)
58 CodeSigning::Required(requirementRef
) = (new SecRequirement(CFDataGetBytePtr(data
), CFDataGetLength(data
)))->handle();
65 // Create a Requirement from data in a file
67 OSStatus
SecRequirementCreateWithResource(CFURLRef resource
, SecCSFlags flags
,
68 SecRequirementRef
*requirementRef
)
73 CFRef
<CFDataRef
> data
= cfLoadFile(resource
);
74 CodeSigning::Required(requirementRef
) =
75 (new SecRequirement(CFDataGetBytePtr(data
), CFDataGetLength(data
)))->handle();
82 // Create a Requirement from source text (compiling it)
84 OSStatus
SecRequirementCreateWithString(CFStringRef text
, SecCSFlags flags
,
85 SecRequirementRef
*requirementRef
)
87 return SecRequirementCreateWithStringAndErrors(text
, flags
, NULL
, requirementRef
);
90 OSStatus
SecRequirementCreateWithStringAndErrors(CFStringRef text
, SecCSFlags flags
,
91 CFErrorRef
*errors
, SecRequirementRef
*requirementRef
)
96 CodeSigning::Required(requirementRef
) = (new SecRequirement(parseRequirement(cfString(text
)), true))->handle();
103 // Create a Requirement group.
104 // This is the canonical point where "application group" is defined.
106 OSStatus
SecRequirementCreateGroup(CFStringRef groupName
, SecCertificateRef anchorRef
,
107 SecCSFlags flags
, SecRequirementRef
*requirementRef
)
112 Requirement::Maker maker
;
113 maker
.put(opAnd
); // both of...
114 maker
.infoKey("Application-Group", cfString(groupName
));
118 MacOSError::check(SecCertificateGetData(anchorRef
, &certData
));
119 maker
.anchor(0, certData
.Data
, certData
.Length
);
121 maker
.anchor(0, SecCertificateGetBytePtr(anchorRef
), SecCertificateGetLength(anchorRef
));
124 maker
.anchor(); // canonical Apple anchor
126 CodeSigning::Required(requirementRef
) = (new SecRequirement(maker
.make(), true))->handle();
133 // Extract the stable binary from from a SecRequirementRef
135 OSStatus
SecRequirementCopyData(SecRequirementRef requirementRef
, SecCSFlags flags
,
140 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
142 CodeSigning::Required(data
);
143 *data
= makeCFData(*req
);
150 // Generate source form for a SecRequirement (decompile/disassemble)
152 OSStatus
SecRequirementCopyString(SecRequirementRef requirementRef
, SecCSFlags flags
,
157 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
159 CodeSigning::Required(text
);
160 *text
= makeCFString(Dumper::dump(req
));
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");
175 OSStatus
SecRequirementEvaluate(SecRequirementRef requirementRef
,
176 CFArrayRef certificateChain
, CFDictionaryRef context
,
181 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
183 CodeSigning::Required(certificateChain
);
185 SecCSDigestAlgorithm checksumAlgorithm
= kSecCodeSignatureNoHash
;
187 CFRef
<CFNumberRef
> num
= (CFNumberRef
)CFDictionaryGetValue(context
, kSecRequirementKeyChecksumAlgorithm
);
189 checksumAlgorithm
= (SecCSDigestAlgorithm
)cfNumber
<uint32_t>(num
);
193 const char *teamID
= NULL
;
194 if (context
&& CFDictionaryGetValue(context
, kSecRequirementKeyTeamIdentifier
)) {
195 CFStringRef str
= (CFStringRef
)CFDictionaryGetValue(context
, kSecRequirementKeyTeamIdentifier
);
196 teamID
= CFStringGetCStringPtr(str
, kCFStringEncodingUTF8
);
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
,
207 false, // can't get forced platform this way
208 context
? CFDateRef(CFDictionaryGetValue(context
, kSecRequirementKeySecureTimestamp
)) : NULL
,
218 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
219 // An empty set is allowed.
221 OSStatus
SecRequirementsCreateFromRequirements(CFDictionaryRef requirements
, SecCSFlags flags
,
222 CFDataRef
*requirementSet
)
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());
238 Requirements
*reqset
= maker
.make(); // malloc'ed
239 CodeSigning::Required(requirementSet
) = makeCFDataMalloc(*reqset
); // takes ownership of reqs
246 // Break a requirement set (given as a CFData) into its constituent requirements
247 // and return it as a CFDictionary.
249 OSStatus
SecRequirementsCopyRequirements(CFDataRef requirementSet
, SecCSFlags flags
,
250 CFDictionaryRef
*requirements
)
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
);
266 CodeSigning::Required(requirements
) = dict
.yield();
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
278 OSStatus
SecRequirementsCreateWithString(CFStringRef text
, SecCSFlags flags
,
279 CFTypeRef
*result
, CFErrorRef
*errors
)
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();
291 case kSecCSParseRequirementSet
: // single only
293 const Requirements
*reqs
= parseRequirements(s
);
294 *result
= makeCFDataMalloc(*reqs
);
298 case kSecCSParseRequirement
| kSecCSParseRequirementSet
:
300 const BlobCore
*any
= parseGeneric(s
);
301 if (any
->is
<Requirement
>())
302 *result
= (new SecRequirement(Requirement::specific(any
), true))->handle();
304 *result
= makeCFDataMalloc(*any
);
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.
318 OSStatus
SecRequirementsCopyString(CFTypeRef input
, SecCSFlags flags
, CFStringRef
*text
)
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));
333 return errSecCSInvalidObjectRef
;