1/* 2 * Copyright (c) 2006-2010,2012-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 * 23 * SecTrustServer.c - certificate trust evaluation engine 24 * 25 * 26 */ 27 28#include <securityd/SecTrustServer.h> 29#include <securityd/SecPolicyServer.h> 30#include <securityd/SecTrustStoreServer.h> 31#include <securityd/SecCAIssuerRequest.h> 32#include <securityd/SecItemServer.h> 33 34#include <utilities/SecIOFormat.h> 35#include <utilities/SecDispatchRelease.h> 36 37#include <Security/SecTrustPriv.h> 38#include <Security/SecItem.h> 39#include <Security/SecCertificateInternal.h> 40#include <Security/SecCertificatePath.h> 41#include <Security/SecFramework.h> 42#include <Security/SecPolicyInternal.h> 43#include <CoreFoundation/CFRuntime.h> 44#include <CoreFoundation/CFSet.h> 45#include <CoreFoundation/CFString.h> 46#include <CoreFoundation/CFNumber.h> 47#include <CoreFoundation/CFArray.h> 48#include <CoreFoundation/CFPropertyList.h> 49#include <AssertMacros.h> 50#include <stdbool.h> 51#include <string.h> 52#include <stdlib.h> 53#include <limits.h> 54#include <Security/SecBase.h> 55#include "SecRSAKey.h" 56#include <libDER/oids.h> 57#include <utilities/debugging.h> 58#include <utilities/SecCFWrappers.h> 59#include <Security/SecInternal.h> 60#include <ipc/securityd_client.h> 61#include <CommonCrypto/CommonDigest.h> 62#include "OTATrustUtilities.h" 63 64 65/******************************************************** 66 ***************** OTA Trust support ******************** 67 ********************************************************/ 68 69 70#ifndef SECITEM_SHIM_OSX 71 72static CFArrayRef subject_to_anchors(CFDataRef nic); 73static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets); 74 75static CFArrayRef subject_to_anchors(CFDataRef nic) 76{ 77 CFArrayRef result = NULL; 78 79 if (NULL == nic) 80 { 81 return result; 82 } 83 84 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); 85 if (NULL == otapkiref) 86 { 87 return result; 88 } 89 90 CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref); 91 CFRelease(otapkiref); 92 93 if (NULL == lookupTable) 94 { 95 return result; 96 } 97 98 unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH]; 99 memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH); 100 101 (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest); 102 CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull); 103 104 105 result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest); 106 CFReleaseSafe(lookupTable); 107 CFReleaseSafe(sha1Digest); 108 109 return result; 110} 111 112static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets) 113{ 114 CFMutableArrayRef result = NULL; 115 116 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); 117 if (NULL == otapkiref) 118 { 119 return result; 120 } 121 122 const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref); 123 if (NULL == anchorTable) 124 { 125 CFReleaseSafe(otapkiref); 126 return result; 127 } 128 129 CFIndex num_offsets = CFArrayGetCount(offsets); 130 131 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 132 133 for (CFIndex idx = 0; idx < num_offsets; idx++) 134 { 135 CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx); 136 uint32_t offset_value = 0; 137 if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value)) 138 { 139 char* pDataPtr = (char *)(anchorTable + offset_value); 140 //int32_t record_length = *((int32_t * )pDataPtr); 141 //record_length = record_length; 142 pDataPtr += sizeof(uint32_t); 143 144 int32_t cert_data_length = *((int32_t * )pDataPtr); 145 pDataPtr += sizeof(uint32_t); 146 147 CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr, 148 cert_data_length, kCFAllocatorNull); 149 if (NULL != cert_data) 150 { 151 CFArrayAppendValue(result, cert_data); 152 CFReleaseSafe(cert_data); 153 } 154 } 155 } 156 CFReleaseSafe(otapkiref); 157 return result; 158} 159 160static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets) 161{ 162 CFMutableArrayRef result = NULL; 163 164 CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets); 165 166 if (NULL != cert_data_array) 167 { 168 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 169 CFIndex num_cert_datas = CFArrayGetCount(cert_data_array); 170 for (CFIndex idx = 0; idx < num_cert_datas; idx++) 171 { 172 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx); 173 if (NULL != cert_data) 174 { 175 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data); 176 if (NULL != cert) 177 { 178 CFArrayAppendValue(result, cert); 179 CFRelease(cert); 180 } 181 } 182 } 183 CFRelease(cert_data_array); 184 } 185 return result; 186 187} 188#endif 189 190/******************************************************** 191 *************** END OTA Trust support ****************** 192 ********************************************************/ 193 194#define MAX_CHAIN_LENGTH 15 195 196/* Forward declaration for use in SecCertificateSource. */ 197static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents); 198 199 200// MARK: - 201// MARK: SecCertificateSource 202/******************************************************** 203 ************ SecCertificateSource object *************** 204 ********************************************************/ 205 206typedef struct SecCertificateSource *SecCertificateSourceRef; 207typedef void(*SecCertificateSourceParents)(void *, CFArrayRef); 208typedef bool(*CopyParents)(SecCertificateSourceRef source, 209 SecCertificateRef certificate, void *context, SecCertificateSourceParents); 210typedef bool(*Contains)(SecCertificateSourceRef source, 211 SecCertificateRef certificate); 212 213struct SecCertificateSource { 214 CopyParents copyParents; 215 Contains contains; 216}; 217 218static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source, 219 SecCertificateRef certificate, 220 void *context, SecCertificateSourceParents callback) { 221 return source->copyParents(source, certificate, context, callback); 222} 223 224static bool SecCertificateSourceContains(SecCertificateSourceRef source, 225 SecCertificateRef certificate) { 226 return source->contains(source, certificate); 227} 228 229// MARK: - 230// MARK: SecItemCertificateSource 231/******************************************************** 232 *********** SecItemCertificateSource object ************ 233 ********************************************************/ 234struct SecItemCertificateSource { 235 struct SecCertificateSource base; 236 CFArrayRef accessGroups; 237}; 238typedef struct SecItemCertificateSource *SecItemCertificateSourceRef; 239 240static CFTypeRef SecItemCertificateSourceResultsPost(CFTypeRef raw_results) { 241 if (isArray(raw_results)) { 242 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); 243 CFArrayForEach(raw_results, ^(const void *value) { 244 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value); 245 if (cert) { 246 CFArrayAppendValue(result, cert); 247 CFRelease(cert); 248 } 249 }); 250 return result; 251 } else if (isData(raw_results)) { 252 return SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results); 253 } 254 return NULL; 255} 256 257static bool SecItemCertificateSourceCopyParents( 258 SecCertificateSourceRef source, SecCertificateRef certificate, 259 void *context, SecCertificateSourceParents callback) { 260 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; 261 /* FIXME: Search for things other than just subject of our issuer if we 262 have a subjectID or authorityKeyIdentifier. */ 263 CFDataRef normalizedIssuer = 264 SecCertificateGetNormalizedIssuerContent(certificate); 265 const void *keys[] = { 266 kSecClass, 267 kSecReturnData, 268 kSecMatchLimit, 269 kSecAttrSubject 270 }, 271 *values[] = { 272 kSecClassCertificate, 273 kCFBooleanTrue, 274 kSecMatchLimitAll, 275 normalizedIssuer 276 }; 277 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, 278 NULL, NULL); 279 CFTypeRef results = NULL; 280 /* We can make this async or run this on a queue now easily. */ 281 CFErrorRef localError = NULL; 282 if (!_SecItemCopyMatching(query, msource->accessGroups, &results, &localError)) { 283 if (CFErrorGetCode(localError) != errSecItemNotFound) { 284 secdebug("trust", "_SecItemCopyMatching: %@", localError); 285 } 286 CFRelease(localError); 287 } 288 CFRelease(query); 289 CFTypeRef certs = SecItemCertificateSourceResultsPost(results); 290 CFReleaseSafe(results); 291 callback(context, certs); 292 CFReleaseSafe(certs); 293 return true; 294} 295 296static bool SecItemCertificateSourceContains(SecCertificateSourceRef source, 297 SecCertificateRef certificate) { 298 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; 299 /* Lookup a certificate by issuer and serial number. */ 300 CFDataRef normalizedSubject = 301 SecCertificateGetNormalizedSubjectContent(certificate); 302 CFDataRef serialNumber = 303 SecCertificateCopySerialNumber(certificate); 304 const void *keys[] = { 305 kSecClass, 306 kSecMatchLimit, 307 kSecAttrIssuer, 308 kSecAttrSerialNumber 309 }, 310 *values[] = { 311 kSecClassCertificate, 312 kSecMatchLimitOne, 313 normalizedSubject, 314 serialNumber 315 }; 316 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 5, 317 NULL, NULL); 318 CFErrorRef localError = NULL; 319 CFTypeRef results = NULL; 320 bool ok = _SecItemCopyMatching(query, msource->accessGroups, &results, &localError); 321 CFRelease(query); 322 CFRelease(serialNumber); 323 CFReleaseSafe(results); 324 if (!ok) { 325 if (CFErrorGetCode(localError) != errSecItemNotFound) { 326 secdebug("trust", "_SecItemCopyMatching: %@", localError); 327 } 328 CFRelease(localError); 329 return false; 330 } 331 return true; 332} 333 334static SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) { 335 SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result)); 336 result->base.copyParents = SecItemCertificateSourceCopyParents; 337 result->base.contains = SecItemCertificateSourceContains; 338 result->accessGroups = accessGroups; 339 CFRetainSafe(accessGroups); 340 return (SecCertificateSourceRef)result; 341} 342 343static void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) { 344 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; 345 CFReleaseSafe(msource->accessGroups); 346 free(msource); 347} 348 349// MARK: - 350// MARK: SecSystemAnchorSource 351/******************************************************** 352 *********** SecSystemAnchorSource object ************ 353 ********************************************************/ 354 355static bool SecSystemAnchorSourceCopyParents( 356 SecCertificateSourceRef source, SecCertificateRef certificate, 357 void *context, SecCertificateSourceParents callback) { 358#ifndef SECITEM_SHIM_OSX 359 CFArrayRef parents = NULL; 360 CFArrayRef anchors = NULL; 361 SecOTAPKIRef otapkiref = NULL; 362 363 CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); 364 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor. 365 It does not matter since we would be returning the wrong anchors */ 366 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */ 367 368 otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); 369 require_quiet(otapkiref, errOut); 370 anchors = subject_to_anchors(nic); 371 require_quiet(anchors, errOut); 372 parents = CopyCertsFromIndices(anchors); 373 374errOut: 375 callback(context, parents); 376 CFReleaseSafe(parents); 377 CFReleaseSafe(otapkiref); 378#endif 379 return true; 380} 381 382/* Quick thought: we can eliminate this method if we search anchor sources 383 before all others and we remember if we got a cert from an anchorsource. */ 384static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source, 385 SecCertificateRef certificate) { 386 bool result = false; 387#ifndef SECITEM_SHIM_OSX 388 CFArrayRef anchors = NULL; 389 SecOTAPKIRef otapkiref = NULL; 390 CFArrayRef cert_datas = NULL; 391 392 CFDataRef nic = SecCertificateGetNormalizedSubjectContent(certificate); 393 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor. 394 It does not matter since we would be returning the wrong anchors */ 395 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */ 396 397 otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); 398 require_quiet(otapkiref, errOut); 399 anchors = subject_to_anchors(nic); 400 require_quiet(anchors, errOut); 401 cert_datas = CopyCertDataFromIndices(anchors); 402 require_quiet(cert_datas, errOut); 403 404 CFIndex cert_length = SecCertificateGetLength(certificate); 405 const UInt8 *cert_data_ptr = SecCertificateGetBytePtr(certificate); 406 407 CFIndex num_cert_datas = CFArrayGetCount(cert_datas); 408 for (CFIndex idx = 0; idx < num_cert_datas; idx++) 409 { 410 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, idx); 411 412 if (NULL != cert_data) 413 { 414 if (CFGetTypeID(cert_data) == CFDataGetTypeID()) 415 { 416 CFIndex aCert_Length = CFDataGetLength(cert_data); 417 const UInt8* aCert_Data_Ptr = CFDataGetBytePtr(cert_data); 418 419 if (aCert_Length == cert_length) 420 { 421 if (!memcmp(cert_data_ptr, aCert_Data_Ptr, cert_length)) 422 { 423 result = true; 424 break; 425 } 426 } 427 } 428 } 429 } 430 431errOut: 432 CFReleaseSafe(cert_datas); 433 CFReleaseSafe(otapkiref); 434#endif 435 return result; 436} 437 438 439 440struct SecCertificateSource kSecSystemAnchorSource = { 441 SecSystemAnchorSourceCopyParents, 442 SecSystemAnchorSourceContains 443}; 444 445// MARK: - 446// MARK: SecUserAnchorSource 447/******************************************************** 448 *********** SecUserAnchorSource object ************ 449 ********************************************************/ 450static bool SecUserAnchorSourceCopyParents( 451 SecCertificateSourceRef source, SecCertificateRef certificate, 452 void *context, SecCertificateSourceParents callback) { 453 CFArrayRef parents = SecTrustStoreCopyParents( 454 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate, NULL); 455 callback(context, parents); 456 CFReleaseSafe(parents); 457 return true; 458} 459 460static bool SecUserAnchorSourceContains(SecCertificateSourceRef source, 461 SecCertificateRef certificate) { 462 return SecTrustStoreContains( 463 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate); 464} 465 466struct SecCertificateSource kSecUserAnchorSource = { 467 SecUserAnchorSourceCopyParents, 468 SecUserAnchorSourceContains 469}; 470 471// MARK: - 472// MARK: SecMemoryCertificateSource 473/******************************************************** 474 *********** SecMemoryCertificateSource object ************ 475 ********************************************************/ 476struct SecMemoryCertificateSource { 477 struct SecCertificateSource base; 478 CFMutableSetRef certificates; 479 CFMutableDictionaryRef subjects; 480}; 481typedef struct SecMemoryCertificateSource *SecMemoryCertificateSourceRef; 482 483static bool SecMemoryCertificateSourceCopyParents( 484 SecCertificateSourceRef source, SecCertificateRef certificate, 485 void *context, SecCertificateSourceParents callback) { 486 SecMemoryCertificateSourceRef msource = 487 (SecMemoryCertificateSourceRef)source; 488 CFDataRef normalizedIssuer = 489 SecCertificateGetNormalizedIssuerContent(certificate); 490 CFArrayRef parents = CFDictionaryGetValue(msource->subjects, 491 normalizedIssuer); 492 /* FIXME filter parents by subjectID if certificate has an 493 authorityKeyIdentifier. */ 494 secdebug("trust", "%@ parents -> %@", certificate, parents); 495 callback(context, parents); 496 return true; 497} 498 499static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source, 500 SecCertificateRef certificate) { 501 SecMemoryCertificateSourceRef msource = 502 (SecMemoryCertificateSourceRef)source; 503 return CFSetContainsValue(msource->certificates, certificate); 504} 505 506static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict, 507 const void *key, const void *value) { 508 if (!key) 509 return; 510 511 CFMutableArrayRef values = 512 (CFMutableArrayRef)CFDictionaryGetValue(dict, key); 513 if (!values) { 514 values = CFArrayCreateMutable(kCFAllocatorDefault, 0, 515 &kCFTypeArrayCallBacks); 516 CFDictionaryAddValue(dict, key, values); 517 CFRelease(values); 518 } 519 520 if (values) 521 CFArrayAppendValue(values, value); 522} 523 524static void SecMemoryCertificateSourceApplierFunction(const void *value, 525 void *context) { 526 SecMemoryCertificateSourceRef msource = 527 (SecMemoryCertificateSourceRef)context; 528 SecCertificateRef certificate = (SecCertificateRef)value; 529 530 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */ 531 if (CFSetContainsValue(msource->certificates, certificate)) 532 return; 533 CFSetAddValue(msource->certificates, certificate); 534 535 CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate); 536 dictAddValueToArrayForKey(msource->subjects, key, value); 537} 538 539static SecCertificateSourceRef SecMemoryCertificateSourceCreate( 540 CFArrayRef certificates) { 541 SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef) 542 malloc(sizeof(*result)); 543 result->base.copyParents = SecMemoryCertificateSourceCopyParents; 544 result->base.contains = SecMemoryCertificateSourceContains; 545 CFIndex count = CFArrayGetCount(certificates); 546 result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count, 547 &kCFTypeSetCallBacks); 548 result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault, 549 count, &kCFTypeDictionaryKeyCallBacks, 550 &kCFTypeDictionaryValueCallBacks); 551 CFRange range = { 0, count }; 552 CFArrayApplyFunction(certificates, range, 553 SecMemoryCertificateSourceApplierFunction, result); 554 555 return (SecCertificateSourceRef)result; 556} 557 558static void SecMemoryCertificateSourceDestroy( 559 SecCertificateSourceRef source) { 560 SecMemoryCertificateSourceRef msource = 561 (SecMemoryCertificateSourceRef)source; 562 CFRelease(msource->certificates); 563 CFRelease(msource->subjects); 564 free(msource); 565} 566 567// MARK: - 568// MARK: SecCAIssuerCertificateSource 569/******************************************************** 570 ********* SecCAIssuerCertificateSource object ********** 571 ********************************************************/ 572static bool SecCAIssuerCertificateSourceCopyParents( 573 SecCertificateSourceRef source, SecCertificateRef certificate, 574 void *context, SecCertificateSourceParents callback) { 575 return SecCAIssuerCopyParents(certificate, SecPathBuilderGetQueue((SecPathBuilderRef)context), context, callback); 576} 577 578static bool SecCAIssuerCertificateSourceContains( 579 SecCertificateSourceRef source, SecCertificateRef certificate) { 580 return false; 581} 582 583struct SecCertificateSource kSecCAIssuerSource = { 584 SecCAIssuerCertificateSourceCopyParents, 585 SecCAIssuerCertificateSourceContains 586}; 587 588// MARK: - 589// MARK: SecPathBuilder 590/******************************************************** 591 *************** SecPathBuilder object ****************** 592 ********************************************************/ 593struct SecPathBuilder { 594 dispatch_queue_t queue; 595 SecCertificateSourceRef certificateSource; 596 SecCertificateSourceRef itemCertificateSource; 597 SecCertificateSourceRef anchorSource; 598 CFMutableArrayRef anchorSources; 599 CFIndex nextParentSource; 600 CFMutableArrayRef parentSources; 601 602 /* Hashed set of all paths we've constructed so far, used to prevent 603 re-considering a path that was already constructed once before. 604 Note that this is the only container in which certificatePath 605 objects are retained. 606 Every certificatePath being considered is always in allPaths and in at 607 most one of partialPaths, rejectedPaths, candidatePath or extendedPaths 608 all of which don't retain their values. */ 609 CFMutableSetRef allPaths; 610 611 /* No trusted anchor, satisfies the linking to intermediates for all 612 policies (unless considerRejected is true). */ 613 CFMutableArrayRef partialPaths; 614 /* No trusted anchor, does not satisfy linking to intermediates for all 615 policies. */ 616 CFMutableArrayRef rejectedPaths; 617 /* Trusted anchor, satisfies the policies so far. */ 618 CFMutableArrayRef candidatePaths; 619 620 CFIndex partialIX; 621 622 CFArrayRef leafDetails; 623 624 CFIndex rejectScore; 625 626 bool considerRejected; 627 bool considerPartials; 628 bool canAccessNetwork; 629 630 struct OpaqueSecPVC path; 631 SecCertificatePathRef bestPath; 632 bool bestPathIsEV; 633 634 CFIndex activations; 635 bool (*state)(SecPathBuilderRef); 636 SecPathBuilderCompleted completed; 637 const void *context; 638}; 639 640/* State functions. Return false if a async job was scheduled, return 641 true to execute the next state. */ 642static bool SecPathBuilderGetNext(SecPathBuilderRef builder); 643static bool SecPathBuilderValidatePath(SecPathBuilderRef builder); 644static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder); 645static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder); 646static bool SecPathBuilderReportResult(SecPathBuilderRef builder); 647 648/* Forward declarations. */ 649static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, 650 SecCertificateRef certificate); 651 652/* IDEA: policies could be made cabable of replacing incoming anchors and 653 anchorsOnly argument values. For example some policies require the 654 Apple Inc. CA and not any other anchor. This can be done in 655 SecPathBuilderLeafCertificateChecks since this only runs once. */ 656static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder, 657 SecCertificatePathRef path) { 658 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable( 659 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, 660 &kCFTypeDictionaryValueCallBacks); 661 builder->leafDetails = CFArrayCreate(kCFAllocatorDefault, 662 (const void **)&certDetail, 1, &kCFTypeArrayCallBacks); 663 CFRelease(certDetail); 664 SecPVCRef pvc = &builder->path; 665 SecPVCSetPath(pvc, path, builder->leafDetails); 666 builder->considerRejected = !SecPVCLeafChecks(pvc); 667} 668 669static void SecPathBuilderInit(SecPathBuilderRef builder, 670 CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, 671 CFArrayRef policies, CFAbsoluteTime verifyTime, CFArrayRef accessGroups, 672 SecPathBuilderCompleted completed, const void *context) { 673 secdebug("alloc", "%p", builder); 674 CFAllocatorRef allocator = kCFAllocatorDefault; 675 676 builder->queue = dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL); 677 678 builder->nextParentSource = 1; 679 builder->considerPartials = false; 680 builder->canAccessNetwork = true; 681 682 builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL); 683 builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL); 684 builder->allPaths = CFSetCreateMutable(allocator, 0, 685 &kCFTypeSetCallBacks); 686 687 builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL); 688 builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL); 689 builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL); 690 builder->partialIX = 0; 691 692 /* Init the policy verification context. */ 693 SecPVCInit(&builder->path, builder, policies, verifyTime); 694 builder->bestPath = NULL; 695 builder->bestPathIsEV = false; 696 builder->rejectScore = 0; 697 698 /* Let's create all the certificate sources we might want to use. */ 699 builder->certificateSource = 700 SecMemoryCertificateSourceCreate(certificates); 701 if (anchors) 702 builder->anchorSource = SecMemoryCertificateSourceCreate(anchors); 703 else 704 builder->anchorSource = NULL; 705 706 /* We always search certificateSource for parents since it includes the 707 leaf itself and it might be self signed. */ 708 CFArrayAppendValue(builder->parentSources, builder->certificateSource); 709 if (builder->anchorSource) { 710 CFArrayAppendValue(builder->anchorSources, builder->anchorSource); 711 } 712 builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups); 713 CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource); 714 if (anchorsOnly) { 715 /* Add the system and user anchor certificate db to the search list 716 if we don't explicitly trust them. */ 717 CFArrayAppendValue(builder->parentSources, &kSecSystemAnchorSource); 718 CFArrayAppendValue(builder->parentSources, &kSecUserAnchorSource); 719 } else { 720 /* Only add the system and user anchor certificate db to the 721 anchorSources if we are supposed to trust them. */ 722 CFArrayAppendValue(builder->anchorSources, &kSecSystemAnchorSource); 723 CFArrayAppendValue(builder->anchorSources, &kSecUserAnchorSource); 724 } 725 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource); 726 727 /* Now let's get the leaf cert and turn it into a path. */ 728 SecCertificateRef leaf = 729 (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0); 730 SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf); 731 CFSetAddValue(builder->allPaths, path); 732 CFArrayAppendValue(builder->partialPaths, path); 733 if (SecPathBuilderIsAnchor(builder, leaf)) { 734 SecCertificatePathSetIsAnchored(path); 735 CFArrayAppendValue(builder->candidatePaths, path); 736 } 737 SecPathBuilderLeafCertificateChecks(builder, path); 738 CFRelease(path); 739 740 builder->activations = 0; 741 builder->state = SecPathBuilderGetNext; 742 builder->completed = completed; 743 builder->context = context; 744} 745 746SecPathBuilderRef SecPathBuilderCreate(CFArrayRef certificates, 747 CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, 748 CFAbsoluteTime verifyTime, CFArrayRef accessGroups, 749 SecPathBuilderCompleted completed, const void *context) { 750 SecPathBuilderRef builder = malloc(sizeof(*builder)); 751 SecPathBuilderInit(builder, certificates, anchors, anchorsOnly, 752 policies, verifyTime, accessGroups, completed, context); 753 return builder; 754} 755 756static void SecPathBuilderDestroy(SecPathBuilderRef builder) { 757 secdebug("alloc", "%p", builder); 758 dispatch_release_null(builder->queue); 759 if (builder->anchorSource) 760 SecMemoryCertificateSourceDestroy(builder->anchorSource); 761 if (builder->certificateSource) 762 SecMemoryCertificateSourceDestroy(builder->certificateSource); 763 if (builder->itemCertificateSource) 764 SecItemCertificateSourceDestroy(builder->itemCertificateSource); 765 CFReleaseSafe(builder->anchorSources); 766 CFReleaseSafe(builder->parentSources); 767 CFReleaseSafe(builder->allPaths); 768 CFReleaseSafe(builder->partialPaths); 769 CFReleaseSafe(builder->rejectedPaths); 770 CFReleaseSafe(builder->candidatePaths); 771 CFReleaseSafe(builder->leafDetails); 772 773 SecPVCDelete(&builder->path); 774} 775 776bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) { 777 return builder->canAccessNetwork; 778} 779 780void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) { 781 if (builder->canAccessNetwork != allow) { 782 builder->canAccessNetwork = allow; 783 if (allow) { 784 secdebug("http", "network access re-enabled by policy"); 785 /* re-enabling network_access re-adds kSecCAIssuerSource as 786 a parent source. */ 787 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource); 788 } else { 789 secdebug("http", "network access disabled by policy"); 790 /* disabling network_access removes kSecCAIssuerSource from 791 the list of parent sources. */ 792 CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources, 793 CFRangeMake(0, CFArrayGetCount(builder->parentSources)), 794 &kSecCAIssuerSource); 795 if (ix >= 0) 796 CFArrayRemoveValueAtIndex(builder->parentSources, ix); 797 } 798 } 799} 800 801static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, 802 SecCertificateRef certificate) { 803 /* We always look through all anchor sources. */ 804 CFIndex count = CFArrayGetCount(builder->anchorSources); 805 CFIndex ix; 806 for (ix = 0; ix < count; ++ix) { 807 SecCertificateSourceRef source = (SecCertificateSourceRef) 808 CFArrayGetValueAtIndex(builder->anchorSources, ix); 809 if (SecCertificateSourceContains(source, certificate)) { 810 return true; 811 } 812 } 813 return false; 814} 815 816/* Return false if path is not a partial, if path was a valid candidate it 817 will have been added to builder->candidatePaths, if path was rejected 818 by the parent certificate checks (because it's expired or some other 819 static chaining check failed) it will have been added to rejectedPaths. 820 Return true path if path is a partial. */ 821static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, 822 SecCertificatePathRef path) { 823 SecPVCRef pvc = &builder->path; 824 SecPVCSetPath(pvc, path, NULL); 825 826 if (!builder->considerRejected && !SecPVCParentCertificateChecks(pvc, 827 SecPVCGetCertificateCount(pvc) - 1)) { 828 secdebug("trust", "Found rejected path %@", path); 829 CFArrayAppendValue(builder->rejectedPaths, path); 830 return false; 831 } 832 833 SecPathVerifyStatus vstatus = SecCertificatePathVerify(path); 834 /* Candidate paths with failed signatures are discarded. */ 835 if (vstatus == kSecPathVerifyFailed) { 836 secdebug("trust", "Verify failed for path %@", path); 837 return false; 838 } 839 840 if (vstatus == kSecPathVerifySuccess) { 841 /* The signature chain verified sucessfully, now let's find 842 out if we have an anchor for path. */ 843 if (SecCertificatePathIsAnchored(path)) { 844 secdebug("trust", "Adding candidate %@", path); 845 CFArrayAppendValue(builder->candidatePaths, path); 846 return false; 847 } 848 } 849 850 return true; 851} 852 853/* Given the builder, a partial chain partial and the parents array, construct 854 a SecCertificatePath for each parent. After discarding previously 855 considered paths and paths with cycles, sort out which array each path 856 should go in, if any. */ 857static void SecPathBuilderProccessParents(SecPathBuilderRef builder, 858 SecCertificatePathRef partial, CFArrayRef parents) { 859 CFIndex rootIX = SecCertificatePathGetCount(partial) - 1; 860 CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0; 861 CFIndex parentIX; 862 bool is_anchor = SecCertificatePathGetNextSourceIndex(partial) <= 863 CFArrayGetCount(builder->anchorSources); 864 secdebug("trust", "found %" PRIdCFIndex " candidate %s", num_parents, 865 (is_anchor ? "anchors" : "parents")); 866 for (parentIX = 0; parentIX < num_parents; ++parentIX) { 867 SecCertificateRef parent = (SecCertificateRef) 868 CFArrayGetValueAtIndex(parents, parentIX); 869 CFIndex ixOfParent = SecCertificatePathGetIndexOfCertificate(partial, 870 parent); 871 if (ixOfParent != kCFNotFound) { 872 /* partial already contains parent. Let's not add the same 873 certificate again. */ 874 if (ixOfParent == rootIX) { 875 /* parent is equal to the root of the partial, so partial 876 looks to be self issued. */ 877 SecCertificatePathSetSelfIssued(partial); 878 } 879 continue; 880 } 881 882 /* FIXME Add more sanity checks to see that parent really can be 883 a parent of partial_root. subjectKeyID == authorityKeyID, 884 signature algorithm matches public key algorithm, etc. */ 885 SecCertificatePathRef path = SecCertificatePathCreate(partial, parent); 886 if (!path) 887 continue; 888 if (!CFSetContainsValue(builder->allPaths, path)) { 889 CFSetAddValue(builder->allPaths, path); 890 if (is_anchor) 891 SecCertificatePathSetIsAnchored(path); 892 if (SecPathBuilderIsPartial(builder, path)) { 893 /* Insert path right at the current position since it's a new 894 candiate partial. */ 895 CFArrayInsertValueAtIndex(builder->partialPaths, 896 ++builder->partialIX, path); 897 secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@", 898 parentIX + 1, num_parents, path); 899 } 900 secdebug("trust", "found new path %@", path); 901 } 902 CFRelease(path); 903 } 904} 905 906/* Callback for the SecPathBuilderGetNext() functions call to 907 SecCertificateSourceCopyParents(). */ 908static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) { 909 SecPathBuilderRef builder = (SecPathBuilderRef)context; 910 SecCertificatePathRef partial = (SecCertificatePathRef) 911 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); 912 secdebug("async", "%@ parents %@", partial, parents); 913 SecPathBuilderProccessParents(builder, partial, parents); 914 915 builder->state = SecPathBuilderGetNext; 916 SecPathBuilderStep(builder); 917} 918 919static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { 920 /* If we have any candidates left to go return those first. */ 921 if (CFArrayGetCount(builder->candidatePaths)) { 922 SecCertificatePathRef path = (SecCertificatePathRef) 923 CFArrayGetValueAtIndex(builder->candidatePaths, 0); 924 CFArrayRemoveValueAtIndex(builder->candidatePaths, 0); 925 secdebug("trust", "SecPathBuilderGetNext returning candidate %@", 926 path); 927 SecPVCSetPath(&builder->path, path, NULL); 928 builder->state = SecPathBuilderValidatePath; 929 return true; 930 } 931 932 /* If we are considering rejected chains we check each rejected path 933 with SecPathBuilderIsPartial() which checks the signature chain and 934 either drops the path if it's not properly signed, add it as a 935 candidate if it has a trusted anchor, or adds it as a partial 936 to be considered once we finish considering all the rejects. */ 937 if (builder->considerRejected) { 938 CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths); 939 if (rejectedIX) { 940 rejectedIX--; 941 SecCertificatePathRef path = (SecCertificatePathRef) 942 CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX); 943 if (SecPathBuilderIsPartial(builder, path)) { 944 CFArrayInsertValueAtIndex(builder->partialPaths, 945 ++builder->partialIX, path); 946 } 947 CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX); 948 949 /* Keep going until we have moved all rejected partials into 950 the regular partials or candidates array. */ 951 return true; 952 } 953 } 954 955 /* If builder->partialIX is < 0 we have considered all partial chains 956 this block must ensure partialIX >= 0 if execution continues past 957 it's end. */ 958 if (builder->partialIX < 0) { 959 CFIndex num_sources = CFArrayGetCount(builder->parentSources); 960 if (builder->nextParentSource < num_sources) { 961 builder->nextParentSource++; 962 secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources", 963 builder->nextParentSource, num_sources); 964 } else { 965 /* We've run out of new sources to consider so let's look at 966 rejected chains and after that even consider partials 967 directly. 968 FIXME we might not want to consider partial paths that 969 are subsets of other partial paths, or not consider them 970 at all if we already have an anchored reject. */ 971 if (!builder->considerRejected) { 972 builder->considerRejected = true; 973 secdebug("trust", "considering rejected paths"); 974 } else if (!builder->considerPartials) { 975 builder->considerPartials = true; 976 secdebug("trust", "considering partials"); 977 } else { 978 /* We're all out of options, so we can't produce any more 979 candidates. Let's calculate details and return the best 980 path we found. */ 981 builder->state = SecPathBuilderComputeDetails; 982 return true; 983 } 984 } 985 builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1; 986 secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1); 987 return true; 988 } 989 990 /* We know builder->partialIX >= 0 if we get here. */ 991 SecCertificatePathRef partial = (SecCertificatePathRef) 992 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); 993 /* Don't try to extend partials anymore once we are in the considerPartials 994 state, since at this point every partial has been extended with every 995 possible parentSource already. */ 996 if (builder->considerPartials) { 997 --builder->partialIX; 998 SecPVCSetPath(&builder->path, partial, NULL); 999 builder->state = SecPathBuilderValidatePath; 1000 return true; 1001 } 1002 1003 /* Attempt to extend this partial path with another certificate. This 1004 should give us a list of potential parents to consider. */ 1005 secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@", 1006 builder->partialIX + 1, CFArrayGetCount(builder->partialPaths), 1007 partial); 1008 1009 /* Attempt to extend partial, leaving all possible extended versions 1010 of partial in builder->extendedPaths. */ 1011 CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial); 1012 CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources); 1013 if (sourceIX < num_anchor_sources + builder->nextParentSource) { 1014 SecCertificateSourceRef source; 1015 if (sourceIX < num_anchor_sources) { 1016 source = (SecCertificateSourceRef) 1017 CFArrayGetValueAtIndex(builder->anchorSources, sourceIX); 1018 secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1, 1019 num_anchor_sources); 1020 } else { 1021 CFIndex parentIX = sourceIX - num_anchor_sources; 1022 source = (SecCertificateSourceRef) 1023 CFArrayGetValueAtIndex(builder->parentSources, parentIX); 1024 secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1, 1025 builder->nextParentSource); 1026 } 1027 SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1); 1028 SecCertificateRef root = SecCertificatePathGetRoot(partial); 1029 return SecCertificateSourceCopyParents(source, root, 1030 builder, SecPathBuilderExtendPaths); 1031 } else { 1032 --builder->partialIX; 1033 } 1034 1035 return true; 1036} 1037 1038/* One or more of the policies did not accept the candidate path. */ 1039static void SecPathBuilderReject(SecPathBuilderRef builder) { 1040 check(builder); 1041 SecPVCRef pvc = &builder->path; 1042 1043 builder->state = SecPathBuilderGetNext; 1044 1045 if (builder->bestPathIsEV && !pvc->is_ev) { 1046 /* We never replace an ev reject with a non ev reject. */ 1047 return; 1048 } 1049 1050 CFIndex rejectScore = builder->rejectScore; 1051 CFIndex score = SecCertificatePathScore(builder->path.path, 1052 SecPVCGetVerifyTime(&builder->path)); 1053 1054 /* The current chain is valid for EV, but revocation checking failed. We 1055 replace any previously accepted or rejected non EV chains with the 1056 current one. */ 1057 if (pvc->is_ev && !builder->bestPathIsEV) { 1058 rejectScore = 0; 1059 } 1060 1061#if 0 1062 if (pvc->is_ev) { 1063 /* Since this means we found a valid ev chain that was revoked, 1064 we might want to switch directly to the 1065 SecPathBuilderComputeDetails state here if we think further 1066 searching for new chains is pointless. For now we'll keep 1067 going, since we could accept an alternate EV certification 1068 path that isn't revoked. */ 1069 builder->state = SecPathBuilderComputeDetails; 1070 } 1071#endif 1072 1073 /* Do this last so that changes to rejectScore above will take affect. */ 1074 if (!builder->bestPath || score > rejectScore) { 1075 if (builder->bestPath) { 1076 secdebug("reject", 1077 "replacing %sev %s score: %ld with %sev reject score: %" PRIdCFIndex " %@", 1078 (builder->bestPathIsEV ? "" : "non "), 1079 (builder->rejectScore == INTPTR_MAX ? "accept" : "reject"), 1080 builder->rejectScore, 1081 (pvc->is_ev ? "" : "non "), (long)score, builder->path.path); 1082 } else { 1083 secdebug("reject", "%sev reject score: %" PRIdCFIndex " %@", 1084 (pvc->is_ev ? "" : "non "), score, builder->path.path); 1085 } 1086 1087 builder->rejectScore = score; 1088 builder->bestPath = pvc->path; 1089 builder->bestPathIsEV = pvc->is_ev; 1090 } else { 1091 secdebug("reject", "%sev reject score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@", 1092 (pvc->is_ev ? "" : "non "), score, rejectScore, builder->path.path); 1093 } 1094} 1095 1096/* All policies accepted the candidate path. */ 1097static void SecPathBuilderAccept(SecPathBuilderRef builder) { 1098 check(builder); 1099 SecPVCRef pvc = &builder->path; 1100 if (pvc->is_ev || !builder->bestPathIsEV) { 1101 secdebug("accept", "replacing %sev accept with %sev %@", 1102 (builder->bestPathIsEV ? "" : "non "), 1103 (pvc->is_ev ? "" : "non "), builder->path.path); 1104 builder->rejectScore = INTPTR_MAX; /* CFIndex is signed long which is INTPTR_T */ 1105 builder->bestPathIsEV = pvc->is_ev; 1106 builder->bestPath = pvc->path; 1107 } 1108 1109 /* If we found the best accept we can we want to switch directly to the 1110 SecPathBuilderComputeDetails state here, since we're done. */ 1111 if (pvc->is_ev || !pvc->optionally_ev) 1112 builder->state = SecPathBuilderComputeDetails; 1113 else 1114 builder->state = SecPathBuilderGetNext; 1115} 1116 1117/* Return true iff a given path satisfies all the specified policies at 1118 verifyTime. */ 1119static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) { 1120 SecPVCRef pvc = &builder->path; 1121 1122 if (builder->considerRejected) { 1123 SecPathBuilderReject(builder); 1124 return true; 1125 } 1126 1127 builder->state = SecPathBuilderDidValidatePath; 1128 return SecPVCPathChecks(pvc); 1129} 1130 1131static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) { 1132 SecPVCRef pvc = &builder->path; 1133 if (pvc->result) { 1134 SecPathBuilderAccept(builder); 1135 } else { 1136 SecPathBuilderReject(builder); 1137 } 1138 assert(builder->state != SecPathBuilderDidValidatePath); 1139 return true; 1140} 1141 1142static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) { 1143 // foobar 1144 SecPVCRef pvc = &builder->path; 1145#if 0 1146 if (!builder->caller_wants_details) { 1147 SecPVCSetPath(pvc, builder->bestPath, NULL); 1148 pvc->result = builder->rejectScore == INTPTR_MAX; 1149 builder->state = SecPathBuilderReportResult; 1150 return true; 1151 } 1152#endif 1153 CFIndex ix, pathLength = SecCertificatePathGetCount(builder->bestPath); 1154 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault, 1155 pathLength, builder->leafDetails); 1156 CFRetainSafe(details); 1157 SecPVCSetPath(pvc, builder->bestPath, details); 1158 /* Only report on EV stuff if the bestPath actually was valid for EV. */ 1159 pvc->optionally_ev = builder->bestPathIsEV; 1160 pvc->info = CFDictionaryCreateMutable(kCFAllocatorDefault, 1161 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1162 for (ix = 1; ix < pathLength; ++ix) { 1163 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable( 1164 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, 1165 &kCFTypeDictionaryValueCallBacks); 1166 CFArrayAppendValue(details, certDetail); 1167 CFRelease(certDetail); 1168 SecPVCParentCertificateChecks(pvc, ix); 1169 SecPVCGrayListedKeyChecks(pvc, ix); 1170 SecPVCBlackListedKeyChecks(pvc, ix); 1171 } 1172 builder->state = SecPathBuilderReportResult; 1173 bool completed = SecPVCPathChecks(pvc); 1174 1175 /* Reject the certificate if it was accepted before but we failed it now. */ 1176 if (builder->rejectScore == INTPTR_MAX && !pvc->result) { 1177 builder->rejectScore = 0; 1178 } 1179 1180 CFReleaseSafe(details); 1181 1182 return completed; 1183} 1184 1185static bool SecPathBuilderReportResult(SecPathBuilderRef builder) { 1186 SecPVCRef pvc = &builder->path; 1187 if (pvc->info && pvc->is_ev && pvc->result) { 1188 CFDictionarySetValue(pvc->info, kSecTrustInfoExtendedValidationKey, 1189 kCFBooleanTrue); 1190 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 1191 CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf); 1192 if (leafCompanyName) { 1193 CFDictionarySetValue(pvc->info, kSecTrustInfoCompanyNameKey, 1194 leafCompanyName); 1195 CFRelease(leafCompanyName); 1196 } 1197 if (pvc->rvcs) { 1198 CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc); 1199 if (nextUpdate == 0) { 1200 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey, 1201 kCFBooleanFalse); 1202 } else { 1203 CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate); 1204 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationValidUntilKey, 1205 validUntil); 1206 CFRelease(validUntil); 1207 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey, 1208 kCFBooleanTrue); 1209 } 1210 } 1211 } 1212 1213 /* This will trigger the outer step function to call the completion 1214 function. */ 1215 builder->state = NULL; 1216 return false; 1217} 1218 1219/* @function SecPathBuilderStep 1220 @summary This is the core of the async engine. 1221 @description Return false iff job is complete, true if a network request 1222 is pending. 1223 builder->state is a function pointer which is to be invoked. 1224 If you call this function from within a builder->state invocation it 1225 immediately returns true. 1226 Otherwise the following steps are repeated endlessly (unless a step returns) 1227 builder->state is invoked. If it returns true and builder->state is still 1228 non NULL this proccess is repeated. 1229 If a state returns false, SecPathBuilder will return true 1230 if builder->state is non NULL. 1231 If builder->state is NULL then regardless of what the state function returns 1232 the completion callback will be invoked and the builder will be deallocated. 1233 */ 1234bool SecPathBuilderStep(SecPathBuilderRef builder) { 1235 if (builder->activations) { 1236 secdebug("async", "activations: %lu returning true", 1237 builder->activations); 1238 return true; 1239 } 1240 1241 secdebug("async", "activations: %lu", builder->activations); 1242 builder->activations++; 1243 while (builder->state && builder->state(builder)); 1244 --builder->activations; 1245 1246 if (builder->state) { 1247 secdebug("async", "waiting for async reply, exiting"); 1248 /* A state returned false, it's waiting for network traffic. Let's 1249 return. */ 1250 return true; 1251 } 1252 1253 if (builder->activations) { 1254 /* There is still at least one other running instance of this builder 1255 somewhere on the stack, we let that instance take care of sending 1256 the client a response. */ 1257 return false; 1258 } 1259 1260 SecTrustResultType result = (builder->rejectScore == INTPTR_MAX 1261 ? kSecTrustResultUnspecified : kSecTrustResultRecoverableTrustFailure); 1262 1263 secdebug("trust", "completed: %@ details: %@ result: %d", 1264 builder->bestPath, builder->path.details, result); 1265 1266 if (builder->completed) { 1267 builder->completed(builder->context, builder->bestPath, 1268 builder->path.details, builder->path.info, result); 1269 } 1270 1271 /* Finally, destroy the builder and free it. */ 1272 SecPathBuilderDestroy(builder); 1273 free(builder); 1274 1275 return false; 1276} 1277 1278dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) { 1279 return builder->queue; 1280} 1281 1282// MARK: - 1283// MARK: SecTrustServer 1284/******************************************************** 1285 ****************** SecTrustServer ********************** 1286 ********************************************************/ 1287 1288typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error); 1289 1290static void 1291SecTrustServerEvaluateCompleted(const void *userData, 1292 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info, 1293 SecTrustResultType result) { 1294 SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData; 1295 evaluated(result, details, info, chain, NULL); 1296 Block_release(evaluated); 1297} 1298 1299void 1300SecTrustServerEvaluateBlock(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) { 1301 SecTrustServerEvaluationCompleted userData = Block_copy(evaluated); 1302 /* Call the actual evaluator function. */ 1303 SecPathBuilderRef builder = SecPathBuilderCreate(certificates, anchors, 1304 anchorsOnly, policies, 1305 verifyTime, accessGroups, 1306 SecTrustServerEvaluateCompleted, userData); 1307 dispatch_async(builder->queue, ^{ SecPathBuilderStep(builder); }); 1308} 1309 1310 1311// NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly 1312SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, CFArrayRef policies, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *pdetails, CFDictionaryRef *pinfo, SecCertificatePathRef *pchain, CFErrorRef *perror) { 1313 dispatch_semaphore_t done = dispatch_semaphore_create(0); 1314 __block SecTrustResultType result = kSecTrustResultInvalid; 1315 SecTrustServerEvaluateBlock(certificates, anchors, anchorsOnly, policies, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) { 1316 result = tr; 1317 if (tr == kSecTrustResultInvalid) { 1318 if (perror) { 1319 *perror = error; 1320 CFRetainSafe(error); 1321 } 1322 } else { 1323 if (pdetails) { 1324 *pdetails = details; 1325 CFRetainSafe(details); 1326 } 1327 if (pinfo) { 1328 *pinfo = info; 1329 CFRetainSafe(info); 1330 } 1331 if (pchain) { 1332 *pchain = chain; 1333 CFRetainSafe(chain); 1334 } 1335 } 1336 dispatch_semaphore_signal(done); 1337 }); 1338 dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER); 1339 1340 return result; 1341} 1342