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