SecRequirement.cpp
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 35 using namespace CodeSigning; 36 37 38 // 39 // CF-standard type code function 40 // 41 CFTypeID 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 // 52 OSStatus 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 // 67 OSStatus 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 // 84 OSStatus SecRequirementCreateWithString(CFStringRef text, SecCSFlags flags, 85 SecRequirementRef *requirementRef) 86 { 87 return SecRequirementCreateWithStringAndErrors(text, flags, NULL, requirementRef); 88 } 89 90 OSStatus 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 // 106 OSStatus 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 #if TARGET_OS_OSX 117 CSSM_DATA certData; 118 MacOSError::check(SecCertificateGetData(anchorRef, &certData)); 119 maker.anchor(0, certData.Data, certData.Length); 120 #else 121 maker.anchor(0, SecCertificateGetBytePtr(anchorRef), SecCertificateGetLength(anchorRef)); 122 #endif 123 } else { 124 maker.anchor(); // canonical Apple anchor 125 } 126 CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle(); 127 128 END_CSAPI 129 } 130 131 132 // 133 // Extract the stable binary from from a SecRequirementRef 134 // 135 OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags flags, 136 CFDataRef *data) 137 { 138 BEGIN_CSAPI 139 140 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 141 checkFlags(flags); 142 CodeSigning::Required(data); 143 *data = makeCFData(*req); 144 145 END_CSAPI 146 } 147 148 149 // 150 // Generate source form for a SecRequirement (decompile/disassemble) 151 // 152 OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags flags, 153 CFStringRef *text) 154 { 155 BEGIN_CSAPI 156 157 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 158 checkFlags(flags); 159 CodeSigning::Required(text); 160 *text = makeCFString(Dumper::dump(req)); 161 162 END_CSAPI 163 } 164 165 166 // 167 CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info"); 168 CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements"); 169 CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier"); 170 CFStringRef kSecRequirementKeyPackageChecksum = CFSTR("requirement:eval:package_checksum"); 171 CFStringRef kSecRequirementKeyChecksumAlgorithm = CFSTR("requirement:eval:package_checksum_algorithm"); 172 CFStringRef kSecRequirementKeySecureTimestamp = CFSTR("requirement:eval:secure_timestamp"); 173 CFStringRef kSecRequirementKeyTeamIdentifier = CFSTR("requirement:eval:team_identifier"); 174 175 OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef, 176 CFArrayRef certificateChain, CFDictionaryRef context, 177 SecCSFlags flags) 178 { 179 BEGIN_CSAPI 180 181 const Requirement *req = SecRequirement::required(requirementRef)->requirement(); 182 checkFlags(flags); 183 CodeSigning::Required(certificateChain); 184 185 SecCSDigestAlgorithm checksumAlgorithm = kSecCodeSignatureNoHash; 186 if (context) { 187 CFRef<CFNumberRef> num = (CFNumberRef)CFDictionaryGetValue(context, kSecRequirementKeyChecksumAlgorithm); 188 if (num) { 189 checksumAlgorithm = (SecCSDigestAlgorithm)cfNumber<uint32_t>(num); 190 } 191 } 192 193 const char *teamID = NULL; 194 if (context && CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier)) { 195 CFStringRef str = (CFStringRef)CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier); 196 teamID = CFStringGetCStringPtr(str, kCFStringEncodingUTF8); 197 } 198 199 Requirement::Context ctx(certificateChain, // mandatory 200 context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL, 201 context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL, 202 (context && CFDictionaryGetValue(context, kSecRequirementKeyIdentifier)) ? 203 cfString(CFStringRef(CFDictionaryGetValue(context, kSecRequirementKeyIdentifier))) : "", 204 NULL, // can't specify a CodeDirectory here 205 context ? CFDataRef(CFDictionaryGetValue(context, kSecRequirementKeyPackageChecksum)) : NULL, 206 checksumAlgorithm, 207 false, // can't get forced platform this way 208 context ? CFDateRef(CFDictionaryGetValue(context, kSecRequirementKeySecureTimestamp)) : NULL, 209 teamID 210 ); 211 req->validate(ctx); 212 213 END_CSAPI 214 } 215 216 217 // 218 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects. 219 // An empty set is allowed. 220 // 221 OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags, 222 CFDataRef *requirementSet) 223 { 224 BEGIN_CSAPI 225 226 checkFlags(flags); 227 if (requirements == NULL) 228 return errSecCSObjectRequired; 229 CFIndex count = CFDictionaryGetCount(requirements); 230 vector<CFNumberRef> keys_vector(count, NULL); 231 vector<SecRequirementRef> reqs_vector(count, NULL); 232 CFDictionaryGetKeysAndValues(requirements, (const void **)keys_vector.data(), (const void **)reqs_vector.data()); 233 Requirements::Maker maker; 234 for (CFIndex n = 0; n < count; n++) { 235 const Requirement *req = SecRequirement::required(reqs_vector[n])->requirement(); 236 maker.add(cfNumber<Requirements::Type>(keys_vector[n]), req->clone()); 237 } 238 Requirements *reqset = maker.make(); // malloc'ed 239 CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset); // takes ownership of reqs 240 241 END_CSAPI 242 } 243 244 245 // 246 // Break a requirement set (given as a CFData) into its constituent requirements 247 // and return it as a CFDictionary. 248 // 249 OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags, 250 CFDictionaryRef *requirements) 251 { 252 BEGIN_CSAPI 253 254 checkFlags(flags); 255 if (requirementSet == NULL) 256 return errSecCSObjectRequired; 257 const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet); 258 if (!reqs->validateBlob()) 259 MacOSError::throwMe(errSecCSReqInvalid); 260 CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary(); 261 unsigned count = reqs->count(); 262 for (unsigned n = 0; n < count; n++) { 263 CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle(); 264 CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req); 265 } 266 CodeSigning::Required(requirements) = dict.yield(); 267 268 END_CSAPI 269 } 270 271 272 // 273 // Generically parse a string as some kind of requirement-related source form. 274 // If properly recognized, return the result as a CF object: 275 // SecRequirementRef for a single requirement 276 // CFDataRef for a requirement set 277 // 278 OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags, 279 CFTypeRef *result, CFErrorRef *errors) 280 { 281 BEGIN_CSAPI 282 283 checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet); 284 if (text == NULL || result == NULL) 285 return errSecCSObjectRequired; 286 std::string s = cfString(text); 287 switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) { 288 case kSecCSParseRequirement: // single only 289 *result = (new SecRequirement(parseRequirement(s), true))->handle(); 290 break; 291 case kSecCSParseRequirementSet: // single only 292 { 293 const Requirements *reqs = parseRequirements(s); 294 *result = makeCFDataMalloc(*reqs); 295 break; 296 } 297 case 0: 298 case kSecCSParseRequirement | kSecCSParseRequirementSet: 299 { 300 const BlobCore *any = parseGeneric(s); 301 if (any->is<Requirement>()) 302 *result = (new SecRequirement(Requirement::specific(any), true))->handle(); 303 else 304 *result = makeCFDataMalloc(*any); 305 break; 306 } 307 } 308 309 END_CSAPI_ERRORS 310 } 311 312 313 // 314 // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text. 315 // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty. 316 // A single requirement will return a single line that is NOT newline-terminated. 317 // 318 OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text) 319 { 320 BEGIN_CSAPI 321 322 checkFlags(flags); 323 if (input == NULL) 324 return errSecCSObjectRequired; 325 if (CFGetTypeID(input) == SecRequirementGetTypeID()) { 326 return SecRequirementCopyString(SecRequirementRef(input), flags, text); 327 } else if (CFGetTypeID(input) == CFDataGetTypeID()) { 328 const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input)); 329 if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input)))) 330 return errSecCSReqInvalid; 331 CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false)); 332 } else 333 return errSecCSInvalidObjectRef; 334 335 END_CSAPI 336 }