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