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
;