]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_keychain/lib/TrustAdditions.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / TrustAdditions.cpp
1 /*
2 * Copyright (c) 2002-2009,2011-2014 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 //
75 static const char *EV_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/EVRoots.plist";
76 static const char *SYSTEM_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/SystemRootCertificates.keychain";
77 static const char *X509ANCHORS_SYSTEM_PATH = "/System/Library/Keychains/X509Anchors";
78
79 //
80 // Static functions
81 //
82 static CFArrayRef _allowedRootCertificatesForOidString(CFStringRef oidString);
83 static CSSM_DATA_PTR _copyFieldDataForOid(CSSM_OID_PTR oid, CSSM_DATA_PTR cert, CSSM_CL_HANDLE clHandle);
84 static CFStringRef _decimalStringForOid(CSSM_OID_PTR oid);
85 static CFDictionaryRef _evCAOidDict();
86 static void _freeFieldData(CSSM_DATA_PTR value, CSSM_OID_PTR oid, CSSM_CL_HANDLE clHandle);
87 static CFStringRef _oidStringForCertificatePolicies(const CE_CertPolicies *certPolicies);
88 static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate);
89 static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate);
90
91 // utility function to safely release (and clear) the given CFTypeRef variable.
92 //
93 static 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 //
105 static 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 }
138 errOut:
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 //
148 static 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 //
196 static 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 //
215 static 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)
318 void showCertSKID(const void *value, void *context);
319 #endif
320
321 static ModuleNexus<Mutex> gPotentialEVChainWithCertificatesMutex;
322
323 // returns a CFArrayRef of SecCertificateRef instances; caller must release the returned array
324 //
325 CFArrayRef 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 //
377 static 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)
485 static 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
502 void 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 //
517 static 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 //
555 static
556 CFArrayRef _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 //
642 CFArrayRef _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 //
699 static 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
746 bool 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 //
766 bool 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 //
792 bool 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 //
812 bool 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 //
825 bool 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 //
858 CFArrayRef 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 //
924 static
925 bool 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 //
957 static
958 CFDictionaryRef 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 //
1082 CFDictionaryRef 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 //
1111 static 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
1149 static 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
1190 static 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
1198 static ModuleNexus<Mutex> gOidStringForCertificatePoliciesMutex;
1199
1200 static 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