2 * Copyright (c) 2006 Apple Computer, 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 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
);
237 CodeSigning::Required(requirements
) = dict
.yield();
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
249 OSStatus
SecRequirementsCreateWithString(CFStringRef text
, SecCSFlags flags
,
250 CFTypeRef
*result
, CFErrorRef
*errors
)
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();
262 case kSecCSParseRequirementSet
: // single only
264 const Requirements
*reqs
= parseRequirements(s
);
265 *result
= makeCFDataMalloc(*reqs
);
269 case kSecCSParseRequirement
| kSecCSParseRequirementSet
:
271 const BlobCore
*any
= parseGeneric(s
);
272 if (any
->is
<Requirement
>())
273 *result
= (new SecRequirement(Requirement::specific(any
), true))->handle();
275 *result
= makeCFDataMalloc(*any
);
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.
289 OSStatus
SecRequirementsCopyString(CFTypeRef input
, SecCSFlags flags
, CFStringRef
*text
)
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
;
302 CodeSigning::Required(text
) = makeCFString(Dumper::dump(reqs
, false));
304 return errSecCSInvalidObjectRef
;