| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/cert_verify_proc_mac.h" | 5 #include "net/cert/cert_verify_proc_mac.h" |
| 6 | 6 |
| 7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
| 9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
| 10 | 10 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 verify_result->has_md5 = true; | 229 verify_result->has_md5 = true; |
| 230 } | 230 } |
| 231 } | 231 } |
| 232 if (!verified_cert) | 232 if (!verified_cert) |
| 233 return; | 233 return; |
| 234 | 234 |
| 235 verify_result->verified_cert = | 235 verify_result->verified_cert = |
| 236 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | 236 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
| 237 } | 237 } |
| 238 | 238 |
| 239 void AppendPublicKeyHashes(CFArrayRef chain, | 239 void AppendPublicKeyHashes(CFArrayRef chain, HashValueVector* hashes) { |
| 240 HashValueVector* hashes) { | |
| 241 const CFIndex n = CFArrayGetCount(chain); | 240 const CFIndex n = CFArrayGetCount(chain); |
| 242 for (CFIndex i = 0; i < n; i++) { | 241 for (CFIndex i = 0; i < n; i++) { |
| 243 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( | 242 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( |
| 244 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); | 243 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); |
| 245 | 244 |
| 246 CSSM_DATA cert_data; | 245 CSSM_DATA cert_data; |
| 247 OSStatus err = SecCertificateGetData(cert, &cert_data); | 246 OSStatus err = SecCertificateGetData(cert, &cert_data); |
| 248 DCHECK_EQ(err, noErr); | 247 DCHECK_EQ(err, noErr); |
| 249 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), | 248 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), |
| 250 cert_data.Length); | 249 cert_data.Length); |
| 251 base::StringPiece spki_bytes; | 250 base::StringPiece spki_bytes; |
| 252 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | 251 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) |
| 253 continue; | 252 continue; |
| 254 | 253 |
| 255 HashValue sha1(HASH_VALUE_SHA1); | 254 HashValue sha1(HASH_VALUE_SHA1); |
| 256 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); | 255 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); |
| 257 hashes->push_back(sha1); | 256 hashes->push_back(sha1); |
| 258 | 257 |
| 259 HashValue sha256(HASH_VALUE_SHA256); | 258 HashValue sha256(HASH_VALUE_SHA256); |
| 260 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); | 259 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 // This function should only be called while the Mac Security Services lock is | 351 // This function should only be called while the Mac Security Services lock is |
| 353 // held. | 352 // held. |
| 354 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, | 353 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, |
| 355 CFArrayRef trust_policies, | 354 CFArrayRef trust_policies, |
| 356 int flags, | 355 int flags, |
| 357 ScopedCFTypeRef<SecTrustRef>* trust_ref, | 356 ScopedCFTypeRef<SecTrustRef>* trust_ref, |
| 358 SecTrustResultType* trust_result, | 357 SecTrustResultType* trust_result, |
| 359 ScopedCFTypeRef<CFArrayRef>* verified_chain, | 358 ScopedCFTypeRef<CFArrayRef>* verified_chain, |
| 360 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) { | 359 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) { |
| 361 SecTrustRef tmp_trust = NULL; | 360 SecTrustRef tmp_trust = NULL; |
| 362 OSStatus status = SecTrustCreateWithCertificates(cert_array, trust_policies, | 361 OSStatus status = |
| 363 &tmp_trust); | 362 SecTrustCreateWithCertificates(cert_array, trust_policies, &tmp_trust); |
| 364 if (status) | 363 if (status) |
| 365 return NetErrorFromOSStatus(status); | 364 return NetErrorFromOSStatus(status); |
| 366 ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust); | 365 ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust); |
| 367 | 366 |
| 368 if (TestRootCerts::HasInstance()) { | 367 if (TestRootCerts::HasInstance()) { |
| 369 status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust); | 368 status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust); |
| 370 if (status) | 369 if (status) |
| 371 return NetErrorFromOSStatus(status); | 370 return NetErrorFromOSStatus(status); |
| 372 } | 371 } |
| 373 | 372 |
| 374 CSSM_APPLE_TP_ACTION_DATA tp_action_data; | 373 CSSM_APPLE_TP_ACTION_DATA tp_action_data; |
| 375 memset(&tp_action_data, 0, sizeof(tp_action_data)); | 374 memset(&tp_action_data, 0, sizeof(tp_action_data)); |
| 376 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; | 375 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; |
| 377 // Allow CSSM to download any missing intermediate certificates if an | 376 // Allow CSSM to download any missing intermediate certificates if an |
| 378 // authorityInfoAccess extension or issuerAltName extension is present. | 377 // authorityInfoAccess extension or issuerAltName extension is present. |
| 379 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | | 378 tp_action_data.ActionFlags = |
| 380 CSSM_TP_ACTION_TRUST_SETTINGS; | 379 CSSM_TP_ACTION_FETCH_CERT_FROM_NET | CSSM_TP_ACTION_TRUST_SETTINGS; |
| 381 | 380 |
| 382 // Note: For EV certificates, the Apple TP will handle setting these flags | 381 // Note: For EV certificates, the Apple TP will handle setting these flags |
| 383 // as part of EV evaluation. | 382 // as part of EV evaluation. |
| 384 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) { | 383 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) { |
| 385 // Require a positive result from an OCSP responder or a CRL (or both) | 384 // Require a positive result from an OCSP responder or a CRL (or both) |
| 386 // for every certificate in the chain. The Apple TP automatically | 385 // for every certificate in the chain. The Apple TP automatically |
| 387 // excludes the self-signed root from this requirement. If a certificate | 386 // excludes the self-signed root from this requirement. If a certificate |
| 388 // is missing both a crlDistributionPoints extension and an | 387 // is missing both a crlDistributionPoints extension and an |
| 389 // authorityInfoAccess extension with an OCSP responder URL, then we | 388 // authorityInfoAccess extension with an OCSP responder URL, then we |
| 390 // will get a kSecTrustResultRecoverableTrustFailure back from | 389 // will get a kSecTrustResultRecoverableTrustFailure back from |
| 391 // SecTrustEvaluate(), with a | 390 // SecTrustEvaluate(), with a |
| 392 // CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK error code. In that case, | 391 // CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK error code. In that case, |
| 393 // we'll set our own result to include | 392 // we'll set our own result to include |
| 394 // CERT_STATUS_NO_REVOCATION_MECHANISM. If one or both extensions are | 393 // CERT_STATUS_NO_REVOCATION_MECHANISM. If one or both extensions are |
| 395 // present, and a check fails (server unavailable, OCSP retry later, | 394 // present, and a check fails (server unavailable, OCSP retry later, |
| 396 // signature mismatch), then we'll set our own result to include | 395 // signature mismatch), then we'll set our own result to include |
| 397 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. | 396 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. |
| 398 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; | 397 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; |
| 399 | 398 |
| 400 // Note, even if revocation checking is disabled, SecTrustEvaluate() will | 399 // Note, even if revocation checking is disabled, SecTrustEvaluate() will |
| 401 // modify the OCSP options so as to attempt OCSP checking if it believes a | 400 // modify the OCSP options so as to attempt OCSP checking if it believes a |
| 402 // certificate may chain to an EV root. However, because network fetches | 401 // certificate may chain to an EV root. However, because network fetches |
| 403 // are disabled in CreateTrustPolicies() when revocation checking is | 402 // are disabled in CreateTrustPolicies() when revocation checking is |
| 404 // disabled, these will only go against the local cache. | 403 // disabled, these will only go against the local cache. |
| 405 } | 404 } |
| 406 | 405 |
| 407 CFDataRef action_data_ref = | 406 CFDataRef action_data_ref = |
| 408 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, | 407 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, |
| 409 reinterpret_cast<UInt8*>(&tp_action_data), | 408 reinterpret_cast<UInt8*>(&tp_action_data), |
| 410 sizeof(tp_action_data), kCFAllocatorNull); | 409 sizeof(tp_action_data), |
| 410 kCFAllocatorNull); |
| 411 if (!action_data_ref) | 411 if (!action_data_ref) |
| 412 return ERR_OUT_OF_MEMORY; | 412 return ERR_OUT_OF_MEMORY; |
| 413 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); | 413 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); |
| 414 status = SecTrustSetParameters(tmp_trust, CSSM_TP_ACTION_DEFAULT, | 414 status = |
| 415 action_data_ref); | 415 SecTrustSetParameters(tmp_trust, CSSM_TP_ACTION_DEFAULT, action_data_ref); |
| 416 if (status) | 416 if (status) |
| 417 return NetErrorFromOSStatus(status); | 417 return NetErrorFromOSStatus(status); |
| 418 | 418 |
| 419 // Verify the certificate. A non-zero result from SecTrustGetResult() | 419 // Verify the certificate. A non-zero result from SecTrustGetResult() |
| 420 // indicates that some fatal error occurred and the chain couldn't be | 420 // indicates that some fatal error occurred and the chain couldn't be |
| 421 // processed, not that the chain contains no errors. We need to examine the | 421 // processed, not that the chain contains no errors. We need to examine the |
| 422 // output of SecTrustGetResult() to determine that. | 422 // output of SecTrustGetResult() to determine that. |
| 423 SecTrustResultType tmp_trust_result; | 423 SecTrustResultType tmp_trust_result; |
| 424 status = SecTrustEvaluate(tmp_trust, &tmp_trust_result); | 424 status = SecTrustEvaluate(tmp_trust, &tmp_trust_result); |
| 425 if (status) | 425 if (status) |
| 426 return NetErrorFromOSStatus(status); | 426 return NetErrorFromOSStatus(status); |
| 427 CFArrayRef tmp_verified_chain = NULL; | 427 CFArrayRef tmp_verified_chain = NULL; |
| 428 CSSM_TP_APPLE_EVIDENCE_INFO* tmp_chain_info; | 428 CSSM_TP_APPLE_EVIDENCE_INFO* tmp_chain_info; |
| 429 status = SecTrustGetResult(tmp_trust, &tmp_trust_result, &tmp_verified_chain, | 429 status = SecTrustGetResult( |
| 430 &tmp_chain_info); | 430 tmp_trust, &tmp_trust_result, &tmp_verified_chain, &tmp_chain_info); |
| 431 if (status) | 431 if (status) |
| 432 return NetErrorFromOSStatus(status); | 432 return NetErrorFromOSStatus(status); |
| 433 | 433 |
| 434 trust_ref->swap(scoped_tmp_trust); | 434 trust_ref->swap(scoped_tmp_trust); |
| 435 *trust_result = tmp_trust_result; | 435 *trust_result = tmp_trust_result; |
| 436 verified_chain->reset(tmp_verified_chain); | 436 verified_chain->reset(tmp_verified_chain); |
| 437 *chain_info = tmp_chain_info; | 437 *chain_info = tmp_chain_info; |
| 438 | 438 |
| 439 return OK; | 439 return OK; |
| 440 } | 440 } |
| 441 | 441 |
| 442 // OS X ships with both "GTE CyberTrust Global Root" and "Baltimore CyberTrust | 442 // OS X ships with both "GTE CyberTrust Global Root" and "Baltimore CyberTrust |
| 443 // Root" as part of its trusted root store. However, a cross-certified version | 443 // Root" as part of its trusted root store. However, a cross-certified version |
| 444 // of the "Baltimore CyberTrust Root" exists that chains to "GTE CyberTrust | 444 // of the "Baltimore CyberTrust Root" exists that chains to "GTE CyberTrust |
| 445 // Global Root". When OS X/Security.framework attempts to evaluate such a | 445 // Global Root". When OS X/Security.framework attempts to evaluate such a |
| 446 // certificate chain, it disregards the "Baltimore CyberTrust Root" that exists | 446 // certificate chain, it disregards the "Baltimore CyberTrust Root" that exists |
| 447 // within Keychain and instead attempts to terminate the chain in the "GTE | 447 // within Keychain and instead attempts to terminate the chain in the "GTE |
| 448 // CyberTrust Global Root". However, the GTE root is scheduled to be removed in | 448 // CyberTrust Global Root". However, the GTE root is scheduled to be removed in |
| 449 // a future OS X update (for sunsetting purposes), and once removed, such | 449 // a future OS X update (for sunsetting purposes), and once removed, such |
| 450 // chains will fail validation, even though a trust anchor still exists. | 450 // chains will fail validation, even though a trust anchor still exists. |
| 451 // | 451 // |
| 452 // Rather than over-generalizing a solution that may mask a number of TLS | 452 // Rather than over-generalizing a solution that may mask a number of TLS |
| 453 // misconfigurations, attempt to specifically match the affected | 453 // misconfigurations, attempt to specifically match the affected |
| 454 // cross-certified certificate and remove it from certificate chain processing. | 454 // cross-certified certificate and remove it from certificate chain processing. |
| 455 bool IsBadBaltimoreGTECertificate(SecCertificateRef cert) { | 455 bool IsBadBaltimoreGTECertificate(SecCertificateRef cert) { |
| 456 // Matches the GTE-signed Baltimore CyberTrust Root | 456 // Matches the GTE-signed Baltimore CyberTrust Root |
| 457 // https://cacert.omniroot.com/Baltimore-to-GTE-04-12.pem | 457 // https://cacert.omniroot.com/Baltimore-to-GTE-04-12.pem |
| 458 static const SHA1HashValue kBadBaltimoreHashNew = | 458 static const SHA1HashValue kBadBaltimoreHashNew = { |
| 459 { { 0x4D, 0x34, 0xEA, 0x92, 0x76, 0x4B, 0x3A, 0x31, 0x49, 0x11, | 459 {0x4D, 0x34, 0xEA, 0x92, 0x76, 0x4B, 0x3A, 0x31, 0x49, 0x11, 0x99, 0x52, |
| 460 0x99, 0x52, 0xF4, 0x19, 0x30, 0xCA, 0x11, 0x34, 0x83, 0x61 } }; | 460 0xF4, 0x19, 0x30, 0xCA, 0x11, 0x34, 0x83, 0x61}}; |
| 461 // Matches the legacy GTE-signed Baltimore CyberTrust Root | 461 // Matches the legacy GTE-signed Baltimore CyberTrust Root |
| 462 // https://cacert.omniroot.com/gte-2-2025.pem | 462 // https://cacert.omniroot.com/gte-2-2025.pem |
| 463 static const SHA1HashValue kBadBaltimoreHashOld = | 463 static const SHA1HashValue kBadBaltimoreHashOld = { |
| 464 { { 0x54, 0xD8, 0xCB, 0x49, 0x1F, 0xA1, 0x6D, 0xF8, 0x87, 0xDC, | 464 {0x54, 0xD8, 0xCB, 0x49, 0x1F, 0xA1, 0x6D, 0xF8, 0x87, 0xDC, 0x94, 0xA9, |
| 465 0x94, 0xA9, 0x34, 0xCC, 0x83, 0x6B, 0xDA, 0xA8, 0xA3, 0x69 } }; | 465 0x34, 0xCC, 0x83, 0x6B, 0xDA, 0xA8, 0xA3, 0x69}}; |
| 466 | 466 |
| 467 SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(cert); | 467 SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(cert); |
| 468 | 468 |
| 469 return fingerprint.Equals(kBadBaltimoreHashNew) || | 469 return fingerprint.Equals(kBadBaltimoreHashNew) || |
| 470 fingerprint.Equals(kBadBaltimoreHashOld); | 470 fingerprint.Equals(kBadBaltimoreHashOld); |
| 471 } | 471 } |
| 472 | 472 |
| 473 // Attempts to re-verify |cert_array| after adjusting the inputs to work around | 473 // Attempts to re-verify |cert_array| after adjusting the inputs to work around |
| 474 // known issues in OS X. To be used if BuildAndEvaluateSecTrustRef fails to | 474 // known issues in OS X. To be used if BuildAndEvaluateSecTrustRef fails to |
| 475 // return a positive result for verification. | 475 // return a positive result for verification. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 497 slice_point = i; | 497 slice_point = i; |
| 498 break; | 498 break; |
| 499 } | 499 } |
| 500 } | 500 } |
| 501 if (slice_point == 0) | 501 if (slice_point == 0) |
| 502 return; // Nothing to do. | 502 return; // Nothing to do. |
| 503 | 503 |
| 504 ScopedCFTypeRef<CFMutableArrayRef> adjusted_cert_array( | 504 ScopedCFTypeRef<CFMutableArrayRef> adjusted_cert_array( |
| 505 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 505 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); |
| 506 // Note: This excludes the certificate at |slice_point|. | 506 // Note: This excludes the certificate at |slice_point|. |
| 507 CFArrayAppendArray(adjusted_cert_array, cert_array, | 507 CFArrayAppendArray( |
| 508 CFRangeMake(0, slice_point)); | 508 adjusted_cert_array, cert_array, CFRangeMake(0, slice_point)); |
| 509 | 509 |
| 510 // Ignore the result; failure will preserve the old verification results. | 510 // Ignore the result; failure will preserve the old verification results. |
| 511 BuildAndEvaluateSecTrustRef( | 511 BuildAndEvaluateSecTrustRef(adjusted_cert_array, |
| 512 adjusted_cert_array, trust_policies, flags, trust_ref, trust_result, | 512 trust_policies, |
| 513 verified_chain, chain_info); | 513 flags, |
| 514 trust_ref, |
| 515 trust_result, |
| 516 verified_chain, |
| 517 chain_info); |
| 514 } | 518 } |
| 515 | 519 |
| 516 } // namespace | 520 } // namespace |
| 517 | 521 |
| 518 CertVerifyProcMac::CertVerifyProcMac() {} | 522 CertVerifyProcMac::CertVerifyProcMac() { |
| 523 } |
| 519 | 524 |
| 520 CertVerifyProcMac::~CertVerifyProcMac() {} | 525 CertVerifyProcMac::~CertVerifyProcMac() { |
| 526 } |
| 521 | 527 |
| 522 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { | 528 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { |
| 523 return false; | 529 return false; |
| 524 } | 530 } |
| 525 | 531 |
| 526 int CertVerifyProcMac::VerifyInternal( | 532 int CertVerifyProcMac::VerifyInternal( |
| 527 X509Certificate* cert, | 533 X509Certificate* cert, |
| 528 const std::string& hostname, | 534 const std::string& hostname, |
| 529 int flags, | 535 int flags, |
| 530 CRLSet* crl_set, | 536 CRLSet* crl_set, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 544 | 550 |
| 545 // Serialize all calls that may use the Keychain, to work around various | 551 // Serialize all calls that may use the Keychain, to work around various |
| 546 // issues in OS X 10.6+ with multi-threaded access to Security.framework. | 552 // issues in OS X 10.6+ with multi-threaded access to Security.framework. |
| 547 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 553 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| 548 | 554 |
| 549 ScopedCFTypeRef<SecTrustRef> trust_ref; | 555 ScopedCFTypeRef<SecTrustRef> trust_ref; |
| 550 SecTrustResultType trust_result = kSecTrustResultDeny; | 556 SecTrustResultType trust_result = kSecTrustResultDeny; |
| 551 ScopedCFTypeRef<CFArrayRef> completed_chain; | 557 ScopedCFTypeRef<CFArrayRef> completed_chain; |
| 552 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; | 558 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; |
| 553 | 559 |
| 554 int rv = BuildAndEvaluateSecTrustRef( | 560 int rv = BuildAndEvaluateSecTrustRef(cert_array, |
| 555 cert_array, trust_policies, flags, &trust_ref, &trust_result, | 561 trust_policies, |
| 556 &completed_chain, &chain_info); | 562 flags, |
| 563 &trust_ref, |
| 564 &trust_result, |
| 565 &completed_chain, |
| 566 &chain_info); |
| 557 if (rv != OK) | 567 if (rv != OK) |
| 558 return rv; | 568 return rv; |
| 559 if (trust_result != kSecTrustResultUnspecified && | 569 if (trust_result != kSecTrustResultUnspecified && |
| 560 trust_result != kSecTrustResultProceed) { | 570 trust_result != kSecTrustResultProceed) { |
| 561 RetrySecTrustEvaluateWithAdjustedChain( | 571 RetrySecTrustEvaluateWithAdjustedChain(cert_array, |
| 562 cert_array, trust_policies, flags, &trust_ref, &trust_result, | 572 trust_policies, |
| 563 &completed_chain, &chain_info); | 573 flags, |
| 574 &trust_ref, |
| 575 &trust_result, |
| 576 &completed_chain, |
| 577 &chain_info); |
| 564 } | 578 } |
| 565 | 579 |
| 566 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) | 580 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) |
| 567 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 581 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 568 | 582 |
| 569 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) | 583 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) |
| 570 verify_result->cert_status |= CERT_STATUS_REVOKED; | 584 verify_result->cert_status |= CERT_STATUS_REVOKED; |
| 571 | 585 |
| 572 GetCertChainInfo(completed_chain, chain_info, verify_result); | 586 GetCertChainInfo(completed_chain, chain_info, verify_result); |
| 573 | 587 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 601 if (status) | 615 if (status) |
| 602 return NetErrorFromOSStatus(status); | 616 return NetErrorFromOSStatus(status); |
| 603 if (cssm_result == CSSMERR_TP_VERIFY_ACTION_FAILED) { | 617 if (cssm_result == CSSMERR_TP_VERIFY_ACTION_FAILED) { |
| 604 policy_failed = true; | 618 policy_failed = true; |
| 605 } else { | 619 } else { |
| 606 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | 620 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); |
| 607 } | 621 } |
| 608 // Walk the chain of error codes in the CSSM_TP_APPLE_EVIDENCE_INFO | 622 // Walk the chain of error codes in the CSSM_TP_APPLE_EVIDENCE_INFO |
| 609 // structure which can catch multiple errors from each certificate. | 623 // structure which can catch multiple errors from each certificate. |
| 610 for (CFIndex index = 0, chain_count = CFArrayGetCount(completed_chain); | 624 for (CFIndex index = 0, chain_count = CFArrayGetCount(completed_chain); |
| 611 index < chain_count; ++index) { | 625 index < chain_count; |
| 626 ++index) { |
| 612 if (chain_info[index].StatusBits & CSSM_CERT_STATUS_EXPIRED || | 627 if (chain_info[index].StatusBits & CSSM_CERT_STATUS_EXPIRED || |
| 613 chain_info[index].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) | 628 chain_info[index].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) |
| 614 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 629 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 615 if (!IsCertStatusError(verify_result->cert_status) && | 630 if (!IsCertStatusError(verify_result->cert_status) && |
| 616 chain_info[index].NumStatusCodes == 0) { | 631 chain_info[index].NumStatusCodes == 0) { |
| 617 LOG(WARNING) << "chain_info[" << index << "].NumStatusCodes is 0" | 632 LOG(WARNING) << "chain_info[" << index << "].NumStatusCodes is 0" |
| 618 ", chain_info[" << index << "].StatusBits is " | 633 ", chain_info[" << index |
| 619 << chain_info[index].StatusBits; | 634 << "].StatusBits is " << chain_info[index].StatusBits; |
| 620 } | 635 } |
| 621 for (uint32 status_code_index = 0; | 636 for (uint32 status_code_index = 0; |
| 622 status_code_index < chain_info[index].NumStatusCodes; | 637 status_code_index < chain_info[index].NumStatusCodes; |
| 623 ++status_code_index) { | 638 ++status_code_index) { |
| 624 // As of OS X 10.9, attempting to verify a certificate chain that | 639 // As of OS X 10.9, attempting to verify a certificate chain that |
| 625 // contains a weak signature algorithm (MD2, MD5) in an intermediate | 640 // contains a weak signature algorithm (MD2, MD5) in an intermediate |
| 626 // or leaf cert will be treated as a (recoverable) policy validation | 641 // or leaf cert will be treated as a (recoverable) policy validation |
| 627 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE | 642 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE |
| 628 // added to the Status Codes. Don't treat this code as an invalid | 643 // added to the Status Codes. Don't treat this code as an invalid |
| 629 // certificate; instead, map it to a weak key. Any truly invalid | 644 // certificate; instead, map it to a weak key. Any truly invalid |
| 630 // certificates will have the major error (cssm_result) set to | 645 // certificates will have the major error (cssm_result) set to |
| 631 // CSSMERR_TP_INVALID_CERTIFICATE, rather than | 646 // CSSMERR_TP_INVALID_CERTIFICATE, rather than |
| 632 // CSSMERR_TP_VERIFY_ACTION_FAILED. | 647 // CSSMERR_TP_VERIFY_ACTION_FAILED. |
| 633 CertStatus mapped_status = 0; | 648 CertStatus mapped_status = 0; |
| 634 if (policy_failed && | 649 if (policy_failed && |
| 635 chain_info[index].StatusCodes[status_code_index] == | 650 chain_info[index].StatusCodes[status_code_index] == |
| 636 CSSMERR_TP_INVALID_CERTIFICATE) { | 651 CSSMERR_TP_INVALID_CERTIFICATE) { |
| 637 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; | 652 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; |
| 653 weak_key_or_signature_algorithm = true; |
| 654 } else { |
| 655 mapped_status = CertStatusFromOSStatus( |
| 656 chain_info[index].StatusCodes[status_code_index]); |
| 657 if (mapped_status == CERT_STATUS_WEAK_KEY) |
| 638 weak_key_or_signature_algorithm = true; | 658 weak_key_or_signature_algorithm = true; |
| 639 } else { | |
| 640 mapped_status = CertStatusFromOSStatus( | |
| 641 chain_info[index].StatusCodes[status_code_index]); | |
| 642 if (mapped_status == CERT_STATUS_WEAK_KEY) | |
| 643 weak_key_or_signature_algorithm = true; | |
| 644 } | 659 } |
| 645 verify_result->cert_status |= mapped_status; | 660 verify_result->cert_status |= mapped_status; |
| 646 } | 661 } |
| 647 } | 662 } |
| 648 if (policy_failed && !weak_key_or_signature_algorithm) { | 663 if (policy_failed && !weak_key_or_signature_algorithm) { |
| 649 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak | 664 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak |
| 650 // key, map it back to an appropriate error code. | 665 // key, map it back to an appropriate error code. |
| 651 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | 666 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); |
| 652 } | 667 } |
| 653 if (!IsCertStatusError(verify_result->cert_status)) { | 668 if (!IsCertStatusError(verify_result->cert_status)) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 | 705 |
| 691 if (flags & CertVerifier::VERIFY_EV_CERT) { | 706 if (flags & CertVerifier::VERIFY_EV_CERT) { |
| 692 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), | 707 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), |
| 693 // which is an internal/private API function added in OS X 10.5.7. | 708 // which is an internal/private API function added in OS X 10.5.7. |
| 694 // Note: "ExtendedResult" means extended validation results. | 709 // Note: "ExtendedResult" means extended validation results. |
| 695 CFBundleRef bundle = | 710 CFBundleRef bundle = |
| 696 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); | 711 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); |
| 697 if (bundle) { | 712 if (bundle) { |
| 698 SecTrustCopyExtendedResultFuncPtr copy_extended_result = | 713 SecTrustCopyExtendedResultFuncPtr copy_extended_result = |
| 699 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( | 714 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( |
| 700 CFBundleGetFunctionPointerForName(bundle, | 715 CFBundleGetFunctionPointerForName( |
| 701 CFSTR("SecTrustCopyExtendedResult"))); | 716 bundle, CFSTR("SecTrustCopyExtendedResult"))); |
| 702 if (copy_extended_result) { | 717 if (copy_extended_result) { |
| 703 CFDictionaryRef ev_dict_temp = NULL; | 718 CFDictionaryRef ev_dict_temp = NULL; |
| 704 status = copy_extended_result(trust_ref, &ev_dict_temp); | 719 status = copy_extended_result(trust_ref, &ev_dict_temp); |
| 705 ScopedCFTypeRef<CFDictionaryRef> ev_dict(ev_dict_temp); | 720 ScopedCFTypeRef<CFDictionaryRef> ev_dict(ev_dict_temp); |
| 706 ev_dict_temp = NULL; | 721 ev_dict_temp = NULL; |
| 707 if (status == noErr && ev_dict) { | 722 if (status == noErr && ev_dict) { |
| 708 // In 10.7.3, SecTrustCopyExtendedResult returns noErr and populates | 723 // In 10.7.3, SecTrustCopyExtendedResult returns noErr and populates |
| 709 // ev_dict even for non-EV certificates, but only EV certificates | 724 // ev_dict even for non-EV certificates, but only EV certificates |
| 710 // will cause ev_dict to contain kSecEVOrganizationName. In previous | 725 // will cause ev_dict to contain kSecEVOrganizationName. In previous |
| 711 // releases, SecTrustCopyExtendedResult would only return noErr and | 726 // releases, SecTrustCopyExtendedResult would only return noErr and |
| 712 // populate ev_dict for EV certificates, but would always include | 727 // populate ev_dict for EV certificates, but would always include |
| 713 // kSecEVOrganizationName in that case, so checking for this key is | 728 // kSecEVOrganizationName in that case, so checking for this key is |
| 714 // appropriate for all known versions of SecTrustCopyExtendedResult. | 729 // appropriate for all known versions of SecTrustCopyExtendedResult. |
| 715 // The actual organization name is unneeded here and can be accessed | 730 // The actual organization name is unneeded here and can be accessed |
| 716 // through other means. All that matters here is the OS' conception | 731 // through other means. All that matters here is the OS' conception |
| 717 // of whether or not the certificate is EV. | 732 // of whether or not the certificate is EV. |
| 718 if (CFDictionaryContainsKey(ev_dict, | 733 if (CFDictionaryContainsKey(ev_dict, kSecEVOrganizationName)) { |
| 719 kSecEVOrganizationName)) { | |
| 720 verify_result->cert_status |= CERT_STATUS_IS_EV; | 734 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 721 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) | 735 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) |
| 722 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 736 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 723 } | 737 } |
| 724 } | 738 } |
| 725 } | 739 } |
| 726 } | 740 } |
| 727 } | 741 } |
| 728 | 742 |
| 729 return OK; | 743 return OK; |
| 730 } | 744 } |
| 731 | 745 |
| 732 } // namespace net | 746 } // namespace net |
| OLD | NEW |