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