1/* 2 * Copyright (c) 2006,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// 25// SecRequirement - API frame for SecRequirement objects 26// 27#include "cs.h" 28#include "Requirements.h" 29#include "reqparser.h" 30#include "reqmaker.h" 31#include "reqdumper.h" 32#include <Security/SecCertificate.h> 33#include <security_utilities/cfutilities.h> 34 35using namespace CodeSigning; 36 37 38// 39// CF-standard type code function 40// 41CFTypeID SecRequirementGetTypeID(void) 42{ 43 BEGIN_CSAPI 44 return gCFObjects().Requirement.typeID; 45 END_CSAPI1(_kCFRuntimeNotATypeID) 46} 47 48 49// 50// Create a Requirement from data 51// 52OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags, 53 SecRequirementRef *requirementRef) 54{ 55 BEGIN_CSAPI 56 57 checkFlags(flags); 58 CodeSigning::Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle(); 59 60 END_CSAPI 61} 62 63 64// 65// Create a Requirement from data in a file 66// 67OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags, 68 SecRequirementRef *requirementRef) 69{ 70 BEGIN_CSAPI 71 72 checkFlags(flags); 73 CFRef<CFDataRef> data = cfLoadFile(resource); 74 CodeSigning::Required(requirementRef) = 75 (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle(); 76 77 END_CSAPI 78} 79 80 81// 82// Create a Requirement from source text (compiling it) 83// 84OSStatus SecRequirementCreateWithString(CFStringRef text, SecCSFlags flags, 85 SecRequirementRef *requirementRef) 86{ 87 return SecRequirementCreateWithStringAndErrors(text, flags, NULL, requirementRef); 88} 89 90OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags flags, 91 CFErrorRef *errors, SecRequirementRef *requirementRef) 92{ 93 BEGIN_CSAPI 94 95 checkFlags(flags); 96 CodeSigning::Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text)), true))->handle(); 97 98 END_CSAPI_ERRORS 99} 100 101 102// 103// Create a Requirement group. 104// This is the canonical point where "application group" is defined. 105// 106OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchorRef, 107 SecCSFlags flags, SecRequirementRef *requirementRef) 108{ 109 BEGIN_CSAPI 110 111 checkFlags(flags); 112 Requirement::Maker maker; 113 maker.put(opAnd); // both of... 114 maker.infoKey("Application-Group", cfString(groupName)); 115 if (anchorRef) { 116 CSSM_DATA certData; 117 MacOSError::check(SecCertificateGetData(anchorRef, &certData)); 118 maker.anchor(0, certData.Data, certData.Length); 119 } else { 120 maker.anchor(); // canonical Apple anchor 121 } 122 CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle(); 123 124 END_CSAPI 125} 126 127 128// 129// Extract the stable binary from from a SecRequirementRef 130// 131OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags flags, 132 CFDataRef *data) 133{ 134 BEGIN_CSAPI 135 136 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 137 checkFlags(flags); 138 CodeSigning::Required(data); 139 *data = makeCFData(*req); 140 141 END_CSAPI 142} 143 144 145// 146// Generate source form for a SecRequirement (decompile/disassemble) 147// 148OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags flags, 149 CFStringRef *text) 150{ 151 BEGIN_CSAPI 152 153 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 154 checkFlags(flags); 155 CodeSigning::Required(text); 156 *text = makeCFString(Dumper::dump(req)); 157 158 END_CSAPI 159} 160 161 162// 163CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info"); 164CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements"); 165CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier"); 166 167OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef, 168 CFArrayRef certificateChain, CFDictionaryRef context, 169 SecCSFlags flags) 170{ 171 BEGIN_CSAPI 172 173 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 174 checkFlags(flags); 175 CodeSigning::Required(certificateChain); 176 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 183 ); 184 req->validate(ctx); 185 186 END_CSAPI 187} 188 189 190// 191// Assemble a requirement set (as a CFData) from a dictionary of requirement objects. 192// An empty set is allowed. 193// 194OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags, 195 CFDataRef *requirementSet) 196{ 197 BEGIN_CSAPI 198 199 checkFlags(flags); 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()); 210 } 211 Requirements *reqset = maker.make(); // malloc'ed 212 CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset); // takes ownership of reqs 213 214 END_CSAPI 215} 216 217 218// 219// Break a requirement set (given as a CFData) into its constituent requirements 220// and return it as a CFDictionary. 221// 222OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags, 223 CFDictionaryRef *requirements) 224{ 225 BEGIN_CSAPI 226 227 checkFlags(flags); 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); 238 } 239 CodeSigning::Required(requirements) = dict.yield(); 240 241 END_CSAPI 242} 243 244 245// 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 250// 251OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags, 252 CFTypeRef *result, CFErrorRef *errors) 253{ 254 BEGIN_CSAPI 255 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(); 263 break; 264 case kSecCSParseRequirementSet: // single only 265 { 266 const Requirements *reqs = parseRequirements(s); 267 *result = makeCFDataMalloc(*reqs); 268 break; 269 } 270 case 0: 271 case kSecCSParseRequirement | kSecCSParseRequirementSet: 272 { 273 const BlobCore *any = parseGeneric(s); 274 if (any->is<Requirement>()) 275 *result = (new SecRequirement(Requirement::specific(any), true))->handle(); 276 else 277 *result = makeCFDataMalloc(*any); 278 break; 279 } 280 } 281 282 END_CSAPI_ERRORS 283} 284 285 286// 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. 290// 291OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text) 292{ 293 BEGIN_CSAPI 294 295 checkFlags(flags); 296 if (input == NULL) 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)); 305 } else 306 return errSecCSInvalidObjectRef; 307 308 END_CSAPI 309} 310