Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: net/cert/cert_verify_proc_mac.cc

Issue 14492003: Work around GTE CyberTrust/Baltimore CyberTrust cross-signing issues (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review feedback Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | net/cert/cert_verify_proc_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 int n = CFArrayGetCount(chain); 338 int n = CFArrayGetCount(chain);
339 if (n < 1) 339 if (n < 1)
340 return false; 340 return false;
341 SecCertificateRef root_ref = reinterpret_cast<SecCertificateRef>( 341 SecCertificateRef root_ref = reinterpret_cast<SecCertificateRef>(
342 const_cast<void*>(CFArrayGetValueAtIndex(chain, n - 1))); 342 const_cast<void*>(CFArrayGetValueAtIndex(chain, n - 1)));
343 SHA1HashValue hash = X509Certificate::CalculateFingerprint(root_ref); 343 SHA1HashValue hash = X509Certificate::CalculateFingerprint(root_ref);
344 return IsSHA1HashInSortedArray( 344 return IsSHA1HashInSortedArray(
345 hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes)); 345 hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes));
346 } 346 }
347 347
348 } // namespace 348 // Builds and evaluates a SecTrustRef for the certificate chain contained
349 349 // in |cert_array|, using the verification policies in |trust_policies|. On
350 CertVerifyProcMac::CertVerifyProcMac() {} 350 // success, returns OK, and updates |trust_ref|, |trust_result|,
351 351 // |verified_chain|, and |chain_info| with the verification results. On
352 CertVerifyProcMac::~CertVerifyProcMac() {} 352 // failure, no output parameters are modified.
353 353 //
354 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { 354 // Note: An OK return does not mean that |cert_array| is trusted, merely that
355 return false; 355 // verification was performed successfully.
356 } 356 //
357 357 // This function should only be called while the Mac Security Services lock is
358 int CertVerifyProcMac::VerifyInternal( 358 // held.
359 X509Certificate* cert, 359 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array,
360 const std::string& hostname, 360 CFArrayRef trust_policies,
361 int flags, 361 int flags,
362 CRLSet* crl_set, 362 ScopedCFTypeRef<SecTrustRef>* trust_ref,
363 const CertificateList& additional_trust_anchors, 363 SecTrustResultType* trust_result,
364 CertVerifyResult* verify_result) { 364 ScopedCFTypeRef<CFArrayRef>* verified_chain,
365 ScopedCFTypeRef<CFArrayRef> trust_policies; 365 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) {
366 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); 366 SecTrustRef tmp_trust = NULL;
367 OSStatus status = SecTrustCreateWithCertificates(cert_array, trust_policies,
368 &tmp_trust);
367 if (status) 369 if (status)
368 return NetErrorFromOSStatus(status); 370 return NetErrorFromOSStatus(status);
369 371 ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust);
370 // Create and configure a SecTrustRef, which takes our certificate(s)
371 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
372 // array of certificates, the first of which is the certificate we're
373 // verifying, and the subsequent (optional) certificates are used for
374 // chain building.
375 ScopedCFTypeRef<CFArrayRef> cert_array(cert->CreateOSCertChainForCert());
376
377 // Serialize all calls that may use the Keychain, to work around various
378 // issues in OS X 10.6+ with multi-threaded access to Security.framework.
379 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
380
381 SecTrustRef trust_ref = NULL;
382 status = SecTrustCreateWithCertificates(cert_array, trust_policies,
383 &trust_ref);
384 if (status)
385 return NetErrorFromOSStatus(status);
386 ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref);
387 372
388 if (TestRootCerts::HasInstance()) { 373 if (TestRootCerts::HasInstance()) {
389 status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref); 374 status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust);
390 if (status) 375 if (status)
391 return NetErrorFromOSStatus(status); 376 return NetErrorFromOSStatus(status);
392 } 377 }
393 378
394 CSSM_APPLE_TP_ACTION_DATA tp_action_data; 379 CSSM_APPLE_TP_ACTION_DATA tp_action_data;
395 memset(&tp_action_data, 0, sizeof(tp_action_data)); 380 memset(&tp_action_data, 0, sizeof(tp_action_data));
396 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; 381 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION;
397 // Allow CSSM to download any missing intermediate certificates if an 382 // Allow CSSM to download any missing intermediate certificates if an
398 // authorityInfoAccess extension or issuerAltName extension is present. 383 // authorityInfoAccess extension or issuerAltName extension is present.
399 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | 384 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET |
400 CSSM_TP_ACTION_TRUST_SETTINGS; 385 CSSM_TP_ACTION_TRUST_SETTINGS;
401 386
402 // Note: For EV certificates, the Apple TP will handle setting these flags 387 // Note: For EV certificates, the Apple TP will handle setting these flags
403 // as part of EV evaluation. 388 // as part of EV evaluation.
404 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) { 389 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) {
405 // Require a positive result from an OCSP responder or a CRL (or both) 390 // Require a positive result from an OCSP responder or a CRL (or both)
406 // for every certificate in the chain. The Apple TP automatically 391 // for every certificate in the chain. The Apple TP automatically
407 // excludes the self-signed root from this requirement. If a certificate 392 // excludes the self-signed root from this requirement. If a certificate
408 // is missing both a crlDistributionPoints extension and an 393 // is missing both a crlDistributionPoints extension and an
409 // authorityInfoAccess extension with an OCSP responder URL, then we 394 // authorityInfoAccess extension with an OCSP responder URL, then we
410 // will get a kSecTrustResultRecoverableTrustFailure back from 395 // will get a kSecTrustResultRecoverableTrustFailure back from
411 // SecTrustEvaluate(), with a 396 // SecTrustEvaluate(), with a
412 // CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK error code. In that case, 397 // CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK error code. In that case,
413 // we'll set our own result to include 398 // we'll set our own result to include
414 // CERT_STATUS_NO_REVOCATION_MECHANISM. If one or both extensions are 399 // CERT_STATUS_NO_REVOCATION_MECHANISM. If one or both extensions are
415 // present, and a check fails (server unavailable, OCSP retry later, 400 // present, and a check fails (server unavailable, OCSP retry later,
416 // signature mismatch), then we'll set our own result to include 401 // signature mismatch), then we'll set our own result to include
417 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. 402 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION.
418 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; 403 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT;
419 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
420 404
421 // Note, even if revocation checking is disabled, SecTrustEvaluate() will 405 // Note, even if revocation checking is disabled, SecTrustEvaluate() will
422 // modify the OCSP options so as to attempt OCSP checking if it believes a 406 // modify the OCSP options so as to attempt OCSP checking if it believes a
423 // certificate may chain to an EV root. However, because network fetches 407 // certificate may chain to an EV root. However, because network fetches
424 // are disabled in CreateTrustPolicies() when revocation checking is 408 // are disabled in CreateTrustPolicies() when revocation checking is
425 // disabled, these will only go against the local cache. 409 // disabled, these will only go against the local cache.
426 } 410 }
427 411
428 CFDataRef action_data_ref = 412 CFDataRef action_data_ref =
429 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 413 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
430 reinterpret_cast<UInt8*>(&tp_action_data), 414 reinterpret_cast<UInt8*>(&tp_action_data),
431 sizeof(tp_action_data), kCFAllocatorNull); 415 sizeof(tp_action_data), kCFAllocatorNull);
432 if (!action_data_ref) 416 if (!action_data_ref)
433 return ERR_OUT_OF_MEMORY; 417 return ERR_OUT_OF_MEMORY;
434 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); 418 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref);
435 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, 419 status = SecTrustSetParameters(tmp_trust, CSSM_TP_ACTION_DEFAULT,
436 action_data_ref); 420 action_data_ref);
437 if (status) 421 if (status)
438 return NetErrorFromOSStatus(status); 422 return NetErrorFromOSStatus(status);
439 423
440 // Verify the certificate. A non-zero result from SecTrustGetResult() 424 // Verify the certificate. A non-zero result from SecTrustGetResult()
441 // indicates that some fatal error occurred and the chain couldn't be 425 // indicates that some fatal error occurred and the chain couldn't be
442 // processed, not that the chain contains no errors. We need to examine the 426 // processed, not that the chain contains no errors. We need to examine the
443 // output of SecTrustGetResult() to determine that. 427 // output of SecTrustGetResult() to determine that.
444 SecTrustResultType trust_result; 428 SecTrustResultType tmp_trust_result;
445 status = SecTrustEvaluate(trust_ref, &trust_result); 429 status = SecTrustEvaluate(tmp_trust, &tmp_trust_result);
446 if (status) 430 if (status)
447 return NetErrorFromOSStatus(status); 431 return NetErrorFromOSStatus(status);
448 CFArrayRef completed_chain = NULL; 432 CFArrayRef tmp_verified_chain = NULL;
449 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; 433 CSSM_TP_APPLE_EVIDENCE_INFO* tmp_chain_info;
450 status = SecTrustGetResult(trust_ref, &trust_result, &completed_chain, 434 status = SecTrustGetResult(tmp_trust, &tmp_trust_result, &tmp_verified_chain,
451 &chain_info); 435 &tmp_chain_info);
452 if (status) 436 if (status)
453 return NetErrorFromOSStatus(status); 437 return NetErrorFromOSStatus(status);
454 ScopedCFTypeRef<CFArrayRef> scoped_completed_chain(completed_chain); 438
439 trust_ref->swap(scoped_tmp_trust);
440 *trust_result = tmp_trust_result;
441 verified_chain->reset(tmp_verified_chain);
442 *chain_info = tmp_chain_info;
443
444 return OK;
445 }
446
447 // OS X ships with both "GTE CyberTrust Global Root" and "Baltimore CyberTrust
448 // Root" as part of its trusted root store. However, a cross-certified version
449 // of the "Baltimore CyberTrust Root" exists that chains to "GTE CyberTrust
450 // Global Root". When OS X/Security.framework attempts to evaluate such a
451 // certificate chain, it disregards the "Baltimore CyberTrust Root" that exists
452 // within Keychain and instead attempts to terminate the chain in the "GTE
453 // CyberTrust Global Root". However, the GTE root is scheduled to be removed in
454 // a future OS X update (for sunsetting purposes), and once removed, such
455 // chains will fail validation, even though a trust anchor still exists.
456 //
457 // Rather than over-generalizing a solution that may mask a number of TLS
458 // misconfigurations, attempt to specifically match the affected
459 // cross-certified certificate and remove it from certificate chain processing.
460 bool IsBadBaltimoreGTECertificate(SecCertificateRef cert) {
461 // Matches the GTE-signed Baltimore CyberTrust Root
462 // https://cacert.omniroot.com/Baltimore-to-GTE-04-12.pem
463 static const SHA1HashValue kBadBaltimoreHashNew =
464 { { 0x4D, 0x34, 0xEA, 0x92, 0x76, 0x4B, 0x3A, 0x31, 0x49, 0x11,
465 0x99, 0x52, 0xF4, 0x19, 0x30, 0xCA, 0x11, 0x34, 0x83, 0x61 } };
466 // Matches the legacy GTE-signed Baltimore CyberTrust Root
467 // https://cacert.omniroot.com/gte-2-2025.pem
468 static const SHA1HashValue kBadBaltimoreHashOld =
469 { { 0x54, 0xD8, 0xCB, 0x49, 0x1F, 0xA1, 0x6D, 0xF8, 0x87, 0xDC,
470 0x94, 0xA9, 0x34, 0xCC, 0x83, 0x6B, 0xDA, 0xA8, 0xA3, 0x69 } };
471
472 SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(cert);
473
474 return fingerprint.Equals(kBadBaltimoreHashNew) ||
475 fingerprint.Equals(kBadBaltimoreHashOld);
476 }
477
478 // Attempts to re-verify |cert_array| after adjusting the inputs to work around
479 // known issues in OS X. To be used if BuildAndEvaluateSecTrustRef fails to
480 // return a positive result for verification.
481 //
482 // This function should only be called while the Mac Security Services lock is
483 // held.
484 void RetrySecTrustEvaluateWithAdjustedChain(
485 CFArrayRef cert_array,
486 CFArrayRef trust_policies,
487 int flags,
488 ScopedCFTypeRef<SecTrustRef>* trust_ref,
489 SecTrustResultType* trust_result,
490 ScopedCFTypeRef<CFArrayRef>* verified_chain,
491 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) {
492 CFIndex count = CFArrayGetCount(*verified_chain);
493 CFIndex slice_point = 0;
494
495 for (CFIndex i = 1; i < count; ++i) {
496 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
497 const_cast<void*>(CFArrayGetValueAtIndex(*verified_chain, i)));
498 if (cert == NULL)
499 return; // Strange times; can't fix things up.
500
501 if (IsBadBaltimoreGTECertificate(cert)) {
502 slice_point = i;
503 break;
504 }
505 }
506 if (slice_point == 0)
507 return; // Nothing to do.
508
509 ScopedCFTypeRef<CFMutableArrayRef> adjusted_cert_array(
510 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
511 // Note: This excludes the certificate at |slice_point|.
512 CFArrayAppendArray(adjusted_cert_array, cert_array,
513 CFRangeMake(0, slice_point));
514
515 // Ignore the result; failure will preserve the old verification results.
516 BuildAndEvaluateSecTrustRef(
517 adjusted_cert_array, trust_policies, flags, trust_ref, trust_result,
518 verified_chain, chain_info);
519 }
520
521 } // namespace
522
523 CertVerifyProcMac::CertVerifyProcMac() {}
524
525 CertVerifyProcMac::~CertVerifyProcMac() {}
526
527 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
528 return false;
529 }
530
531 int CertVerifyProcMac::VerifyInternal(
532 X509Certificate* cert,
533 const std::string& hostname,
534 int flags,
535 CRLSet* crl_set,
536 const CertificateList& additional_trust_anchors,
537 CertVerifyResult* verify_result) {
538 ScopedCFTypeRef<CFArrayRef> trust_policies;
539 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies);
540 if (status)
541 return NetErrorFromOSStatus(status);
542
543 // Create and configure a SecTrustRef, which takes our certificate(s)
544 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
545 // array of certificates, the first of which is the certificate we're
546 // verifying, and the subsequent (optional) certificates are used for
547 // chain building.
548 ScopedCFTypeRef<CFArrayRef> cert_array(cert->CreateOSCertChainForCert());
549
550 // Serialize all calls that may use the Keychain, to work around various
551 // issues in OS X 10.6+ with multi-threaded access to Security.framework.
552 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
553
554 ScopedCFTypeRef<SecTrustRef> trust_ref;
555 SecTrustResultType trust_result = kSecTrustResultDeny;
556 ScopedCFTypeRef<CFArrayRef> completed_chain;
557 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL;
558
559 int rv = BuildAndEvaluateSecTrustRef(
560 cert_array, trust_policies, flags, &trust_ref, &trust_result,
561 &completed_chain, &chain_info);
562 if (rv != OK)
563 return rv;
564 if (trust_result != kSecTrustResultUnspecified &&
565 trust_result != kSecTrustResultProceed) {
566 RetrySecTrustEvaluateWithAdjustedChain(
567 cert_array, trust_policies, flags, &trust_ref, &trust_result,
568 &completed_chain, &chain_info);
569 }
570
571 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)
572 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
455 573
456 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) 574 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set))
457 verify_result->cert_status |= CERT_STATUS_REVOKED; 575 verify_result->cert_status |= CERT_STATUS_REVOKED;
458 576
459 GetCertChainInfo(scoped_completed_chain.get(), chain_info, verify_result); 577 GetCertChainInfo(completed_chain, chain_info, verify_result);
460 578
461 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits 579 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits
462 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds 580 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds
463 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping 581 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping
464 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only 582 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only
465 // error was due to an unsupported key size. 583 // error was due to an unsupported key size.
466 bool policy_failed = false; 584 bool policy_failed = false;
467 bool weak_key = false; 585 bool weak_key = false;
468 586
469 // Evaluate the results 587 // Evaluate the results
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 } 710 }
593 } 711 }
594 } 712 }
595 } 713 }
596 } 714 }
597 715
598 return OK; 716 return OK;
599 } 717 }
600 718
601 } // namespace net 719 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/cert/cert_verify_proc_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698