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
));
117 MacOSError::check(SecCertificateGetData(anchorRef
, &certData
));
118 maker
.anchor(0, certData
.Data
, certData
.Length
);
120 maker
.anchor(); // canonical Apple anchor
122 CodeSigning::Required(requirementRef
) = (new SecRequirement(maker
.make(), true))->handle();
129 // Extract the stable binary from from a SecRequirementRef
131 OSStatus
SecRequirementCopyData(SecRequirementRef requirementRef
, SecCSFlags flags
,
136 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
138 CodeSigning::Required(data
);
139 *data
= makeCFData(*req
);
146 // Generate source form for a SecRequirement (decompile/disassemble)
148 OSStatus
SecRequirementCopyString(SecRequirementRef requirementRef
, SecCSFlags flags
,
153 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
155 CodeSigning::Required(text
);
156 *text
= makeCFString(Dumper::dump(req
));
163 CFStringRef kSecRequirementKeyInfoPlist
= CFSTR("requirement:eval:info");
164 CFStringRef kSecRequirementKeyEntitlements
= CFSTR("requirement:eval:entitlements");
165 CFStringRef kSecRequirementKeyIdentifier
= CFSTR("requirement:eval:identifier");
167 OSStatus
SecRequirementEvaluate(SecRequirementRef requirementRef
,
168 CFArrayRef certificateChain
, CFDictionaryRef context
,
173 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
175 CodeSigning::Required(certificateChain
);
177 Requirement::Context
ctx(certificateChain
, // mandatory
178 context
? CFDictionaryRef(CFDictionaryGetValue(context
, kSecRequirementKeyInfoPlist
)) : NULL
,
179 context
? CFDictionaryRef(CFDictionaryGetValue(context
, kSecRequirementKeyEntitlements
)) : NULL
,
180 (context
&& CFDictionaryGetValue(context
, kSecRequirementKeyIdentifier
)) ?
181 cfString(CFStringRef(CFDictionaryGetValue(context
, kSecRequirementKeyIdentifier
))) : "",
182 NULL
// can't specify a CodeDirectory here
191 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
192 // An empty set is allowed.
194 OSStatus
SecRequirementsCreateFromRequirements(CFDictionaryRef requirements
, SecCSFlags flags
,
195 CFDataRef
*requirementSet
)
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());
211 Requirements
*reqset
= maker
.make(); // malloc'ed
212 CodeSigning::Required(requirementSet
) = makeCFDataMalloc(*reqset
); // takes ownership of reqs
219 // Break a requirement set (given as a CFData) into its constituent requirements
220 // and return it as a CFDictionary.
222 OSStatus
SecRequirementsCopyRequirements(CFDataRef requirementSet
, SecCSFlags flags
,
223 CFDictionaryRef
*requirements
)
228 if (requirementSet
== NULL
)
229 return errSecCSObjectRequired
;
230 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(requirementSet
);
231 if (!reqs
->validateBlob())
232 MacOSError::throwMe(errSecCSReqInvalid
);
233 CFRef
<CFMutableDictionaryRef
> dict
= makeCFMutableDictionary();
234 unsigned count
= reqs
->count();
235 for (unsigned n
= 0; n
< count
; n
++) {
236 CFRef
<SecRequirementRef
> req
= (new SecRequirement(reqs
->blob
<Requirement
>(n
)))->handle();
237 CFDictionaryAddValue(dict
, CFTempNumber(reqs
->type(n
)), req
);
239 CodeSigning::Required(requirements
) = dict
.yield();
246 // Generically parse a string as some kind of requirement-related source form.
247 // If properly recognized, return the result as a CF object:
248 // SecRequirementRef for a single requirement
249 // CFDataRef for a requirement set
251 OSStatus
SecRequirementsCreateWithString(CFStringRef text
, SecCSFlags flags
,
252 CFTypeRef
*result
, CFErrorRef
*errors
)
256 checkFlags(flags
, kSecCSParseRequirement
| kSecCSParseRequirementSet
);
257 if (text
== NULL
|| result
== NULL
)
258 return errSecCSObjectRequired
;
259 std::string s
= cfString(text
);
260 switch (flags
& (kSecCSParseRequirement
| kSecCSParseRequirementSet
)) {
261 case kSecCSParseRequirement
: // single only
262 *result
= (new SecRequirement(parseRequirement(s
), true))->handle();
264 case kSecCSParseRequirementSet
: // single only
266 const Requirements
*reqs
= parseRequirements(s
);
267 *result
= makeCFDataMalloc(*reqs
);
271 case kSecCSParseRequirement
| kSecCSParseRequirementSet
:
273 const BlobCore
*any
= parseGeneric(s
);
274 if (any
->is
<Requirement
>())
275 *result
= (new SecRequirement(Requirement::specific(any
), true))->handle();
277 *result
= makeCFDataMalloc(*any
);
287 // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
288 // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
289 // A single requirement will return a single line that is NOT newline-terminated.
291 OSStatus
SecRequirementsCopyString(CFTypeRef input
, SecCSFlags flags
, CFStringRef
*text
)
297 return errSecCSObjectRequired
;
298 if (CFGetTypeID(input
) == SecRequirementGetTypeID()) {
299 return SecRequirementCopyString(SecRequirementRef(input
), flags
, text
);
300 } else if (CFGetTypeID(input
) == CFDataGetTypeID()) {
301 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(CFDataRef(input
));
302 if (!reqs
->validateBlob(CFDataGetLength(CFDataRef(input
))))
303 return errSecCSReqInvalid
;
304 CodeSigning::Required(text
) = makeCFString(Dumper::dump(reqs
, false));
306 return errSecCSInvalidObjectRef
;