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 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 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 Required(requirementRef
) = (new SecRequirement(parseRequirement(cfString(text
))))->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 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();
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();
156 *text
= makeCFString(Dumper::dump(req
));
163 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
164 // An empty set is allowed.
166 OSStatus
SecRequirementsCreateFromRequirements(CFDictionaryRef requirements
, SecCSFlags flags
,
167 CFDataRef
*requirementSet
)
172 if (requirements
== NULL
)
173 return errSecCSObjectRequired
;
174 CFIndex count
= CFDictionaryGetCount(requirements
);
175 CFNumberRef keys
[count
];
176 SecRequirementRef reqs
[count
];
177 CFDictionaryGetKeysAndValues(requirements
, (const void **)keys
, (const void **)reqs
);
178 Requirements::Maker maker
;
179 for (CFIndex n
= 0; n
< count
; n
++) {
180 const Requirement
*req
= SecRequirement::required(reqs
[n
])->requirement();
181 maker
.add(cfNumber
<Requirements::Type
>(keys
[n
]), req
->clone());
183 Requirements
*reqset
= maker
.make(); // malloc'ed
184 Required(requirementSet
) = makeCFDataMalloc(*reqset
); // takes ownership of reqs
191 // Break a requirement set (given as a CFData) into its constituent requirements
192 // and return it as a CFDictionary.
194 OSStatus
SecRequirementsCopyRequirements(CFDataRef requirementSet
, SecCSFlags flags
,
195 CFDictionaryRef
*requirements
)
200 if (requirementSet
== NULL
)
201 return errSecCSObjectRequired
;
202 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(requirementSet
);
203 CFRef
<CFMutableDictionaryRef
> dict
= makeCFMutableDictionary();
204 unsigned count
= reqs
->count();
205 for (unsigned n
= 0; n
< count
; n
++) {
206 CFRef
<SecRequirementRef
> req
= (new SecRequirement(reqs
->blob
<Requirement
>(n
)))->handle();
207 CFDictionaryAddValue(dict
, CFTempNumber(reqs
->type(n
)), req
);
209 Required(requirements
) = dict
.yield();
216 // Generically parse a string as some kind of requirement-related source form.
217 // If properly recognized, return the result as a CF object:
218 // SecRequirementRef for a single requirement
219 // CFDataRef for a requirement set
221 OSStatus
SecRequirementsCreateWithString(CFStringRef text
, SecCSFlags flags
,
222 CFTypeRef
*result
, CFErrorRef
*errors
)
226 checkFlags(flags
, kSecCSParseRequirement
| kSecCSParseRequirementSet
);
227 if (text
== NULL
|| result
== NULL
)
228 return errSecCSObjectRequired
;
229 std::string s
= cfString(text
);
230 switch (flags
& (kSecCSParseRequirement
| kSecCSParseRequirementSet
)) {
231 case kSecCSParseRequirement
: // single only
232 *result
= (new SecRequirement(parseRequirement(s
), true))->handle();
234 case kSecCSParseRequirementSet
: // single only
236 const Requirements
*reqs
= parseRequirements(s
);
237 *result
= makeCFDataMalloc(*reqs
);
241 case kSecCSParseRequirement
| kSecCSParseRequirementSet
:
243 const BlobCore
*any
= parseGeneric(s
);
244 if (any
->is
<Requirement
>())
245 *result
= (new SecRequirement(Requirement::specific(any
), true))->handle();
247 *result
= makeCFDataMalloc(*any
);
257 // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
258 // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
259 // A single requirement will return a single line that is NOT newline-terminated.
261 OSStatus
SecRequirementsCopyString(CFTypeRef input
, SecCSFlags flags
, CFStringRef
*text
)
267 return errSecCSObjectRequired
;
268 if (CFGetTypeID(input
) == SecRequirementGetTypeID()) {
269 return SecRequirementCopyString(SecRequirementRef(input
), flags
, text
);
270 } else if (CFGetTypeID(input
) == CFDataGetTypeID()) {
271 const Requirements
*reqs
= (const Requirements
*)CFDataGetBytePtr(CFDataRef(input
));
272 if (!reqs
->validateBlob(CFDataGetLength(CFDataRef(input
))))
273 return errSecCSReqInvalid
;
274 Required(text
) = makeCFString(Dumper::dump(reqs
, false));
276 return errSecCSInvalidObjectRef
;