1/* 2 * Copyright (c) 2002-2010,2012-2013 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#include "SecTrust.h" 25#include "SecTrustPriv.h" 26#include "Trust.h" 27#include <security_keychain/SecTrustSettingsPriv.h> 28#include "SecBridge.h" 29#include "SecInternal.h" 30#include "SecInternalP.h" 31#include "SecTrustSettings.h" 32#include "SecCertificatePriv.h" 33#include "SecCertificateP.h" 34#include "SecCertificatePrivP.h" 35#include <security_utilities/cfutilities.h> 36#include <security_utilities/cfmunge.h> 37#include <CoreFoundation/CoreFoundation.h> 38 39// forward declarations 40CFArrayRef SecTrustCopyDetails(SecTrustRef trust); 41static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix); 42static void SecTrustCheckException(const void *key, const void *value, void *context); 43 44typedef struct SecTrustCheckExceptionContext { 45 CFDictionaryRef exception; 46 bool exceptionNotFound; 47} SecTrustCheckExceptionContext; 48 49// public trust result constants 50CFTypeRef kSecTrustEvaluationDate = CFSTR("TrustEvaluationDate"); 51CFTypeRef kSecTrustExtendedValidation = CFSTR("TrustExtendedValidation"); 52CFTypeRef kSecTrustOrganizationName = CFSTR("Organization"); 53CFTypeRef kSecTrustResultValue = CFSTR("TrustResultValue"); 54CFTypeRef kSecTrustRevocationChecked = CFSTR("TrustRevocationChecked"); 55CFTypeRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate"); 56CFTypeRef kSecTrustResultDetails = CFSTR("TrustResultDetails"); 57 58// 59// CF boilerplate 60// 61CFTypeID SecTrustGetTypeID(void) 62{ 63 BEGIN_SECAPI 64 65 return gTypes().Trust.typeID; 66 67 END_SECAPI1(_kCFRuntimeNotATypeID) 68} 69 70 71// 72// Sec* API bridge functions 73// 74OSStatus SecTrustCreateWithCertificates( 75 CFTypeRef certificates, 76 CFTypeRef policies, 77 SecTrustRef *trustRef) 78{ 79 BEGIN_SECAPI 80 Required(trustRef); 81 *trustRef = (new Trust(certificates, policies))->handle(); 82 END_SECAPI 83} 84 85OSStatus 86SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies) 87{ 88 BEGIN_SECAPI 89 Trust::required(trustRef)->policies(policies); 90 END_SECAPI 91} 92 93OSStatus 94SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) 95{ 96 BEGIN_SECAPI 97 CSSM_APPLE_TP_ACTION_DATA actionData = { 98 CSSM_APPLE_TP_ACTION_VERSION, 99 (CSSM_APPLE_TP_ACTION_FLAGS)options 100 }; 101 Trust *trust = Trust::required(trustRef); 102 CFDataRef actionDataRef = CFDataCreate(NULL, 103 (const UInt8 *)&actionData, 104 (CFIndex)sizeof(CSSM_APPLE_TP_ACTION_DATA)); 105 trust->action(CSSM_TP_ACTION_DEFAULT); 106 trust->actionData(actionDataRef); 107 if (actionDataRef) CFRelease(actionDataRef); 108 END_SECAPI 109} 110 111OSStatus SecTrustSetParameters( 112 SecTrustRef trustRef, 113 CSSM_TP_ACTION action, 114 CFDataRef actionData) 115{ 116 BEGIN_SECAPI 117 Trust *trust = Trust::required(trustRef); 118 trust->action(action); 119 trust->actionData(actionData); 120 END_SECAPI 121} 122 123 124OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates) 125{ 126 BEGIN_SECAPI 127 Trust::required(trust)->anchors(anchorCertificates); 128 END_SECAPI 129} 130 131OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, Boolean anchorCertificatesOnly) 132{ 133 BEGIN_SECAPI 134 Trust::AnchorPolicy policy = (anchorCertificatesOnly) ? Trust::useAnchorsOnly : Trust::useAnchorsAndBuiltIns; 135 Trust::required(trust)->anchorPolicy(policy); 136 END_SECAPI 137} 138 139OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray) 140{ 141 BEGIN_SECAPI 142 StorageManager::KeychainList keychains; 143 // avoid unnecessary global initializations if an empty array is passed in 144 if (!( (keychainOrArray != NULL) && 145 (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && 146 (CFArrayGetCount((CFArrayRef)keychainOrArray) == 0) )) { 147 globals().storageManager.optionalSearchList(keychainOrArray, keychains); 148 } 149 Trust::required(trust)->searchLibs(keychains); 150 END_SECAPI 151} 152 153 154OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) 155{ 156 BEGIN_SECAPI 157 Trust::required(trust)->time(verifyDate); 158 END_SECAPI 159} 160 161 162CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) 163{ 164 CFAbsoluteTime verifyTime = 0; 165 OSStatus __secapiresult = errSecSuccess; 166 try { 167 CFRef<CFDateRef> verifyDate = Trust::required(trust)->time(); 168 verifyTime = CFDateGetAbsoluteTime(verifyDate); 169 } 170 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 171 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 172 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 173 catch (...) { __secapiresult=errSecInternalComponent; } 174 return verifyTime; 175} 176 177 178OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *resultP) 179{ 180 SecTrustResultType trustResult = kSecTrustResultInvalid; 181 CFArrayRef exceptions = NULL; 182 OSStatus __secapiresult = errSecSuccess; 183 try { 184 Trust *trustObj = Trust::required(trust); 185 trustObj->evaluate(); 186 trustResult = trustObj->result(); 187 exceptions = trustObj->exceptions(); 188 } 189 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 190 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 191 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 192 catch (...) { __secapiresult=errSecInternalComponent; } 193 194 if (__secapiresult) { 195 return __secapiresult; 196 } 197 198 /* post-process trust result based on exceptions */ 199 if (trustResult == kSecTrustResultUnspecified) { 200 /* If leaf is in exceptions -> proceed, otherwise unspecified. */ 201 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) 202 trustResult = kSecTrustResultProceed; 203 } 204 else if (trustResult == kSecTrustResultRecoverableTrustFailure && exceptions) { 205 /* If we have exceptions get details and match to exceptions. */ 206 CFArrayRef details = SecTrustCopyDetails(trust); 207 if (details) { 208 CFIndex pathLength = CFArrayGetCount(details); 209 struct SecTrustCheckExceptionContext context = {}; 210 CFIndex ix; 211 for (ix = 0; ix < pathLength; ++ix) { 212 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); 213 // if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) 214 // trustResult = kSecTrustResultFatalTrustFailure; 215 context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix); 216 CFDictionaryApplyFunction(detail, SecTrustCheckException, &context); 217 if (context.exceptionNotFound) { 218 break; 219 } 220 } 221 if (!context.exceptionNotFound) 222 trustResult = kSecTrustResultProceed; 223 } 224 } 225 226 227 secdebug("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult); 228 if (resultP) { 229 *resultP = trustResult; 230 } 231 return __secapiresult; 232} 233 234OSStatus SecTrustEvaluateAsync(SecTrustRef trust, 235 dispatch_queue_t queue, SecTrustCallback result) 236{ 237 BEGIN_SECAPI 238 dispatch_async(queue, ^{ 239 try { 240 Trust *trustObj = Trust::required(trust); 241 trustObj->evaluate(); 242 SecTrustResultType trustResult = trustObj->result(); 243 result(trust, trustResult); 244 } 245 catch (...) { 246 result(trust, kSecTrustResultInvalid); 247 }; 248 }); 249 END_SECAPI 250} 251 252// 253// Construct the "official" result evidence and return it 254// 255OSStatus SecTrustGetResult( 256 SecTrustRef trustRef, 257 SecTrustResultType *result, 258 CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain) 259{ 260 BEGIN_SECAPI 261 Trust *trust = Trust::required(trustRef); 262 if (result) 263 *result = trust->result(); 264 if (certChain && statusChain) 265 trust->buildEvidence(*certChain, TPEvidenceInfo::overlayVar(*statusChain)); 266 END_SECAPI 267} 268 269// 270// Retrieve result of trust evaluation only 271// 272OSStatus SecTrustGetTrustResult(SecTrustRef trustRef, 273 SecTrustResultType *result) 274{ 275 BEGIN_SECAPI 276 Trust *trust = Trust::required(trustRef); 277 if (result) *result = trust->result(); 278 END_SECAPI 279} 280 281// 282// Retrieve extended validation trust results 283// 284OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result) 285{ 286 BEGIN_SECAPI 287 Trust *trustObj = Trust::required(trust); 288 if (result == nil) 289 return errSecParam; 290 trustObj->extendedResult(*result); 291 END_SECAPI 292} 293 294// 295// Retrieve CSSM-level information for those who want to dig down 296// 297OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result) 298{ 299 BEGIN_SECAPI 300 Required(result) = Trust::required(trust)->cssmResult(); 301 END_SECAPI 302} 303 304// 305// Retrieve CSSM_LEVEL TP return code 306// 307OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result) 308{ 309 BEGIN_SECAPI 310 Trust *trust = Trust::required(trustRef); 311 if (trust->result() == kSecTrustResultInvalid) 312 return errSecParam; 313 else 314 Required(result) = trust->cssmResultCode(); 315 END_SECAPI 316} 317 318OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) 319{ 320 BEGIN_SECAPI 321 Required(handle) = Trust::required(trust)->getTPHandle(); 322 END_SECAPI 323} 324 325OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) 326{ 327 BEGIN_SECAPI 328 CFArrayRef currentPolicies = Trust::required(trust)->policies(); 329 if (currentPolicies != NULL) 330 { 331 CFRetain(currentPolicies); 332 } 333 334 Required(policies) = currentPolicies; 335 END_SECAPI 336} 337 338OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) 339{ 340 BEGIN_SECAPI 341 Trust *trustObj = Trust::required(trust); 342 Trust::NetworkPolicy netPolicy = (allowFetch) ? 343 Trust::useNetworkEnabled : Trust::useNetworkDisabled; 344 trustObj->networkPolicy(netPolicy); 345 END_SECAPI 346} 347 348OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) 349{ 350 BEGIN_SECAPI 351 Boolean allowed = false; 352 Trust *trustObj = Trust::required(trust); 353 Trust::NetworkPolicy netPolicy = trustObj->networkPolicy(); 354 if (netPolicy == Trust::useNetworkDefault) { 355 // network fetch is enabled by default for SSL only 356 allowed = trustObj->policySpecified(trustObj->policies(), CSSMOID_APPLE_TP_SSL); 357 } else { 358 // caller has explicitly set the network policy 359 allowed = (netPolicy == Trust::useNetworkEnabled); 360 } 361 Required(allowFetch) = allowed; 362 END_SECAPI 363} 364 365OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) 366{ 367 BEGIN_SECAPI 368 Trust::required(trust)->responses(responseData); 369 END_SECAPI 370} 371 372OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchorCertificates) 373{ 374 BEGIN_SECAPI 375 CFArrayRef customAnchors = Trust::required(trust)->anchors(); 376 Required(anchorCertificates) = (customAnchors) ? 377 (const CFArrayRef)CFRetain(customAnchors) : (const CFArrayRef)NULL; 378 END_SECAPI 379} 380 381// 382// Get the user's default anchor certificate set 383// 384OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates) 385{ 386 BEGIN_SECAPI 387 388 return SecTrustSettingsCopyUnrestrictedRoots( 389 true, true, true, /* all domains */ 390 anchorCertificates); 391 392 END_SECAPI 393} 394 395/* new in 10.6 */ 396SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) 397{ 398 SecKeyRef pubKey = NULL; 399 CFArrayRef certChain = NULL; 400 CFArrayRef evidenceChain = NULL; 401 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 402 OSStatus __secapiresult = errSecSuccess; 403 try { 404 Trust *trustObj = Trust::required(trust); 405 if (trustObj->result() == kSecTrustResultInvalid) { 406 // Trust hasn't been evaluated; attempt to retrieve public key from leaf. 407 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0); 408 __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey); 409 if (pubKey) { 410 return pubKey; 411 } 412 // Otherwise, we must evaluate first. 413 trustObj->evaluate(); 414 if (trustObj->result() == kSecTrustResultInvalid) { 415 MacOSError::throwMe(errSecTrustNotAvailable); 416 } 417 } 418 if (trustObj->evidence() == nil) { 419 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); 420 } 421 evidenceChain = trustObj->evidence(); 422 } 423 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 424 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 425 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 426 catch (...) { __secapiresult=errSecInternalComponent; } 427 428 if (certChain) 429 CFRelease(certChain); 430 431 if (evidenceChain) { 432 if (CFArrayGetCount(evidenceChain) > 0) { 433 SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, 0); 434 __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey); 435 } 436 // do not release evidenceChain, as it is owned by the trust object. 437 } 438 return pubKey; 439} 440 441/* new in 10.6 */ 442CFIndex SecTrustGetCertificateCount(SecTrustRef trust) 443{ 444 CFIndex chainLen = 0; 445 CFArrayRef certChain = NULL; 446 CFArrayRef evidenceChain = NULL; 447 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 448 OSStatus __secapiresult = errSecSuccess; 449 try { 450 Trust *trustObj = Trust::required(trust); 451 if (trustObj->result() == kSecTrustResultInvalid) { 452 trustObj->evaluate(); 453 if (trustObj->result() == kSecTrustResultInvalid) 454 MacOSError::throwMe(errSecTrustNotAvailable); 455 } 456 if (trustObj->evidence() == nil) 457 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); 458 evidenceChain = trustObj->evidence(); 459 } 460 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 461 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 462 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 463 catch (...) { __secapiresult=errSecInternalComponent; } 464 465 if (certChain) 466 CFRelease(certChain); 467 468 if (evidenceChain) 469 chainLen = CFArrayGetCount(evidenceChain); // don't release, trust object owns it. 470 471 return chainLen; 472} 473 474/* new in 10.6 */ 475SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix) 476{ 477 SecCertificateRef certificate = NULL; 478 CFArrayRef certChain = NULL; 479 CFArrayRef evidenceChain = NULL; 480 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 481 OSStatus __secapiresult = errSecSuccess; 482 try { 483 Trust *trustObj = Trust::required(trust); 484 if (trustObj->result() == kSecTrustResultInvalid) { 485 // If caller is asking for the leaf, we can return it without 486 // having to evaluate the entire chain. Note that we don't retain 487 // the cert as it's owned by the trust and this is a 'Get' API. 488 if (ix == 0) { 489 CFArrayRef certs = trustObj->certificates(); 490 if (certs && (CFArrayGetCount(certs) > 0)) { 491 certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0); 492 if (certificate) { 493 return certificate; 494 } 495 } 496 } 497 // Otherwise, we must evaluate first. 498 trustObj->evaluate(); 499 if (trustObj->result() == kSecTrustResultInvalid) { 500 MacOSError::throwMe(errSecTrustNotAvailable); 501 } 502 } 503 if (trustObj->evidence() == nil) { 504 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); 505 } 506 evidenceChain = trustObj->evidence(); 507 } 508 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 509 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 510 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 511 catch (...) { __secapiresult=errSecInternalComponent; } 512 513 if (certChain) 514 CFRelease(certChain); 515 516 if (evidenceChain) { 517 if (ix < CFArrayGetCount(evidenceChain)) { 518 certificate = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, ix); 519 // note: we do not retain this certificate. The assumption here is 520 // that the certificate is retained by the trust object, so it is 521 // valid unil the trust is released (or until re-evaluated.) 522 // also note: we do not release the evidenceChain, as it is owned 523 // by the trust object. 524 } 525 } 526 return certificate; 527} 528 529 530static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest"); 531static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes"); 532 533static void 534_AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) 535{ 536 if (!array) 537 return; 538 SInt32 num = statusCode; 539 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num); 540 if (!numRef) 541 return; 542 CFArrayAppendValue(array, numRef); 543 CFRelease(numRef); 544} 545 546CFArrayRef SecTrustCopyDetails(SecTrustRef trust) 547{ 548 // This function returns an array of dictionaries, one per certificate, 549 // holding status info for each certificate in the evaluated chain. 550 // 551 CFIndex count, chainLen = 0; 552 CFArrayRef certChain = NULL; 553 CFMutableArrayRef details = NULL; 554 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 555 OSStatus __secapiresult = errSecSuccess; 556 try { 557 Trust *trustObj = Trust::required(trust); 558 if (trustObj->result() == kSecTrustResultInvalid) { 559 trustObj->evaluate(); 560 if (trustObj->result() == kSecTrustResultInvalid) 561 MacOSError::throwMe(errSecTrustNotAvailable); 562 } 563 trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); 564 } 565 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 566 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 567 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 568 catch (...) { __secapiresult=errSecInternalComponent; } 569 570 if (certChain) { 571 chainLen = CFArrayGetCount(certChain); 572 CFRelease(certChain); 573 } 574 if (statusChain) { 575 details = CFArrayCreateMutable(NULL, chainLen, &kCFTypeArrayCallBacks); 576 for (count = 0; count < chainLen; count++) { 577 CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 578 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 579 CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault, 580 0, &kCFTypeArrayCallBacks); 581 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &statusChain[count]; 582 CSSM_TP_APPLE_CERT_STATUS statBits = evInfo->StatusBits; 583 584 // translate status bits 585 if (statBits & CSSM_CERT_STATUS_EXPIRED) 586 _AppendStatusCode(statusCodes, errSecCertificateExpired); 587 if (statBits & CSSM_CERT_STATUS_NOT_VALID_YET) 588 _AppendStatusCode(statusCodes, errSecCertificateNotValidYet); 589 if (statBits & CSSM_CERT_STATUS_TRUST_SETTINGS_DENY) 590 _AppendStatusCode(statusCodes, errSecTrustSettingDeny); 591 592 // translate status codes 593 unsigned int i; 594 for (i = 0; i < evInfo->NumStatusCodes; i++) { 595 CSSM_RETURN scode = evInfo->StatusCodes[i]; 596 _AppendStatusCode(statusCodes, (OSStatus)scode); 597 } 598 599 CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes); 600 CFRelease(statusCodes); 601 CFArrayAppendValue(details, certDict); 602 CFRelease(certDict); 603 } 604 } 605 return details; 606} 607 608static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) 609{ 610 CFArrayRef exceptions = NULL; 611 OSStatus __secapiresult = errSecSuccess; 612 try { 613 exceptions = Trust::required(trust)->exceptions(); 614 } 615 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 616 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 617 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 618 catch (...) { __secapiresult=errSecInternalComponent; } 619 620 if (!exceptions || ix >= CFArrayGetCount(exceptions)) 621 return NULL; 622 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); 623 if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) 624 return NULL; 625 626 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); 627 if (!certificate) 628 return NULL; 629 630 /* If the exception contains the current certificate's sha1Digest in the 631 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */ 632 CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate); 633 CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest); 634 if (!digestValue || !CFEqual(sha1Digest, digestValue)) 635 exception = NULL; 636 637 return exception; 638} 639 640static void SecTrustCheckException(const void *key, const void *value, void *context) 641{ 642 struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context; 643 if (cec->exception) { 644 CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key); 645 if (!exceptionValue || !CFEqual(value, exceptionValue)) { 646 cec->exceptionNotFound = true; 647 } 648 } else { 649 cec->exceptionNotFound = true; 650 } 651} 652 653/* new in 10.9 */ 654CFDataRef SecTrustCopyExceptions(SecTrustRef trust) 655{ 656 CFArrayRef details = SecTrustCopyDetails(trust); 657 CFIndex pathLength = details ? CFArrayGetCount(details) : 0; 658 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, 659 pathLength, &kCFTypeArrayCallBacks); 660 CFIndex ix; 661 for (ix = 0; ix < pathLength; ++ix) { 662 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); 663 CFIndex detailCount = CFDictionaryGetCount(detail); 664 CFMutableDictionaryRef exception; 665 if (ix == 0 || detailCount > 0) { 666 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 667 detailCount + 1, detail); 668 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); 669 CFDataRef digest = SecCertificateGetSHA1Digest(certificate); 670 if (digest) { 671 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest); 672 } 673 } else { 674 /* Add empty exception dictionaries for non leaf certs which have no exceptions 675 * to save space. 676 */ 677 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, 678 NULL, NULL, 0, 679 &kCFTypeDictionaryKeyCallBacks, 680 &kCFTypeDictionaryValueCallBacks); 681 } 682 CFArrayAppendValue(exceptions, exception); 683 CFReleaseNull(exception); 684 } 685 CFReleaseSafe(details); 686 687 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf 688 since it will never be empty). */ 689 for (ix = pathLength; ix-- > 1;) { 690 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); 691 if (CFDictionaryGetCount(exception) == 0) { 692 CFArrayRemoveValueAtIndex(exceptions, ix); 693 } else { 694 break; 695 } 696 } 697 698 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault, 699 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL); 700 CFRelease(exceptions); 701 702 return encodedExceptions; 703} 704 705/* new in 10.9 */ 706bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) 707{ 708 CFArrayRef exceptions; 709 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault, 710 encodedExceptions, kCFPropertyListImmutable, NULL, NULL); 711 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) { 712 CFRelease(exceptions); 713 exceptions = NULL; 714 } 715 716 OSStatus __secapiresult = errSecSuccess; 717 try { 718 Trust::required(trust)->exceptions(exceptions); 719 } 720 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 721 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 722 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 723 catch (...) { __secapiresult=errSecInternalComponent; } 724 725 /* If there is a valid exception entry for our current leaf we're golden. */ 726 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) 727 return true; 728 729 /* The passed in exceptions didn't match our current leaf, so we discard it. */ 730 try { 731 Trust::required(trust)->exceptions(NULL); 732 __secapiresult = errSecSuccess; 733 } 734 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } 735 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } 736 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } 737 catch (...) { __secapiresult=errSecInternalComponent; } 738 739 return false; 740} 741 742/* new in 10.9 */ 743CFDictionaryRef 744SecTrustCopyResult(SecTrustRef trust) 745{ 746 CFDictionaryRef result = NULL; 747 try { 748 result = Trust::required(trust)->results(); 749 // merge details into result 750 CFArrayRef details = SecTrustCopyDetails(trust); 751 if (details) { 752 CFDictionarySetValue((CFMutableDictionaryRef)result, 753 kSecTrustResultDetails, details); 754 CFRelease(details); 755 } 756 } 757 catch (...) { 758 if (result) { 759 CFRelease(result); 760 result = NULL; 761 } 762 } 763 return result; 764} 765 766/* new in 10.7 */ 767CFArrayRef 768SecTrustCopyProperties(SecTrustRef trust) 769{ 770 /* can't use SECAPI macros, since this function does not return OSStatus */ 771 CFArrayRef result = NULL; 772 try { 773 result = Trust::required(trust)->properties(); 774 } 775 catch (...) { 776 if (result) { 777 CFRelease(result); 778 result = NULL; 779 } 780 } 781 return result; 782} 783 784 785/* deprecated in 10.5 */ 786OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors, 787 uint32 *cssmAnchorCount) 788{ 789 BEGIN_SECAPI 790 CertGroup certs; 791 Trust::gStore().getCssmRootCertificates(certs); 792 Required(cssmAnchors) = certs.blobCerts(); 793 Required(cssmAnchorCount) = certs.count(); 794 END_SECAPI 795} 796 797 798// 799// Get and set user trust settings. Deprecated in 10.5. 800// User Trust getter, deprecated, works as it always has. 801// 802OSStatus SecTrustGetUserTrust(SecCertificateRef certificate, 803 SecPolicyRef policy, SecTrustUserSetting *trustSetting) 804{ 805 BEGIN_SECAPI 806 StorageManager::KeychainList searchList; 807 globals().storageManager.getSearchList(searchList); 808 Required(trustSetting) = Trust::gStore().find( 809 Certificate::required(certificate), 810 Policy::required(policy), 811 searchList); 812 END_SECAPI 813} 814 815// 816// The public setter, also deprecated; it maps to the appropriate 817// Trust Settings call if possible, else throws errSecUnimplemented. 818// 819OSStatus SecTrustSetUserTrust(SecCertificateRef certificate, 820 SecPolicyRef policy, SecTrustUserSetting trustSetting) 821{ 822 SecTrustSettingsResult tsResult = kSecTrustSettingsResultInvalid; 823 OSStatus ortn; 824 Boolean isRoot; 825 826 Policy::required(policy); 827 switch(trustSetting) { 828 case kSecTrustResultProceed: 829 /* different SecTrustSettingsResult depending in root-ness */ 830 ortn = SecCertificateIsSelfSigned(certificate, &isRoot); 831 if(ortn) { 832 return ortn; 833 } 834 if(isRoot) { 835 tsResult = kSecTrustSettingsResultTrustRoot; 836 } 837 else { 838 tsResult = kSecTrustSettingsResultTrustAsRoot; 839 } 840 break; 841 case kSecTrustResultDeny: 842 tsResult = kSecTrustSettingsResultDeny; 843 break; 844 default: 845 return errSecUnimplemented; 846 } 847 848 /* make a usage constraints dictionary */ 849 CFRef<CFMutableDictionaryRef> usageDict(CFDictionaryCreateMutable(NULL, 850 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 851 CFDictionaryAddValue(usageDict, kSecTrustSettingsPolicy, policy); 852 if(tsResult != kSecTrustSettingsResultTrustRoot) { 853 /* skip if we're specifying the default */ 854 SInt32 result = tsResult; 855 CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &result); 856 CFDictionarySetValue(usageDict, kSecTrustSettingsResult, cfNum); 857 CFRelease(cfNum); 858 } 859 return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser, 860 usageDict); 861} 862 863// 864// This one is the now-private version of what SecTrustSetUserTrust() used to 865// be. The public API can no longer manipulate User Trust settings, only 866// view them. 867// 868OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate, 869 SecPolicyRef policy, SecTrustUserSetting trustSetting) 870{ 871 BEGIN_SECAPI 872 switch (trustSetting) { 873 case kSecTrustResultProceed: 874 case kSecTrustResultConfirm: 875 case kSecTrustResultDeny: 876 case kSecTrustResultUnspecified: 877 break; 878 default: 879 MacOSError::throwMe(errSecInvalidTrustSetting); 880 } 881 Trust::gStore().assign( 882 Certificate::required(certificate), 883 Policy::required(policy), 884 trustSetting); 885 END_SECAPI 886} 887 888/* SecGetAppleTPHandle - @@@NOT EXPORTED YET; copied from SecurityInterface, 889 but could be useful in the future. 890*/ 891/* 892CSSM_TP_HANDLE 893SecGetAppleTPHandle() 894{ 895 BEGIN_SECAPI 896 return TP(gGuidAppleX509TP)->handle(); 897 END_SECAPI1(NULL); 898} 899*/ 900 901 902