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