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