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
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
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 true if the given revocation status code can be ignored.
831 bool ignorableRevocationStatusCode(CSSM_RETURN statusCode
)
833 if (!isRevocationStatusCode(statusCode
))
836 // if OCSP and/or CRL revocation info was unavailable for this certificate,
837 // and revocation checking is not required, we can ignore this status code.
839 CFStringRef ocsp_val
= (CFStringRef
) CFPreferencesCopyValue(kSecRevocationOcspStyle
, CFSTR(kSecRevocationDomain
), kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
840 CFStringRef crl_val
= (CFStringRef
) CFPreferencesCopyValue(kSecRevocationCrlStyle
, CFSTR(kSecRevocationDomain
), kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
841 bool ocspRequired
= (ocsp_val
&& CFEqual(ocsp_val
, kSecRevocationRequireForAll
));
842 bool crlRequired
= (crl_val
&& CFEqual(crl_val
, kSecRevocationRequireForAll
));
843 if (!ocspRequired
&& ocsp_val
&& CFEqual(ocsp_val
, kSecRevocationRequireIfPresent
))
844 ocspRequired
= (statusCode
!= CSSMERR_APPLETP_OCSP_UNAVAILABLE
);
845 if (!crlRequired
&& crl_val
&& CFEqual(crl_val
, kSecRevocationRequireIfPresent
))
846 crlRequired
= (statusCode
!= CSSMERR_APPLETP_CRL_NOT_FOUND
);
852 if (isOCSPStatusCode(statusCode
))
853 return (ocspRequired
) ? false : true;
854 if (isCRLStatusCode(statusCode
))
855 return (crlRequired
) ? false : true;
860 // returns a CFArrayRef of allowed root certificates for the provided leaf certificate
861 // if it passes initial EV evaluation criteria and should be subject to OCSP revocation
862 // checking; otherwise, NULL is returned. (Caller must release the result if not NULL.)
864 CFArrayRef
allowedEVRootsForLeafCertificate(CFArrayRef certificates
)
866 // Given a partial certificate chain (which may or may not include the root,
867 // and does not have a guaranteed order except the first item is the leaf),
868 // determine whether the leaf claims to have a supported EV policy OID.
870 // Unless this function returns NULL, a full SSL trust evaluation with OCSP revocation
871 // checking must be performed successfully for the certificate to be considered valid.
872 // This function is intended to be called before the chain has been evaluated,
873 // in order to obtain the list of allowed roots for the evaluation. Once the "regular"
874 // TP evaluation has taken place, chainMeetsExtendedValidationCriteria() should be
875 // called to complete extended validation checking.
877 CFIndex count
= (certificates
) ? CFArrayGetCount(certificates
) : 0;
881 CSSM_CL_HANDLE clHandle
= 0;
882 CSSM_DATA certData
= { 0, NULL
};
883 SecCertificateRef certRef
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, 0);
884 OSStatus status
= errSecSuccess
;
885 // note: Sec* APIs are not re-entrant due to the API lock
886 // status = SecCertificateGetCLHandle(certRef, &clHandle);
887 BEGIN_SECAPI_INTERNAL_CALL
888 clHandle
= Certificate::required(certRef
)->clHandle();
889 END_SECAPI_INTERNAL_CALL
892 // note: Sec* APIs are not re-entrant due to the API lock
893 // status = SecCertificateGetData(certRef, &certData);
894 BEGIN_SECAPI_INTERNAL_CALL
895 certData
= Certificate::required(certRef
)->data();
896 END_SECAPI_INTERNAL_CALL
900 // Does the leaf certificate contain a Certificate Policies extension?
901 const CSSM_OID_PTR oidPtr
= (CSSM_OID_PTR
) &CSSMOID_CertificatePolicies
;
902 CSSM_DATA_PTR extensionDataPtr
= _copyFieldDataForOid(oidPtr
, &certData
, clHandle
);
903 if (!extensionDataPtr
)
906 // Does the extension contain one of the magic EV CA OIDs we know about?
907 CSSM_X509_EXTENSION
*cssmExtension
= (CSSM_X509_EXTENSION
*)extensionDataPtr
->Data
;
908 CE_CertPolicies
*certPolicies
= (CE_CertPolicies
*)cssmExtension
->value
.parsedValue
;
909 CFStringRef oidString
= _oidStringForCertificatePolicies(certPolicies
);
910 _freeFieldData(extensionDataPtr
, oidPtr
, clHandle
);
912 // Fetch the allowed root CA certificates for this OID, if any
913 CFArrayRef allowedRoots
= (oidString
) ? _allowedRootCertificatesForOidString(oidString
) : NULL
;
914 CFIndex rootCount
= (allowedRoots
) ? CFArrayGetCount(allowedRoots
) : 0;
915 secinfo("evTrust", "allowedEVRootsForLeafCertificate: found %d allowed roots", (int)rootCount
);
916 SafeCFRelease(&oidString
);
917 if (!allowedRoots
|| !rootCount
) {
918 SafeCFRelease(&allowedRoots
);
922 // The leaf certificate needs extended validation (with revocation checking).
923 // Return the array of allowed roots for this leaf certificate.
927 // returns true if the provided certificate contains a wildcard in either
928 // its common name or subject alternative name.
931 bool hasWildcardDNSName(SecCertificateRef certRef
)
933 OSStatus status
= errSecSuccess
;
934 CFArrayRef dnsNames
= NULL
;
936 BEGIN_SECAPI_INTERNAL_CALL
937 Required(&dnsNames
) = Certificate::required(certRef
)->copyDNSNames();
938 END_SECAPI_INTERNAL_CALL
939 if (status
|| !dnsNames
)
942 bool hasWildcard
= false;
943 const CFStringRef wildcard
= CFSTR("*");
944 CFIndex index
, count
= CFArrayGetCount(dnsNames
);
945 for (index
= 0; index
< count
; index
++) {
946 CFStringRef name
= (CFStringRef
) CFArrayGetValueAtIndex(dnsNames
, index
);
948 CFRange foundRange
= CFStringFind(name
, wildcard
, 0);
949 if (foundRange
.length
!= 0 && foundRange
.location
!= kCFNotFound
) {
959 // returns a CFDictionaryRef of extended validation results for the given chain,
960 // or NULL if the certificate chain did not meet all EV criteria. (Caller must
961 // release the result if not NULL.)
964 CFDictionaryRef
extendedValidationResults(CFArrayRef certChain
, SecTrustResultType trustResult
, OSStatus tpResult
)
966 // This function is intended to be called after the "regular" TP evaluation
967 // has taken place (i.e. trustResult and tpResult are available), and there
968 // is a full certificate chain to examine.
970 CFIndex chainIndex
, chainLen
= (certChain
) ? CFArrayGetCount(certChain
) : 0;
972 return NULL
; // invalid chain length
975 if (trustResult
!= kSecTrustResultUnspecified
) {
977 // "Recoverable" means the certificate failed to meet all policy requirements, but is intrinsically OK.
978 // One of the failures we might encounter is if the OCSP responder tells us to go away. Since this is a
979 // real-world case, we'll check for OCSP and CRL meta-errors specifically.
980 bool recovered
= false;
981 if (trustResult
== kSecTrustResultRecoverableTrustFailure
) {
982 recovered
= isRevocationServerMetaError((CSSM_RETURN
)tpResult
);
990 // What we know at this point:
992 // 1. From a previous call to allowedEVRootsForLeafCertificate
993 // (or we wouldn't be getting called by extendedTrustResults):
994 // - a leaf certificate exists
995 // - that certificate contains a Certificate Policies extension
996 // - that extension contains an OID from one of the trusted EV CAs we know about
997 // - we have found at least one allowed EV root for that OID
999 // 2. From the TP evaluation:
1000 // - the leaf certificate verifies back to a trusted EV root (with no trust settings overrides)
1001 // - SSL trust evaluation with OCSP revocation checking enabled returned no (fatal) errors
1003 // We need to verify the following additional requirements for the leaf (as of EV 1.1, 6(a)(2)):
1004 // - cannot specify a wildcard in commonName or subjectAltName
1005 // (note: this is a change since EV 1.0 (9.2.1), which stated that "Wildcard FQDNs are permitted.")
1007 // Finally, we need to check the following requirements (EV 1.1 specification, Appendix B):
1008 // - the trusted root, if created after 10/31/2006, must have:
1009 // - critical basicConstraints extension with CA bit set
1010 // - critical keyUsage extension with keyCertSign and cRLSign bits set
1011 // - intermediate certs, if present, must have:
1012 // - certificatePolicies extension, containing either a known EV CA OID, or anyPolicy
1013 // - non-critical cRLDistributionPoint extension
1014 // - critical basicConstraints extension with CA bit set
1015 // - critical keyUsage extension with keyCertSign and cRLSign bits set
1018 // check leaf certificate for wildcard names
1019 if (hasWildcardDNSName((SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, 0))) {
1020 trustDebug("has wildcard name (does not meet EV criteria)\n");
1024 // check intermediate CA certificates for required extensions per Appendix B of EV 1.1 specification.
1025 bool hasRequiredExtensions
= true;
1026 CSSM_CL_HANDLE clHandle
= 0;
1027 CSSM_DATA certData
= { 0, NULL
};
1028 CSSM_OID_PTR oidPtr
= (CSSM_OID_PTR
) &CSSMOID_CertificatePolicies
;
1029 for (chainIndex
= 1; hasRequiredExtensions
&& chainLen
> 2 && chainIndex
< chainLen
- 1; chainIndex
++) {
1030 SecCertificateRef intermediateCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, chainIndex
);
1031 OSStatus status
= errSecSuccess
;
1032 // note: Sec* APIs are not re-entrant due to the API lock
1033 // status = SecCertificateGetCLHandle(intermediateCert, &clHandle);
1034 BEGIN_SECAPI_INTERNAL_CALL
1035 clHandle
= Certificate::required(intermediateCert
)->clHandle();
1036 END_SECAPI_INTERNAL_CALL
1039 // note: Sec* APIs are not re-entrant due to the API lock
1040 // status = SecCertificateGetData(intermediateCert, &certData);
1041 BEGIN_SECAPI_INTERNAL_CALL
1042 certData
= Certificate::required(intermediateCert
)->data();
1043 END_SECAPI_INTERNAL_CALL
1047 CSSM_DATA_PTR extensionDataPtr
= _copyFieldDataForOid(oidPtr
, &certData
, clHandle
);
1048 if (!extensionDataPtr
)
1051 CSSM_X509_EXTENSION
*cssmExtension
= (CSSM_X509_EXTENSION
*)extensionDataPtr
->Data
;
1052 CE_CertPolicies
*certPolicies
= (CE_CertPolicies
*)cssmExtension
->value
.parsedValue
;
1053 CFStringRef oidString
= _oidStringForCertificatePolicies(certPolicies
);
1054 hasRequiredExtensions
= (oidString
!= NULL
);
1055 SafeCFRelease(&oidString
);
1056 _freeFieldData(extensionDataPtr
, oidPtr
, clHandle
);
1058 // FIX: add checks for the following (not essential to this implementation):
1059 // - non-critical cRLDistributionPoint extension
1060 // - critical basicConstraints extension with CA bit set
1061 // - critical keyUsage extension with keyCertSign and cRLSign bits set
1062 // Tracked by <rdar://problem/6119322>
1065 if (hasRequiredExtensions
) {
1066 SecCertificateRef leafCert
= (SecCertificateRef
) CFArrayGetValueAtIndex(certChain
, 0);
1067 CFStringRef organizationName
= organizationNameForCertificate(leafCert
);
1068 if (organizationName
!= NULL
) {
1069 CFMutableDictionaryRef resultDict
= CFDictionaryCreateMutable(NULL
, 0,
1070 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1071 CFDictionaryAddValue(resultDict
, kSecEVOrganizationName
, organizationName
);
1072 trustDebug("[EV] extended validation succeeded\n");
1073 SafeCFRelease(&organizationName
);
1081 // returns a CFDictionaryRef containing extended trust results.
1082 // Caller must release this dictionary.
1084 // If the isEVCandidate argument is true, extended validation checking is performed
1085 // and the kSecEVOrganizationName key will be set in the dictionary if EV criteria is met.
1086 // In all cases, kSecTrustEvaluationDate and kSecTrustExpirationDate will be set.
1088 CFDictionaryRef
extendedTrustResults(CFArrayRef certChain
, SecTrustResultType trustResult
, OSStatus tpResult
, bool isEVCandidate
)
1090 CFMutableDictionaryRef resultDict
= NULL
;
1091 if (isEVCandidate
) {
1092 resultDict
= (CFMutableDictionaryRef
) extendedValidationResults(certChain
, trustResult
, tpResult
);
1095 resultDict
= CFDictionaryCreateMutable(NULL
, 0,
1096 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1101 CFAbsoluteTime at
= CFAbsoluteTimeGetCurrent();
1102 CFDateRef trustEvaluationDate
= CFDateCreate(kCFAllocatorDefault
, at
);
1103 // by default, permit caching of trust evaluation results for up to 2 hours
1104 // FIXME: need to modify this based on cert expiration and OCSP/CRL validity
1105 CFDateRef trustExpirationDate
= CFDateCreate(kCFAllocatorDefault
, at
+ (60*60*2));
1106 CFDictionaryAddValue(resultDict
, kSecTrustEvaluationDate
, trustEvaluationDate
);
1107 SafeCFRelease(&trustEvaluationDate
);
1108 CFDictionaryAddValue(resultDict
, kSecTrustExpirationDate
, trustExpirationDate
);
1109 SafeCFRelease(&trustExpirationDate
);
1114 // returns a CFDictionaryRef containing mappings from supported EV CA OIDs to SHA-1 hash values;
1115 // caller must release
1117 static CFDictionaryRef
_evCAOidDict()
1119 static CFDictionaryRef s_evCAOidDict
= NULL
;
1120 if (s_evCAOidDict
) {
1121 CFRetain(s_evCAOidDict
);
1122 secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict
));
1123 return s_evCAOidDict
;
1125 secinfo("evTrust", "_evCAOidDict: initializing static instance");
1127 s_evCAOidDict
= dictionaryWithContentsOfPlistFile(EV_ROOTS_PLIST_SYSTEM_PATH
);
1131 #if !defined MAC_OS_X_VERSION_10_6 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
1132 // Work around rdar://6302788 by hard coding a hash that was missed when addressing <rdar://problem/6238289&6238296>
1133 // This is being addressed in SnowLeopard by rdar://6305989
1134 CFStringRef oidString
= CFSTR("2.16.840.1.114028.10.1.2");
1135 CFMutableArrayRef hashes
= (CFMutableArrayRef
) CFDictionaryGetValue(s_evCAOidDict
, oidString
);
1137 uint8 hashBytes
[] = {0xB3, 0x1E, 0xB1, 0xB7, 0x40, 0xE3, 0x6C, 0x84, 0x02, 0xDA, 0xDC, 0x37, 0xD4, 0x4D, 0xF5, 0xD4, 0x67, 0x49, 0x52, 0xF9};
1138 CFDataRef hashData
= CFDataCreate(NULL
, hashBytes
, sizeof(hashBytes
));
1139 CFIndex hashCount
= CFArrayGetCount(hashes
);
1140 if (hashData
&& CFArrayContainsValue(hashes
, CFRangeMake(0, hashCount
), hashData
)) {
1141 secinfo("evTrust", "_evCAOidDict: added hardcoded hash value");
1142 CFArrayAppendValue(hashes
, hashData
);
1144 SafeCFRelease(&hashData
);
1147 CFRetain(s_evCAOidDict
);
1148 secinfo("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict
));
1149 return s_evCAOidDict
;
1152 // returns a CFStringRef containing a decimal representation of the given OID.
1153 // Caller must release.
1155 static CFStringRef
_decimalStringForOid(CSSM_OID_PTR oid
)
1157 CFMutableStringRef str
= CFStringCreateMutable(NULL
, 0);
1158 if (!str
|| oid
->Length
> 32)
1161 // The first two levels are encoded into one byte, since the root level
1162 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
1163 // y may be > 39, so we have to add special-case handling for this.
1164 unsigned long value
= 0;
1165 unsigned int x
= oid
->Data
[0] / 40;
1166 unsigned int y
= oid
->Data
[0] % 40;
1168 // Handle special case for large y if x = 2
1173 CFStringAppendFormat(str
, NULL
, CFSTR("%d.%d"), x
, y
);
1175 for (x
= 1; x
< oid
->Length
; x
++) {
1176 value
= (value
<< 7) | (oid
->Data
[x
] & 0x7F);
1177 if(!(oid
->Data
[x
] & 0x80)) {
1178 CFStringAppendFormat(str
, NULL
, CFSTR(".%ld"), value
);
1183 #if !defined(NDEBUG)
1184 CFIndex nameLen
= CFStringGetLength(str
);
1185 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
1186 char *nameBuf
= (char *)malloc(bufLen
);
1187 if (!CFStringGetCString(str
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
1189 secinfo("evTrust", "_decimalStringForOid: \"%s\"", nameBuf
);
1196 static void _freeFieldData(CSSM_DATA_PTR value
, CSSM_OID_PTR oid
, CSSM_CL_HANDLE clHandle
)
1198 if (value
&& value
->Data
) {
1199 CSSM_CL_FreeFieldValue(clHandle
, oid
, value
);
1204 static ModuleNexus
<Mutex
> gOidStringForCertificatePoliciesMutex
;
1206 static CFStringRef CF_RETURNS_RETAINED
_oidStringForCertificatePolicies(const CE_CertPolicies
*certPolicies
)
1208 StLock
<Mutex
> _(gOidStringForCertificatePoliciesMutex());
1210 // returns the first EV OID (as a string) found in the given Certificate Policies extension,
1211 // or NULL if the extension does not contain any known EV OIDs. (Note that the "any policy" OID
1212 // is a special case and will be returned if present, although its presence is only meaningful
1213 // in an intermediate CA.)
1215 if (!certPolicies
) {
1216 secinfo("evTrust", "oidStringForCertificatePolicies: missing certPolicies!");
1220 CFDictionaryRef evOidDict
= _evCAOidDict();
1222 secinfo("evTrust", "oidStringForCertificatePolicies: nil OID dictionary!");
1226 CFStringRef foundOidStr
= NULL
;
1227 uint32 policyIndex
, maxIndex
= 10; // sanity check; EV certs normally have EV OID as first policy
1228 for (policyIndex
= 0; policyIndex
< certPolicies
->numPolicies
&& policyIndex
< maxIndex
; policyIndex
++) {
1229 CE_PolicyInformation
*certPolicyInfo
= &certPolicies
->policies
[policyIndex
];
1230 CSSM_OID_PTR oid
= &certPolicyInfo
->certPolicyId
;
1231 CFStringRef oidStr
= _decimalStringForOid(oid
);
1234 if (!CFStringCompare(oidStr
, CFSTR("2.5.29.32.0"), 0) || // is it the "any" OID, or
1235 CFDictionaryGetValue(evOidDict
, oidStr
) != NULL
) { // a known EV CA OID?
1236 foundOidStr
= CFStringCreateCopy(NULL
, oidStr
);
1238 SafeCFRelease(&oidStr
);
1242 SafeCFRelease(&evOidDict
);