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");
171 OSStatus
SecRequirementEvaluate(SecRequirementRef requirementRef
,
172 CFArrayRef certificateChain
, CFDictionaryRef context
,
177 const Requirement
*req
= SecRequirement::required(requirementRef
)->requirement();
179 CodeSigning::Required(certificateChain
);
181 Requirement::Context
ctx(certificateChain
, // mandatory
182 context
? CFDictionaryRef(CFDictionaryGetValue(context
, kSecRequirementKeyInfoPlist
)) : NULL
,
183 context
? CFDictionaryRef(CFDictionaryGetValue(context
, kSecRequirementKeyEntitlements
)) : NULL
,
184 (context
&& CFDictionaryGetValue(context
, kSecRequirementKeyIdentifier
)) ?
185 cfString(CFStringRef(CFDictionaryGetValue(context
, kSecRequirementKeyIdentifier
))) : "",
186 NULL
// can't specify a CodeDirectory here
195 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
196 // An empty set is allowed.
198 OSStatus
SecRequirementsCreateFromRequirements(CFDictionaryRef requirements
, SecCSFlags flags
,
199 CFDataRef
*requirementSet
)
204 if (requirements
== NULL
)
205 return errSecCSObjectRequired
;
206 CFIndex count
= CFDictionaryGetCount(requirements
);
207 CFNumberRef keys
[count
];
208 SecRequirementRef reqs
[count
];
209 CFDictionaryGetKeysAndValues(requirements
, (const void **)keys
, (const void **)reqs
);
210 Requirements::Maker maker
;
211 for (CFIndex n
= 0; n
< count
; n
++) {
212 const Requirement
*req
= SecRequirement::required(reqs
[n
])->requirement();
213 maker
.add(cfNumber
<Requirements::Type
>(keys
[n
]), req
->clone());
215 Requirements
*reqset
= maker
.make(); // malloc'ed
216 CodeSigning::Required(requirementSet
) = makeCFDataMalloc(*reqset
); // takes ownership of reqs
223 // Break a requirement set (given as a CFData) into its constituent requirements
224 // and return it as a CFDictionary.
226 OSStatus
SecRequirementsCopyRequirements(CFDataRef requirementSet
, SecCSFlags flags
,
227 CFDictionaryRef
*requirements
)
232 if (requirementSet
== NULL
)
233 return errSecCSObjectRequired
;
234 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(requirementSet
);
235 if (!reqs
->validateBlob())
236 MacOSError::throwMe(errSecCSReqInvalid
);
237 CFRef
<CFMutableDictionaryRef
> dict
= makeCFMutableDictionary();
238 unsigned count
= reqs
->count();
239 for (unsigned n
= 0; n
< count
; n
++) {
240 CFRef
<SecRequirementRef
> req
= (new SecRequirement(reqs
->blob
<Requirement
>(n
)))->handle();
241 CFDictionaryAddValue(dict
, CFTempNumber(reqs
->type(n
)), req
);
243 CodeSigning::Required(requirements
) = dict
.yield();
250 // Generically parse a string as some kind of requirement-related source form.
251 // If properly recognized, return the result as a CF object:
252 // SecRequirementRef for a single requirement
253 // CFDataRef for a requirement set
255 OSStatus
SecRequirementsCreateWithString(CFStringRef text
, SecCSFlags flags
,
256 CFTypeRef
*result
, CFErrorRef
*errors
)
260 checkFlags(flags
, kSecCSParseRequirement
| kSecCSParseRequirementSet
);
261 if (text
== NULL
|| result
== NULL
)
262 return errSecCSObjectRequired
;
263 std::string s
= cfString(text
);
264 switch (flags
& (kSecCSParseRequirement
| kSecCSParseRequirementSet
)) {
265 case kSecCSParseRequirement
: // single only
266 *result
= (new SecRequirement(parseRequirement(s
), true))->handle();
268 case kSecCSParseRequirementSet
: // single only
270 const Requirements
*reqs
= parseRequirements(s
);
271 *result
= makeCFDataMalloc(*reqs
);
275 case kSecCSParseRequirement
| kSecCSParseRequirementSet
:
277 const BlobCore
*any
= parseGeneric(s
);
278 if (any
->is
<Requirement
>())
279 *result
= (new SecRequirement(Requirement::specific(any
), true))->handle();
281 *result
= makeCFDataMalloc(*any
);
291 // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
292 // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
293 // A single requirement will return a single line that is NOT newline-terminated.
295 OSStatus
SecRequirementsCopyString(CFTypeRef input
, SecCSFlags flags
, CFStringRef
*text
)
301 return errSecCSObjectRequired
;
302 if (CFGetTypeID(input
) == SecRequirementGetTypeID()) {
303 return SecRequirementCopyString(SecRequirementRef(input
), flags
, text
);
304 } else if (CFGetTypeID(input
) == CFDataGetTypeID()) {
305 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(CFDataRef(input
));
306 if (!reqs
->validateBlob(CFDataGetLength(CFDataRef(input
))))
307 return errSecCSReqInvalid
;
308 CodeSigning::Required(text
) = makeCFString(Dumper::dump(reqs
, false));
310 return errSecCSInvalidObjectRef
;