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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | net/cert/cert_verify_proc_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/cert/cert_verify_proc_mac.cc
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index 77346df3b7973e148ecdf1bcd5fd893cc75e2fc7..da284d43c28c1166e8e130fcd3bc2e0bb695dd88 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -345,48 +345,33 @@ bool IsIssuedByKnownRoot(CFArrayRef chain) {
hash, &kKnownRootCertSHA1Hashes[0][0], sizeof(kKnownRootCertSHA1Hashes));
}
-} // namespace
-
-CertVerifyProcMac::CertVerifyProcMac() {}
-
-CertVerifyProcMac::~CertVerifyProcMac() {}
-
-bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
- return false;
-}
-
-int CertVerifyProcMac::VerifyInternal(
- X509Certificate* cert,
- const std::string& hostname,
- int flags,
- CRLSet* crl_set,
- const CertificateList& additional_trust_anchors,
- CertVerifyResult* verify_result) {
- ScopedCFTypeRef<CFArrayRef> trust_policies;
- OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies);
+// Builds and evaluates a SecTrustRef for the certificate chain contained
+// in |cert_array|, using the verification policies in |trust_policies|. On
+// success, returns OK, and updates |trust_ref|, |trust_result|,
+// |verified_chain|, and |chain_info| with the verification results. On
+// failure, no output parameters are modified.
+//
+// Note: An OK return does not mean that |cert_array| is trusted, merely that
+// verification was performed successfully.
+//
+// This function should only be called while the Mac Security Services lock is
+// held.
+int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array,
+ CFArrayRef trust_policies,
+ int flags,
+ ScopedCFTypeRef<SecTrustRef>* trust_ref,
+ SecTrustResultType* trust_result,
+ ScopedCFTypeRef<CFArrayRef>* verified_chain,
+ CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) {
+ SecTrustRef tmp_trust = NULL;
+ OSStatus status = SecTrustCreateWithCertificates(cert_array, trust_policies,
+ &tmp_trust);
if (status)
return NetErrorFromOSStatus(status);
-
- // Create and configure a SecTrustRef, which takes our certificate(s)
- // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
- // array of certificates, the first of which is the certificate we're
- // verifying, and the subsequent (optional) certificates are used for
- // chain building.
- ScopedCFTypeRef<CFArrayRef> cert_array(cert->CreateOSCertChainForCert());
-
- // Serialize all calls that may use the Keychain, to work around various
- // issues in OS X 10.6+ with multi-threaded access to Security.framework.
- base::AutoLock lock(crypto::GetMacSecurityServicesLock());
-
- SecTrustRef trust_ref = NULL;
- status = SecTrustCreateWithCertificates(cert_array, trust_policies,
- &trust_ref);
- if (status)
- return NetErrorFromOSStatus(status);
- ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref);
+ ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust);
if (TestRootCerts::HasInstance()) {
- status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref);
+ status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust);
if (status)
return NetErrorFromOSStatus(status);
}
@@ -416,7 +401,6 @@ int CertVerifyProcMac::VerifyInternal(
// signature mismatch), then we'll set our own result to include
// CERT_STATUS_UNABLE_TO_CHECK_REVOCATION.
tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT;
- verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
// Note, even if revocation checking is disabled, SecTrustEvaluate() will
// modify the OCSP options so as to attempt OCSP checking if it believes a
@@ -432,7 +416,7 @@ int CertVerifyProcMac::VerifyInternal(
if (!action_data_ref)
return ERR_OUT_OF_MEMORY;
ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref);
- status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT,
+ status = SecTrustSetParameters(tmp_trust, CSSM_TP_ACTION_DEFAULT,
action_data_ref);
if (status)
return NetErrorFromOSStatus(status);
@@ -441,22 +425,156 @@ int CertVerifyProcMac::VerifyInternal(
// indicates that some fatal error occurred and the chain couldn't be
// processed, not that the chain contains no errors. We need to examine the
// output of SecTrustGetResult() to determine that.
- SecTrustResultType trust_result;
- status = SecTrustEvaluate(trust_ref, &trust_result);
+ SecTrustResultType tmp_trust_result;
+ status = SecTrustEvaluate(tmp_trust, &tmp_trust_result);
if (status)
return NetErrorFromOSStatus(status);
- CFArrayRef completed_chain = NULL;
- CSSM_TP_APPLE_EVIDENCE_INFO* chain_info;
- status = SecTrustGetResult(trust_ref, &trust_result, &completed_chain,
- &chain_info);
+ CFArrayRef tmp_verified_chain = NULL;
+ CSSM_TP_APPLE_EVIDENCE_INFO* tmp_chain_info;
+ status = SecTrustGetResult(tmp_trust, &tmp_trust_result, &tmp_verified_chain,
+ &tmp_chain_info);
if (status)
return NetErrorFromOSStatus(status);
- ScopedCFTypeRef<CFArrayRef> scoped_completed_chain(completed_chain);
+
+ trust_ref->swap(scoped_tmp_trust);
+ *trust_result = tmp_trust_result;
+ verified_chain->reset(tmp_verified_chain);
+ *chain_info = tmp_chain_info;
+
+ return OK;
+}
+
+// OS X ships with both "GTE CyberTrust Global Root" and "Baltimore CyberTrust
+// Root" as part of its trusted root store. However, a cross-certified version
+// of the "Baltimore CyberTrust Root" exists that chains to "GTE CyberTrust
+// Global Root". When OS X/Security.framework attempts to evaluate such a
+// certificate chain, it disregards the "Baltimore CyberTrust Root" that exists
+// within Keychain and instead attempts to terminate the chain in the "GTE
+// CyberTrust Global Root". However, the GTE root is scheduled to be removed in
+// a future OS X update (for sunsetting purposes), and once removed, such
+// chains will fail validation, even though a trust anchor still exists.
+//
+// Rather than over-generalizing a solution that may mask a number of TLS
+// misconfigurations, attempt to specifically match the affected
+// cross-certified certificate and remove it from certificate chain processing.
+bool IsBadBaltimoreGTECertificate(SecCertificateRef cert) {
+ // Matches the GTE-signed Baltimore CyberTrust Root
+ // https://cacert.omniroot.com/Baltimore-to-GTE-04-12.pem
+ static const SHA1HashValue kBadBaltimoreHashNew =
+ { { 0x4D, 0x34, 0xEA, 0x92, 0x76, 0x4B, 0x3A, 0x31, 0x49, 0x11,
+ 0x99, 0x52, 0xF4, 0x19, 0x30, 0xCA, 0x11, 0x34, 0x83, 0x61 } };
+ // Matches the legacy GTE-signed Baltimore CyberTrust Root
+ // https://cacert.omniroot.com/gte-2-2025.pem
+ static const SHA1HashValue kBadBaltimoreHashOld =
+ { { 0x54, 0xD8, 0xCB, 0x49, 0x1F, 0xA1, 0x6D, 0xF8, 0x87, 0xDC,
+ 0x94, 0xA9, 0x34, 0xCC, 0x83, 0x6B, 0xDA, 0xA8, 0xA3, 0x69 } };
+
+ SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(cert);
+
+ return fingerprint.Equals(kBadBaltimoreHashNew) ||
+ fingerprint.Equals(kBadBaltimoreHashOld);
+}
+
+// Attempts to re-verify |cert_array| after adjusting the inputs to work around
+// known issues in OS X. To be used if BuildAndEvaluateSecTrustRef fails to
+// return a positive result for verification.
+//
+// This function should only be called while the Mac Security Services lock is
+// held.
+void RetrySecTrustEvaluateWithAdjustedChain(
+ CFArrayRef cert_array,
+ CFArrayRef trust_policies,
+ int flags,
+ ScopedCFTypeRef<SecTrustRef>* trust_ref,
+ SecTrustResultType* trust_result,
+ ScopedCFTypeRef<CFArrayRef>* verified_chain,
+ CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) {
+ CFIndex count = CFArrayGetCount(*verified_chain);
+ CFIndex slice_point = 0;
+
+ for (CFIndex i = 1; i < count; ++i) {
+ SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(*verified_chain, i)));
+ if (cert == NULL)
+ return; // Strange times; can't fix things up.
+
+ if (IsBadBaltimoreGTECertificate(cert)) {
+ slice_point = i;
+ break;
+ }
+ }
+ if (slice_point == 0)
+ return; // Nothing to do.
+
+ ScopedCFTypeRef<CFMutableArrayRef> adjusted_cert_array(
+ CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
+ // Note: This excludes the certificate at |slice_point|.
+ CFArrayAppendArray(adjusted_cert_array, cert_array,
+ CFRangeMake(0, slice_point));
+
+ // Ignore the result; failure will preserve the old verification results.
+ BuildAndEvaluateSecTrustRef(
+ adjusted_cert_array, trust_policies, flags, trust_ref, trust_result,
+ verified_chain, chain_info);
+}
+
+} // namespace
+
+CertVerifyProcMac::CertVerifyProcMac() {}
+
+CertVerifyProcMac::~CertVerifyProcMac() {}
+
+bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
+ return false;
+}
+
+int CertVerifyProcMac::VerifyInternal(
+ X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CRLSet* crl_set,
+ const CertificateList& additional_trust_anchors,
+ CertVerifyResult* verify_result) {
+ ScopedCFTypeRef<CFArrayRef> trust_policies;
+ OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies);
+ if (status)
+ return NetErrorFromOSStatus(status);
+
+ // Create and configure a SecTrustRef, which takes our certificate(s)
+ // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
+ // array of certificates, the first of which is the certificate we're
+ // verifying, and the subsequent (optional) certificates are used for
+ // chain building.
+ ScopedCFTypeRef<CFArrayRef> cert_array(cert->CreateOSCertChainForCert());
+
+ // Serialize all calls that may use the Keychain, to work around various
+ // issues in OS X 10.6+ with multi-threaded access to Security.framework.
+ base::AutoLock lock(crypto::GetMacSecurityServicesLock());
+
+ ScopedCFTypeRef<SecTrustRef> trust_ref;
+ SecTrustResultType trust_result = kSecTrustResultDeny;
+ ScopedCFTypeRef<CFArrayRef> completed_chain;
+ CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL;
+
+ int rv = BuildAndEvaluateSecTrustRef(
+ cert_array, trust_policies, flags, &trust_ref, &trust_result,
+ &completed_chain, &chain_info);
+ if (rv != OK)
+ return rv;
+ if (trust_result != kSecTrustResultUnspecified &&
+ trust_result != kSecTrustResultProceed) {
+ RetrySecTrustEvaluateWithAdjustedChain(
+ cert_array, trust_policies, flags, &trust_ref, &trust_result,
+ &completed_chain, &chain_info);
+ }
+
+ if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)
+ verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set))
verify_result->cert_status |= CERT_STATUS_REVOKED;
- GetCertChainInfo(scoped_completed_chain.get(), chain_info, verify_result);
+ GetCertChainInfo(completed_chain, chain_info, verify_result);
// As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits
// is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds
« 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