TrustAdditions.cpp
1 /* 2 * Copyright (c) 2002-2009,2011-2015 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 // TrustAdditions.cpp 26 // 27 #include "TrustAdditions.h" 28 #include "TrustKeychains.h" 29 #include "SecBridge.h" 30 #include <security_keychain/SecCFTypes.h> 31 #include <security_keychain/Globals.h> 32 #include <security_keychain/Certificate.h> 33 #include <security_keychain/Item.h> 34 #include <security_keychain/KCCursor.h> 35 #include <security_keychain/KCUtilities.h> 36 37 #include <sys/stat.h> 38 #include <sys/file.h> 39 #include <sys/unistd.h> 40 #include <string> 41 #include <AvailabilityMacros.h> 42 #include <CoreFoundation/CoreFoundation.h> 43 #include <CommonCrypto/CommonDigest.h> 44 #include <Security/SecBase.h> 45 #include <Security/Security.h> 46 #include <Security/SecCertificatePriv.h> 47 #include <Security/cssmtype.h> 48 #include <Security/cssmapplePriv.h> // for CSSM_APPLE_TP_OCSP_OPTIONS, CSSM_APPLE_TP_OCSP_OPT_FLAGS 49 50 #include <Security/SecTrustPriv.h> 51 #include <Security/SecTrustSettings.h> 52 #include <Security/SecTrustSettingsPriv.h> 53 54 // 55 // Macros 56 // 57 #define BEGIN_SECAPI_INTERNAL_CALL \ 58 try { 59 #define END_SECAPI_INTERNAL_CALL \ 60 } /* status is only set on error */ \ 61 catch (const MacOSError &err) { status=err.osStatus(); } \ 62 catch (const CommonError &err) { status=SecKeychainErrFromOSStatus(err.osStatus()); } \ 63 catch (const std::bad_alloc &) { status=errSecAllocate; } \ 64 catch (...) { status=errSecInternalComponent; } 65 66 #ifdef NDEBUG 67 /* this actually compiles to nothing */ 68 #define trustDebug(args...) secinfo("trust", ## args) 69 #else 70 #define trustDebug(args...) printf(args) 71 #endif 72 73 // 74 // Static constants 75 // 76 static const char *EV_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/EVRoots.plist"; 77 static const char *SYSTEM_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/SystemRootCertificates.keychain"; 78 static const char *X509ANCHORS_SYSTEM_PATH = "/System/Library/Keychains/X509Anchors"; 79 80 // 81 // Static functions 82 // 83 static CFArrayRef CF_RETURNS_RETAINED _allowedRootCertificatesForOidString(CFStringRef oidString); 84 static CSSM_DATA_PTR _copyFieldDataForOid(CSSM_OID_PTR oid, CSSM_DATA_PTR cert, CSSM_CL_HANDLE clHandle); 85 static CFStringRef CF_RETURNS_RETAINED _decimalStringForOid(CSSM_OID_PTR oid); 86 static CFDictionaryRef CF_RETURNS_RETAINED _evCAOidDict(); 87 static void _freeFieldData(CSSM_DATA_PTR value, CSSM_OID_PTR oid, CSSM_CL_HANDLE clHandle); 88 static CFStringRef CF_RETURNS_RETAINED _oidStringForCertificatePolicies(const CE_CertPolicies *certPolicies); 89 static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate); 90 static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate); 91 92 // utility function to safely release (and clear) the given CFTypeRef variable. 93 // 94 static void SafeCFRelease(void * CF_CONSUMED cfTypeRefPtr) 95 { 96 CFTypeRef *obj = (CFTypeRef *)cfTypeRefPtr; 97 if (obj && *obj) { 98 CFRelease(*obj); 99 *obj = NULL; 100 } 101 } 102 103 // utility function to create a CFDataRef from the contents of the specified file; 104 // caller must release 105 // 106 static CFDataRef CF_RETURNS_RETAINED dataWithContentsOfFile(const char *fileName) 107 { 108 int rtn; 109 int fd; 110 struct stat sb; 111 size_t fileSize; 112 UInt8 *fileData = NULL; 113 CFDataRef outCFData = NULL; 114 115 fd = open(fileName, O_RDONLY, 0); 116 if(fd < 0) 117 return NULL; 118 119 rtn = fstat(fd, &sb); 120 if(rtn) 121 goto errOut; 122 123 fileSize = (size_t)sb.st_size; 124 fileData = (UInt8 *) malloc(fileSize); 125 if(fileData == NULL) 126 goto errOut; 127 128 rtn = (int)lseek(fd, 0, SEEK_SET); 129 if(rtn < 0) 130 goto errOut; 131 132 rtn = (int)read(fd, fileData, fileSize); 133 if(rtn != (int)fileSize) { 134 rtn = EIO; 135 } else { 136 rtn = 0; 137 outCFData = CFDataCreate(NULL, fileData, fileSize); 138 } 139 errOut: 140 close(fd); 141 if (fileData) { 142 free(fileData); 143 } 144 return outCFData; 145 } 146 147 // returns a SecKeychainRef for the system root certificate store; caller must release 148 // 149 static SecKeychainRef systemRootStore() 150 { 151 SecKeychainStatus keychainStatus = 0; 152 SecKeychainRef systemRoots = NULL; 153 OSStatus status = errSecSuccess; 154 // note: Sec* APIs are not re-entrant due to the API lock 155 // status = SecKeychainOpen(SYSTEM_ROOTS_PLIST_SYSTEM_PATH, &systemRoots); 156 BEGIN_SECAPI_INTERNAL_CALL 157 systemRoots=globals().storageManager.make(SYSTEM_ROOTS_PLIST_SYSTEM_PATH, false)->handle(); 158 END_SECAPI_INTERNAL_CALL 159 160 // SecKeychainOpen will return errSecSuccess even if the file didn't exist on disk. 161 // We need to do a further check using SecKeychainGetStatus(). 162 if (!status && systemRoots) { 163 // note: Sec* APIs are not re-entrant due to the API lock 164 // status = SecKeychainGetStatus(systemRoots, &keychainStatus); 165 BEGIN_SECAPI_INTERNAL_CALL 166 keychainStatus=(SecKeychainStatus)Keychain::optional(systemRoots)->status(); 167 END_SECAPI_INTERNAL_CALL 168 } 169 if (status || !systemRoots) { 170 // SystemRootCertificates.keychain can't be opened; look in X509Anchors instead. 171 SafeCFRelease(&systemRoots); 172 // note: Sec* APIs are not re-entrant due to the API lock 173 // status = SecKeychainOpen(X509ANCHORS_SYSTEM_PATH, &systemRoots); 174 BEGIN_SECAPI_INTERNAL_CALL 175 systemRoots=globals().storageManager.make(X509ANCHORS_SYSTEM_PATH, false)->handle(); 176 END_SECAPI_INTERNAL_CALL 177 // SecKeychainOpen will return errSecSuccess even if the file didn't exist on disk. 178 // We need to do a further check using SecKeychainGetStatus(). 179 if (!status && systemRoots) { 180 // note: Sec* APIs are not re-entrant due to the API lock 181 // status = SecKeychainGetStatus(systemRoots, &keychainStatus); 182 BEGIN_SECAPI_INTERNAL_CALL 183 keychainStatus=(SecKeychainStatus)Keychain::optional(systemRoots)->status(); 184 END_SECAPI_INTERNAL_CALL 185 } 186 } 187 if (status || !systemRoots) { 188 // Cannot get root certificates if there is no trusted system root certificate store. 189 SafeCFRelease(&systemRoots); 190 return NULL; 191 } 192 return systemRoots; 193 } 194 195 // returns a CFDictionaryRef created from the specified XML plist file; caller must release 196 // 197 static CFDictionaryRef CF_RETURNS_RETAINED dictionaryWithContentsOfPlistFile(const char *fileName) 198 { 199 CFDictionaryRef resultDict = NULL; 200 CFDataRef fileData = dataWithContentsOfFile(fileName); 201 if (fileData) { 202 CFPropertyListRef xmlPlist = CFPropertyListCreateFromXMLData(NULL, fileData, kCFPropertyListImmutable, NULL); 203 if (xmlPlist && CFGetTypeID(xmlPlist) == CFDictionaryGetTypeID()) { 204 resultDict = (CFDictionaryRef)xmlPlist; 205 } else { 206 SafeCFRelease(&xmlPlist); 207 } 208 SafeCFRelease(&fileData); 209 } 210 return resultDict; 211 } 212 213 // returns the Organization component of the given certificate's subject name, 214 // or nil if that component could not be found. Caller must release the string. 215 // 216 static CFStringRef organizationNameForCertificate(SecCertificateRef certificate) 217 { 218 CFStringRef organizationName = nil; 219 OSStatus status = errSecSuccess; 220 221 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4 222 CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_OrganizationName; 223 // note: Sec* APIs are not re-entrant due to the API lock 224 // status = SecCertificateCopySubjectComponent(certificate, oidPtr, &organizationName); 225 BEGIN_SECAPI_INTERNAL_CALL 226 organizationName = Certificate::required(certificate)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, oidPtr); 227 END_SECAPI_INTERNAL_CALL 228 if (status) { 229 return (CFStringRef)NULL; 230 } 231 #else 232 // SecCertificateCopySubjectComponent() doesn't exist on Tiger, so we have 233 // to go get the CSSMOID_OrganizationName the hard way, ourselves. 234 CSSM_DATA_PTR *fieldValues = NULL; 235 // note: Sec* APIs are not re-entrant due to the API lock 236 // status = SecCertificateCopyFieldValues(certificate, &CSSMOID_X509V1SubjectNameCStruct, &fieldValues); 237 BEGIN_SECAPI_INTERNAL_CALL 238 fieldValues = Certificate::required(certificate)->copyFieldValues(&CSSMOID_X509V1SubjectNameCStruct); 239 END_SECAPI_INTERNAL_CALL 240 if (*fieldValues == NULL) { 241 return (CFStringRef)NULL; 242 } 243 if (status || (*fieldValues)->Length == 0 || (*fieldValues)->Data == NULL) { 244 // note: Sec* APIs are not re-entrant due to the API lock 245 // status = SecCertificateReleaseFieldValues(certificate, &CSSMOID_X509V1SubjectNameCStruct, fieldValues); 246 BEGIN_SECAPI_INTERNAL_CALL 247 Certificate::required(certificate)->releaseFieldValues(&CSSMOID_X509V1SubjectNameCStruct, fieldValues); 248 END_SECAPI_INTERNAL_CALL 249 return (CFStringRef)NULL; 250 } 251 252 CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)(*fieldValues)->Data; 253 254 // Iterate over all the relative distinguished name (RDN) entries... 255 unsigned rdnIndex = 0; 256 bool foundIt = FALSE; 257 for (rdnIndex = 0; rdnIndex < x509Name->numberOfRDNs; rdnIndex++) { 258 CSSM_X509_RDN *rdnPtr = x509Name->RelativeDistinguishedName + rdnIndex; 259 260 // And then iterate over the attribute-value pairs of each RDN, looking for a CSSMOID_OrganizationName. 261 unsigned pairIndex; 262 for (pairIndex = 0; pairIndex < rdnPtr->numberOfPairs; pairIndex++) { 263 CSSM_X509_TYPE_VALUE_PAIR *pair = rdnPtr->AttributeTypeAndValue + pairIndex; 264 265 // If this pair isn't the organization name, move on to check the next one. 266 if (!oidsAreEqual(&pair->type, &CSSMOID_OrganizationName)) 267 continue; 268 269 // We've found the organization name. Convert value to a string (eg, "Apple Inc.") 270 // Note: there can be more than one organization name in any given CSSM_X509_RDN. 271 // In practice, it's OK to use the first one. In future, if we have a means for 272 // displaying more than one name, this would be where they should be collected 273 // into an array. 274 switch (pair->valueType) { 275 case BER_TAG_PKIX_UTF8_STRING: 276 case BER_TAG_PKIX_UNIVERSAL_STRING: 277 case BER_TAG_GENERAL_STRING: 278 organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUTF8, FALSE); 279 break; 280 case BER_TAG_PRINTABLE_STRING: 281 case BER_TAG_IA5_STRING: 282 organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingASCII, FALSE); 283 break; 284 case BER_TAG_T61_STRING: 285 case BER_TAG_VIDEOTEX_STRING: 286 case BER_TAG_ISO646_STRING: 287 organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUTF8, FALSE); 288 // If the data cannot be represented as a UTF-8 string, fall back to ISO Latin 1 289 if (!organizationName) { 290 organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingISOLatin1, FALSE); 291 } 292 break; 293 case BER_TAG_PKIX_BMP_STRING: 294 organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUnicode, FALSE); 295 break; 296 default: 297 break; 298 } 299 300 // If we found the organization name, there's no need to keep looping. 301 if (organizationName) { 302 foundIt = TRUE; 303 break; 304 } 305 } 306 if (foundIt) 307 break; 308 } 309 // note: Sec* APIs are not re-entrant due to the API lock 310 // status = SecCertificateReleaseFieldValues(certificate, &CSSMOID_X509V1SubjectNameCStruct, fieldValues); 311 BEGIN_SECAPI_INTERNAL_CALL 312 Certificate::required(certificate)->releaseFieldValues(&CSSMOID_X509V1SubjectNameCStruct, fieldValues); 313 END_SECAPI_INTERNAL_CALL 314 #endif 315 return organizationName; 316 } 317 318 #if !defined(NDEBUG) 319 void showCertSKID(const void *value, void *context); 320 #endif 321 322 static ModuleNexus<Mutex> gPotentialEVChainWithCertificatesMutex; 323 324 // returns a CFArrayRef of SecCertificateRef instances; caller must release the returned array 325 // 326 CFArrayRef potentialEVChainWithCertificates(CFArrayRef certificates) 327 { 328 StLock<Mutex> _(gPotentialEVChainWithCertificatesMutex()); 329 330 // Given a partial certificate chain (which may or may not include the root, 331 // and does not have a guaranteed order except the first item is the leaf), 332 // examine intermediate certificates to see if they are cross-certified (i.e. 333 // have the same subject and public key as a trusted root); if so, remove the 334 // intermediate from the returned certificate array. 335 336 CFIndex chainIndex, chainLen = (certificates) ? CFArrayGetCount(certificates) : 0; 337 secinfo("trusteval", "potentialEVChainWithCertificates: chainLen: %ld", chainLen); 338 if (chainLen < 2) { 339 if (certificates) { 340 CFRetain(certificates); 341 } 342 return certificates; 343 } 344 345 CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 346 for (chainIndex = 0; chainIndex < chainLen; chainIndex++) { 347 SecCertificateRef aCert = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, chainIndex); 348 SecCertificateRef replacementCert = NULL; 349 secinfo("trusteval", "potentialEVChainWithCertificates: examining chainIndex: %ld", chainIndex); 350 if (chainIndex > 0) { 351 // if this is not the leaf, then look for a possible replacement root to end the chain 352 // Try lookup using Subject Key ID first 353 replacementCert = _rootCertificateWithSubjectKeyIDOfCertificate(aCert); 354 if (!replacementCert) 355 { 356 secinfo("trusteval", " not found using SKID, try by subject"); 357 replacementCert = _rootCertificateWithSubjectOfCertificate(aCert); 358 } 359 } 360 if (!replacementCert) { 361 secinfo("trusteval", " No replacement found using SKID or subject; keeping original intermediate"); 362 CFArrayAppendValue(certArray, aCert); 363 } 364 SafeCFRelease(&replacementCert); 365 } 366 secinfo("trusteval", "potentialEVChainWithCertificates: exit: new chainLen: %ld", CFArrayGetCount(certArray)); 367 #if !defined(NDEBUG) 368 CFArrayApplyFunction(certArray, CFRangeMake(0, CFArrayGetCount(certArray)), showCertSKID, NULL); 369 #endif 370 371 return certArray; 372 } 373 374 // returns a reference to a root certificate, if one can be found in the 375 // system root store whose subject name and public key are identical to 376 // that of the provided certificate, otherwise returns nil. 377 // 378 static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate) 379 { 380 if (!certificate) { 381 return NULL; 382 } 383 384 StLock<Mutex> _(SecTrustKeychainsGetMutex()); 385 386 // get data+length for the provided certificate 387 CSSM_CL_HANDLE clHandle = 0; 388 CSSM_DATA certData = { 0, NULL }; 389 OSStatus status = errSecSuccess; 390 // note: Sec* APIs are not re-entrant due to the API lock 391 // status = SecCertificateGetCLHandle(certificate, &clHandle); 392 BEGIN_SECAPI_INTERNAL_CALL 393 clHandle = Certificate::required(certificate)->clHandle(); 394 END_SECAPI_INTERNAL_CALL 395 if (status) 396 return NULL; 397 // note: Sec* APIs are not re-entrant due to the API lock 398 // status = SecCertificateGetData(certificate, &certData); 399 BEGIN_SECAPI_INTERNAL_CALL 400 certData = Certificate::required(certificate)->data(); 401 END_SECAPI_INTERNAL_CALL 402 if (status) 403 return NULL; 404 405 // get system roots keychain reference 406 SecKeychainRef systemRoots = systemRootStore(); 407 if (!systemRoots) 408 return NULL; 409 410 // copy (normalized) subject for the provided certificate 411 const CSSM_OID_PTR oidPtr = (const CSSM_OID_PTR) &CSSMOID_X509V1SubjectName; 412 const CSSM_DATA_PTR subjectDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle); 413 if (!subjectDataPtr) 414 return NULL; 415 416 // copy public key for the provided certificate 417 SecKeyRef keyRef = NULL; 418 SecCertificateRef resultCert = NULL; 419 // note: Sec* APIs are not re-entrant due to the API lock 420 BEGIN_SECAPI_INTERNAL_CALL 421 keyRef = Certificate::required(certificate)->publicKey()->handle(); 422 END_SECAPI_INTERNAL_CALL 423 if (!status) { 424 const CSSM_KEY *cssmKey = NULL; 425 // note: Sec* APIs are not re-entrant due to the API lock 426 // status = SecKeyGetCSSMKey(keyRef, &cssmKey); 427 BEGIN_SECAPI_INTERNAL_CALL 428 cssmKey = KeyItem::required(keyRef)->key(); 429 END_SECAPI_INTERNAL_CALL 430 if (!status) { 431 // get SHA-1 hash of the public key 432 uint8 buf[CC_SHA1_DIGEST_LENGTH]; 433 CSSM_DATA digest = { sizeof(buf), buf }; 434 if (!cssmKey || !cssmKey->KeyData.Data || !cssmKey->KeyData.Length) { 435 status = errSecParam; 436 } else { 437 CC_SHA1(cssmKey->KeyData.Data, (CC_LONG)cssmKey->KeyData.Length, buf); 438 } 439 if (!status) { 440 // set up attribute vector (each attribute consists of {tag, length, pointer}) 441 // we want to match on the public key hash and the normalized subject name 442 // as well as ensure that the issuer matches the subject 443 SecKeychainAttribute attrs[] = { 444 { kSecPublicKeyHashItemAttr, (UInt32)digest.Length, (void *)digest.Data }, 445 { kSecSubjectItemAttr, (UInt32)subjectDataPtr->Length, (void *)subjectDataPtr->Data }, 446 { kSecIssuerItemAttr, (UInt32)subjectDataPtr->Length, (void *)subjectDataPtr->Data } 447 }; 448 const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; 449 SecKeychainSearchRef searchRef = NULL; 450 // note: Sec* APIs are not re-entrant due to the API lock 451 // status = SecKeychainSearchCreateFromAttributes(systemRoots, kSecCertificateItemClass, &attributes, &searchRef); 452 BEGIN_SECAPI_INTERNAL_CALL 453 StorageManager::KeychainList keychains; 454 globals().storageManager.optionalSearchList(systemRoots, keychains); 455 KCCursor cursor(keychains, kSecCertificateItemClass, &attributes); 456 searchRef = cursor->handle(); 457 END_SECAPI_INTERNAL_CALL 458 if (!status && searchRef) { 459 SecKeychainItemRef certRef = nil; 460 // note: Sec* APIs are not re-entrant due to the API lock 461 // status = SecKeychainSearchCopyNext(searchRef, &certRef); // only need the first one that matches 462 BEGIN_SECAPI_INTERNAL_CALL 463 Item item; 464 if (!KCCursorImpl::required(searchRef)->next(item)) { 465 status=errSecItemNotFound; 466 } else { 467 certRef=item->handle(); 468 } 469 END_SECAPI_INTERNAL_CALL 470 if (!status) 471 resultCert = (SecCertificateRef)certRef; // caller must release 472 SafeCFRelease(&searchRef); 473 } 474 } 475 } 476 } 477 _freeFieldData(subjectDataPtr, oidPtr, clHandle); 478 SafeCFRelease(&keyRef); 479 SafeCFRelease(&systemRoots); 480 481 return resultCert; 482 } 483 484 485 #if !defined(NDEBUG) 486 static void logSKID(const char *msg, const CssmData &subjectKeyID) 487 { 488 const unsigned char *px = (const unsigned char *)subjectKeyID.data(); 489 char buffer[256]={0,}; 490 char bytes[16]; 491 if (px && msg) 492 { 493 strcpy(buffer, msg); 494 for (unsigned int ix=0; ix<20; ix++) 495 { 496 sprintf(bytes, "%02X", px[ix]); 497 strcat(buffer, bytes); 498 } 499 secinfo("trusteval", " SKID: %s",buffer); 500 } 501 } 502 503 void showCertSKID(const void *value, void *context) 504 { 505 SecCertificateRef certificate = (SecCertificateRef)value; 506 OSStatus status = errSecSuccess; 507 BEGIN_SECAPI_INTERNAL_CALL 508 const CssmData &subjectKeyID = Certificate::required(certificate)->subjectKeyIdentifier(); 509 logSKID("subjectKeyID: ", subjectKeyID); 510 END_SECAPI_INTERNAL_CALL 511 } 512 #endif 513 514 // returns a reference to a root certificate, if one can be found in the 515 // system root store whose subject key ID are identical to 516 // that of the provided certificate, otherwise returns nil. 517 // 518 static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate) 519 { 520 SecCertificateRef resultCert = NULL; 521 OSStatus status = errSecSuccess; 522 523 if (!certificate) { 524 return NULL; 525 } 526 527 StLock<Mutex> _(SecTrustKeychainsGetMutex()); 528 529 // get system roots keychain reference 530 SecKeychainRef systemRoots = systemRootStore(); 531 if (!systemRoots) 532 return NULL; 533 534 StorageManager::KeychainList keychains; 535 globals().storageManager.optionalSearchList(systemRoots, keychains); 536 537 BEGIN_SECAPI_INTERNAL_CALL 538 const CssmData &subjectKeyID = Certificate::required(certificate)->subjectKeyIdentifier(); 539 #if !defined(NDEBUG) 540 logSKID("search for SKID: ", subjectKeyID); 541 #endif 542 // caller must release 543 resultCert = Certificate::required(certificate)->findBySubjectKeyID(keychains, subjectKeyID)->handle(); 544 #if !defined(NDEBUG) 545 logSKID(" found SKID: ", subjectKeyID); 546 #endif 547 END_SECAPI_INTERNAL_CALL 548 549 SafeCFRelease(&systemRoots); 550 551 return resultCert; 552 } 553 554 // returns an array of possible root certificates (SecCertificateRef instances) 555 // for the given EV OID (a hex string); caller must release the array 556 // 557 static 558 CFArrayRef CF_RETURNS_RETAINED _possibleRootCertificatesForOidString(CFStringRef oidString) 559 { 560 StLock<Mutex> _(SecTrustKeychainsGetMutex()); 561 562 if (!oidString) { 563 return NULL; 564 } 565 CFDictionaryRef evOidDict = _evCAOidDict(); 566 if (!evOidDict) 567 return NULL; 568 CFArrayRef possibleCertificateHashes = (CFArrayRef) CFDictionaryGetValue(evOidDict, oidString); 569 SecKeychainRef systemRoots = systemRootStore(); 570 if (!possibleCertificateHashes || !systemRoots) { 571 SafeCFRelease(&evOidDict); 572 return NULL; 573 } 574 575 CFMutableArrayRef possibleRootCertificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 576 CFIndex hashCount = CFArrayGetCount(possibleCertificateHashes); 577 secinfo("evTrust", "_possibleRootCertificatesForOidString: %d possible hashes", (int)hashCount); 578 579 OSStatus status = errSecSuccess; 580 SecKeychainSearchRef searchRef = NULL; 581 // note: Sec* APIs are not re-entrant due to the API lock 582 // status = SecKeychainSearchCreateFromAttributes(systemRoots, kSecCertificateItemClass, NULL, &searchRef); 583 BEGIN_SECAPI_INTERNAL_CALL 584 StorageManager::KeychainList keychains; 585 globals().storageManager.optionalSearchList(systemRoots, keychains); 586 KCCursor cursor(keychains, kSecCertificateItemClass, NULL); 587 searchRef = cursor->handle(); 588 END_SECAPI_INTERNAL_CALL 589 if (searchRef) { 590 while (!status) { 591 SecKeychainItemRef certRef = NULL; 592 // note: Sec* APIs are not re-entrant due to the API lock 593 // status = SecKeychainSearchCopyNext(searchRef, &certRef); 594 BEGIN_SECAPI_INTERNAL_CALL 595 Item item; 596 if (!KCCursorImpl::required(searchRef)->next(item)) { 597 certRef=NULL; 598 status=errSecItemNotFound; 599 } else { 600 certRef=item->handle(); 601 } 602 END_SECAPI_INTERNAL_CALL 603 if (status || !certRef) { 604 break; 605 } 606 607 CSSM_DATA certData = { 0, NULL }; 608 // note: Sec* APIs are not re-entrant due to the API lock 609 // status = SecCertificateGetData((SecCertificateRef) certRef, &certData); 610 BEGIN_SECAPI_INTERNAL_CALL 611 certData = Certificate::required((SecCertificateRef)certRef)->data(); 612 END_SECAPI_INTERNAL_CALL 613 if (!status) { 614 uint8 buf[CC_SHA1_DIGEST_LENGTH]; 615 CSSM_DATA digest = { sizeof(buf), buf }; 616 if (!certData.Data || !certData.Length) { 617 status = errSecParam; 618 } else { 619 CC_SHA1(certData.Data, (CC_LONG)certData.Length, buf); 620 } 621 if (!status) { 622 CFDataRef hashData = CFDataCreateWithBytesNoCopy(NULL, digest.Data, digest.Length, kCFAllocatorNull); 623 if (hashData && CFArrayContainsValue(possibleCertificateHashes, CFRangeMake(0, hashCount), hashData)) { 624 CFArrayAppendValue(possibleRootCertificates, certRef); 625 } 626 SafeCFRelease(&hashData); 627 } 628 } 629 SafeCFRelease(&certRef); 630 } 631 } 632 SafeCFRelease(&searchRef); 633 SafeCFRelease(&systemRoots); 634 SafeCFRelease(&evOidDict); 635 636 return possibleRootCertificates; 637 } 638 639 // returns an array of allowed root certificates (SecCertificateRef instances) 640 // for the given EV OID (a hex string); caller must release the array. 641 // This differs from _possibleRootCertificatesForOidString in that each possible 642 // certificate is further checked for trust settings, so we don't include 643 // a certificate which is untrusted (or explicitly distrusted). 644 // 645 CFArrayRef _allowedRootCertificatesForOidString(CFStringRef oidString) 646 { 647 CFMutableArrayRef allowedRootCertificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 648 CFArrayRef possibleRootCertificates = _possibleRootCertificatesForOidString(oidString); 649 if (possibleRootCertificates) { 650 CFIndex idx, count = CFArrayGetCount(possibleRootCertificates); 651 for (idx=0; idx<count; idx++) { 652 SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(possibleRootCertificates, idx); 653 /* Need a unified SecCertificateRef instance to hand to SecTrustSettingsCertHashStrFromCert */ 654 SecCertificateRef certRef = SecCertificateCreateFromItemImplInstance(cert); 655 CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(certRef); 656 if (hashStr) { 657 bool foundMatch = false; 658 bool foundAny = false; 659 CSSM_RETURN *errors = NULL; 660 uint32 errorCount = 0; 661 SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser; 662 SecTrustSettingsResult result = kSecTrustSettingsResultInvalid; 663 OSStatus status = SecTrustSettingsEvaluateCert( 664 hashStr, /* certHashStr */ 665 NULL, /* policyOID (optional) */ 666 NULL, /* policyString (optional) */ 667 0, /* policyStringLen */ 668 0, /* keyUsage */ 669 true, /* isRootCert */ 670 &foundDomain, /* foundDomain */ 671 &errors, /* allowedErrors */ 672 &errorCount, /* numAllowedErrors */ 673 &result, /* resultType */ 674 &foundMatch, /* foundMatchingEntry */ 675 &foundAny); /* foundAnyEntry */ 676 677 if (status == errSecSuccess) { 678 secinfo("evTrust", "_allowedRootCertificatesForOidString: cert %lu has result %d from domain %d", 679 idx, (int)result, (int)foundDomain); 680 // Root certificates must be trusted by the system (and not have 681 // any explicit trust overrides) to be allowed for EV use. 682 if (foundMatch && foundDomain == kSecTrustSettingsDomainSystem && 683 result == kSecTrustSettingsResultTrustRoot) { 684 CFArrayAppendValue(allowedRootCertificates, cert); 685 } 686 } else { 687 secinfo("evTrust", "_allowedRootCertificatesForOidString: cert %lu SecTrustSettingsEvaluateCert error %d", 688 idx, (int)status); 689 } 690 if (errors) { 691 free(errors); 692 } 693 CFRelease(hashStr); 694 } 695 if (certRef) { 696 CFRelease(certRef); 697 } 698 } 699 CFRelease(possibleRootCertificates); 700 } 701 702 return allowedRootCertificates; 703 } 704 705 // return a CSSM_DATA_PTR containing field data; caller must release with _freeFieldData 706 // 707 static CSSM_DATA_PTR _copyFieldDataForOid(CSSM_OID_PTR oid, CSSM_DATA_PTR cert, CSSM_CL_HANDLE clHandle) 708 { 709 uint32 numFields = 0; 710 CSSM_HANDLE results = 0; 711 CSSM_DATA_PTR value = 0; 712 CSSM_RETURN crtn = CSSM_CL_CertGetFirstFieldValue(clHandle, cert, oid, &results, &numFields, &value); 713 714 // we aren't going to look for any further fields, so free the results handle immediately 715 if (results) { 716 CSSM_CL_CertAbortQuery(clHandle, results); 717 } 718 719 return (crtn || !numFields) ? NULL : value; 720 } 721 722 // Some errors are ignorable errors because they do not indicate a problem 723 // with the certificate itself, but rather a problem getting a response from 724 // the CA server. The EV Certificate spec does not mandate that the application 725 // software vendor *must* get a response from OCSP or CRL, it is a "best 726 // attempt" approach which will not fail if the server does not respond. 727 // 728 // The EV spec (26. EV Certificate Status Checking) says that CAs have to 729 // maintain either a CRL or OCSP server. They are not required to maintain 730 // an OCSP server until after Dec 31, 2010. 731 // 732 // As to the responsibility of the application software vendor to perform 733 // revocation checking, this is only covered by the following section (37.2.): 734 // 735 // This [indemnification of Application Software Vendors] 736 // shall not apply, however, to any claim, damages, or loss 737 // suffered by such Application Software Vendor related to an EV Certificate 738 // issued by the CA where such claim, damage, or loss was directly caused by 739 // such Application Software Vendor’s software displaying as not trustworthy an 740 // EV Certificate that is still valid, or displaying as trustworthy: (1) an EV 741 // Certificate that has expired, or (2) an EV Certificate that has been revoked 742 // (but only in cases where the revocation status is currently available from the 743 // CA online, and the browser software either failed to check such status or 744 // ignored an indication of revoked status). 745 // 746 // The last section describes what a browser is required to do: it must attempt 747 // to check revocation status (as indicated by the OCSP or CRL server info in 748 // the certificate), and it cannot ignore an indication of revoked status 749 // (i.e. a positive thumbs-down response from the server, which would be a 750 // different error than the ones being skipped.) However, given that we meet 751 // those requirements, if the revocation server is down or will not give us a 752 // response for whatever reason, that is not our problem. 753 754 bool isRevocationServerMetaError(CSSM_RETURN statusCode) 755 { 756 switch (statusCode) { 757 case CSSMERR_APPLETP_CRL_NOT_FOUND: // 13. CRL not found 758 case CSSMERR_APPLETP_CRL_SERVER_DOWN: // 14. CRL server down 759 case CSSMERR_APPLETP_OCSP_UNAVAILABLE: // 33. OCSP service unavailable 760 case CSSMERR_APPLETP_NETWORK_FAILURE: // 36. General network failure 761 case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ: // 41. OCSP responder status: malformed request 762 case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR: // 42. OCSP responder status: internal error 763 case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER: // 43. OCSP responder status: try later 764 case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED: // 44. OCSP responder status: signature required 765 case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED: // 45. OCSP responder status: unauthorized 766 return true; 767 default: 768 return false; 769 } 770 } 771 772 // returns true if the given status code is related to performing an OCSP revocation check 773 // 774 bool isOCSPStatusCode(CSSM_RETURN statusCode) 775 { 776 switch (statusCode) 777 { 778 case CSSMERR_APPLETP_OCSP_BAD_RESPONSE: // 31. Unparseable OCSP response 779 case CSSMERR_APPLETP_OCSP_BAD_REQUEST: // 32. Unparseable OCSP request 780 case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ: // 41. OCSP responder status: malformed request 781 case CSSMERR_APPLETP_OCSP_UNAVAILABLE: // 33. OCSP service unavailable 782 case CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED: // 34. OCSP status: cert unrecognized 783 case CSSMERR_APPLETP_OCSP_NOT_TRUSTED: // 37. OCSP response not verifiable to anchor or root 784 case CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT: // 38. OCSP response verified to untrusted root 785 case CSSMERR_APPLETP_OCSP_SIG_ERROR: // 39. OCSP response signature error 786 case CSSMERR_APPLETP_OCSP_NO_SIGNER: // 40. No signer for OCSP response found 787 case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR: // 42. OCSP responder status: internal error 788 case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER: // 43. OCSP responder status: try later 789 case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED: // 44. OCSP responder status: signature required 790 case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED: // 45. OCSP responder status: unauthorized 791 case CSSMERR_APPLETP_OCSP_NONCE_MISMATCH: // 46. OCSP response nonce did not match request 792 return true; 793 default: 794 return false; 795 } 796 } 797 798 // returns true if the given status code is related to performing a CRL revocation check 799 // 800 bool isCRLStatusCode(CSSM_RETURN statusCode) 801 { 802 switch (statusCode) 803 { 804 case CSSMERR_APPLETP_CRL_EXPIRED: // 11. CRL expired 805 case CSSMERR_APPLETP_CRL_NOT_VALID_YET: // 12. CRL not yet valid 806 case CSSMERR_APPLETP_CRL_NOT_FOUND: // 13. CRL not found 807 case CSSMERR_APPLETP_CRL_SERVER_DOWN: // 14. CRL server down 808 case CSSMERR_APPLETP_CRL_BAD_URI: // 15. Illegal CRL distribution point URI 809 case CSSMERR_APPLETP_CRL_NOT_TRUSTED: // 18. CRL not verifiable to anchor or root 810 case CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT: // 19. CRL verified to untrusted root 811 case CSSMERR_APPLETP_CRL_POLICY_FAIL: // 20. CRL failed policy verification 812 return true; 813 default: 814 return false; 815 } 816 } 817 818 // returns true if the given status code is related to performing a revocation check 819 // 820 bool isRevocationStatusCode(CSSM_RETURN statusCode) 821 { 822 if (statusCode == CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK || // 35. Revocation check not successful for each cert 823 statusCode == CSSMERR_APPLETP_NETWORK_FAILURE || // 36. General network error 824 isOCSPStatusCode(statusCode) == true || // OCSP error 825 isCRLStatusCode(statusCode) == true) // CRL error 826 return true; 827 else 828 return false; 829 } 830 831 // returns a CFArrayRef of allowed root certificates for the provided leaf certificate 832 // if it passes initial EV evaluation criteria and should be subject to OCSP revocation 833 // checking; otherwise, NULL is returned. (Caller must release the result if not NULL.) 834 // 835 CFArrayRef allowedEVRootsForLeafCertificate(CFArrayRef certificates) 836 { 837 // Given a partial certificate chain (which may or may not include the root, 838 // and does not have a guaranteed order except the first item is the leaf), 839 // determine whether the leaf claims to have a supported EV policy OID. 840 // 841 // Unless this function returns NULL, a full SSL trust evaluation with OCSP revocation 842 // checking must be performed successfully for the certificate to be considered valid. 843 // This function is intended to be called before the chain has been evaluated, 844 // in order to obtain the list of allowed roots for the evaluation. Once the "regular" 845 // TP evaluation has taken place, chainMeetsExtendedValidationCriteria() should be 846 // called to complete extended validation checking. 847 848 CFIndex count = (certificates) ? CFArrayGetCount(certificates) : 0; 849 if (count < 1) 850 return NULL; 851 852 CSSM_CL_HANDLE clHandle = 0; 853 CSSM_DATA certData = { 0, NULL }; 854 SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, 0); 855 OSStatus status = errSecSuccess; 856 // note: Sec* APIs are not re-entrant due to the API lock 857 // status = SecCertificateGetCLHandle(certRef, &clHandle); 858 BEGIN_SECAPI_INTERNAL_CALL 859 clHandle = Certificate::required(certRef)->clHandle(); 860 END_SECAPI_INTERNAL_CALL 861 if (status) 862 return NULL; 863 // note: Sec* APIs are not re-entrant due to the API lock 864 // status = SecCertificateGetData(certRef, &certData); 865 BEGIN_SECAPI_INTERNAL_CALL 866 certData = Certificate::required(certRef)->data(); 867 END_SECAPI_INTERNAL_CALL 868 if (status) 869 return NULL; 870 871 // Does the leaf certificate contain a Certificate Policies extension? 872 const CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_CertificatePolicies; 873 CSSM_DATA_PTR extensionDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle); 874 if (!extensionDataPtr) 875 return NULL; 876 877 // Does the extension contain one of the magic EV CA OIDs we know about? 878 CSSM_X509_EXTENSION *cssmExtension = (CSSM_X509_EXTENSION *)extensionDataPtr->Data; 879 CE_CertPolicies *certPolicies = (CE_CertPolicies *)cssmExtension->value.parsedValue; 880 CFStringRef oidString = _oidStringForCertificatePolicies(certPolicies); 881 _freeFieldData(extensionDataPtr, oidPtr, clHandle); 882 883 // Fetch the allowed root CA certificates for this OID, if any 884 CFArrayRef allowedRoots = (oidString) ? _allowedRootCertificatesForOidString(oidString) : NULL; 885 CFIndex rootCount = (allowedRoots) ? CFArrayGetCount(allowedRoots) : 0; 886 secinfo("evTrust", "allowedEVRootsForLeafCertificate: found %d allowed roots", (int)rootCount); 887 SafeCFRelease(&oidString); 888 if (!allowedRoots || !rootCount) { 889 SafeCFRelease(&allowedRoots); 890 return NULL; 891 } 892 893 // The leaf certificate needs extended validation (with revocation checking). 894 // Return the array of allowed roots for this leaf certificate. 895 return allowedRoots; 896 } 897 898 // returns true if the provided certificate contains a wildcard in either 899 // its common name or subject alternative name. 900 // 901 static 902 bool hasWildcardDNSName(SecCertificateRef certRef) 903 { 904 OSStatus status = errSecSuccess; 905 CFArrayRef dnsNames = NULL; 906 907 BEGIN_SECAPI_INTERNAL_CALL 908 Required(&dnsNames) = Certificate::required(certRef)->copyDNSNames(); 909 END_SECAPI_INTERNAL_CALL 910 if (status || !dnsNames) 911 return false; 912 913 bool hasWildcard = false; 914 const CFStringRef wildcard = CFSTR("*"); 915 CFIndex index, count = CFArrayGetCount(dnsNames); 916 for (index = 0; index < count; index ++) { 917 CFStringRef name = (CFStringRef) CFArrayGetValueAtIndex(dnsNames, index); 918 if (name) { 919 CFRange foundRange = CFStringFind(name, wildcard, 0); 920 if (foundRange.length != 0 && foundRange.location != kCFNotFound) { 921 hasWildcard = true; 922 break; 923 } 924 } 925 } 926 CFRelease(dnsNames); 927 return hasWildcard; 928 } 929 930 // returns a CFDictionaryRef of extended validation results for the given chain, 931 // or NULL if the certificate chain did not meet all EV criteria. (Caller must 932 // release the result if not NULL.) 933 // 934 static 935 CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultType trustResult, OSStatus tpResult) 936 { 937 // This function is intended to be called after the "regular" TP evaluation 938 // has taken place (i.e. trustResult and tpResult are available), and there 939 // is a full certificate chain to examine. 940 941 CFIndex chainIndex, chainLen = (certChain) ? CFArrayGetCount(certChain) : 0; 942 if (chainLen < 2) { 943 return NULL; // invalid chain length 944 } 945 946 if (trustResult != kSecTrustResultUnspecified) { 947 948 // "Recoverable" means the certificate failed to meet all policy requirements, but is intrinsically OK. 949 // One of the failures we might encounter is if the OCSP responder tells us to go away. Since this is a 950 // real-world case, we'll check for OCSP and CRL meta-errors specifically. 951 bool recovered = false; 952 if (trustResult == kSecTrustResultRecoverableTrustFailure) { 953 recovered = isRevocationServerMetaError((CSSM_RETURN)tpResult); 954 } 955 if (!recovered) { 956 return NULL; 957 } 958 } 959 960 // 961 // What we know at this point: 962 // 963 // 1. From a previous call to allowedEVRootsForLeafCertificate 964 // (or we wouldn't be getting called by extendedTrustResults): 965 // - a leaf certificate exists 966 // - that certificate contains a Certificate Policies extension 967 // - that extension contains an OID from one of the trusted EV CAs we know about 968 // - we have found at least one allowed EV root for that OID 969 // 970 // 2. From the TP evaluation: 971 // - the leaf certificate verifies back to a trusted EV root (with no trust settings overrides) 972 // - SSL trust evaluation with OCSP revocation checking enabled returned no (fatal) errors 973 // 974 // We need to verify the following additional requirements for the leaf (as of EV 1.1, 6(a)(2)): 975 // - cannot specify a wildcard in commonName or subjectAltName 976 // (note: this is a change since EV 1.0 (9.2.1), which stated that "Wildcard FQDNs are permitted.") 977 // 978 // Finally, we need to check the following requirements (EV 1.1 specification, Appendix B): 979 // - the trusted root, if created after 10/31/2006, must have: 980 // - critical basicConstraints extension with CA bit set 981 // - critical keyUsage extension with keyCertSign and cRLSign bits set 982 // - intermediate certs, if present, must have: 983 // - certificatePolicies extension, containing either a known EV CA OID, or anyPolicy 984 // - non-critical cRLDistributionPoint extension 985 // - critical basicConstraints extension with CA bit set 986 // - critical keyUsage extension with keyCertSign and cRLSign bits set 987 // 988 989 // check leaf certificate for wildcard names 990 if (hasWildcardDNSName((SecCertificateRef) CFArrayGetValueAtIndex(certChain, 0))) { 991 trustDebug("has wildcard name (does not meet EV criteria)\n"); 992 return NULL; 993 } 994 995 // check intermediate CA certificates for required extensions per Appendix B of EV 1.1 specification. 996 bool hasRequiredExtensions = true; 997 CSSM_CL_HANDLE clHandle = 0; 998 CSSM_DATA certData = { 0, NULL }; 999 CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_CertificatePolicies; 1000 for (chainIndex = 1; hasRequiredExtensions && chainLen > 2 && chainIndex < chainLen - 1; chainIndex++) { 1001 SecCertificateRef intermediateCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, chainIndex); 1002 OSStatus status = errSecSuccess; 1003 // note: Sec* APIs are not re-entrant due to the API lock 1004 // status = SecCertificateGetCLHandle(intermediateCert, &clHandle); 1005 BEGIN_SECAPI_INTERNAL_CALL 1006 clHandle = Certificate::required(intermediateCert)->clHandle(); 1007 END_SECAPI_INTERNAL_CALL 1008 if (status) 1009 return NULL; 1010 // note: Sec* APIs are not re-entrant due to the API lock 1011 // status = SecCertificateGetData(intermediateCert, &certData); 1012 BEGIN_SECAPI_INTERNAL_CALL 1013 certData = Certificate::required(intermediateCert)->data(); 1014 END_SECAPI_INTERNAL_CALL 1015 if (status) 1016 return NULL; 1017 1018 CSSM_DATA_PTR extensionDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle); 1019 if (!extensionDataPtr) 1020 return NULL; 1021 1022 CSSM_X509_EXTENSION *cssmExtension = (CSSM_X509_EXTENSION *)extensionDataPtr->Data; 1023 CE_CertPolicies *certPolicies = (CE_CertPolicies *)cssmExtension->value.parsedValue; 1024 CFStringRef oidString = _oidStringForCertificatePolicies(certPolicies); 1025 hasRequiredExtensions = (oidString != NULL); 1026 SafeCFRelease(&oidString); 1027 _freeFieldData(extensionDataPtr, oidPtr, clHandle); 1028 1029 // FIX: add checks for the following (not essential to this implementation): 1030 // - non-critical cRLDistributionPoint extension 1031 // - critical basicConstraints extension with CA bit set 1032 // - critical keyUsage extension with keyCertSign and cRLSign bits set 1033 // Tracked by <rdar://problem/6119322> 1034 } 1035 1036 if (hasRequiredExtensions) { 1037 SecCertificateRef leafCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, 0); 1038 CFStringRef organizationName = organizationNameForCertificate(leafCert); 1039 if (organizationName != NULL) { 1040 CFMutableDictionaryRef resultDict = CFDictionaryCreateMutable(NULL, 0, 1041 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1042 CFDictionaryAddValue(resultDict, kSecEVOrganizationName, organizationName); 1043 trustDebug("[EV] extended validation succeeded\n"); 1044 SafeCFRelease(&organizationName); 1045 return resultDict; 1046 } 1047 } 1048 1049 return NULL; 1050 } 1051 1052 // returns a CFDictionaryRef containing extended trust results. 1053 // Caller must release this dictionary. 1054 // 1055 // If the isEVCandidate argument is true, extended validation checking is performed 1056 // and the kSecEVOrganizationName key will be set in the dictionary if EV criteria is met. 1057 // In all cases, kSecTrustEvaluationDate and kSecTrustExpirationDate will be set. 1058 // 1059 CFDictionaryRef extendedTrustResults(CFArrayRef certChain, SecTrustResultType trustResult, OSStatus tpResult, bool isEVCandidate) 1060 { 1061 CFMutableDictionaryRef resultDict = NULL; 1062 if (isEVCandidate) { 1063 resultDict = (CFMutableDictionaryRef) extendedValidationResults(certChain, trustResult, tpResult); 1064 } 1065 if (!resultDict) { 1066 resultDict = CFDictionaryCreateMutable(NULL, 0, 1067 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1068 if (!resultDict) { 1069 return NULL; 1070 } 1071 } 1072 CFAbsoluteTime at = CFAbsoluteTimeGetCurrent(); 1073 CFDateRef trustEvaluationDate = CFDateCreate(kCFAllocatorDefault, at); 1074 // by default, permit caching of trust evaluation results for up to 2 hours 1075 // FIXME: need to modify this based on cert expiration and OCSP/CRL validity 1076 CFDateRef trustExpirationDate = CFDateCreate(kCFAllocatorDefault, at + (60*60*2)); 1077 CFDictionaryAddValue(resultDict, kSecTrustEvaluationDate, trustEvaluationDate); 1078 SafeCFRelease(&trustEvaluationDate); 1079 CFDictionaryAddValue(resultDict, kSecTrustExpirationDate, trustExpirationDate); 1080 SafeCFRelease(&trustExpirationDate); 1081 1082 return resultDict; 1083 } 1084 1085 // returns a CFDictionaryRef containing mappings from supported EV CA OIDs to SHA-1 hash values; 1086 // caller must release 1087 // 1088 static CFDictionaryRef _evCAOidDict() 1089 { 1090 static CFDictionaryRef s_evCAOidDict = NULL; 1091 if (s_evCAOidDict) { 1092 CFRetain(s_evCAOidDict); 1093 secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict)); 1094 return s_evCAOidDict; 1095 } 1096 secinfo("evTrust", "_evCAOidDict: initializing static instance"); 1097 1098 s_evCAOidDict = dictionaryWithContentsOfPlistFile(EV_ROOTS_PLIST_SYSTEM_PATH); 1099 if (!s_evCAOidDict) 1100 return NULL; 1101 1102 #if !defined MAC_OS_X_VERSION_10_6 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 1103 // Work around rdar://6302788 by hard coding a hash that was missed when addressing <rdar://problem/6238289&6238296> 1104 // This is being addressed in SnowLeopard by rdar://6305989 1105 CFStringRef oidString = CFSTR("2.16.840.1.114028.10.1.2"); 1106 CFMutableArrayRef hashes = (CFMutableArrayRef) CFDictionaryGetValue(s_evCAOidDict, oidString); 1107 if (hashes) { 1108 uint8 hashBytes[] = {0xB3, 0x1E, 0xB1, 0xB7, 0x40, 0xE3, 0x6C, 0x84, 0x02, 0xDA, 0xDC, 0x37, 0xD4, 0x4D, 0xF5, 0xD4, 0x67, 0x49, 0x52, 0xF9}; 1109 CFDataRef hashData = CFDataCreate(NULL, hashBytes, sizeof(hashBytes)); 1110 CFIndex hashCount = CFArrayGetCount(hashes); 1111 if (hashData && CFArrayContainsValue(hashes, CFRangeMake(0, hashCount), hashData)) { 1112 secinfo("evTrust", "_evCAOidDict: added hardcoded hash value"); 1113 CFArrayAppendValue(hashes, hashData); 1114 } 1115 SafeCFRelease(&hashData); 1116 } 1117 #endif 1118 CFRetain(s_evCAOidDict); 1119 secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict)); 1120 return s_evCAOidDict; 1121 } 1122 1123 // returns a CFStringRef containing a decimal representation of the given OID. 1124 // Caller must release. 1125 1126 static CFStringRef _decimalStringForOid(CSSM_OID_PTR oid) 1127 { 1128 CFMutableStringRef str = CFStringCreateMutable(NULL, 0); 1129 if (!str || oid->Length > 32) 1130 return str; 1131 1132 // The first two levels are encoded into one byte, since the root level 1133 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then 1134 // y may be > 39, so we have to add special-case handling for this. 1135 unsigned long value = 0; 1136 unsigned int x = oid->Data[0] / 40; 1137 unsigned int y = oid->Data[0] % 40; 1138 if (x > 2) { 1139 // Handle special case for large y if x = 2 1140 y += (x - 2) * 40; 1141 x = 2; 1142 } 1143 1144 CFStringAppendFormat(str, NULL, CFSTR("%d.%d"), x, y); 1145 1146 for (x = 1; x < oid->Length; x++) { 1147 value = (value << 7) | (oid->Data[x] & 0x7F); 1148 if(!(oid->Data[x] & 0x80)) { 1149 CFStringAppendFormat(str, NULL, CFSTR(".%ld"), value); 1150 value = 0; 1151 } 1152 } 1153 1154 #if !defined(NDEBUG) 1155 CFIndex nameLen = CFStringGetLength(str); 1156 CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); 1157 char *nameBuf = (char *)malloc(bufLen); 1158 if (!CFStringGetCString(str, nameBuf, bufLen-1, kCFStringEncodingUTF8)) 1159 nameBuf[0]=0; 1160 secinfo("evTrust", "_decimalStringForOid: \"%s\"", nameBuf); 1161 free(nameBuf); 1162 #endif 1163 1164 return str; 1165 } 1166 1167 static void _freeFieldData(CSSM_DATA_PTR value, CSSM_OID_PTR oid, CSSM_CL_HANDLE clHandle) 1168 { 1169 if (value && value->Data) { 1170 CSSM_CL_FreeFieldValue(clHandle, oid, value); 1171 } 1172 return; 1173 } 1174 1175 static ModuleNexus<Mutex> gOidStringForCertificatePoliciesMutex; 1176 1177 static CFStringRef CF_RETURNS_RETAINED _oidStringForCertificatePolicies(const CE_CertPolicies *certPolicies) 1178 { 1179 StLock<Mutex> _(gOidStringForCertificatePoliciesMutex()); 1180 1181 // returns the first EV OID (as a string) found in the given Certificate Policies extension, 1182 // or NULL if the extension does not contain any known EV OIDs. (Note that the "any policy" OID 1183 // is a special case and will be returned if present, although its presence is only meaningful 1184 // in an intermediate CA.) 1185 1186 if (!certPolicies) { 1187 secinfo("evTrust", "oidStringForCertificatePolicies: missing certPolicies!"); 1188 return NULL; 1189 } 1190 1191 CFDictionaryRef evOidDict = _evCAOidDict(); 1192 if (!evOidDict) { 1193 secinfo("evTrust", "oidStringForCertificatePolicies: nil OID dictionary!"); 1194 return NULL; 1195 } 1196 1197 CFStringRef foundOidStr = NULL; 1198 uint32 policyIndex, maxIndex = 10; // sanity check; EV certs normally have EV OID as first policy 1199 for (policyIndex = 0; policyIndex < certPolicies->numPolicies && policyIndex < maxIndex; policyIndex++) { 1200 CE_PolicyInformation *certPolicyInfo = &certPolicies->policies[policyIndex]; 1201 CSSM_OID_PTR oid = &certPolicyInfo->certPolicyId; 1202 CFStringRef oidStr = _decimalStringForOid(oid); 1203 if (!oidStr) 1204 continue; 1205 if (!CFStringCompare(oidStr, CFSTR("2.5.29.32.0"), 0) || // is it the "any" OID, or 1206 CFDictionaryGetValue(evOidDict, oidStr) != NULL) { // a known EV CA OID? 1207 foundOidStr = CFStringCreateCopy(NULL, oidStr); 1208 } 1209 SafeCFRelease(&oidStr); 1210 if (foundOidStr) 1211 break; 1212 } 1213 SafeCFRelease(&evOidDict); 1214 1215 return foundOidStr; 1216 } 1217