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