1/* 2 * Copyright (c) 2008-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 24/* 25 * SecPolicyServer.c - Trust policies dealing with certificate revocation. 26 */ 27 28#include <securityd/SecPolicyServer.h> 29#include <Security/SecPolicyInternal.h> 30#include <Security/SecPolicyPriv.h> 31#include <utilities/SecIOFormat.h> 32#include <securityd/asynchttp.h> 33#include <securityd/policytree.h> 34#include <CoreFoundation/CFTimeZone.h> 35#include <wctype.h> 36#include <libDER/oids.h> 37#include <CoreFoundation/CFNumber.h> 38#include <Security/SecCertificateInternal.h> 39#include <AssertMacros.h> 40#include <utilities/debugging.h> 41#include <security_asn1/SecAsn1Coder.h> 42#include <security_asn1/ocspTemplates.h> 43#include <security_asn1/oidsalg.h> 44#include <security_asn1/oidsocsp.h> 45#include <CommonCrypto/CommonDigest.h> 46#include <Security/SecFramework.h> 47#include <Security/SecPolicyInternal.h> 48#include <Security/SecTrustPriv.h> 49#include <Security/SecInternal.h> 50#include <CFNetwork/CFHTTPMessage.h> 51#include <CFNetwork/CFHTTPStream.h> 52#include <SystemConfiguration/SCDynamicStoreCopySpecific.h> 53#include <asl.h> 54#include <securityd/SecOCSPRequest.h> 55#include <securityd/SecOCSPResponse.h> 56#include <securityd/asynchttp.h> 57#include <securityd/SecTrustServer.h> 58#include <securityd/SecOCSPCache.h> 59#include <utilities/array_size.h> 60#include <utilities/SecCFWrappers.h> 61#include "OTATrustUtilities.h" 62 63#define ocspdErrorLog(args...) asl_log(NULL, NULL, ASL_LEVEL_ERR, ## args) 64 65/* Set this to 1 to dump the ocsp responses received in DER form in /tmp. */ 66#ifndef DUMP_OCSPRESPONSES 67#define DUMP_OCSPRESPONSES 0 68#endif 69 70#if DUMP_OCSPRESPONSES 71 72#include <unistd.h> 73#include <fcntl.h> 74 75static void secdumpdata(CFDataRef data, const char *name) { 76 int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0666); 77 write(fd, CFDataGetBytePtr(data), CFDataGetLength(data)); 78 close(fd); 79} 80 81#endif 82 83 84/******************************************************** 85 ****************** SecPolicy object ******************** 86 ********************************************************/ 87 88static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL; 89static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL; 90 91static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID) 92{ 93 CFArrayRef result = NULL; 94 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); 95 if (NULL == otapkiRef) 96 { 97 return result; 98 } 99 100 CFDictionaryRef evToPolicyAnchorDigest = SecOTAPKICopyEVPolicyToAnchorMapping(otapkiRef); 101 CFRelease(otapkiRef); 102 103 if (NULL == evToPolicyAnchorDigest) 104 { 105 return result; 106 } 107 108 CFArrayRef roots = NULL; 109 CFStringRef oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, policyOID); 110 if (oid && evToPolicyAnchorDigest) 111 { 112 result = (CFArrayRef)CFDictionaryGetValue(evToPolicyAnchorDigest, oid); 113 if (roots && CFGetTypeID(result) != CFArrayGetTypeID()) 114 { 115 ocspdErrorLog("EVRoot.plist has non array value"); 116 result = NULL; 117 } 118 CFRelease(oid); 119 } 120 CFReleaseSafe(evToPolicyAnchorDigest); 121 return result; 122} 123 124 125static bool SecPolicyIsEVPolicy(const DERItem *policyOID) { 126 return SecPolicyAnchorDigestsForEVPolicy(policyOID); 127} 128 129static bool SecPolicyRootCACertificateIsEV(SecCertificateRef certificate, 130 policy_set_t valid_policies) { 131 /* Ensure that this certificate is a valid anchor for one of the 132 certificate policy oids specified in the leaf. */ 133 CFDataRef digest = SecCertificateGetSHA1Digest(certificate); 134 policy_set_t ix; 135 bool good_ev_anchor = false; 136 for (ix = valid_policies; ix; ix = ix->oid_next) { 137 CFArrayRef digests = SecPolicyAnchorDigestsForEVPolicy(&ix->oid); 138 if (digests && CFArrayContainsValue(digests, 139 CFRangeMake(0, CFArrayGetCount(digests)), digest)) { 140 secdebug("ev", "found anchor for policy oid"); 141 good_ev_anchor = true; 142 break; 143 } 144 } 145 require_quiet(good_ev_anchor, notEV); 146 147 CFAbsoluteTime october2006 = 178761600; 148 if (SecCertificateVersion(certificate) >= 3 149 && SecCertificateNotValidBefore(certificate) >= october2006) { 150 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); 151 require_quiet(bc && bc->isCA == true, notEV); 152 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); 153 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) 154 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV); 155 } 156 157 CFAbsoluteTime jan2011 = 315532800; 158 if (SecCertificateNotValidBefore(certificate) < jan2011) { 159 /* At least MD5, SHA-1 with RSA 2048 or ECC NIST P-256. */ 160 } else { 161 /* At least SHA-1, SHA-256, SHA-384 or SHA-512 with RSA 2048 or 162 ECC NIST P-256. */ 163 } 164 165 return true; 166notEV: 167 return false; 168} 169 170static bool SecPolicySubordinateCACertificateCouldBeEV(SecCertificateRef certificate) { 171 const SecCECertificatePolicies *cp; 172 cp = SecCertificateGetCertificatePolicies(certificate); 173 require_quiet(cp && cp->numPolicies > 0, notEV); 174 /* SecCertificateGetCRLDistributionPoints() is a noop right now */ 175#if 0 176 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate); 177 require_quiet(cdp && CFArrayGetCount(cdp) > 0, notEV); 178#endif 179 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); 180 require_quiet(bc && bc->isCA == true, notEV); 181 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); 182 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) 183 == (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign), notEV); 184 CFAbsoluteTime jan2011 = 315532800; 185 if (SecCertificateNotValidBefore(certificate) < jan2011) { 186 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */ 187 } else { 188 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or 189 ECC NIST P-256. */ 190 } 191 192 return true; 193notEV: 194 return false; 195} 196 197bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) { 198 /* 3. Subscriber Certificate. */ 199 200 /* (a) certificate Policies */ 201 const SecCECertificatePolicies *cp; 202 cp = SecCertificateGetCertificatePolicies(certificate); 203 require_quiet(cp && cp->numPolicies > 0, notEV); 204 /* Now find at least one policy in here that has a qualifierID of id-qt 2 205 and a policyQualifier that is a URI to the CPS and an EV policy OID. */ 206 uint32_t ix = 0; 207 bool found_ev_anchor_for_leaf_policy = false; 208 for (ix = 0; ix < cp->numPolicies; ++ix) { 209 if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) { 210 found_ev_anchor_for_leaf_policy = true; 211 } 212 } 213 require_quiet(found_ev_anchor_for_leaf_policy, notEV); 214 215 /* SecCertificateGetCRLDistributionPoints() is a noop right now */ 216#if 0 217 /* (b) cRLDistributionPoint 218 (c) authorityInformationAccess */ 219 CFArrayRef cdp = SecCertificateGetCRLDistributionPoints(certificate); 220 if (cdp) { 221 require_quiet(CFArrayGetCount(cdp) > 0, notEV); 222 } else { 223 CFArrayRef or = SecCertificateGetOCSPResponders(certificate); 224 require_quiet(or && CFArrayGetCount(or) > 0, notEV); 225 //CFArrayRef ci = SecCertificateGetCAIssuers(certificate); 226 } 227#endif 228 229 /* (d) basicConstraints 230 If present, the cA field MUST be set false. */ 231 const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); 232 if (bc) { 233 require_quiet(bc->isCA == false, notEV); 234 } 235 236 /* (e) keyUsage. */ 237 SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); 238 if (ku) { 239 require_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV); 240 } 241 242#if 0 243 /* The EV Cert Spec errata specifies this, though this is a check for SSL 244 not specifically EV. */ 245 246 /* (e) extKeyUsage 247 248Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */ 249 SecCertificateCopyExtendedKeyUsage(certificate); 250#endif 251 252 CFAbsoluteTime jan2011 = 315532800; 253 if (SecCertificateNotValidAfter(certificate) < jan2011) { 254 /* At least SHA-1 with RSA 1024 or ECC NIST P-256. */ 255 } else { 256 /* At least SHA-1, SHA-256, SHA-284 or SHA-512 with RSA 2028 or 257 ECC NIST P-256. */ 258 } 259 260 return true; 261notEV: 262 return false; 263} 264 265/******************************************************** 266 **************** SecPolicy Callbacks ******************* 267 ********************************************************/ 268static void SecPolicyCheckCriticalExtensions(SecPVCRef pvc, 269 CFStringRef key) { 270} 271 272static void SecPolicyCheckIdLinkage(SecPVCRef pvc, 273 CFStringRef key) { 274 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 275 CFDataRef parentSubjectKeyID = NULL; 276 for (ix = count - 1; ix >= 0; --ix) { 277 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 278 /* If the previous certificate in the chain had a SubjectKeyID, 279 make sure it matches the current certificates AuthorityKeyID. */ 280 if (parentSubjectKeyID) { 281 /* @@@ According to RFC 2459 neither AuthorityKeyID nor 282 SubjectKeyID can be critical. Currenty we don't check 283 for this. */ 284 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(cert); 285 if (authorityKeyID) { 286 if (!CFEqual(parentSubjectKeyID, authorityKeyID)) { 287 /* AuthorityKeyID doesn't match issuers SubjectKeyID. */ 288 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 289 return; 290 } 291 } 292 } 293 294 parentSubjectKeyID = SecCertificateGetSubjectKeyID(cert); 295 } 296} 297 298static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) { 299 if (!xku || CFGetTypeID(xku) != CFNumberGetTypeID()) 300 return false; 301 302 SInt32 dku; 303 CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku); 304 SecKeyUsage ku = (SecKeyUsage)dku; 305 return (keyUsage & ku) == ku; 306} 307 308static void SecPolicyCheckKeyUsage(SecPVCRef pvc, 309 CFStringRef key) { 310 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 311 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(leaf); 312 bool match = false; 313 SecPolicyRef policy = SecPVCGetPolicy(pvc); 314 CFTypeRef xku = CFDictionaryGetValue(policy->_options, key); 315 if (isArray(xku)) { 316 CFIndex ix, count = CFArrayGetCount(xku); 317 for (ix = 0; ix < count; ++ix) { 318 CFTypeRef ku = CFArrayGetValueAtIndex(xku, ix); 319 if (keyusage_allows(keyUsage, ku)) { 320 match = true; 321 break; 322 } 323 } 324 } else { 325 match = keyusage_allows(keyUsage, xku); 326 } 327 if (!match) { 328 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 329 } 330} 331 332static bool extendedkeyusage_allows(CFArrayRef extendedKeyUsage, 333 CFTypeRef xeku) { 334 if (!xeku || CFGetTypeID(xeku) != CFDataGetTypeID()) 335 return false; 336 if (extendedKeyUsage) { 337 CFRange all = { 0, CFArrayGetCount(extendedKeyUsage) }; 338 return CFArrayContainsValue(extendedKeyUsage, all, xeku); 339 } else { 340 /* Certificate has no extended key usage, only a match if the policy 341 contains a 0 length CFDataRef. */ 342 return CFDataGetLength((CFDataRef)xeku) == 0; 343 } 344} 345 346/* AUDIT[securityd](done): 347 policy->_options is a caller provided dictionary, only its cf type has 348 been checked. 349 */ 350static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) { 351 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 352 CFArrayRef leafExtendedKeyUsage = SecCertificateCopyExtendedKeyUsage(leaf); 353 bool match = false; 354 SecPolicyRef policy = SecPVCGetPolicy(pvc); 355 CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key); 356 if (isArray(xeku)) { 357 CFIndex ix, count = CFArrayGetCount(xeku); 358 for (ix = 0; ix < count; ix++) { 359 CFTypeRef eku = CFArrayGetValueAtIndex(xeku, ix); 360 if (extendedkeyusage_allows(leafExtendedKeyUsage, eku)) { 361 match = true; 362 break; 363 } 364 } 365 } else { 366 match = extendedkeyusage_allows(leafExtendedKeyUsage, xeku); 367 } 368 CFReleaseSafe(leafExtendedKeyUsage); 369 if (!match) { 370 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 371 } 372} 373 374#if 0 375static void SecPolicyCheckBasicContraintsCommon(SecPVCRef pvc, 376 CFStringRef key, bool strict) { 377 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 378 for (ix = 0; ix < count; ++ix) { 379 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 380 const SecCEBasicConstraints *bc = 381 SecCertificateGetBasicConstraints(cert); 382 if (bc) { 383 if (strict) { 384 if (ix == 0) { 385 /* Leaf certificate has basic constraints extension. */ 386 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 387 return; 388 } else if (!bc->critical) { 389 /* Basic constraints extension is not marked critical. */ 390 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 391 return; 392 } 393 } 394 395 if (ix > 0 || count == 1) { 396 if (!bc->isCA) { 397 /* Non leaf certificate marked as isCA false. */ 398 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 399 return; 400 } 401 402 if (bc->pathLenConstraintPresent) { 403 if (bc->pathLenConstraint < (uint32_t)(ix - 1)) { 404#if 0 405 /* @@@ If a self signed certificate is issued by 406 another cert that is trusted, then we are supposed 407 to treat the self signed cert itself as the anchor 408 for path length purposes. */ 409 CFIndex ssix = SecCertificatePathSelfSignedIndex(path); 410 if (ssix >= 0 && ix >= ssix) { 411 /* It's ok if the pathLenConstraint isn't met for 412 certificates signing a self signed cert in the 413 chain. */ 414 } else 415#endif 416 { 417 /* Path Length Constraint Exceeded. */ 418 if (!SecPVCSetResult(pvc, key, ix, 419 kCFBooleanFalse)) 420 return; 421 } 422 } 423 } 424 } 425 } else if (strict && ix > 0) { 426 /* In strict mode all CA certificates *MUST* have a critical 427 basic constraints extension and the leaf certificate 428 *MUST NOT* have a basic constraints extension. */ 429 /* CA certificate is missing basicConstraints extension. */ 430 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 431 return; 432 } 433 } 434} 435#endif 436 437static void SecPolicyCheckBasicContraints(SecPVCRef pvc, 438 CFStringRef key) { 439 //SecPolicyCheckBasicContraintsCommon(pvc, key, false); 440} 441 442static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc, 443 CFStringRef key) { 444 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 445 for (ix = 0; ix < count; ++ix) { 446 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 447 /* If the certificate has a subject, or 448 if it doesn't, and it's the leaf and not self signed, 449 and also has a critical subjectAltName extension it's valid. */ 450 if (!SecCertificateHasSubject(cert)) { 451 if (ix == 0 && count > 1) { 452 if (!SecCertificateHasCriticalSubjectAltName(cert)) { 453 /* Leaf certificate with empty subject does not have 454 a critical subject alt name extension. */ 455 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 456 return; 457 } 458 } else { 459 /* CA certificate has empty subject. */ 460 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 461 return; 462 } 463 } 464 } 465} 466 467static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc, 468 CFStringRef key) { 469} 470 471/* Compare hostname suffix to domain name. 472 This function does not process wildcards, and allows hostname to match 473 any subdomain level of the provided domain. 474 475 To match, the last domain length chars of hostname must equal domain, 476 and the character immediately preceding domain in hostname (if any) 477 must be a dot. This means that domain 'bar.com' will match hostname 478 values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'. 479 480 Characters in each string are converted to lowercase for the comparison. 481 Trailing '.' characters in both names will be ignored. 482 483 Returns true on match, else false. 484 */ 485static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) { 486 CFStringInlineBuffer hbuf, dbuf; 487 UniChar hch, dch; 488 CFIndex hix, dix, 489 hlength = CFStringGetLength(hostname), 490 dlength = CFStringGetLength(domain); 491 CFRange hrange = { 0, hlength }, drange = { 0, dlength }; 492 CFStringInitInlineBuffer(hostname, &hbuf, hrange); 493 CFStringInitInlineBuffer(domain, &dbuf, drange); 494 495 if((hlength == 0) || (dlength == 0)) { 496 /* trivial case with at least one empty name */ 497 return (hlength == dlength) ? true : false; 498 } 499 500 /* trim off trailing dots */ 501 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1); 502 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1); 503 if(hch == '.') { 504 hrange.length = --hlength; 505 } 506 if(dch == '.') { 507 drange.length = --dlength; 508 } 509 510 /* trim off leading dot in suffix, if present */ 511 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0); 512 if((dlength > 0) && (dch == '.')) { 513 drange.location++; 514 drange.length = --dlength; 515 } 516 517 if(hlength < dlength) { 518 return false; 519 } 520 521 /* perform case-insensitive comparison of domain suffix */ 522 for (hix = (hlength-dlength), 523 dix = drange.location; dix < drange.length; dix++) { 524 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix); 525 dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix); 526 if (towlower(hch) != towlower(dch)) { 527 return false; 528 } 529 } 530 531 /* require a dot prior to domain suffix, unless hostname == domain */ 532 if(hlength > dlength) { 533 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1))); 534 if(hch != '.') { 535 return false; 536 } 537 } 538 539 return true; 540} 541 542/* Compare hostname, to a server name obtained from the server's cert 543 Obtained from the SubjectAltName or the CommonName entry in the Subject. 544 Limited wildcard checking is performed here as outlined in 545 546 RFC 2818 Section 3.1. Server Identity 547 548 [...] Names may contain the wildcard 549 character * which is considered to match any single domain name 550 component or component fragment. E.g., *.a.com matches foo.a.com but 551 not bar.foo.a.com. f*.com matches foo.com but not bar.com. 552 [...] 553 554 Trailing '.' characters in the hostname will be ignored. 555 556 Returns true on match, else false. 557 */ 558static bool SecDNSMatch(CFStringRef hostname, CFStringRef servername) { 559 CFStringInlineBuffer hbuf, sbuf; 560 CFIndex hix, six, 561 hlength = CFStringGetLength(hostname), 562 slength = CFStringGetLength(servername); 563 CFRange hrange = { 0, hlength }, srange = { 0, slength }; 564 CFStringInitInlineBuffer(hostname, &hbuf, hrange); 565 CFStringInitInlineBuffer(servername, &sbuf, srange); 566 567 for (hix = six = 0; six < slength; ++six) { 568 UniChar hch, sch = CFStringGetCharacterFromInlineBuffer(&sbuf, six); 569 if (sch == '*') { 570 if (six + 1 >= slength) { 571 /* Trailing '*' in servername, match until end of hostname or 572 trailing '.'. */ 573 do { 574 if (hix >= hlength) { 575 /* If we reach the end of the hostname we have a 576 match. */ 577 return true; 578 } 579 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++); 580 } while (hch != '.'); 581 /* We reached the end of servername and found a '.' in 582 hostname. Return true if hostname has a single 583 trailing '.' return false if there is anything after it. */ 584 return hix == hlength; 585 } 586 587 /* Grab the character after the '*'. */ 588 sch = CFStringGetCharacterFromInlineBuffer(&sbuf, ++six); 589 if (sch != '.') { 590 /* We have something of the form '*foo.com'. Or '**.com' 591 We don't deal with that yet, since it might require 592 backtracking. Also RFC 2818 doesn't seem to require it. */ 593 return false; 594 } 595 596 /* We're looking at the '.' after the '*' in something of the 597 form 'foo*.com' or '*.com'. Match until next '.' in hostname. */ 598 do { 599 /* Since we're not at the end of servername yet (that case 600 was handled above), running out of chars in hostname 601 means we don't have a match. */ 602 if (hix >= hlength) 603 return false; 604 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++); 605 } while (hch != '.'); 606 } else { 607 /* We're looking at a non wildcard character in the servername. 608 If we reached the end of hostname it's not a match. */ 609 if (hix >= hlength) 610 return false; 611 612 /* Otherwise make sure the hostname matches the character in the 613 servername, case insensitively. */ 614 hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix++); 615 if (towlower(hch) != towlower(sch)) 616 return false; 617 } 618 } 619 620 if (hix < hlength) { 621 /* We reached the end of servername but we have one or more characters 622 left to compare against in the hostname. */ 623 if (hix + 1 == hlength && 624 CFStringGetCharacterFromInlineBuffer(&hbuf, hix) == '.') { 625 /* Hostname has a single trailing '.', we're ok with that. */ 626 return true; 627 } 628 /* Anything else is not a match. */ 629 return false; 630 } 631 632 return true; 633} 634 635#define kSecPolicySHA1Size 20 636static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = { 637 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1, 638 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE 639}; 640 641/* Check whether hostname is in a particular set of allowed domains. 642 Returns true if OK, false if not allowed. 643 */ 644static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname) 645{ 646 CFIndex count = SecPVCGetCertificateCount(pvc); 647 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); 648 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert); 649 650 /* is this chain anchored by kAppleCorpCASHA1? */ 651 CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL, 652 kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull); 653 bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1)); 654 CFReleaseSafe(corpSHA1); 655 if (isCorpSHA1) { 656 /* limit hostname to specified domains */ 657 const CFStringRef dnlist[] = { 658 CFSTR("apple.com"), 659 CFSTR("icloud.com"), 660 }; 661 unsigned int idx, dncount=2; 662 for (idx = 0; idx < dncount; idx++) { 663 if (SecDomainSuffixMatch(hostname, dnlist[idx])) { 664 return true; 665 } 666 } 667 return false; 668 } 669 /* %%% other CA pinning checks TBA */ 670 671 return true; 672} 673 674/* AUDIT[securityd](done): 675 policy->_options is a caller provided dictionary, only its cf type has 676 been checked. 677 */ 678static void SecPolicyCheckSSLHostname(SecPVCRef pvc, 679 CFStringRef key) { 680 /* @@@ Consider what to do if the caller passes in no hostname. Should 681 we then still fail if the leaf has no dnsNames or IPAddresses at all? */ 682 SecPolicyRef policy = SecPVCGetPolicy(pvc); 683 CFStringRef hostName = (CFStringRef) 684 CFDictionaryGetValue(policy->_options, key); 685 if (!isString(hostName)) { 686 /* @@@ We can't return an error here and making the evaluation fail 687 won't help much either. */ 688 return; 689 } 690 691 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 692 bool dnsMatch = false; 693 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf); 694 if (dnsNames) { 695 CFIndex ix, count = CFArrayGetCount(dnsNames); 696 for (ix = 0; ix < count; ++ix) { 697 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix); 698 if (SecDNSMatch(hostName, dns)) { 699 dnsMatch = true; 700 break; 701 } 702 } 703 CFRelease(dnsNames); 704 } 705 706 if (!dnsMatch) { 707 /* Maybe hostname is an IPv4 or IPv6 address, let's compare against 708 the values returned by SecCertificateCopyIPAddresses() instead. */ 709 CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(leaf); 710 if (ipAddresses) { 711 CFIndex ix, count = CFArrayGetCount(ipAddresses); 712 for (ix = 0; ix < count; ++ix) { 713 CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix); 714 if (!CFStringCompare(hostName, ipAddress, kCFCompareCaseInsensitive)) { 715 dnsMatch = true; 716 break; 717 } 718 } 719 CFRelease(ipAddresses); 720 } 721 } 722 723 if (!dnsMatch) { 724 /* Hostname mismatch or no hostnames found in certificate. */ 725 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 726 } 727 else if (!SecPolicyCheckDomain(pvc, hostName)) { 728 /* Hostname match, but domain not allowed for this CA */ 729 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 730 } 731 732 if ((dnsMatch || pvc->details) 733 && SecPolicySubscriberCertificateCouldBeEV(leaf)) { 734 secdebug("policy", "enabling optionally_ev"); 735 pvc->optionally_ev = true; 736 /* optionally_ev => check_revocation, so we don't enable revocation 737 checking here, since we don't want it on for non EV ssl certs. */ 738#if 0 739 /* Check revocation status if the certificate asks for it (and we 740 support it) currently we only support ocsp. */ 741 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(leaf); 742 if (ocspResponders) { 743 SecPVCSetCheckRevocation(pvc); 744 } 745#endif 746 } 747} 748 749/* AUDIT[securityd](done): 750 policy->_options is a caller provided dictionary, only its cf type has 751 been checked. 752 */ 753static void SecPolicyCheckEmail(SecPVCRef pvc, CFStringRef key) { 754 SecPolicyRef policy = SecPVCGetPolicy(pvc); 755 CFStringRef email = (CFStringRef)CFDictionaryGetValue(policy->_options, key); 756 bool match = false; 757 if (!isString(email)) { 758 /* We can't return an error here and making the evaluation fail 759 won't help much either. */ 760 return; 761 } 762 763 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 764 CFArrayRef addrs = SecCertificateCopyRFC822Names(leaf); 765 if (addrs) { 766 CFIndex ix, count = CFArrayGetCount(addrs); 767 for (ix = 0; ix < count; ++ix) { 768 CFStringRef addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, ix); 769 if (!CFStringCompare(email, addr, kCFCompareCaseInsensitive)) { 770 match = true; 771 break; 772 } 773 } 774 CFRelease(addrs); 775 } 776 777 if (!match) { 778 /* Hostname mismatch or no hostnames found in certificate. */ 779 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 780 } 781} 782 783static void SecPolicyCheckValidIntermediates(SecPVCRef pvc, 784 CFStringRef key) { 785 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 786 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); 787 for (ix = 1; ix < count - 1; ++ix) { 788 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 789 if (!SecCertificateIsValid(cert, verifyTime)) { 790 /* Intermediate certificate has expired. */ 791 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 792 return; 793 } 794 } 795} 796 797static void SecPolicyCheckValidLeaf(SecPVCRef pvc, 798 CFStringRef key) { 799 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); 800 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 801 if (!SecCertificateIsValid(cert, verifyTime)) { 802 /* Leaf certificate has expired. */ 803 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) 804 return; 805 } 806} 807 808static void SecPolicyCheckValidRoot(SecPVCRef pvc, 809 CFStringRef key) { 810 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 811 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); 812 ix = count - 1; 813 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 814 if (!SecCertificateIsValid(cert, verifyTime)) { 815 /* Root certificate has expired. */ 816 if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) 817 return; 818 } 819} 820 821/* AUDIT[securityd](done): 822 policy->_options is a caller provided dictionary, only its cf type has 823 been checked. 824 */ 825static void SecPolicyCheckIssuerCommonName(SecPVCRef pvc, 826 CFStringRef key) { 827 CFIndex count = SecPVCGetCertificateCount(pvc); 828 if (count < 2) { 829 /* Can't check intermediates common name if there is no intermediate. */ 830 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 831 return; 832 } 833 834 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 1); 835 SecPolicyRef policy = SecPVCGetPolicy(pvc); 836 CFStringRef commonName = 837 (CFStringRef)CFDictionaryGetValue(policy->_options, key); 838 if (!isString(commonName)) { 839 /* @@@ We can't return an error here and making the evaluation fail 840 won't help much either. */ 841 return; 842 } 843 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert); 844 if (!commonNames || CFArrayGetCount(commonNames) != 1 || 845 !CFEqual(commonName, CFArrayGetValueAtIndex(commonNames, 0))) { 846 /* Common Name mismatch. */ 847 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 848 } 849 CFReleaseSafe(commonNames); 850} 851 852/* AUDIT[securityd](done): 853 policy->_options is a caller provided dictionary, only its cf type has 854 been checked. 855 */ 856static void SecPolicyCheckSubjectCommonName(SecPVCRef pvc, 857 CFStringRef key) { 858 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 859 SecPolicyRef policy = SecPVCGetPolicy(pvc); 860 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, 861 key); 862 if (!isString(common_name)) { 863 /* @@@ We can't return an error here and making the evaluation fail 864 won't help much either. */ 865 return; 866 } 867 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert); 868 if (!commonNames || CFArrayGetCount(commonNames) != 1 || 869 !CFEqual(common_name, CFArrayGetValueAtIndex(commonNames, 0))) { 870 /* Common Name mismatch. */ 871 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 872 } 873 CFReleaseSafe(commonNames); 874} 875 876/* AUDIT[securityd](done): 877 policy->_options is a caller provided dictionary, only its cf type has 878 been checked. 879 */ 880static void SecPolicyCheckSubjectCommonNamePrefix(SecPVCRef pvc, 881 CFStringRef key) { 882 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 883 SecPolicyRef policy = SecPVCGetPolicy(pvc); 884 CFStringRef prefix = (CFStringRef)CFDictionaryGetValue(policy->_options, 885 key); 886 if (!isString(prefix)) { 887 /* @@@ We can't return an error here and making the evaluation fail 888 won't help much either. */ 889 return; 890 } 891 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert); 892 if (!commonNames || CFArrayGetCount(commonNames) != 1 || 893 !CFStringHasPrefix(CFArrayGetValueAtIndex(commonNames, 0), prefix)) { 894 /* Common Name prefix mismatch. */ 895 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 896 } 897 CFReleaseSafe(commonNames); 898} 899 900/* AUDIT[securityd](done): 901 policy->_options is a caller provided dictionary, only its cf type has 902 been checked. 903 */ 904static void SecPolicyCheckSubjectCommonNameTEST(SecPVCRef pvc, 905 CFStringRef key) { 906 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 907 SecPolicyRef policy = SecPVCGetPolicy(pvc); 908 CFStringRef common_name = (CFStringRef)CFDictionaryGetValue(policy->_options, 909 key); 910 if (!isString(common_name)) { 911 /* @@@ We can't return an error here and making the evaluation fail 912 won't help much either. */ 913 return; 914 } 915 CFArrayRef commonNames = SecCertificateCopyCommonNames(cert); 916 if (!commonNames || CFArrayGetCount(commonNames) != 1) { 917 CFStringRef cert_common_name = CFArrayGetValueAtIndex(commonNames, 0); 918 CFStringRef test_common_name = common_name ? 919 CFStringCreateWithFormat(kCFAllocatorDefault, 920 NULL, CFSTR("TEST %@ TEST"), common_name) : 921 NULL; 922 if (!CFEqual(common_name, cert_common_name) && 923 (!test_common_name || !CFEqual(test_common_name, cert_common_name))) 924 /* Common Name mismatch. */ 925 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 926 CFReleaseSafe(test_common_name); 927 } 928 CFReleaseSafe(commonNames); 929} 930 931/* AUDIT[securityd](done): 932 policy->_options is a caller provided dictionary, only its cf type has 933 been checked. 934 */ 935static void SecPolicyCheckNotValidBefore(SecPVCRef pvc, 936 CFStringRef key) { 937 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 938 SecPolicyRef policy = SecPVCGetPolicy(pvc); 939 CFDateRef date = (CFDateRef)CFDictionaryGetValue(policy->_options, key); 940 if (!isDate(date)) { 941 /* @@@ We can't return an error here and making the evaluation fail 942 won't help much either. */ 943 return; 944 } 945 CFAbsoluteTime at = CFDateGetAbsoluteTime(date); 946 if (SecCertificateNotValidBefore(cert) <= at) { 947 /* Leaf certificate has not valid before that is too old. */ 948 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) 949 return; 950 } 951} 952 953/* AUDIT[securityd](done): 954 policy->_options is a caller provided dictionary, only its cf type has 955 been checked. 956 */ 957static void SecPolicyCheckChainLength(SecPVCRef pvc, 958 CFStringRef key) { 959 CFIndex count = SecPVCGetCertificateCount(pvc); 960 SecPolicyRef policy = SecPVCGetPolicy(pvc); 961 CFNumberRef chainLength = 962 (CFNumberRef)CFDictionaryGetValue(policy->_options, key); 963 CFIndex value; 964 if (!chainLength || CFGetTypeID(chainLength) != CFNumberGetTypeID() || 965 !CFNumberGetValue(chainLength, kCFNumberCFIndexType, &value)) { 966 /* @@@ We can't return an error here and making the evaluation fail 967 won't help much either. */ 968 return; 969 } 970 if (value != count) { 971 /* Chain length doesn't match policy requirement. */ 972 if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) 973 return; 974 } 975} 976 977/* AUDIT[securityd](done): 978 policy->_options is a caller provided dictionary, only its cf type has 979 been checked. 980 */ 981static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc, 982 CFStringRef key) { 983 CFIndex count = SecPVCGetCertificateCount(pvc); 984 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); 985 SecPolicyRef policy = SecPVCGetPolicy(pvc); 986 CFTypeRef value = CFDictionaryGetValue(policy->_options, key); 987 CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert); 988 989 bool foundMatch = false; 990 991 if (isData(value)) 992 foundMatch = CFEqual(anchorSHA1, value); 993 else if (isArray(value)) 994 foundMatch = CFArrayContainsValue((CFArrayRef) value, CFRangeMake(0, CFArrayGetCount((CFArrayRef) value)), anchorSHA1); 995 else { 996 /* @@@ We only support Data and Array but we can't return an error here so. 997 we let the evaluation fail (not much help) and assert in debug. */ 998 assert(false); 999 } 1000 1001 if (!foundMatch) 1002 if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, 0, kCFBooleanFalse)) 1003 return; 1004 1005 return; 1006} 1007 1008/* AUDIT[securityd](done): 1009 policy->_options is a caller provided dictionary, only its cf type has 1010 been checked. 1011 */ 1012static void SecPolicyCheckSubjectOrganization(SecPVCRef pvc, 1013 CFStringRef key) { 1014 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 1015 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1016 CFStringRef org = (CFStringRef)CFDictionaryGetValue(policy->_options, 1017 key); 1018 if (!isString(org)) { 1019 /* @@@ We can't return an error here and making the evaluation fail 1020 won't help much either. */ 1021 return; 1022 } 1023 CFArrayRef organization = SecCertificateCopyOrganization(cert); 1024 if (!organization || CFArrayGetCount(organization) != 1 || 1025 !CFEqual(org, CFArrayGetValueAtIndex(organization, 0))) { 1026 /* Leaf Subject Organization mismatch. */ 1027 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1028 } 1029 CFReleaseSafe(organization); 1030} 1031 1032static void SecPolicyCheckSubjectOrganizationalUnit(SecPVCRef pvc, 1033 CFStringRef key) { 1034 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 1035 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1036 CFStringRef orgUnit = (CFStringRef)CFDictionaryGetValue(policy->_options, 1037 key); 1038 if (!isString(orgUnit)) { 1039 /* @@@ We can't return an error here and making the evaluation fail 1040 won't help much either. */ 1041 return; 1042 } 1043 CFArrayRef organizationalUnit = SecCertificateCopyOrganizationalUnit(cert); 1044 if (!organizationalUnit || CFArrayGetCount(organizationalUnit) != 1 || 1045 !CFEqual(orgUnit, CFArrayGetValueAtIndex(organizationalUnit, 0))) { 1046 /* Leaf Subject Organizational Unit mismatch. */ 1047 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1048 } 1049 CFReleaseSafe(organizationalUnit); 1050} 1051 1052/* AUDIT[securityd](done): 1053 policy->_options is a caller provided dictionary, only its cf type has 1054 been checked. 1055 */ 1056static void SecPolicyCheckEAPTrustedServerNames(SecPVCRef pvc, 1057 CFStringRef key) { 1058 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1059 CFArrayRef trustedServerNames = (CFArrayRef) 1060 CFDictionaryGetValue(policy->_options, key); 1061 /* No names specified means we accept any name. */ 1062 if (!trustedServerNames) 1063 return; 1064 if (!isArray(trustedServerNames)) { 1065 /* @@@ We can't return an error here and making the evaluation fail 1066 won't help much either. */ 1067 return; 1068 } 1069 1070 CFIndex tsnCount = CFArrayGetCount(trustedServerNames); 1071 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); 1072 bool dnsMatch = false; 1073 CFArrayRef dnsNames = SecCertificateCopyDNSNames(leaf); 1074 if (dnsNames) { 1075 CFIndex ix, count = CFArrayGetCount(dnsNames); 1076 // @@@ This is O(N^2) unfortunately we can't do better easily unless 1077 // we don't do wildcard matching. */ 1078 for (ix = 0; !dnsMatch && ix < count; ++ix) { 1079 CFStringRef dns = (CFStringRef)CFArrayGetValueAtIndex(dnsNames, ix); 1080 CFIndex tix; 1081 for (tix = 0; tix < tsnCount; ++tix) { 1082 CFStringRef serverName = 1083 (CFStringRef)CFArrayGetValueAtIndex(trustedServerNames, tix); 1084 if (!isString(serverName)) { 1085 /* @@@ We can't return an error here and making the 1086 evaluation fail won't help much either. */ 1087 CFReleaseSafe(dnsNames); 1088 return; 1089 } 1090 /* we purposefully reverse the arguments here such that dns names 1091 from the cert are matched against a server name list, where 1092 the server names list can contain wildcards and the dns name 1093 cannot. References: http://support.microsoft.com/kb/941123 1094 It's easy to find occurrences where people tried to use 1095 wildcard certificates and were told that those don't work 1096 in this context. */ 1097 if (SecDNSMatch(dns, serverName)) { 1098 dnsMatch = true; 1099 break; 1100 } 1101 } 1102 } 1103 CFRelease(dnsNames); 1104 } 1105 1106 if (!dnsMatch) { 1107 /* Hostname mismatch or no hostnames found in certificate. */ 1108 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1109 } 1110} 1111 1112static const unsigned char UTN_USERFirst_Hardware_Serial[][16] = { 1113{ 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d, 0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0 }, 1114{ 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69, 0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43 }, 1115{ 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5, 0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0 }, 1116{ 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc, 0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47 }, 1117{ 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a, 0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29 }, 1118{ 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21, 0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71 }, 1119{ 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b, 0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3 }, 1120{ 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0, 0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e }, 1121{ 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a, 0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06 } }; 1122 1123static const unsigned char UTN_USERFirst_Hardware_Normalized_Issuer[] = { 1124 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 1125 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 1126 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 1127 0x0e, 0x53, 0x41, 0x4c, 0x54, 0x20, 0x4c, 0x41, 0x4b, 0x45, 0x20, 0x43, 1128 0x49, 0x54, 0x59, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 1129 0x13, 0x15, 0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 1130 0x55, 0x53, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x31, 1131 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x48, 0x54, 1132 0x54, 0x50, 0x3a, 0x2f, 0x2f, 0x57, 0x57, 0x57, 0x2e, 0x55, 0x53, 0x45, 1133 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x2e, 0x43, 0x4f, 0x4d, 0x31, 0x1f, 1134 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e, 1135 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x49, 0x52, 0x53, 0x54, 0x2d, 0x48, 1136 0x41, 0x52, 0x44, 0x57, 0x41, 0x52, 0x45 1137}; 1138static const unsigned int UTN_USERFirst_Hardware_Normalized_Issuer_len = 151; 1139 1140 1141static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc, 1142 CFStringRef key) { 1143 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 1144 CFDataRef issuer = cert ? SecCertificateGetNormalizedIssuerContent(cert) : NULL; 1145 1146 if (issuer && (CFDataGetLength(issuer) == (CFIndex)UTN_USERFirst_Hardware_Normalized_Issuer_len) && 1147 (0 == memcmp(UTN_USERFirst_Hardware_Normalized_Issuer, CFDataGetBytePtr(issuer), 1148 UTN_USERFirst_Hardware_Normalized_Issuer_len))) 1149 { 1150 CFDataRef serial = SecCertificateCopySerialNumber(cert); 1151 if (serial) { 1152 CFIndex serial_length = CFDataGetLength(serial); 1153 const uint8_t *serial_ptr = CFDataGetBytePtr(serial); 1154 1155 while ((serial_length > 0) && (*serial_ptr == 0)) { 1156 serial_ptr++; 1157 serial_length--; 1158 } 1159 1160 if (serial_length == (CFIndex)sizeof(*UTN_USERFirst_Hardware_Serial)) { 1161 unsigned int i; 1162 for (i = 0; i < array_size(UTN_USERFirst_Hardware_Serial); i++) 1163 { 1164 if (0 == memcmp(UTN_USERFirst_Hardware_Serial[i], 1165 serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial))) 1166 { 1167 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1168 CFReleaseSafe(serial); 1169 return; 1170 } 1171 } 1172 } 1173 CFRelease(serial); 1174 } 1175 } 1176 1177 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); 1178 if (NULL != otapkiRef) 1179 { 1180 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); 1181 CFRelease(otapkiRef); 1182 if (NULL != blackListedKeys) 1183 { 1184 /* Check for blacklisted intermediates keys. */ 1185 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); 1186 if (dgst) 1187 { 1188 /* Check dgst against blacklist. */ 1189 if (CFSetContainsValue(blackListedKeys, dgst)) 1190 { 1191 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1192 } 1193 CFRelease(dgst); 1194 } 1195 CFRelease(blackListedKeys); 1196 } 1197 } 1198} 1199 1200static void SecPolicyCheckGrayListedLeaf(SecPVCRef pvc, CFStringRef key) 1201{ 1202 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); 1203 if (NULL != otapkiRef) 1204 { 1205 CFSetRef grayListedKeys = SecOTAPKICopyGrayList(otapkiRef); 1206 CFRelease(otapkiRef); 1207 if (NULL != grayListedKeys) 1208 { 1209 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 1210 1211 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); 1212 if (dgst) 1213 { 1214 /* Check dgst against gray. */ 1215 if (CFSetContainsValue(grayListedKeys, dgst)) 1216 { 1217 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1218 } 1219 CFRelease(dgst); 1220 } 1221 CFRelease(grayListedKeys); 1222 } 1223 } 1224 } 1225 1226static void SecPolicyCheckLeafMarkerOid(SecPVCRef pvc, CFStringRef key) 1227{ 1228 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, 0); 1229 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1230 CFTypeRef value = CFDictionaryGetValue(policy->_options, key); 1231 1232 if (value && SecCertificateHasMarkerExtension(cert, value)) 1233 return; 1234 1235 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1236} 1237 1238static void SecPolicyCheckIntermediateMarkerOid(SecPVCRef pvc, CFStringRef key) 1239{ 1240 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 1241 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1242 CFTypeRef value = CFDictionaryGetValue(policy->_options, key); 1243 1244 for (ix = 1; ix < count - 1; ix++) { 1245 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 1246 if (SecCertificateHasMarkerExtension(cert, value)) 1247 return; 1248 } 1249 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1250} 1251 1252 1253 1254/**************************************************************************** 1255 *********************** New rfc5280 Chain Validation *********************** 1256 ****************************************************************************/ 1257 1258#if 0 1259typedef struct cert_path *cert_path_t; 1260struct cert_path { 1261 int length; 1262}; 1263 1264typedef struct x500_name *x500_name_t; 1265struct x500_name { 1266}; 1267 1268typedef struct algorithm_id *algorithm_id_t; 1269struct algorithm_id { 1270 oid_t algorithm_oid; 1271 der_t parameters; 1272}; 1273 1274typedef struct trust_anchor *trust_anchor_t; 1275struct trust_anchor { 1276 x500_name_t issuer_name; 1277 algorithm_id_t public_key_algorithm; /* includes optional params */ 1278 SecKeyRef public_key; 1279}; 1280 1281typedef struct certificate_policy *certificate_policy_t; 1282struct certificate_policy { 1283 policy_qualifier_t qualifiers; 1284 oid_t oid; 1285 SLIST_ENTRY(certificate_policy) policies; 1286}; 1287 1288typedef struct policy_mapping *policy_mapping_t; 1289struct policy_mapping { 1290 SLIST_ENTRY(policy_mapping) mappings; 1291 oid_t issuer_domain_policy; 1292 oid_t subject_domain_policy; 1293}; 1294 1295typedef struct root_name *root_name_t; 1296struct root_name { 1297}; 1298#endif 1299 1300struct policy_tree_add_ctx { 1301 oid_t p_oid; 1302 policy_qualifier_t p_q; 1303}; 1304 1305/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ 1306static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) { 1307 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; 1308 policy_set_t policy_set; 1309 for (policy_set = node->expected_policy_set; 1310 policy_set; 1311 policy_set = policy_set->oid_next) { 1312 if (oid_equal(policy_set->oid, info->p_oid)) { 1313 policy_tree_add_child(node, &info->p_oid, info->p_q); 1314 return true; 1315 } 1316 } 1317 return false; 1318} 1319 1320/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ 1321static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) { 1322 struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; 1323 if (oid_equal(node->valid_policy, oidAnyPolicy)) { 1324 policy_tree_add_child(node, &info->p_oid, info->p_q); 1325 return true; 1326 } 1327 return false; 1328} 1329 1330/* Return true iff node has a child with a valid_policy equal to oid. */ 1331static bool policy_tree_has_child_with_oid(policy_tree_t node, 1332 const oid_t *oid) { 1333 policy_tree_t child; 1334 for (child = node->children; child; child = child->siblings) { 1335 if (oid_equal(child->valid_policy, (*oid))) { 1336 return true; 1337 } 1338 } 1339 return false; 1340} 1341 1342/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */ 1343static bool policy_tree_add_expected(policy_tree_t node, void *ctx) { 1344 policy_qualifier_t p_q = (policy_qualifier_t)ctx; 1345 policy_set_t policy_set; 1346 bool added_node = false; 1347 for (policy_set = node->expected_policy_set; 1348 policy_set; 1349 policy_set = policy_set->oid_next) { 1350 if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) { 1351 policy_tree_add_child(node, &policy_set->oid, p_q); 1352 added_node = true; 1353 } 1354 } 1355 return added_node; 1356} 1357 1358#if 0 1359/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ 1360static bool policy_tree_map(policy_tree_t node, void *ctx) { 1361 /* Can't map oidAnyPolicy. */ 1362 if (oid_equal(node->valid_policy, oidAnyPolicy)) 1363 return false; 1364 1365 const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; 1366 uint32_t mapping_ix, mapping_count = pm->numMappings; 1367 policy_set_t policy_set = NULL; 1368 /* First count how many mappings match this nodes valid_policy. */ 1369 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { 1370 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; 1371 if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { 1372 policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set)); 1373 p_node->oid = mapping->subjectDomainPolicy; 1374 p_node->oid_next = policy_set ? policy_set : NULL; 1375 policy_set = p_node; 1376 } 1377 } 1378 if (policy_set) { 1379 policy_tree_set_expected_policy(node, policy_set); 1380 return true; 1381 } 1382 return false; 1383} 1384#endif 1385 1386#define POLICY_MAPPING 0 1387#define POLICY_SUBTREES 0 1388 1389/* rfc5280 basic cert processing. */ 1390static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, 1391 CFStringRef key) { 1392 /* Inputs */ 1393 //cert_path_t path; 1394 CFIndex count = SecPVCGetCertificateCount(pvc); 1395 /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */ 1396 assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ 1397 uint32_t n = (uint32_t)count; 1398 bool is_anchored = SecPVCIsAnchored(pvc); 1399 if (is_anchored) { 1400 /* If the anchor is trusted we don't procces the last cert in the 1401 chain (root). */ 1402 n--; 1403 } else { 1404 /* Add a detail for the root not being trusted. */ 1405 if (SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted, 1406 n - 1, kCFBooleanFalse, true)) 1407 return; 1408 } 1409 1410 CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc); 1411 //policy_set_t user_initial_policy_set = NULL; 1412 //trust_anchor_t anchor; 1413 bool initial_policy_mapping_inhibit = false; 1414 bool initial_explicit_policy = false; 1415 bool initial_any_policy_inhibit = false; 1416#if POLICY_SUBTREES 1417 root_name_t initial_permitted_subtrees = NULL; 1418 root_name_t initial_excluded_subtrees = NULL; 1419#endif 1420 1421 /* Initialization */ 1422 pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL); 1423#if POLICY_SUBTREES 1424 root_name_t permitted_subtrees = initial_permitted_subtrees; 1425 root_name_t excluded_subtrees = initial_excluded_subtrees; 1426#endif 1427 uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1; 1428 uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1; 1429 uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1; 1430 1431#if 0 1432 /* Path builder ensures we only get cert chains with proper issuer 1433 chaining with valid signatures along the way. */ 1434 algorithm_id_t working_public_key_algorithm = anchor->public_key_algorithm; 1435 SecKeyRef working_public_key = anchor->public_key; 1436 x500_name_t working_issuer_name = anchor->issuer_name; 1437#endif 1438 uint32_t i, max_path_length = n; 1439 SecCertificateRef cert = NULL; 1440 for (i = 1; i <= n; ++i) { 1441 /* Process Cert */ 1442 cert = SecPVCGetCertificateAtIndex(pvc, n - i); 1443 bool is_self_issued = SecPVCIsCertificateAtIndexSelfSigned(pvc, n - i); 1444 1445 /* (a) Verify the basic certificate information. */ 1446 /* @@@ Ensure that cert was signed with working_public_key_algorithm 1447 using the working_public_key and the working_public_key_parameters. */ 1448#if 1 1449 /* Already done by chain builder. */ 1450 if (!SecCertificateIsValid(cert, verify_time)) { 1451 CFStringRef fail_key = i == n ? kSecPolicyCheckValidLeaf : kSecPolicyCheckValidIntermediates; 1452 if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) 1453 return; 1454 } 1455#endif 1456#if 0 1457 /* Check revocation status if the certificate asks for it. */ 1458 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); 1459 if (ocspResponders) { 1460 SecPVCSetCheckRevocation(pvc); 1461 } 1462#endif 1463 /* @@@ cert.issuer == working_issuer_name. */ 1464 1465#if POLICY_SUBTREES 1466 /* (b) (c) */ 1467 if (!is_self_issued || i == n) { 1468 /* Verify that the subject name is within one of the permitted_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is within one of the permitted_subtrees for that name type. */ 1469 /* Verify that the subject name is not within any of the excluded_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is not within any of the excluded_subtrees for that name type. */ 1470 } 1471#endif 1472 /* (d) */ 1473 if (pvc->valid_policy_tree) { 1474 const SecCECertificatePolicies *cp = 1475 SecCertificateGetCertificatePolicies(cert); 1476 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; 1477 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { 1478 const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; 1479 oid_t p_oid = policy->policyIdentifier; 1480 policy_qualifier_t p_q = &policy->policyQualifiers; 1481 struct policy_tree_add_ctx ctx = { p_oid, p_q }; 1482 if (!oid_equal(p_oid, oidAnyPolicy)) { 1483 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, 1484 policy_tree_add_if_match, &ctx)) { 1485 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, 1486 policy_tree_add_if_any, &ctx); 1487 } 1488 } 1489 } 1490 /* The certificate policies extension includes the policy 1491 anyPolicy with the qualifier set AP-Q and either 1492 (a) inhibit_anyPolicy is greater than 0 or 1493 (b) i < n and the certificate is self-issued. */ 1494 if (inhibit_any_policy > 0 || (i < n && is_self_issued)) { 1495 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { 1496 const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; 1497 oid_t p_oid = policy->policyIdentifier; 1498 policy_qualifier_t p_q = &policy->policyQualifiers; 1499 if (oid_equal(p_oid, oidAnyPolicy)) { 1500 policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, 1501 policy_tree_add_expected, (void *)p_q); 1502 } 1503 } 1504 } 1505 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1); 1506 /* (e) */ 1507 if (!cp) { 1508 if (pvc->valid_policy_tree) 1509 policy_tree_prune(&pvc->valid_policy_tree); 1510 } 1511 } 1512 /* (f) Verify that either explicit_policy is greater than 0 or the 1513 valid_policy_tree is not equal to NULL. */ 1514 if (!pvc->valid_policy_tree && explicit_policy == 0) { 1515 /* valid_policy_tree is empty and explicit policy is 0, illegal. */ 1516 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) 1517 return; 1518 } 1519 /* If Last Cert in Path */ 1520 if (i == n) 1521 break; 1522 1523 /* Prepare for Next Cert */ 1524#if POLICY_MAPPING 1525 /* (a) verify that anyPolicy does not appear as an 1526 issuerDomainPolicy or a subjectDomainPolicy */ 1527 CFDictionaryRef pm = SecCertificateGetPolicyMappings(cert); 1528 if (pm) { 1529 uint32_t mapping_ix, mapping_count = pm->numMappings; 1530 for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { 1531 const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; 1532 if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy) 1533 || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) { 1534 /* Policy mapping uses anyPolicy, illegal. */ 1535 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse)) 1536 return; 1537 } 1538 } 1539 /* (b) */ 1540 /* (1) If the policy_mapping variable is greater than 0 */ 1541 if (policy_mapping > 0) { 1542 if (!policy_tree_walk_depth(pvc->valid_policy_tree, i, 1543 policy_tree_map, (void *)pm)) { 1544 /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows: 1545 1546 (i) set the valid_policy to ID-P; 1547 1548 (ii) set the qualifier_set to the qualifier set of the 1549 policy anyPolicy in the certificate policies 1550 extension of certificate i; and 1551 (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ 1552 } 1553 } else { 1554 #if 0 1555 /* (i) delete each node of depth i in the valid_policy_tree 1556 where ID-P is the valid_policy. */ 1557 struct policy_tree_map_ctx ctx = { idp_oid, sdp_oid }; 1558 policy_tree_walk_depth(pvc->valid_policy_tree, i, 1559 policy_tree_delete_if_match, &ctx); 1560 #endif 1561 /* (ii) If there is a node in the valid_policy_tree of depth 1562 i-1 or less without any child nodes, delete that 1563 node. Repeat this step until there are no nodes of 1564 depth i-1 or less without children. */ 1565 policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1); 1566 } 1567 } 1568#endif /* POLICY_MAPPING */ 1569 /* (c)(d)(e)(f) */ 1570 //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert); 1571 //working_public_key = SecCertificateCopyPublicKey(cert); 1572 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert); 1573 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert); 1574#if POLICY_SUBTREES 1575 /* (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows: 1576 */ 1577 /* @@@ handle name constraints. */ 1578#endif 1579 /* (h) */ 1580 if (!is_self_issued) { 1581 if (explicit_policy) 1582 explicit_policy--; 1583 if (policy_mapping) 1584 policy_mapping--; 1585 if (inhibit_any_policy) 1586 inhibit_any_policy--; 1587 } 1588 /* (i) */ 1589 const SecCEPolicyConstraints *pc = 1590 SecCertificateGetPolicyConstraints(cert); 1591 if (pc) { 1592 if (pc->requireExplicitPolicyPresent 1593 && pc->requireExplicitPolicy < explicit_policy) { 1594 explicit_policy = pc->requireExplicitPolicy; 1595 } 1596 if (pc->inhibitPolicyMappingPresent 1597 && pc->inhibitPolicyMapping < policy_mapping) { 1598 policy_mapping = pc->inhibitPolicyMapping; 1599 } 1600 } 1601 /* (j) */ 1602 uint32_t iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert); 1603 if (iap < inhibit_any_policy) { 1604 inhibit_any_policy = iap; 1605 } 1606 /* (k) */ 1607 const SecCEBasicConstraints *bc = 1608 SecCertificateGetBasicConstraints(cert); 1609#if 0 /* Checked in chain builder pre signature verify already. */ 1610 if (!bc || !bc->isCA) { 1611 /* Basic constraints not present or not marked as isCA, illegal. */ 1612 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints, 1613 n - i, kCFBooleanFalse)) 1614 return; 1615 } 1616#endif 1617 /* (l) */ 1618 if (!is_self_issued) { 1619 if (max_path_length > 0) { 1620 max_path_length--; 1621 } else { 1622 /* max_path_len exceeded, illegal. */ 1623 if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicContraints, 1624 n - i, kCFBooleanFalse)) 1625 return; 1626 } 1627 } 1628 /* (m) */ 1629 if (bc && bc->pathLenConstraintPresent 1630 && bc->pathLenConstraint < max_path_length) { 1631 max_path_length = bc->pathLenConstraint; 1632 } 1633#if 0 /* Checked in chain builder pre signature verify already. */ 1634 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ 1635 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); 1636 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { 1637 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage, 1638 n - i, kCFBooleanFalse, true)) 1639 return; 1640 } 1641#endif 1642 /* (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate that is relevant to path processing. */ 1643 if (SecCertificateHasUnknownCriticalExtension(cert)) { 1644 /* Certificate contains one or more unknown critical extensions. */ 1645 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, 1646 n - i, kCFBooleanFalse)) 1647 return; 1648 } 1649 } 1650 /* Wrap up */ 1651 cert = SecPVCGetCertificateAtIndex(pvc, 0); 1652 /* (a) */ 1653 if (explicit_policy) 1654 explicit_policy--; 1655 /* (b) */ 1656 const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert); 1657 if (pc) { 1658 if (pc->requireExplicitPolicyPresent 1659 && pc->requireExplicitPolicy == 0) { 1660 explicit_policy = 0; 1661 } 1662 } 1663 /* (c) */ 1664 //working_public_key = SecCertificateCopyPublicKey(cert); 1665 /* (d) */ 1666 /* If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the 1667working_public_key_algorithm are different, set the working_public_key_parameters to null. */ 1668 //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert); 1669 /* (e) */ 1670 //working_public_key_algorithm = SecCertificateCopyPublicKeyAlgorithm(cert); 1671 /* (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n that is relevant to path processing. */ 1672 if (SecCertificateHasUnknownCriticalExtension(cert)) { 1673 /* Certificate contains one or more unknown critical extensions. */ 1674 if (!SecPVCSetResult(pvc, kSecPolicyCheckCriticalExtensions, 1675 0, kCFBooleanFalse)) 1676 return; 1677 } 1678 /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */ 1679 1680 if (pvc->valid_policy_tree) { 1681#if !defined(NDEBUG) 1682 policy_tree_dump(pvc->valid_policy_tree); 1683#endif 1684 /* (g3c4) */ 1685 //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1); 1686 } 1687 1688 /* If either (1) the value of explicit_policy variable is greater than 1689 zero or (2) the valid_policy_tree is not NULL, then path processing 1690 has succeeded. */ 1691 if (!pvc->valid_policy_tree && explicit_policy == 0) { 1692 /* valid_policy_tree is empty and explicit policy is 0, illegal. */ 1693 if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true)) 1694 return; 1695 } 1696} 1697 1698static policy_set_t policies_for_cert(SecCertificateRef cert) { 1699 policy_set_t policies = NULL; 1700 const SecCECertificatePolicies *cp = 1701 SecCertificateGetCertificatePolicies(cert); 1702 size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; 1703 for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { 1704 policy_set_add(&policies, &cp->policies[policy_ix].policyIdentifier); 1705 } 1706 return policies; 1707} 1708 1709static void SecPolicyCheckEV(SecPVCRef pvc, 1710 CFStringRef key) { 1711 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 1712 policy_set_t valid_policies = NULL; 1713 1714 for (ix = 0; ix < count; ++ix) { 1715 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 1716 policy_set_t policies = policies_for_cert(cert); 1717 if (ix == 0) { 1718 /* Subscriber */ 1719 /* anyPolicy in the leaf isn't allowed for EV, so only init 1720 valid_policies if we have real policies. */ 1721 if (!policy_set_contains(policies, &oidAnyPolicy)) { 1722 valid_policies = policies; 1723 policies = NULL; 1724 } 1725 } else if (ix < count - 1) { 1726 /* Subordinate CA */ 1727 if (!SecPolicySubordinateCACertificateCouldBeEV(cert)) { 1728 secdebug("ev", "subordinate certificate is not ev"); 1729 if (SecPVCSetResultForced(pvc, key, 1730 ix, kCFBooleanFalse, true)) { 1731 policy_set_free(valid_policies); 1732 policy_set_free(policies); 1733 return; 1734 } 1735 } 1736 policy_set_intersect(&valid_policies, policies); 1737 } else { 1738 /* Root CA */ 1739 if (!SecPolicyRootCACertificateIsEV(cert, valid_policies)) { 1740 secdebug("ev", "anchor certificate is not ev"); 1741 if (SecPVCSetResultForced(pvc, key, 1742 ix, kCFBooleanFalse, true)) { 1743 policy_set_free(valid_policies); 1744 policy_set_free(policies); 1745 return; 1746 } 1747 } 1748 } 1749 policy_set_free(policies); 1750 if (!valid_policies) { 1751 secdebug("ev", "valid_policies set is empty: chain not ev"); 1752 /* If we ever get into a state where no policies are valid anymore 1753 this can't be an ev chain. */ 1754 if (SecPVCSetResultForced(pvc, key, 1755 ix, kCFBooleanFalse, true)) { 1756 return; 1757 } 1758 } 1759 } 1760 1761 policy_set_free(valid_policies); 1762 1763 /* (a) EV Subscriber Certificates Each EV Certificate issued by the CA to a 1764Subscriber MUST contain an OID defined by the CA in the certificate’s 1765certificatePolicies extension that: (i) indicates which CA policy statement relates 1766to that certificate, (ii) asserts the CA’s adherence to and compliance with these 1767Guidelines, and (iii), by pre-agreement with the Application Software Vendor, 1768marks the certificate as being an EV Certificate. 1769(b) EV Subordinate CA Certificates 1770(1) Certificates issued to Subordinate CAs that are not controlled by the issuing 1771CA MUST contain one or more OIDs defined by the issuing CA that 1772explicitly identify the EV Policies that are implemented by the Subordinate 1773CA; 1774(2) Certificates issued to Subordinate CAs that are controlled by the Root CA 1775MAY contain the special anyPolicy OID (2.5.29.32.0). 1776(c) Root CA Certificates Root CA Certificates SHOULD NOT contain the 1777certificatePolicies or extendedKeyUsage extensions. 1778*/ 1779} 1780 1781 1782static void SecPolicyCheckCertificatePolicyOid(SecPVCRef pvc, CFStringRef key) 1783{ 1784 CFIndex ix, count = SecPVCGetCertificateCount(pvc); 1785 SecPolicyRef policy = SecPVCGetPolicy(pvc); 1786 CFTypeRef value = CFDictionaryGetValue(policy->_options, key); 1787 DERItem key_value; 1788 key_value.data = NULL; 1789 key_value.length = 0; 1790 1791 if (CFGetTypeID(value) == CFDataGetTypeID()) 1792 { 1793 CFDataRef key_data = (CFDataRef)value; 1794 key_value.data = (DERByte *)CFDataGetBytePtr(key_data); 1795 key_value.length = (DERSize)CFDataGetLength(key_data); 1796 1797 for (ix = 0; ix < count; ix++) { 1798 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 1799 policy_set_t policies = policies_for_cert(cert); 1800 1801 if (policy_set_contains(policies, &key_value)) { 1802 return; 1803 } 1804 } 1805 SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); 1806 } 1807} 1808 1809 1810static void SecPolicyCheckRevocation(SecPVCRef pvc, 1811 CFStringRef key) { 1812 SecPVCSetCheckRevocation(pvc); 1813} 1814 1815static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc, 1816 CFStringRef key) { 1817 SecPathBuilderSetCanAccessNetwork(pvc->builder, false); 1818} 1819 1820// MARK: - 1821// MARK: SecRVCRef 1822/******************************************************** 1823 ****************** SecRVCRef Functions ***************** 1824 ********************************************************/ 1825 1826/* Revocation verification context. */ 1827struct OpaqueSecRVC { 1828 /* Will contain the response data. */ 1829 asynchttp_t http; 1830 1831 /* Pointer to the pvc for this revocation check. */ 1832 SecPVCRef pvc; 1833 1834 /* The ocsp request we send to each responder. */ 1835 SecOCSPRequestRef ocspRequest; 1836 1837 /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ 1838 CFIndex certIX; 1839 1840 /* Index in array returned by SecCertificateGetOCSPResponders() for current 1841 responder. */ 1842 CFIndex responderIX; 1843 1844 /* URL of current responder. */ 1845 CFURLRef responder; 1846 1847 /* Date until which this revocation status is valid. */ 1848 CFAbsoluteTime nextUpdate; 1849 1850 bool done; 1851}; 1852typedef struct OpaqueSecRVC *SecRVCRef; 1853 1854static void SecRVCDelete(SecRVCRef rvc) { 1855 secdebug("alloc", "%p", rvc); 1856 asynchttp_free(&rvc->http); 1857 SecOCSPRequestFinalize(rvc->ocspRequest); 1858} 1859 1860/* Return the next responder we should contact for this rvc or NULL if we 1861 exhausted them all. */ 1862static CFURLRef SecRVCGetNextResponder(SecRVCRef rvc) { 1863 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); 1864 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); 1865 if (ocspResponders) { 1866 CFIndex responderCount = CFArrayGetCount(ocspResponders); 1867 while (rvc->responderIX < responderCount) { 1868 CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX); 1869 rvc->responderIX++; 1870 CFStringRef scheme = CFURLCopyScheme(responder); 1871 if (scheme) { 1872 /* We only support http and https responders currently. */ 1873 bool valid_responder = (CFEqual(CFSTR("http"), scheme) || 1874 CFEqual(CFSTR("https"), scheme)); 1875 CFRelease(scheme); 1876 if (valid_responder) 1877 return responder; 1878 } 1879 } 1880 } 1881 return NULL; 1882} 1883 1884/* Fire off an async http request for this certs revocation status, return 1885 false if request was queued, true if we're done. */ 1886static bool SecRVCFetchNext(SecRVCRef rvc) { 1887 while ((rvc->responder = SecRVCGetNextResponder(rvc))) { 1888 CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest); 1889 if (!request) 1890 goto errOut; 1891 1892 if (!asyncHttpPost(rvc->responder, request, &rvc->http)) { 1893 /* Async request was posted, wait for reply. */ 1894 return false; 1895 } 1896 } 1897 1898errOut: 1899 rvc->done = true; 1900 return true; 1901} 1902 1903/* Proccess a verified ocsp response for a given cert. Return true if the 1904 certificate status was obtained. */ 1905static bool SecOCSPSingleResponseProccess(SecOCSPSingleResponseRef this, 1906 SecRVCRef rvc) { 1907 bool proccessed; 1908 switch (this->certStatus) { 1909 case CS_Good: 1910 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX); 1911 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one) 1912 in the info dictionary. */ 1913 //cert.revokeCheckGood(true); 1914 rvc->nextUpdate = this->nextUpdate; 1915 proccessed = true; 1916 break; 1917 case CS_Revoked: 1918 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX); 1919 /* @@@ Mark cert as revoked (with reason) at revocation date in 1920 the info dictionary, or perhaps we should use a different key per 1921 reason? That way a client using exceptions can ignore some but 1922 not all reasons. */ 1923 SInt32 reason = this->crlReason; 1924 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); 1925 SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX, 1926 cfreason, true); 1927 CFRelease(cfreason); 1928 proccessed = true; 1929 break; 1930 case CS_Unknown: 1931 /* not an error, no per-cert status, nothing here */ 1932 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX); 1933 proccessed = false; 1934 break; 1935 default: 1936 secdebug("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex, 1937 (int)this->certStatus, rvc->certIX); 1938 proccessed = false; 1939 break; 1940 } 1941 1942 return proccessed; 1943} 1944 1945static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecRVCRef rvc) { 1946 bool trusted; 1947 SecCertificatePathRef issuer = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1); 1948 SecCertificatePathRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer); 1949 CFRelease(issuer); 1950 1951 if (signer) { 1952 if (signer == issuer) { 1953 /* We already know we trust issuer since it's the path we are 1954 trying to verify minus the leaf. */ 1955 secdebug("ocsp", "ocsp responder: %@ response signed by issuer", 1956 rvc->responder); 1957 trusted = true; 1958 } else { 1959 secdebug("ocsp", 1960 "ocsp responder: %@ response signed by cert issued by issuer", 1961 rvc->responder); 1962 /* @@@ Now check that we trust signer. */ 1963 const void *ocspSigner = SecPolicyCreateOCSPSigner(); 1964 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault, 1965 &ocspSigner, 1, &kCFTypeArrayCallBacks); 1966 CFRelease(ocspSigner); 1967 CFAbsoluteTime verifyTime = SecOCSPResponseVerifyTime(ocspResponse); 1968 struct OpaqueSecPVC ospvc; 1969 SecPVCInit(&ospvc, rvc->pvc->builder, policies, verifyTime); 1970 CFRelease(policies); 1971 SecPVCSetPath(&ospvc, signer, NULL); 1972 SecPVCLeafChecks(&ospvc); 1973 if (ospvc.result) { 1974 bool completed = SecPVCPathChecks(&ospvc); 1975 /* If completed is false we are waiting for a callback, this 1976 shouldn't happen since we aren't asking for details, no 1977 revocation checking is done. */ 1978 if (!completed) { 1979 ocspdErrorLog("SecPVCPathChecks unexpectedly started " 1980 "background job!"); 1981 /* @@@ assert() or abort here perhaps? */ 1982 } 1983 } 1984 if (ospvc.result) { 1985 secdebug("ocsp", "response satisfies ocspSigner policy (%@)", 1986 rvc->responder); 1987 trusted = true; 1988 } else { 1989 /* @@@ We don't trust the cert so don't use this response. */ 1990 ocspdErrorLog("ocsp response signed by certificate which " 1991 "does not satisfy ocspSigner policy"); 1992 trusted = false; 1993 } 1994 SecPVCDelete(&ospvc); 1995 } 1996 1997 CFRelease(signer); 1998 } else { 1999 /* @@@ No signer found for this ocsp response, discard it. */ 2000 secdebug("ocsp", "ocsp responder: %@ no signer found for response", 2001 rvc->responder); 2002 trusted = false; 2003 } 2004 2005#if DUMP_OCSPRESPONSES 2006 char buf[40]; 2007 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der", 2008 rvc->certIX, (trusted ? "t" : "u")); 2009 secdumpdata(ocspResponse->data, buf); 2010#endif 2011 2012 return trusted; 2013} 2014 2015/* Callback from async http code after an ocsp response has been received. */ 2016static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) { 2017 SecRVCRef rvc = (SecRVCRef)http->info; 2018 SecPVCRef pvc = rvc->pvc; 2019 SecOCSPResponseRef ocspResponse = NULL; 2020 if (http->response) { 2021 CFDataRef data = CFHTTPMessageCopyBody(http->response); 2022 if (data) { 2023 /* Parse the returned data as if it's an ocspResponse. */ 2024 ocspResponse = SecOCSPResponseCreate(data, maxAge); 2025 CFRelease(data); 2026 } 2027 } 2028 2029 if (ocspResponse) { 2030 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse); 2031 if (orStatus == kSecOCSPSuccess) { 2032 SecOCSPSingleResponseRef sr = 2033 SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest); 2034 if (!sr) { 2035 /* The ocsp response didn't have a singleResponse for the cert 2036 we are looking for, let's try the next responder. */ 2037 secdebug("ocsp", 2038 "ocsp responder: %@ did not include status of requested cert", 2039 rvc->responder); 2040 } else { 2041 /* We got a singleResponse for the cert we are interested in, 2042 let's proccess it. */ 2043 /* @@@ If the responder doesn't have the ocsp-nocheck extension 2044 we should check whether the leaf was revoked (we are 2045 already checking the rest of the chain). */ 2046 /* Check the OCSP response signature and verify the 2047 response. */ 2048 if (SecOCSPResponseVerify(ocspResponse, rvc)) { 2049 secdebug("ocsp","responder: %@ sent proper response", 2050 rvc->responder); 2051 2052 if (SecOCSPSingleResponseProccess(sr, rvc)) { 2053 if (rvc->nextUpdate == 0) { 2054 rvc->nextUpdate = 2055 SecOCSPResponseGetExpirationTime(ocspResponse); 2056 } 2057 /* If the singleResponse had meaningful information, we 2058 cache the response. */ 2059 SecOCSPCacheAddResponse(ocspResponse, rvc->responder); 2060 rvc->done = true; 2061 } 2062 } 2063 SecOCSPSingleResponseDestroy(sr); 2064 } 2065 } else { 2066 /* ocsp response not ok. Let's try next responder. */ 2067 secdebug("ocsp", "responder: %@ returned status: %d", 2068 rvc->responder, orStatus); 2069#if 0 2070 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckRevocation, 2071 rvc->certIX, kCFBooleanFalse, true)) 2072 return; 2073#endif 2074 } 2075 SecOCSPResponseFinalize(ocspResponse); 2076 } 2077 2078 if (!rvc->done) { 2079 /* Clear the data for the next response. */ 2080 asynchttp_free(http); 2081 SecRVCFetchNext(rvc); 2082 } 2083 2084 if (rvc->done) { 2085 SecRVCDelete(rvc); 2086 if (!--pvc->asyncJobCount) { 2087 SecPathBuilderStep(pvc->builder); 2088 } 2089 } 2090} 2091 2092static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) { 2093 secdebug("alloc", "%p", rvc); 2094 rvc->pvc = pvc; 2095 rvc->certIX = certIX; 2096 rvc->http.queue = SecPathBuilderGetQueue(pvc->builder); 2097 rvc->http.completed = SecOCSPFetchCompleted; 2098 rvc->http.info = rvc; 2099 rvc->ocspRequest = NULL; 2100 rvc->responderIX = 0; 2101 rvc->responder = NULL; 2102 rvc->nextUpdate = 0; 2103 rvc->done = false; 2104} 2105 2106 2107static bool SecPVCCheckRevocation(SecPVCRef pvc) { 2108 secdebug("ocsp", "checking revocation"); 2109 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); 2110 bool completed = true; 2111 if (certCount <= 1) { 2112 /* Can't verify without an issuer; we're done */ 2113 return completed; 2114 } 2115 if (!SecPVCIsAnchored(pvc)) { 2116 /* We can't check revocation for chains without a trusted anchor. */ 2117 return completed; 2118 } 2119 certCount--; 2120 2121#if 0 2122 /* @@@ Implement getting this value from the client. 2123 Optional responder passed in though policy. */ 2124 CFURLRef localResponder = NULL; 2125 /* Generate a nonce in outgoing request if true. */ 2126 bool genNonce = false; 2127 /* Require a nonce in response if true. */ 2128 bool requireRespNonce = false; 2129 bool cacheReadDisable = false; 2130 bool cacheWriteDisable = false; 2131#endif 2132 2133 if (pvc->rvcs) { 2134 /* We have done revocation checking already, we're done. */ 2135 secdebug("ocsp", "Not rechecking revocation"); 2136 return completed; 2137 } 2138 2139 /* Setup things so we check revocation status of all certs except the 2140 anchor. */ 2141 pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount); 2142 2143#if 0 2144 /* Lookup cached revocation data for each certificate. */ 2145 for (certIX = 0; certIX < certCount; ++certIX) { 2146 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); 2147 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); 2148 if (ocspResponders) { 2149 /* First look though passed in ocsp responses. */ 2150 //SecPVCGetOCSPResponseForCertificateAtIndex(pvc, ix, singleResponse); 2151 2152 /* Then look though shared cache (we don't care which responder 2153 something came from here). */ 2154 CFDataRef ocspResponse = SecOCSPCacheCopyMatching(SecCertIDRef certID, NULL); 2155 2156 /* Now let's parse the response. */ 2157 if (decodeOCSPResponse(ocspResp)) { 2158 secdebug("ocsp", "response ok: %@", ocspResp); 2159 } else { 2160 secdebug("ocsp", "response bad: %@", ocspResp); 2161 /* ocsp response not ok. */ 2162 if (!SecPVCSetResultForced(pvc, key, ix, kCFBooleanFalse, true)) 2163 return completed; 2164 } 2165 CFReleaseSafe(ocspResp); 2166 } else { 2167 /* Check if certificate has any crl distributionPoints. */ 2168 CFArrayRef distributionPoints = SecCertificateGetCRLDistributionPoints(cert); 2169 if (distributionPoints) { 2170 /* Look for a cached CRL and potentially delta CRL for this certificate. */ 2171 } 2172 } 2173 } 2174#endif 2175 2176 /* Note that if we are multi threaded and a job completes after it 2177 is started but before we return from this function, we don't want 2178 a callback to decrement asyncJobCount to zero before we finish issuing 2179 all the jobs. To avoid this we pretend we issued certCount async jobs, 2180 and decrement pvc->asyncJobCount for each cert that we don't start a 2181 background fetch for. */ 2182 pvc->asyncJobCount = (unsigned int) certCount; 2183 2184 /* Loop though certificates again and issue an ocsp fetch if the 2185 revocation status checking isn't done yet. */ 2186 for (certIX = 0; certIX < certCount; ++certIX) { 2187 secdebug("ocsp", "checking revocation for cert: %ld", certIX); 2188 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX]; 2189 SecRVCInit(rvc, pvc, certIX); 2190 if (rvc->done) 2191 continue; 2192 2193 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, 2194 rvc->certIX); 2195 /* The certIX + 1 is ok here since certCount is always at least 1 2196 less than the actual number of certs. */ 2197 SecCertificateRef issuer = SecPVCGetCertificateAtIndex(rvc->pvc, 2198 rvc->certIX + 1); 2199 2200 rvc->ocspRequest = SecOCSPRequestCreate(cert, issuer); 2201 SecOCSPResponseRef ocspResponse; 2202 ocspResponse = SecOCSPCacheCopyMatching(rvc->ocspRequest, NULL); 2203 if (ocspResponse) { 2204 SecOCSPSingleResponseRef sr = 2205 SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest); 2206 if (!sr) { 2207 /* The cached ocsp response didn't have a singleResponse for 2208 the cert we are looking for, it's shouldn't be in the cache. */ 2209 secdebug("ocsp", "cached ocsp response did not include status" 2210 " of requested cert"); 2211 } else { 2212 /* We got a singleResponse for the cert we are interested in, 2213 let's proccess it. */ 2214 2215 /* @@@ If the responder doesn't have the ocsp-nocheck extension 2216 we should check whether the leaf was revoked (we are 2217 already checking the rest of the chain). */ 2218 /* Recheck the OCSP response signature and verify the 2219 response. */ 2220 if (SecOCSPResponseVerify(ocspResponse, rvc)) { 2221 secdebug("ocsp","cached response still has valid signature"); 2222 2223 if (SecOCSPSingleResponseProccess(sr, rvc)) { 2224 CFAbsoluteTime expTime = 2225 SecOCSPResponseGetExpirationTime(ocspResponse); 2226 if (rvc->nextUpdate == 0 || expTime < rvc->nextUpdate) 2227 rvc->nextUpdate = expTime; 2228 rvc->done = true; 2229 } 2230 } 2231 SecOCSPSingleResponseDestroy(sr); 2232 } 2233 SecOCSPResponseFinalize(ocspResponse); 2234 } 2235 2236 /* Unless we succefully checked the revocation status of this cert 2237 based on the cache, Attempt to fire off an async http request 2238 for this certs revocation status. */ 2239 bool fetch_done = true; 2240 if (rvc->done || !SecPathBuilderCanAccessNetwork(pvc->builder) || 2241 (fetch_done = SecRVCFetchNext(rvc))) { 2242 /* We got a cache hit or we aren't allowed to access the network, 2243 or the async http post failed. */ 2244 SecRVCDelete(rvc); 2245 /* We didn't really start a background job for this cert. */ 2246 pvc->asyncJobCount--; 2247 } else if (!fetch_done) { 2248 /* We started at least one background fetch. */ 2249 completed = false; 2250 } 2251 } 2252 2253 /* Return false if we started any background jobs. */ 2254 /* We can't just return !pvc->asyncJobCount here, since if we started any 2255 jobs the completion callback will be called eventually and it will call 2256 SecPathBuilderStep(). If for some reason everything completed before we 2257 get here we still want the outer SecPathBuilderStep() to terminate so we 2258 keep track of whether we started any jobs and return false if so. */ 2259 return completed; 2260} 2261 2262 2263void SecPolicyServerInitalize(void) { 2264 gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 2265 &kCFTypeDictionaryKeyCallBacks, NULL); 2266 gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 2267 &kCFTypeDictionaryKeyCallBacks, NULL); 2268 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2269 kSecPolicyCheckBasicCertificateProcessing, 2270 SecPolicyCheckBasicCertificateProcessing); 2271 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2272 kSecPolicyCheckCriticalExtensions, SecPolicyCheckCriticalExtensions); 2273 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2274 kSecPolicyCheckIdLinkage, SecPolicyCheckIdLinkage); 2275 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2276 kSecPolicyCheckKeyUsage, SecPolicyCheckKeyUsage); 2277 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2278 kSecPolicyCheckExtendedKeyUsage, SecPolicyCheckExtendedKeyUsage); 2279 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2280 kSecPolicyCheckBasicContraints, SecPolicyCheckBasicContraints); 2281 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2282 kSecPolicyCheckNonEmptySubject, SecPolicyCheckNonEmptySubject); 2283 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2284 kSecPolicyCheckQualifiedCertStatements, 2285 SecPolicyCheckQualifiedCertStatements); 2286 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2287 kSecPolicyCheckSSLHostname, SecPolicyCheckSSLHostname); 2288 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2289 kSecPolicyCheckEmail, SecPolicyCheckEmail); 2290 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2291 kSecPolicyCheckValidIntermediates, SecPolicyCheckValidIntermediates); 2292 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2293 kSecPolicyCheckValidLeaf, SecPolicyCheckValidLeaf); 2294 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2295 kSecPolicyCheckValidRoot, SecPolicyCheckValidRoot); 2296 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2297 kSecPolicyCheckIssuerCommonName, SecPolicyCheckIssuerCommonName); 2298 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2299 kSecPolicyCheckSubjectCommonNamePrefix, 2300 SecPolicyCheckSubjectCommonNamePrefix); 2301 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2302 kSecPolicyCheckSubjectCommonName, 2303 SecPolicyCheckSubjectCommonName); 2304 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2305 kSecPolicyCheckNotValidBefore, 2306 SecPolicyCheckNotValidBefore); 2307 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2308 kSecPolicyCheckChainLength, SecPolicyCheckChainLength); 2309 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2310 kSecPolicyCheckAnchorSHA1, SecPolicyCheckAnchorSHA1); 2311 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2312 kSecPolicyCheckSubjectOrganization, 2313 SecPolicyCheckSubjectOrganization); 2314 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2315 kSecPolicyCheckSubjectOrganizationalUnit, 2316 SecPolicyCheckSubjectOrganizationalUnit); 2317 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2318 kSecPolicyCheckEAPTrustedServerNames, 2319 SecPolicyCheckEAPTrustedServerNames); 2320 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2321 kSecPolicyCheckSubjectCommonNameTEST, 2322 SecPolicyCheckSubjectCommonNameTEST); 2323 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2324 kSecPolicyCheckRevocation, 2325 SecPolicyCheckRevocation); 2326 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2327 kSecPolicyCheckNoNetworkAccess, 2328 SecPolicyCheckNoNetworkAccess); 2329 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2330 kSecPolicyCheckBlackListedLeaf, 2331 SecPolicyCheckBlackListedLeaf); 2332 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2333 kSecPolicyCheckGrayListedLeaf, 2334 SecPolicyCheckGrayListedLeaf); 2335 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2336 kSecPolicyCheckLeafMarkerOid, 2337 SecPolicyCheckLeafMarkerOid); 2338 CFDictionaryAddValue(gSecPolicyPathCallbacks, 2339 kSecPolicyCheckIntermediateMarkerOid, 2340 SecPolicyCheckIntermediateMarkerOid); 2341 CFDictionaryAddValue(gSecPolicyLeafCallbacks, 2342 kSecPolicyCheckCertificatePolicy, 2343 SecPolicyCheckCertificatePolicyOid); 2344} 2345 2346/* AUDIT[securityd](done): 2347 array (ok) is a caller provided array, only its cf type has 2348 been checked. 2349 The options (ok) field ends up in policy->_options unchecked, so every access 2350 of policy->_options needs to be validated. 2351 */ 2352static SecPolicyRef SecPolicyCreateWithArray(CFArrayRef array) { 2353 SecPolicyRef policy = NULL; 2354 require_quiet(array && CFArrayGetCount(array) == 2, errOut); 2355 CFStringRef oid = (CFStringRef)CFArrayGetValueAtIndex(array, 0); 2356 require_quiet(isString(oid), errOut); 2357 CFDictionaryRef options = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 1); 2358 require_quiet(isDictionary(options), errOut); 2359 policy = SecPolicyCreate(oid, options); 2360errOut: 2361 return policy; 2362} 2363 2364/* AUDIT[securityd](done): 2365 value (ok) is an element in a caller provided array. 2366 */ 2367static void deserializePolicy(const void *value, void *context) { 2368 CFArrayRef policyArray = (CFArrayRef)value; 2369 if (isArray(policyArray)) { 2370 CFTypeRef deserializedPolicy = SecPolicyCreateWithArray(policyArray); 2371 if (deserializedPolicy) { 2372 CFArrayAppendValue((CFMutableArrayRef)context, deserializedPolicy); 2373 CFRelease(deserializedPolicy); 2374 } 2375 } 2376} 2377 2378/* AUDIT[securityd](done): 2379 serializedPolicies (ok) is a caller provided array, only its cf type has 2380 been checked. 2381 */ 2382CFArrayRef SecPolicyArrayDeserialize(CFArrayRef serializedPolicies) { 2383 CFMutableArrayRef result = NULL; 2384 require_quiet(isArray(serializedPolicies), errOut); 2385 CFIndex count = CFArrayGetCount(serializedPolicies); 2386 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); 2387 CFRange all_policies = { 0, count }; 2388 CFArrayApplyFunction(serializedPolicies, all_policies, deserializePolicy, result); 2389errOut: 2390 return result; 2391} 2392 2393// MARK: - 2394// MARK: SecPVCRef 2395/******************************************************** 2396 ****************** SecPVCRef Functions ***************** 2397 ********************************************************/ 2398 2399void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies, 2400 CFAbsoluteTime verifyTime) { 2401 secdebug("alloc", "%p", pvc); 2402 // Weird logging policies crashes. 2403 //secdebug("policy", "%@", policies); 2404 pvc->builder = builder; 2405 pvc->policies = policies; 2406 if (policies) 2407 CFRetain(policies); 2408 pvc->verifyTime = verifyTime; 2409 pvc->path = NULL; 2410 pvc->details = NULL; 2411 pvc->info = NULL; 2412 pvc->valid_policy_tree = NULL; 2413 pvc->callbacks = NULL; 2414 pvc->policyIX = 0; 2415 pvc->rvcs = NULL; 2416 pvc->asyncJobCount = 0; 2417 pvc->check_revocation = false; 2418 pvc->optionally_ev = false; 2419 pvc->is_ev = false; 2420 pvc->result = true; 2421} 2422 2423static void SecPVCDeleteRVCs(SecPVCRef pvc) { 2424 secdebug("alloc", "%p", pvc); 2425 if (pvc->rvcs) { 2426 free(pvc->rvcs); 2427 pvc->rvcs = NULL; 2428 } 2429} 2430 2431void SecPVCDelete(SecPVCRef pvc) { 2432 secdebug("alloc", "%p", pvc); 2433 CFReleaseNull(pvc->policies); 2434 CFReleaseNull(pvc->details); 2435 CFReleaseNull(pvc->info); 2436 if (pvc->valid_policy_tree) { 2437 policy_tree_prune(&pvc->valid_policy_tree); 2438 } 2439 SecPVCDeleteRVCs(pvc); 2440} 2441 2442void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path, 2443 CF_CONSUMED CFArrayRef details) { 2444 secdebug("policy", "%@", path); 2445 if (pvc->path != path) { 2446 /* Changing path makes us clear the Revocation Verification Contexts */ 2447 SecPVCDeleteRVCs(pvc); 2448 pvc->path = path; 2449 } 2450 pvc->details = details; 2451 CFReleaseNull(pvc->info); 2452 if (pvc->valid_policy_tree) { 2453 policy_tree_prune(&pvc->valid_policy_tree); 2454 } 2455 pvc->policyIX = 0; 2456 pvc->result = true; 2457} 2458 2459SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) { 2460 return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX); 2461} 2462 2463CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { 2464 return SecCertificatePathGetCount(pvc->path); 2465} 2466 2467SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { 2468 return SecCertificatePathGetCertificateAtIndex(pvc->path, ix); 2469} 2470 2471bool SecPVCIsCertificateAtIndexSelfSigned(SecPVCRef pvc, CFIndex ix) { 2472 return SecCertificatePathSelfSignedIndex(pvc->path) == ix; 2473} 2474 2475void SecPVCSetCheckRevocation(SecPVCRef pvc) { 2476 pvc->check_revocation = true; 2477 secdebug("ocsp", "deferred revocation checking enabled"); 2478} 2479 2480bool SecPVCIsAnchored(SecPVCRef pvc) { 2481 return SecCertificatePathIsAnchored(pvc->path); 2482} 2483 2484CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { 2485 return pvc->verifyTime; 2486} 2487 2488/* AUDIT[securityd](done): 2489 policy->_options is a caller provided dictionary, only its cf type has 2490 been checked. 2491 */ 2492bool SecPVCSetResultForced(SecPVCRef pvc, 2493 CFStringRef key, CFIndex ix, CFTypeRef result, bool force) { 2494 2495 secdebug("policy", "cert[%d]: %@ =(%s)[%s]> %@", (int) ix, key, 2496 (pvc->callbacks == gSecPolicyLeafCallbacks ? "leaf" 2497 : (pvc->callbacks == gSecPolicyPathCallbacks ? "path" 2498 : "custom")), 2499 (force ? "force" : ""), result); 2500 2501 /* If this is not something the current policy cares about ignore 2502 this error and return true so our caller continues evaluation. */ 2503 if (!force) { 2504 /* @@@ The right long term fix might be to check if none of the passed 2505 in policies contain this key, since not all checks are run for all 2506 policies. */ 2507 SecPolicyRef policy = SecPVCGetPolicy(pvc); 2508 if (policy && !CFDictionaryContainsKey(policy->_options, key)) 2509 return true; 2510 } 2511 2512 /* @@@ Check to see if the SecTrustSettings for the certificate in question 2513 tell us to ignore this error. */ 2514 pvc->result = false; 2515 if (!pvc->details) 2516 return false; 2517 2518 CFMutableDictionaryRef detail = 2519 (CFMutableDictionaryRef)CFArrayGetValueAtIndex(pvc->details, ix); 2520 2521 /* Perhaps detail should have an array of results per key? As it stands 2522 in the case of multiple policy failures the last failure stands. */ 2523 CFDictionarySetValue(detail, key, result); 2524 2525 return true; 2526} 2527 2528bool SecPVCSetResult(SecPVCRef pvc, 2529 CFStringRef key, CFIndex ix, CFTypeRef result) { 2530 return SecPVCSetResultForced(pvc, key, ix, result, false); 2531} 2532 2533/* AUDIT[securityd](done): 2534 key(ok) is a caller provided. 2535 value(ok, unused) is a caller provided. 2536 */ 2537static void SecPVCValidateKey(const void *key, const void *value, 2538 void *context) { 2539 SecPVCRef pvc = (SecPVCRef)context; 2540 2541 /* If our caller doesn't want full details and we failed earlier there is 2542 no point in doing additional checks. */ 2543 if (!pvc->result && !pvc->details) 2544 return; 2545 2546 SecPolicyCheckFunction fcn = (SecPolicyCheckFunction) 2547 CFDictionaryGetValue(pvc->callbacks, key); 2548 2549 if (!fcn) { 2550#if 0 2551 /* Why not to have optional policy checks rant: 2552 Not all keys are in all dictionaries anymore, so why not make checks 2553 optional? This way a client can ask for something and the server will 2554 do a best effort based on the supported flags. It works since they are 2555 synchronized now, but we need some debug checking here for now. */ 2556 pvc->result = false; 2557#endif 2558 if (pvc->callbacks == gSecPolicyLeafCallbacks) { 2559 if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) { 2560 pvc->result = false; 2561 } 2562 } else if (pvc->callbacks == gSecPolicyPathCallbacks) { 2563 if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) { 2564 pvc->result = false; 2565 } 2566 } else { 2567 /* Non standard valdation phase, nothing is optional. */ 2568 pvc->result = false; 2569 } 2570 return; 2571 } 2572 2573 fcn(pvc, (CFStringRef)key); 2574} 2575 2576/* AUDIT[securityd](done): 2577 policy->_options is a caller provided dictionary, only its cf type has 2578 been checked. 2579 */ 2580bool SecPVCLeafChecks(SecPVCRef pvc) { 2581 pvc->result = true; 2582 CFArrayRef policies = pvc->policies; 2583 CFIndex ix, count = CFArrayGetCount(policies); 2584 for (ix = 0; ix < count; ++ix) { 2585 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, ix); 2586 pvc->policyIX = ix; 2587 /* Validate all keys for all policies. */ 2588 pvc->callbacks = gSecPolicyLeafCallbacks; 2589 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); 2590 if (!pvc->result && !pvc->details) 2591 return pvc->result; 2592 } 2593 2594 return pvc->result; 2595} 2596 2597bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) { 2598 /* Check stuff common to intermediate and anchors. */ 2599 CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); 2600 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 2601 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1 2602 && SecPVCIsAnchored(pvc)); 2603 if (!SecCertificateIsValid(cert, verifyTime)) { 2604 /* Certificate has expired. */ 2605 if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot 2606 : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse)) 2607 goto errOut; 2608 } 2609 2610 if (is_anchor) { 2611 /* Perform anchor specific checks. */ 2612 /* Don't think we have any of these. */ 2613 } else { 2614 /* Perform intermediate specific checks. */ 2615 2616 /* (k) */ 2617 const SecCEBasicConstraints *bc = 2618 SecCertificateGetBasicConstraints(cert); 2619 if (!bc || !bc->isCA) { 2620 /* Basic constraints not present or not marked as isCA, illegal. */ 2621 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicContraints, 2622 ix, kCFBooleanFalse, true)) 2623 goto errOut; 2624 } 2625 /* Consider adding (l) max_path_length checking here. */ 2626 2627 /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ 2628 SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); 2629 if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { 2630 if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage, 2631 ix, kCFBooleanFalse, true)) 2632 goto errOut; 2633 } 2634 } 2635 2636errOut: 2637 return pvc->result; 2638} 2639 2640bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { 2641 /* Check stuff common to intermediate and anchors. */ 2642 2643 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); 2644 if (NULL != otapkiRef) 2645 { 2646 CFSetRef blackListedKeys = SecOTAPKICopyBlackListSet(otapkiRef); 2647 CFRelease(otapkiRef); 2648 if (NULL != blackListedKeys) 2649 { 2650 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 2651 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1 2652 && SecPVCIsAnchored(pvc)); 2653 if (!is_anchor) { 2654 /* Check for blacklisted intermediates keys. */ 2655 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); 2656 if (dgst) { 2657 /* Check dgst against blacklist. */ 2658 if (CFSetContainsValue(blackListedKeys, dgst)) { 2659 SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, 2660 ix, kCFBooleanFalse, true); 2661 } 2662 CFRelease(dgst); 2663 } 2664 } 2665 CFRelease(blackListedKeys); 2666 return pvc->result; 2667 } 2668 } 2669 // Assume OK 2670 return true; 2671} 2672 2673bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) 2674{ 2675 /* Check stuff common to intermediate and anchors. */ 2676 SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); 2677 if (NULL != otapkiRef) 2678 { 2679 CFSetRef grayListKeys = SecOTAPKICopyGrayList(otapkiRef); 2680 CFRelease(otapkiRef); 2681 if (NULL != grayListKeys) 2682 { 2683 SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); 2684 bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1 2685 && SecPVCIsAnchored(pvc)); 2686 if (!is_anchor) { 2687 /* Check for gray listed intermediates keys. */ 2688 CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); 2689 if (dgst) { 2690 /* Check dgst against gray list. */ 2691 if (CFSetContainsValue(grayListKeys, dgst)) { 2692 SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey, 2693 ix, kCFBooleanFalse, true); 2694 } 2695 CFRelease(dgst); 2696 } 2697 } 2698 CFRelease(grayListKeys); 2699 return pvc->result; 2700 } 2701 } 2702 // Assume ok 2703 return true; 2704} 2705 2706/* AUDIT[securityd](done): 2707 policy->_options is a caller provided dictionary, only its cf type has 2708 been checked. 2709 */ 2710bool SecPVCPathChecks(SecPVCRef pvc) { 2711 secdebug("policy", "begin path: %@", pvc->path); 2712 bool completed = true; 2713 /* This needs to be initialized before we call any function that might call 2714 SecPVCSetResultForced(). */ 2715 pvc->policyIX = 0; 2716 SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage); 2717 if (pvc->result || pvc->details) { 2718 SecPolicyCheckBasicCertificateProcessing(pvc, 2719 kSecPolicyCheckBasicCertificateProcessing); 2720 } 2721 2722 CFArrayRef policies = pvc->policies; 2723 CFIndex count = CFArrayGetCount(policies); 2724 for (; pvc->policyIX < count; ++pvc->policyIX) { 2725 /* Validate all keys for all policies. */ 2726 pvc->callbacks = gSecPolicyPathCallbacks; 2727 SecPolicyRef policy = SecPVCGetPolicy(pvc); 2728 CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); 2729 if (!pvc->result && !pvc->details) 2730 return completed; 2731 } 2732 2733 /* Check the things we can't check statically for the certificate path. */ 2734 /* Critical Extensions, chainLength. */ 2735 2736 /* Policy tests. */ 2737 pvc->is_ev = false; 2738 if ((pvc->result || pvc->details) && pvc->optionally_ev) { 2739 bool pre_ev_check_result = pvc->result; 2740 SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation); 2741 pvc->is_ev = pvc->result; 2742 /* If ev checking failed, we still want to accept this chain 2743 as a non EV one, if it was valid as such. */ 2744 pvc->result = pre_ev_check_result; 2745 } 2746 /* Check revocation only if the chain is valid so far. Then only check 2747 revocation if the client asked for it explicitly or is_ev is 2748 true. */ 2749 if (pvc->result && (pvc->is_ev || pvc->check_revocation)) { 2750 completed = SecPVCCheckRevocation(pvc); 2751 } 2752 2753//errOut: 2754 secdebug("policy", "end %strusted completed: %d path: %@", 2755 (pvc->result ? "" : "not "), completed, pvc->path); 2756 return completed; 2757} 2758 2759/* This function returns 0 to indicate revocation checking was not completed 2760 for this certificate chain, otherwise return to date at which the first 2761 piece of revocation checking info we used expires. */ 2762CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) { 2763 CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); 2764 CFAbsoluteTime enu = 0; 2765 if (certCount <= 1 || !pvc->rvcs) { 2766 return enu; 2767 } 2768 certCount--; 2769 2770 for (certIX = 0; certIX < certCount; ++certIX) { 2771 SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX]; 2772 if (rvc->nextUpdate == 0) { 2773 if (certIX > 0) { 2774 /* We allow for CA certs to not be revocation checked if they 2775 have no ocspResponders to check against, but the leaf 2776 must be checked in order for us to claim we did revocation 2777 checking. */ 2778 SecCertificateRef cert = 2779 SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); 2780 CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); 2781 if (!ocspResponders || CFArrayGetCount(ocspResponders) == 0) { 2782 /* We can't check this cert so we don't consider it a soft 2783 failure that we didn't. Ideally we should support crl 2784 checking and remove this workaround, since that more 2785 strict. */ 2786 continue; 2787 } 2788 } 2789 secdebug("ocsp", "revocation checking soft failure for cert: %ld", 2790 certIX); 2791 enu = rvc->nextUpdate; 2792 break; 2793 } 2794 if (enu == 0 || rvc->nextUpdate < enu) { 2795 enu = rvc->nextUpdate; 2796 } 2797#if 0 2798 /* Perhaps we don't want to do this since some policies might 2799 ignore the certificate experation but still use revocation 2800 checking. */ 2801 2802 /* Earliest certificate expiration date. */ 2803 SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); 2804 CFAbsoluteTime nva = SecCertificateNotValidAfter(cert); 2805 if (nva && (enu == 0 || nva < enu) 2806 enu = nva; 2807#endif 2808 } 2809 2810 secdebug("ocsp", "revocation valid until: %lg", enu); 2811 return enu; 2812} 2813