2  * Copyright (c) 2002-2009,2011-2015 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  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> 
  39 #include <sys/unistd.h> 
  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 
  50 #include "SecTrustPriv.h" 
  51 #include "SecTrustSettings.h" 
  52 #include "SecTrustSettingsPriv.h" 
  57 #define BEGIN_SECAPI_INTERNAL_CALL \ 
  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; } 
  67 /* this actually compiles to nothing */ 
  68 #define trustDebug(args...)             secinfo("trust", ## args) 
  70 #define trustDebug(args...)             printf(args) 
  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"; 
  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
); 
  92 // utility function to safely release (and clear) the given CFTypeRef variable. 
  94 static void SafeCFRelease(void * CF_CONSUMED cfTypeRefPtr
) 
  96         CFTypeRef 
*obj 
= (CFTypeRef 
*)cfTypeRefPtr
; 
 103 // utility function to create a CFDataRef from the contents of the specified file; 
 104 // caller must release 
 106 static CFDataRef CF_RETURNS_RETAINED 
dataWithContentsOfFile(const char *fileName
) 
 112         UInt8 
*fileData 
= NULL
; 
 113         CFDataRef outCFData 
= NULL
; 
 115         fd 
= open(fileName
, O_RDONLY
, 0); 
 119         rtn 
= fstat(fd
, &sb
); 
 123         fileSize 
= (size_t)sb
.st_size
; 
 124         fileData 
= (UInt8 
*) malloc(fileSize
); 
 128         rtn 
= (int)lseek(fd
, 0, SEEK_SET
); 
 132         rtn 
= (int)read(fd
, fileData
, fileSize
); 
 133         if(rtn 
!= (int)fileSize
) { 
 137                 outCFData 
= CFDataCreate(NULL
, fileData
, fileSize
); 
 147 // returns a SecKeychainRef for the system root certificate store; caller must release 
 149 static SecKeychainRef 
systemRootStore() 
 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
 
 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
 
 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
 
 187     if (status 
|| !systemRoots
) { 
 188                 // Cannot get root certificates if there is no trusted system root certificate store. 
 189         SafeCFRelease(&systemRoots
); 
 195 // returns a CFDictionaryRef created from the specified XML plist file; caller must release 
 197 static CFDictionaryRef CF_RETURNS_RETAINED 
dictionaryWithContentsOfPlistFile(const char *fileName
) 
 199         CFDictionaryRef resultDict 
= NULL
; 
 200         CFDataRef fileData 
= dataWithContentsOfFile(fileName
); 
 202                 CFPropertyListRef xmlPlist 
= CFPropertyListCreateFromXMLData(NULL
, fileData
, kCFPropertyListImmutable
, NULL
); 
 203                 if (xmlPlist 
&& CFGetTypeID(xmlPlist
) == CFDictionaryGetTypeID()) { 
 204                         resultDict 
= (CFDictionaryRef
)xmlPlist
; 
 206                         SafeCFRelease(&xmlPlist
); 
 208                 SafeCFRelease(&fileData
); 
 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. 
 216 static CFStringRef 
organizationNameForCertificate(SecCertificateRef certificate
) 
 218     CFStringRef organizationName 
= nil
; 
 219         OSStatus status 
= errSecSuccess
; 
 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
 
 229         return (CFStringRef
)NULL
; 
 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
; 
 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
; 
 252     CSSM_X509_NAME_PTR x509Name 
= (CSSM_X509_NAME_PTR
)(*fieldValues
)->Data
; 
 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
; 
 260         // And then iterate over the attribute-value pairs of each RDN, looking for a CSSMOID_OrganizationName. 
 262         for (pairIndex 
= 0; pairIndex 
< rdnPtr
->numberOfPairs
; pairIndex
++) { 
 263             CSSM_X509_TYPE_VALUE_PAIR 
*pair 
= rdnPtr
->AttributeTypeAndValue 
+ pairIndex
; 
 265             // If this pair isn't the organization name, move on to check the next one. 
 266             if (!oidsAreEqual(&pair
->type
, &CSSMOID_OrganizationName
)) 
 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 
 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
); 
 280                 case BER_TAG_PRINTABLE_STRING
: 
 281                 case BER_TAG_IA5_STRING
: 
 282                                         organizationName 
= CFStringCreateWithBytes(NULL
, pair
->value
.Data
, pair
->value
.Length
, kCFStringEncodingASCII
, FALSE
); 
 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
); 
 293                 case BER_TAG_PKIX_BMP_STRING
: 
 294                                         organizationName 
= CFStringCreateWithBytes(NULL
, pair
->value
.Data
, pair
->value
.Length
, kCFStringEncodingUnicode
, FALSE
); 
 300             // If we found the organization name, there's no need to keep looping. 
 301             if (organizationName
) { 
 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
 
 315     return organizationName
; 
 319 void showCertSKID(const void *value
, void *context
); 
 322 static ModuleNexus
<Mutex
> gPotentialEVChainWithCertificatesMutex
; 
 324 // returns a CFArrayRef of SecCertificateRef instances; caller must release the returned array 
 326 CFArrayRef 
potentialEVChainWithCertificates(CFArrayRef certificates
) 
 328         StLock
<Mutex
> _(gPotentialEVChainWithCertificatesMutex()); 
 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. 
 336         CFIndex chainIndex
, chainLen 
= (certificates
) ? CFArrayGetCount(certificates
) : 0; 
 337         secinfo("trusteval", "potentialEVChainWithCertificates: chainLen: %ld", chainLen
); 
 340                         CFRetain(certificates
); 
 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
) 
 356                                 secinfo("trusteval", "  not found using SKID, try by subject"); 
 357             replacementCert 
= _rootCertificateWithSubjectOfCertificate(aCert
); 
 360         if (!replacementCert
) { 
 361                         secinfo("trusteval", "  No replacement found using SKID or subject; keeping original intermediate"); 
 362             CFArrayAppendValue(certArray
, aCert
); 
 364         SafeCFRelease(&replacementCert
); 
 366         secinfo("trusteval", "potentialEVChainWithCertificates: exit: new chainLen: %ld", CFArrayGetCount(certArray
)); 
 368         CFArrayApplyFunction(certArray
, CFRangeMake(0, CFArrayGetCount(certArray
)), showCertSKID
, NULL
); 
 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. 
 378 static SecCertificateRef 
_rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate
) 
 383         StLock
<Mutex
> _(SecTrustKeychainsGetMutex()); 
 385     // get data+length for the provided certificate 
 386     CSSM_CL_HANDLE clHandle 
= 0; 
 387     CSSM_DATA certData 
= { 0, NULL 
}; 
 388         OSStatus status 
= errSecSuccess
; 
 389         // note: Sec* APIs are not re-entrant due to the API lock 
 390         // status = SecCertificateGetCLHandle(certificate, &clHandle); 
 391         BEGIN_SECAPI_INTERNAL_CALL
 
 392         clHandle 
= Certificate::required(certificate
)->clHandle(); 
 393         END_SECAPI_INTERNAL_CALL
 
 396         // note: Sec* APIs are not re-entrant due to the API lock 
 397         // status = SecCertificateGetData(certificate, &certData); 
 398         BEGIN_SECAPI_INTERNAL_CALL
 
 399         certData 
= Certificate::required(certificate
)->data(); 
 400         END_SECAPI_INTERNAL_CALL
 
 404         // get system roots keychain reference 
 405     SecKeychainRef systemRoots 
= systemRootStore(); 
 409     // copy (normalized) subject for the provided certificate 
 410     const CSSM_OID_PTR oidPtr 
= (const CSSM_OID_PTR
) &CSSMOID_X509V1SubjectName
; 
 411     const CSSM_DATA_PTR subjectDataPtr 
= _copyFieldDataForOid(oidPtr
, &certData
, clHandle
); 
 415     // copy public key for the provided certificate 
 416     SecKeyRef keyRef 
= NULL
; 
 417     SecCertificateRef resultCert 
= NULL
; 
 418         // note: Sec* APIs are not re-entrant due to the API lock 
 419         // status = SecCertificateCopyPublicKey(certificate, &keyRef); 
 420         BEGIN_SECAPI_INTERNAL_CALL
 
 421         keyRef 
= Certificate::required(certificate
)->publicKey()->handle(); 
 422         END_SECAPI_INTERNAL_CALL
 
 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
 
 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
; 
 437                                 CC_SHA1(cssmKey
->KeyData
.Data
, (CC_LONG
)cssmKey
->KeyData
.Length
, buf
); 
 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 
} 
 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
 
 464                                         if (!KCCursorImpl::required(searchRef
)->next(item
)) { 
 465                                                 status
=errSecItemNotFound
; 
 467                                                 certRef
=item
->handle(); 
 469                                         END_SECAPI_INTERNAL_CALL
 
 471                         resultCert 
= (SecCertificateRef
)certRef
; // caller must release 
 472                     SafeCFRelease(&searchRef
); 
 477     _freeFieldData(subjectDataPtr
, oidPtr
, clHandle
); 
 478     SafeCFRelease(&keyRef
); 
 479         SafeCFRelease(&systemRoots
); 
 486 static void logSKID(const char *msg
, const CssmData 
&subjectKeyID
) 
 488         const unsigned char *px 
= (const unsigned char *)subjectKeyID
.data(); 
 489         char buffer
[256]={0,}; 
 494                 for (unsigned int ix
=0; ix
<20; ix
++) 
 496                         sprintf(bytes
, "%02X", px
[ix
]); 
 497                         strcat(buffer
, bytes
); 
 499                 secinfo("trusteval", " SKID: %s",buffer
); 
 503 void showCertSKID(const void *value
, void *context
) 
 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
 
 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. 
 518 static SecCertificateRef 
_rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate
) 
 520     SecCertificateRef resultCert 
= NULL
; 
 521         OSStatus status 
= errSecSuccess
; 
 526         StLock
<Mutex
> _(SecTrustKeychainsGetMutex()); 
 528         // get system roots keychain reference 
 529     SecKeychainRef systemRoots 
= systemRootStore(); 
 533         StorageManager::KeychainList keychains
; 
 534         globals().storageManager
.optionalSearchList(systemRoots
, keychains
); 
 536         BEGIN_SECAPI_INTERNAL_CALL
 
 537         const CssmData 
&subjectKeyID 
= Certificate::required(certificate
)->subjectKeyIdentifier(); 
 539         logSKID("search for SKID: ", subjectKeyID
); 
 541         // caller must release 
 542         resultCert 
= Certificate::required(certificate
)->findBySubjectKeyID(keychains
, subjectKeyID
)->handle(); 
 544         logSKID("  found SKID: ", subjectKeyID
); 
 546         END_SECAPI_INTERNAL_CALL
 
 548         SafeCFRelease(&systemRoots
); 
 553 // returns an array of possible root certificates (SecCertificateRef instances) 
 554 // for the given EV OID (a hex string); caller must release the array 
 557 CFArrayRef CF_RETURNS_RETAINED 
_possibleRootCertificatesForOidString(CFStringRef oidString
) 
 559         StLock
<Mutex
> _(SecTrustKeychainsGetMutex()); 
 563         CFDictionaryRef evOidDict 
= _evCAOidDict(); 
 566         CFArrayRef possibleCertificateHashes 
= (CFArrayRef
) CFDictionaryGetValue(evOidDict
, oidString
); 
 567     SecKeychainRef systemRoots 
= systemRootStore(); 
 568     if (!possibleCertificateHashes 
|| !systemRoots
) { 
 569                 SafeCFRelease(&evOidDict
); 
 573         CFMutableArrayRef possibleRootCertificates 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 574         CFIndex hashCount 
= CFArrayGetCount(possibleCertificateHashes
); 
 575         secinfo("evTrust", "_possibleRootCertificatesForOidString: %d possible hashes", (int)hashCount
); 
 577         OSStatus status 
= errSecSuccess
; 
 578         SecKeychainSearchRef searchRef 
= NULL
; 
 579         // note: Sec* APIs are not re-entrant due to the API lock 
 580         // status = SecKeychainSearchCreateFromAttributes(systemRoots, kSecCertificateItemClass, NULL, &searchRef); 
 581         BEGIN_SECAPI_INTERNAL_CALL
 
 582         StorageManager::KeychainList keychains
; 
 583         globals().storageManager
.optionalSearchList(systemRoots
, keychains
); 
 584         KCCursor 
cursor(keychains
, kSecCertificateItemClass
, NULL
); 
 585         searchRef 
= cursor
->handle(); 
 586         END_SECAPI_INTERNAL_CALL
 
 589                         SecKeychainItemRef certRef 
= NULL
; 
 590                         // note: Sec* APIs are not re-entrant due to the API lock 
 591                         // status = SecKeychainSearchCopyNext(searchRef, &certRef); 
 592                         BEGIN_SECAPI_INTERNAL_CALL
 
 594                         if (!KCCursorImpl::required(searchRef
)->next(item
)) { 
 596                                 status
=errSecItemNotFound
; 
 598                                 certRef
=item
->handle(); 
 600                         END_SECAPI_INTERNAL_CALL
 
 601                         if (status 
|| !certRef
) { 
 605                         CSSM_DATA certData 
= { 0, NULL 
}; 
 606                         // note: Sec* APIs are not re-entrant due to the API lock 
 607                         // status = SecCertificateGetData((SecCertificateRef) certRef, &certData); 
 608                         BEGIN_SECAPI_INTERNAL_CALL
 
 609                         certData 
= Certificate::required((SecCertificateRef
)certRef
)->data(); 
 610                         END_SECAPI_INTERNAL_CALL
 
 612                                 uint8 buf
[CC_SHA1_DIGEST_LENGTH
]; 
 613                                 CSSM_DATA digest 
= { sizeof(buf
), buf 
}; 
 614                                 if (!certData
.Data 
|| !certData
.Length
) { 
 615                                         status 
= errSecParam
; 
 617                                         CC_SHA1(certData
.Data
, (CC_LONG
)certData
.Length
, buf
); 
 620                                         CFDataRef hashData 
= CFDataCreateWithBytesNoCopy(NULL
, digest
.Data
, digest
.Length
, kCFAllocatorNull
); 
 621                                         if (hashData 
&& CFArrayContainsValue(possibleCertificateHashes
, CFRangeMake(0, hashCount
), hashData
)) { 
 622                                                 CFArrayAppendValue(possibleRootCertificates
, certRef
); 
 624                                         SafeCFRelease(&hashData
); 
 627                         SafeCFRelease(&certRef
); 
 630         SafeCFRelease(&searchRef
); 
 631     SafeCFRelease(&systemRoots
); 
 632         SafeCFRelease(&evOidDict
); 
 634     return possibleRootCertificates
; 
 637 // returns an array of allowed root certificates (SecCertificateRef instances) 
 638 // for the given EV OID (a hex string); caller must release the array. 
 639 // This differs from _possibleRootCertificatesForOidString in that each possible 
 640 // certificate is further checked for trust settings, so we don't include 
 641 // a certificate which is untrusted (or explicitly distrusted). 
 643 CFArrayRef 
_allowedRootCertificatesForOidString(CFStringRef oidString
) 
 645         CFMutableArrayRef allowedRootCertificates 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 646         CFArrayRef possibleRootCertificates 
= _possibleRootCertificatesForOidString(oidString
); 
 647         if (possibleRootCertificates
) { 
 648                 CFIndex idx
, count 
= CFArrayGetCount(possibleRootCertificates
); 
 649                 for (idx
=0; idx
<count
; idx
++) { 
 650                         SecCertificateRef cert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(possibleRootCertificates
, idx
); 
 651                         /* Need a unified SecCertificateRef instance to hand to SecTrustSettingsCertHashStrFromCert */ 
 652                         SecCertificateRef certRef 
= SecCertificateCreateFromItemImplInstance(cert
); 
 653                         CFStringRef hashStr 
= SecTrustSettingsCertHashStrFromCert(certRef
); 
 655                                 bool foundMatch 
= false; 
 656                                 bool foundAny 
= false; 
 657                                 CSSM_RETURN 
*errors 
= NULL
; 
 658                                 uint32 errorCount 
= 0; 
 659                                 SecTrustSettingsDomain foundDomain 
= kSecTrustSettingsDomainUser
; 
 660                                 SecTrustSettingsResult result 
= kSecTrustSettingsResultInvalid
; 
 661                                 OSStatus status 
= SecTrustSettingsEvaluateCert( 
 662                                         hashStr
,                /* certHashStr */ 
 663                                         NULL
,                   /* policyOID (optional) */ 
 664                                         NULL
,                   /* policyString (optional) */ 
 665                                         0,                              /* policyStringLen */ 
 667                                         true,                   /* isRootCert */ 
 668                                         &foundDomain
,   /* foundDomain */ 
 669                                         &errors
,                /* allowedErrors */ 
 670                                         &errorCount
,    /* numAllowedErrors */ 
 671                                         &result
,                /* resultType */ 
 672                                         &foundMatch
,    /* foundMatchingEntry */ 
 673                                         &foundAny
);             /* foundAnyEntry */ 
 675                                 if (status 
== errSecSuccess
) { 
 676                                         secinfo("evTrust", "_allowedRootCertificatesForOidString: cert %lu has result %d from domain %d", 
 677                                                 idx
, (int)result
, (int)foundDomain
); 
 678                                         // Root certificates must be trusted by the system (and not have 
 679                                         // any explicit trust overrides) to be allowed for EV use. 
 680                                         if (foundMatch 
&& foundDomain 
== kSecTrustSettingsDomainSystem 
&& 
 681                                                 result 
== kSecTrustSettingsResultTrustRoot
) { 
 682                                                 CFArrayAppendValue(allowedRootCertificates
, cert
); 
 685                                         secinfo("evTrust", "_allowedRootCertificatesForOidString: cert %lu SecTrustSettingsEvaluateCert error %d", 
 697                 CFRelease(possibleRootCertificates
); 
 700         return allowedRootCertificates
; 
 703 // return a CSSM_DATA_PTR containing field data; caller must release with _freeFieldData 
 705 static CSSM_DATA_PTR 
_copyFieldDataForOid(CSSM_OID_PTR oid
, CSSM_DATA_PTR cert
, CSSM_CL_HANDLE clHandle
) 
 707     uint32 numFields 
= 0; 
 708     CSSM_HANDLE results 
= 0; 
 709     CSSM_DATA_PTR value 
= 0; 
 710     CSSM_RETURN crtn 
= CSSM_CL_CertGetFirstFieldValue(clHandle
, cert
, oid
, &results
, &numFields
, &value
); 
 712         // we aren't going to look for any further fields, so free the results handle immediately 
 714                 CSSM_CL_CertAbortQuery(clHandle
, results
); 
 717     return (crtn 
|| !numFields
) ? NULL 
: value
; 
 720 // Some errors are ignorable errors because they do not indicate a problem 
 721 // with the certificate itself, but rather a problem getting a response from 
 722 // the CA server. The EV Certificate spec does not mandate that the application 
 723 // software vendor *must* get a response from OCSP or CRL, it is a "best 
 724 // attempt" approach which will not fail if the server does not respond. 
 726 // The EV spec (26. EV Certificate Status Checking) says that CAs have to 
 727 // maintain either a CRL or OCSP server. They are not required to maintain 
 728 // an OCSP server until after Dec 31, 2010. 
 730 // As to the responsibility of the application software vendor to perform 
 731 // revocation checking, this is only covered by the following section (37.2.): 
 733 // This [indemnification of Application Software Vendors] 
 734 // shall not apply, however, to any claim, damages, or loss 
 735 // suffered by such Application Software Vendor related to an EV Certificate 
 736 // issued by the CA where such claim, damage, or loss was directly caused by 
 737 // such Application Software Vendor’s software displaying as not trustworthy an 
 738 // EV Certificate that is still valid, or displaying as trustworthy: (1) an EV 
 739 // Certificate that has expired, or (2) an EV Certificate that has been revoked 
 740 // (but only in cases where the revocation status is currently available from the 
 741 // CA online, and the browser software either failed to check such status or 
 742 // ignored an indication of revoked status). 
 744 // The last section describes what a browser is required to do: it must attempt 
 745 // to check revocation status (as indicated by the OCSP or CRL server info in 
 746 // the certificate), and it cannot ignore an indication of revoked status 
 747 // (i.e. a positive thumbs-down response from the server, which would be a 
 748 // different error than the ones being skipped.) However, given that we meet 
 749 // those requirements, if the revocation server is down or will not give us a 
 750 // response for whatever reason, that is not our problem. 
 752 bool isRevocationServerMetaError(CSSM_RETURN statusCode
) 
 754    switch (statusCode
) { 
 755        case CSSMERR_APPLETP_CRL_NOT_FOUND
:             // 13. CRL not found 
 756        case CSSMERR_APPLETP_CRL_SERVER_DOWN
:           // 14. CRL server down 
 757        case CSSMERR_APPLETP_OCSP_UNAVAILABLE
:          // 33. OCSP service unavailable 
 758        case CSSMERR_APPLETP_NETWORK_FAILURE
:           // 36. General network failure 
 759        case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ
:   // 41. OCSP responder status: malformed request 
 760        case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR
:    // 42. OCSP responder status: internal error 
 761        case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
:       // 43. OCSP responder status: try later 
 762        case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED
:    // 44. OCSP responder status: signature required 
 763        case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED
:    // 45. OCSP responder status: unauthorized 
 770 // returns true if the given status code is related to performing an OCSP revocation check 
 772 bool isOCSPStatusCode(CSSM_RETURN statusCode
) 
 776         case CSSMERR_APPLETP_OCSP_BAD_RESPONSE
:         // 31. Unparseable OCSP response 
 777         case CSSMERR_APPLETP_OCSP_BAD_REQUEST
:          // 32. Unparseable OCSP request 
 778         case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ
:   // 41. OCSP responder status: malformed request 
 779         case CSSMERR_APPLETP_OCSP_UNAVAILABLE
:          // 33. OCSP service unavailable 
 780         case CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED
:  // 34. OCSP status: cert unrecognized 
 781         case CSSMERR_APPLETP_OCSP_NOT_TRUSTED
:          // 37. OCSP response not verifiable to anchor or root 
 782         case CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT
:  // 38. OCSP response verified to untrusted root 
 783         case CSSMERR_APPLETP_OCSP_SIG_ERROR
:            // 39. OCSP response signature error 
 784         case CSSMERR_APPLETP_OCSP_NO_SIGNER
:            // 40. No signer for OCSP response found 
 785         case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR
:    // 42. OCSP responder status: internal error 
 786         case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
:       // 43. OCSP responder status: try later 
 787         case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED
:    // 44. OCSP responder status: signature required 
 788         case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED
:    // 45. OCSP responder status: unauthorized 
 789         case CSSMERR_APPLETP_OCSP_NONCE_MISMATCH
:       // 46. OCSP response nonce did not match request 
 796 // returns true if the given status code is related to performing a CRL revocation check 
 798 bool isCRLStatusCode(CSSM_RETURN statusCode
) 
 802         case CSSMERR_APPLETP_CRL_EXPIRED
:               // 11. CRL expired 
 803         case CSSMERR_APPLETP_CRL_NOT_VALID_YET
:         // 12. CRL not yet valid 
 804         case CSSMERR_APPLETP_CRL_NOT_FOUND
:             // 13. CRL not found 
 805         case CSSMERR_APPLETP_CRL_SERVER_DOWN
:           // 14. CRL server down 
 806         case CSSMERR_APPLETP_CRL_BAD_URI
:               // 15. Illegal CRL distribution point URI 
 807         case CSSMERR_APPLETP_CRL_NOT_TRUSTED
:           // 18. CRL not verifiable to anchor or root 
 808         case CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT
:   // 19. CRL verified to untrusted root 
 809         case CSSMERR_APPLETP_CRL_POLICY_FAIL
:           // 20. CRL failed policy verification 
 816 // returns true if the given status code is related to performing a revocation check 
 818 bool isRevocationStatusCode(CSSM_RETURN statusCode
) 
 820     if (statusCode 
== CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK 
||  // 35. Revocation check not successful for each cert 
 821         statusCode 
== CSSMERR_APPLETP_NETWORK_FAILURE 
||              // 36. General network error 
 822         isOCSPStatusCode(statusCode
) == true ||                       // OCSP error 
 823         isCRLStatusCode(statusCode
) == true)                          // CRL error 
 829 // returns a CFArrayRef of allowed root certificates for the provided leaf certificate 
 830 // if it passes initial EV evaluation criteria and should be subject to OCSP revocation 
 831 // checking; otherwise, NULL is returned. (Caller must release the result if not NULL.) 
 833 CFArrayRef 
allowedEVRootsForLeafCertificate(CFArrayRef certificates
) 
 835     // Given a partial certificate chain (which may or may not include the root, 
 836     // and does not have a guaranteed order except the first item is the leaf), 
 837         // determine whether the leaf claims to have a supported EV policy OID. 
 839         // Unless this function returns NULL, a full SSL trust evaluation with OCSP revocation 
 840         // checking must be performed successfully for the certificate to be considered valid. 
 841         // This function is intended to be called before the chain has been evaluated, 
 842         // in order to obtain the list of allowed roots for the evaluation. Once the "regular" 
 843         // TP evaluation has taken place, chainMeetsExtendedValidationCriteria() should be 
 844         // called to complete extended validation checking. 
 846         CFIndex count 
= (certificates
) ? CFArrayGetCount(certificates
) : 0; 
 850     CSSM_CL_HANDLE clHandle 
= 0; 
 851     CSSM_DATA certData 
= { 0, NULL 
}; 
 852     SecCertificateRef certRef 
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, 0); 
 853         OSStatus status 
= errSecSuccess
; 
 854         // note: Sec* APIs are not re-entrant due to the API lock 
 855         // status = SecCertificateGetCLHandle(certRef, &clHandle); 
 856         BEGIN_SECAPI_INTERNAL_CALL
 
 857         clHandle 
= Certificate::required(certRef
)->clHandle(); 
 858         END_SECAPI_INTERNAL_CALL
 
 861         // note: Sec* APIs are not re-entrant due to the API lock 
 862         // status = SecCertificateGetData(certRef, &certData); 
 863         BEGIN_SECAPI_INTERNAL_CALL
 
 864         certData 
= Certificate::required(certRef
)->data(); 
 865         END_SECAPI_INTERNAL_CALL
 
 869     // Does the leaf certificate contain a Certificate Policies extension? 
 870     const CSSM_OID_PTR oidPtr 
= (CSSM_OID_PTR
) &CSSMOID_CertificatePolicies
; 
 871     CSSM_DATA_PTR extensionDataPtr 
= _copyFieldDataForOid(oidPtr
, &certData
, clHandle
); 
 872     if (!extensionDataPtr
) 
 875     // Does the extension contain one of the magic EV CA OIDs we know about? 
 876     CSSM_X509_EXTENSION 
*cssmExtension 
= (CSSM_X509_EXTENSION 
*)extensionDataPtr
->Data
; 
 877     CE_CertPolicies 
*certPolicies 
= (CE_CertPolicies 
*)cssmExtension
->value
.parsedValue
; 
 878     CFStringRef oidString 
= _oidStringForCertificatePolicies(certPolicies
); 
 879         _freeFieldData(extensionDataPtr
, oidPtr
, clHandle
); 
 881     // Fetch the allowed root CA certificates for this OID, if any 
 882     CFArrayRef allowedRoots 
= (oidString
) ? _allowedRootCertificatesForOidString(oidString
) : NULL
; 
 883         CFIndex rootCount 
= (allowedRoots
) ? CFArrayGetCount(allowedRoots
) : 0; 
 884         secinfo("evTrust", "allowedEVRootsForLeafCertificate: found %d allowed roots", (int)rootCount
); 
 885         SafeCFRelease(&oidString
); 
 886         if (!allowedRoots 
|| !rootCount
) { 
 887                 SafeCFRelease(&allowedRoots
); 
 891         // The leaf certificate needs extended validation (with revocation checking). 
 892         // Return the array of allowed roots for this leaf certificate. 
 896 // returns true if the provided certificate contains a wildcard in either 
 897 // its common name or subject alternative name. 
 900 bool hasWildcardDNSName(SecCertificateRef certRef
) 
 902         OSStatus status 
= errSecSuccess
; 
 903         CFArrayRef dnsNames 
= NULL
; 
 905         BEGIN_SECAPI_INTERNAL_CALL
 
 906         Required(&dnsNames
) = Certificate::required(certRef
)->copyDNSNames(); 
 907         END_SECAPI_INTERNAL_CALL
 
 908         if (status 
|| !dnsNames
) 
 911         bool hasWildcard 
= false; 
 912         const CFStringRef wildcard 
= CFSTR("*"); 
 913         CFIndex index
, count 
= CFArrayGetCount(dnsNames
); 
 914         for (index 
= 0; index 
< count
; index 
++) { 
 915                 CFStringRef name 
= (CFStringRef
) CFArrayGetValueAtIndex(dnsNames
, index
); 
 917                         CFRange foundRange 
= CFStringFind(name
, wildcard
, 0); 
 918                         if (foundRange
.length 
!= 0 && foundRange
.location 
!= kCFNotFound
) { 
 928 // returns a CFDictionaryRef of extended validation results for the given chain, 
 929 // or NULL if the certificate chain did not meet all EV criteria. (Caller must 
 930 // release the result if not NULL.) 
 933 CFDictionaryRef 
extendedValidationResults(CFArrayRef certChain
, SecTrustResultType trustResult
, OSStatus tpResult
) 
 935         // This function is intended to be called after the "regular" TP evaluation 
 936         // has taken place (i.e. trustResult and tpResult are available), and there 
 937         // is a full certificate chain to examine. 
 939     CFIndex chainIndex
, chainLen 
= (certChain
) ? CFArrayGetCount(certChain
) : 0; 
 941                 return NULL
; // invalid chain length 
 944     if (trustResult 
!= kSecTrustResultUnspecified
) { 
 946         // "Recoverable" means the certificate failed to meet all policy requirements, but is intrinsically OK. 
 947         // One of the failures we might encounter is if the OCSP responder tells us to go away. Since this is a 
 948         // real-world case, we'll check for OCSP and CRL meta-errors specifically. 
 949         bool recovered 
= false; 
 950         if (trustResult 
== kSecTrustResultRecoverableTrustFailure
) { 
 951             recovered 
= isRevocationServerMetaError((CSSM_RETURN
)tpResult
); 
 959     // What we know at this point: 
 961         // 1. From a previous call to allowedEVRootsForLeafCertificate 
 962         // (or we wouldn't be getting called by extendedTrustResults): 
 963     // - a leaf certificate exists 
 964     // - that certificate contains a Certificate Policies extension 
 965     // - that extension contains an OID from one of the trusted EV CAs we know about 
 966         // - we have found at least one allowed EV root for that OID 
 968         // 2. From the TP evaluation: 
 969     // - the leaf certificate verifies back to a trusted EV root (with no trust settings overrides) 
 970     // - SSL trust evaluation with OCSP revocation checking enabled returned no (fatal) errors 
 972     // We need to verify the following additional requirements for the leaf (as of EV 1.1, 6(a)(2)): 
 973     // - cannot specify a wildcard in commonName or subjectAltName 
 974     // (note: this is a change since EV 1.0 (9.2.1), which stated that "Wildcard FQDNs are permitted.") 
 976         // Finally, we need to check the following requirements (EV 1.1 specification, Appendix B): 
 977     // - the trusted root, if created after 10/31/2006, must have: 
 978     //      - critical basicConstraints extension with CA bit set 
 979     //      - critical keyUsage extension with keyCertSign and cRLSign bits set 
 980     // - intermediate certs, if present, must have: 
 981     //      - certificatePolicies extension, containing either a known EV CA OID, or anyPolicy 
 982     //      - non-critical cRLDistributionPoint extension 
 983     //      - critical basicConstraints extension with CA bit set 
 984     //      - critical keyUsage extension with keyCertSign and cRLSign bits set 
 987         // check leaf certificate for wildcard names 
 988         if (hasWildcardDNSName((SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, 0))) { 
 989                 trustDebug("has wildcard name (does not meet EV criteria)\n"); 
 993     // check intermediate CA certificates for required extensions per Appendix B of EV 1.1 specification. 
 994     bool hasRequiredExtensions 
= true; 
 995         CSSM_CL_HANDLE clHandle 
= 0; 
 996         CSSM_DATA certData 
= { 0, NULL 
}; 
 997         CSSM_OID_PTR oidPtr 
= (CSSM_OID_PTR
) &CSSMOID_CertificatePolicies
; 
 998     for (chainIndex 
= 1; hasRequiredExtensions 
&& chainLen 
> 2 && chainIndex 
< chainLen 
- 1; chainIndex
++) { 
 999         SecCertificateRef intermediateCert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, chainIndex
); 
1000                 OSStatus status 
= errSecSuccess
; 
1001                 // note: Sec* APIs are not re-entrant due to the API lock 
1002                 // status = SecCertificateGetCLHandle(intermediateCert, &clHandle); 
1003                 BEGIN_SECAPI_INTERNAL_CALL
 
1004                 clHandle 
= Certificate::required(intermediateCert
)->clHandle(); 
1005                 END_SECAPI_INTERNAL_CALL
 
1008                 // note: Sec* APIs are not re-entrant due to the API lock 
1009                 // status = SecCertificateGetData(intermediateCert, &certData); 
1010                 BEGIN_SECAPI_INTERNAL_CALL
 
1011                 certData 
= Certificate::required(intermediateCert
)->data(); 
1012                 END_SECAPI_INTERNAL_CALL
 
1016         CSSM_DATA_PTR extensionDataPtr 
= _copyFieldDataForOid(oidPtr
, &certData
, clHandle
); 
1017         if (!extensionDataPtr
) 
1020         CSSM_X509_EXTENSION 
*cssmExtension 
= (CSSM_X509_EXTENSION 
*)extensionDataPtr
->Data
; 
1021         CE_CertPolicies 
*certPolicies 
= (CE_CertPolicies 
*)cssmExtension
->value
.parsedValue
; 
1022                 CFStringRef oidString 
= _oidStringForCertificatePolicies(certPolicies
); 
1023         hasRequiredExtensions 
= (oidString 
!= NULL
); 
1024                 SafeCFRelease(&oidString
); 
1025         _freeFieldData(extensionDataPtr
, oidPtr
, clHandle
); 
1027         // FIX: add checks for the following (not essential to this implementation): 
1028         //      - non-critical cRLDistributionPoint extension 
1029         //      - critical basicConstraints extension with CA bit set 
1030         //      - critical keyUsage extension with keyCertSign and cRLSign bits set 
1031         // Tracked by <rdar://problem/6119322> 
1034     if (hasRequiredExtensions
) { 
1035                 SecCertificateRef leafCert 
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, 0); 
1036                 CFStringRef organizationName 
= organizationNameForCertificate(leafCert
); 
1037                 if (organizationName 
!= NULL
) { 
1038                         CFMutableDictionaryRef resultDict 
= CFDictionaryCreateMutable(NULL
, 0, 
1039                                 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1040                         CFDictionaryAddValue(resultDict
, kSecEVOrganizationName
, organizationName
); 
1041                         trustDebug("[EV] extended validation succeeded\n"); 
1042                         SafeCFRelease(&organizationName
); 
1050 // returns a CFDictionaryRef containing extended trust results. 
1051 // Caller must release this dictionary. 
1053 // If the isEVCandidate argument is true, extended validation checking is performed 
1054 // and the kSecEVOrganizationName key will be set in the dictionary if EV criteria is met. 
1055 // In all cases, kSecTrustEvaluationDate and kSecTrustExpirationDate will be set. 
1057 CFDictionaryRef 
extendedTrustResults(CFArrayRef certChain
, SecTrustResultType trustResult
, OSStatus tpResult
, bool isEVCandidate
) 
1059         CFMutableDictionaryRef resultDict 
= NULL
; 
1060         if (isEVCandidate
) { 
1061                 resultDict 
= (CFMutableDictionaryRef
) extendedValidationResults(certChain
, trustResult
, tpResult
); 
1064                 resultDict 
= CFDictionaryCreateMutable(NULL
, 0, 
1065                         &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1070         CFAbsoluteTime at 
= CFAbsoluteTimeGetCurrent(); 
1071         CFDateRef trustEvaluationDate 
= CFDateCreate(kCFAllocatorDefault
, at
); 
1072         // by default, permit caching of trust evaluation results for up to 2 hours 
1073         // FIXME: need to modify this based on cert expiration and OCSP/CRL validity 
1074         CFDateRef trustExpirationDate 
= CFDateCreate(kCFAllocatorDefault
, at 
+ (60*60*2)); 
1075         CFDictionaryAddValue(resultDict
, kSecTrustEvaluationDate
, trustEvaluationDate
); 
1076         SafeCFRelease(&trustEvaluationDate
); 
1077         CFDictionaryAddValue(resultDict
, kSecTrustExpirationDate
, trustExpirationDate
); 
1078         SafeCFRelease(&trustExpirationDate
); 
1083 // returns a CFDictionaryRef containing mappings from supported EV CA OIDs to SHA-1 hash values; 
1084 // caller must release 
1086 static CFDictionaryRef 
_evCAOidDict() 
1088     static CFDictionaryRef s_evCAOidDict 
= NULL
; 
1089     if (s_evCAOidDict
) { 
1090                 CFRetain(s_evCAOidDict
); 
1091                 secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict
)); 
1092         return s_evCAOidDict
; 
1094         secinfo("evTrust", "_evCAOidDict: initializing static instance"); 
1096         s_evCAOidDict 
= dictionaryWithContentsOfPlistFile(EV_ROOTS_PLIST_SYSTEM_PATH
); 
1100 #if !defined MAC_OS_X_VERSION_10_6 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 
1101         // Work around rdar://6302788 by hard coding a hash that was missed when addressing <rdar://problem/6238289&6238296> 
1102         // This is being addressed in SnowLeopard by rdar://6305989 
1103         CFStringRef oidString 
= CFSTR("2.16.840.1.114028.10.1.2"); 
1104         CFMutableArrayRef hashes 
= (CFMutableArrayRef
) CFDictionaryGetValue(s_evCAOidDict
, oidString
); 
1106                 uint8 hashBytes
[] = {0xB3, 0x1E, 0xB1, 0xB7, 0x40, 0xE3, 0x6C, 0x84, 0x02, 0xDA, 0xDC, 0x37, 0xD4, 0x4D, 0xF5, 0xD4, 0x67, 0x49, 0x52, 0xF9}; 
1107                 CFDataRef hashData 
= CFDataCreate(NULL
, hashBytes
, sizeof(hashBytes
)); 
1108                 CFIndex hashCount 
= CFArrayGetCount(hashes
); 
1109                 if (hashData 
&& CFArrayContainsValue(hashes
, CFRangeMake(0, hashCount
), hashData
)) { 
1110                         secinfo("evTrust", "_evCAOidDict: added hardcoded hash value"); 
1111                         CFArrayAppendValue(hashes
, hashData
); 
1113                 SafeCFRelease(&hashData
); 
1116         CFRetain(s_evCAOidDict
); 
1117         secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict
)); 
1118     return s_evCAOidDict
; 
1121 // returns a CFStringRef containing a decimal representation of the given OID. 
1122 // Caller must release. 
1124 static CFStringRef 
_decimalStringForOid(CSSM_OID_PTR oid
) 
1126     CFMutableStringRef str 
= CFStringCreateMutable(NULL
, 0); 
1127     if (!str 
|| oid
->Length 
> 32) 
1130     // The first two levels are encoded into one byte, since the root level 
1131     // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then 
1132     // y may be > 39, so we have to add special-case handling for this. 
1133     unsigned long value 
= 0; 
1134     unsigned int x 
= oid
->Data
[0] / 40; 
1135     unsigned int y 
= oid
->Data
[0] % 40; 
1137         // Handle special case for large y if x = 2 
1142         CFStringAppendFormat(str
, NULL
, CFSTR("%d.%d"), x
, y
); 
1144     for (x 
= 1; x 
< oid
->Length
; x
++) { 
1145         value 
= (value 
<< 7) | (oid
->Data
[x
] & 0x7F); 
1146         if(!(oid
->Data
[x
] & 0x80)) { 
1147                         CFStringAppendFormat(str
, NULL
, CFSTR(".%ld"), value
); 
1152 #if !defined(NDEBUG) 
1153         CFIndex nameLen 
= CFStringGetLength(str
); 
1154         CFIndex bufLen 
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
); 
1155         char *nameBuf 
= (char *)malloc(bufLen
); 
1156         if (!CFStringGetCString(str
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
)) 
1158         secinfo("evTrust", "_decimalStringForOid: \"%s\"", nameBuf
); 
1165 static void _freeFieldData(CSSM_DATA_PTR value
, CSSM_OID_PTR oid
, CSSM_CL_HANDLE clHandle
) 
1167         if (value 
&& value
->Data
) { 
1168                 CSSM_CL_FreeFieldValue(clHandle
, oid
, value
); 
1173 static ModuleNexus
<Mutex
> gOidStringForCertificatePoliciesMutex
; 
1175 static CFStringRef CF_RETURNS_RETAINED 
_oidStringForCertificatePolicies(const CE_CertPolicies 
*certPolicies
) 
1177         StLock
<Mutex
> _(gOidStringForCertificatePoliciesMutex()); 
1179     // returns the first EV OID (as a string) found in the given Certificate Policies extension, 
1180     // or NULL if the extension does not contain any known EV OIDs. (Note that the "any policy" OID 
1181     // is a special case and will be returned if present, although its presence is only meaningful 
1182     // in an intermediate CA.) 
1184     if (!certPolicies
) { 
1185                 secinfo("evTrust", "oidStringForCertificatePolicies: missing certPolicies!"); 
1189         CFDictionaryRef evOidDict 
= _evCAOidDict(); 
1191                 secinfo("evTrust", "oidStringForCertificatePolicies: nil OID dictionary!"); 
1195         CFStringRef foundOidStr 
= NULL
; 
1196     uint32 policyIndex
, maxIndex 
= 10; // sanity check; EV certs normally have EV OID as first policy 
1197     for (policyIndex 
= 0; policyIndex 
< certPolicies
->numPolicies 
&& policyIndex 
< maxIndex
; policyIndex
++) { 
1198         CE_PolicyInformation 
*certPolicyInfo 
= &certPolicies
->policies
[policyIndex
]; 
1199         CSSM_OID_PTR oid 
= &certPolicyInfo
->certPolicyId
; 
1200         CFStringRef oidStr 
= _decimalStringForOid(oid
); 
1203                 if (!CFStringCompare(oidStr
, CFSTR("2.5.29.32.0"), 0) ||        // is it the "any" OID, or 
1204                         CFDictionaryGetValue(evOidDict
, oidStr
) != NULL
) {              // a known EV CA OID? 
1205                         foundOidStr 
= CFStringCreateCopy(NULL
, oidStr
); 
1207                 SafeCFRelease(&oidStr
); 
1211         SafeCFRelease(&evOidDict
);