diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/cert/ct_policy_enforcer.cc | 86 | ||||
-rw-r--r-- | net/cert/ct_policy_enforcer.h | 28 | ||||
-rw-r--r-- | net/cert/ct_policy_enforcer_unittest.cc | 79 | ||||
-rw-r--r-- | net/cert/ct_policy_status.h | 39 | ||||
-rw-r--r-- | net/cert/ct_verify_result.cc | 6 | ||||
-rw-r--r-- | net/cert/ct_verify_result.h | 15 | ||||
-rw-r--r-- | net/net.gypi | 1 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium.cc | 18 | ||||
-rw-r--r-- | net/quic/crypto/proof_verifier_chromium_test.cc | 24 | ||||
-rw-r--r-- | net/quic/quic_chromium_client_session.cc | 2 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 22 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.h | 2 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.cc | 22 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.h | 5 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 15 | ||||
-rw-r--r-- | net/ssl/ssl_info.cc | 14 | ||||
-rw-r--r-- | net/ssl/ssl_info.h | 32 |
17 files changed, 280 insertions, 130 deletions
diff --git a/net/cert/ct_policy_enforcer.cc b/net/cert/ct_policy_enforcer.cc index 32181d4..aa8838b 100644 --- a/net/cert/ct_policy_enforcer.cc +++ b/net/cert/ct_policy_enforcer.cc @@ -19,6 +19,7 @@ #include "base/version.h" #include "net/cert/ct_ev_whitelist.h" #include "net/cert/ct_known_logs.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verify_result.h" #include "net/cert/signed_certificate_timestamp.h" #include "net/cert/x509_certificate.h" @@ -78,11 +79,10 @@ void RoundedDownMonthDifference(const base::Time& start, } bool HasRequiredNumberOfSCTs(const X509Certificate& cert, - const ct::CTVerifyResult& ct_result) { - size_t num_valid_scts = ct_result.verified_scts.size(); + const ct::SCTList& verified_scts) { + size_t num_valid_scts = verified_scts.size(); size_t num_embedded_scts = base::checked_cast<size_t>( - std::count_if(ct_result.verified_scts.begin(), - ct_result.verified_scts.end(), IsEmbeddedSCT)); + std::count_if(verified_scts.begin(), verified_scts.end(), IsEmbeddedSCT)); size_t num_non_embedded_scts = num_valid_scts - num_embedded_scts; // If at least two valid SCTs were delivered by means other than embedding @@ -166,8 +166,8 @@ enum EVWhitelistStatus { EV_WHITELIST_MAX, }; -void LogCTComplianceStatusToUMA(CTComplianceStatus status, - const ct::EVCertsWhitelist* ev_whitelist) { +void LogCTEVComplianceStatusToUMA(CTComplianceStatus status, + const ct::EVCertsWhitelist* ev_whitelist) { UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status, CT_COMPLIANCE_MAX); if (status == CT_NOT_COMPLIANT) { @@ -185,18 +185,11 @@ void LogCTComplianceStatusToUMA(CTComplianceStatus status, } struct ComplianceDetails { - ComplianceDetails() - : ct_presence_required(false), - build_timely(false), - status(CT_NOT_COMPLIANT) {} - - // Whether enforcement of the policy was required or not. - bool ct_presence_required; - // Whether the build is not older than 10 weeks. The value is meaningful only - // if |ct_presence_required| is true. + ComplianceDetails() : build_timely(false), status(CT_NOT_COMPLIANT) {} + + // Whether the build is not older than 10 weeks. bool build_timely; - // Compliance status - meaningful only if |ct_presence_required| and - // |build_timely| are true. + // Compliance status - meaningful only if |build_timely| is true. CTComplianceStatus status; // EV whitelist version. base::Version whitelist_version; @@ -208,17 +201,14 @@ scoped_ptr<base::Value> NetLogComplianceCheckResultCallback( NetLogCaptureMode capture_mode) { scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); dict->Set("certificate", NetLogX509CertificateCallback(cert, capture_mode)); - dict->SetBoolean("policy_enforcement_required", - details->ct_presence_required); - if (details->ct_presence_required) { - dict->SetBoolean("build_timely", details->build_timely); - if (details->build_timely) { - dict->SetString("ct_compliance_status", - ComplianceStatusToString(details->status)); - if (details->whitelist_version.IsValid()) - dict->SetString("ev_whitelist_version", - details->whitelist_version.GetString()); - } + dict->SetBoolean("policy_enforcement_required", true); + dict->SetBoolean("build_timely", details->build_timely); + if (details->build_timely) { + dict->SetString("ct_compliance_status", + ComplianceStatusToString(details->status)); + if (details->whitelist_version.IsValid()) + dict->SetString("ev_whitelist_version", + details->whitelist_version.GetString()); } return std::move(dict); } @@ -259,10 +249,8 @@ bool IsCertificateInWhitelist(const X509Certificate& cert, void CheckCTEVPolicyCompliance(X509Certificate* cert, const ct::EVCertsWhitelist* ev_whitelist, - const ct::CTVerifyResult& ct_result, + const ct::SCTList& verified_scts, ComplianceDetails* result) { - result->ct_presence_required = true; - if (!IsBuildTimely()) return; result->build_timely = true; @@ -275,14 +263,13 @@ void CheckCTEVPolicyCompliance(X509Certificate* cert, return; } - if (!HasRequiredNumberOfSCTs(*cert, ct_result)) { + if (!HasRequiredNumberOfSCTs(*cert, verified_scts)) { result->status = CT_NOT_COMPLIANT; return; } - if (AllSCTsPastDistinctSCTRequirementEnforcementDate( - ct_result.verified_scts) && - !HasEnoughDiverseSCTs(ct_result.verified_scts)) { + if (AllSCTsPastDistinctSCTRequirementEnforcementDate(verified_scts) && + !HasEnoughDiverseSCTs(verified_scts)) { result->status = CT_NOT_ENOUGH_DIVERSE_SCTS; return; } @@ -292,14 +279,14 @@ void CheckCTEVPolicyCompliance(X509Certificate* cert, } // namespace -bool CTPolicyEnforcer::DoesConformToCTEVPolicy( +ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy( X509Certificate* cert, const ct::EVCertsWhitelist* ev_whitelist, - const ct::CTVerifyResult& ct_result, + const ct::SCTList& verified_scts, const BoundNetLog& net_log) { ComplianceDetails details; - CheckCTEVPolicyCompliance(cert, ev_whitelist, ct_result, &details); + CheckCTEVPolicyCompliance(cert, ev_whitelist, verified_scts, &details); NetLog::ParametersCallback net_log_callback = base::Bind(&NetLogComplianceCheckResultCallback, base::Unretained(cert), @@ -308,18 +295,25 @@ bool CTPolicyEnforcer::DoesConformToCTEVPolicy( net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED, net_log_callback); - if (!details.ct_presence_required) - return true; - if (!details.build_timely) - return false; + return ct::EVPolicyCompliance::EV_POLICY_BUILD_NOT_TIMELY; - LogCTComplianceStatusToUMA(details.status, ev_whitelist); + LogCTEVComplianceStatusToUMA(details.status, ev_whitelist); - if (details.status == CT_IN_WHITELIST || details.status == CT_ENOUGH_SCTS) - return true; + switch (details.status) { + case CT_NOT_COMPLIANT: + return ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS; + case CT_IN_WHITELIST: + return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST; + case CT_ENOUGH_SCTS: + return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS; + case CT_NOT_ENOUGH_DIVERSE_SCTS: + return ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS; + case CT_COMPLIANCE_MAX: + return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; + } - return false; + return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; } } // namespace net diff --git a/net/cert/ct_policy_enforcer.h b/net/cert/ct_policy_enforcer.h index 8c29da5e..a2db8f0 100644 --- a/net/cert/ct_policy_enforcer.h +++ b/net/cert/ct_policy_enforcer.h @@ -1,25 +1,30 @@ // Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + #ifndef NET_CERT_CT_POLICY_ENFORCER_H #define NET_CERT_CT_POLICY_ENFORCER_H #include <stddef.h> +#include <vector> #include "net/base/net_export.h" +#include "net/cert/signed_certificate_timestamp.h" #include "net/log/net_log.h" namespace net { namespace ct { -struct CTVerifyResult; class EVCertsWhitelist; +enum class EVPolicyCompliance; } // namespace ct class X509Certificate; +using SCTList = std::vector<scoped_refptr<ct::SignedCertificateTimestamp>>; + // Class for checking that a given certificate conforms to security-related // policies. class NET_EXPORT CTPolicyEnforcer { @@ -27,16 +32,17 @@ class NET_EXPORT CTPolicyEnforcer { CTPolicyEnforcer() {} virtual ~CTPolicyEnforcer() {} - // Returns true if the collection of SCTs for the given certificate - // conforms with the CT/EV policy. Conformance details are logged to - // |net_log|. - // |cert| is the certificate for which the SCTs apply. - // |ct_result| must contain the result of verifying any SCTs associated with - // |cert| prior to invoking this method. - virtual bool DoesConformToCTEVPolicy(X509Certificate* cert, - const ct::EVCertsWhitelist* ev_whitelist, - const ct::CTVerifyResult& ct_result, - const BoundNetLog& net_log); + // Returns the CT/EV policy compliance status for a given certificate + // and collection of SCTs. + // |cert| is the certificate for which to check compliance, and + // |verified_scts| contains any/all SCTs associated with |cert| that + // have been verified (well-formed, issued by known logs, and applying to + // |cert|). + virtual ct::EVPolicyCompliance DoesConformToCTEVPolicy( + X509Certificate* cert, + const ct::EVCertsWhitelist* ev_whitelist, + const SCTList& verified_scts, + const BoundNetLog& net_log); }; } // namespace net diff --git a/net/cert/ct_policy_enforcer_unittest.cc b/net/cert/ct_policy_enforcer_unittest.cc index 4355252..c6c61b3 100644 --- a/net/cert/ct_policy_enforcer_unittest.cc +++ b/net/cert/ct_policy_enforcer_unittest.cc @@ -12,6 +12,7 @@ #include "crypto/sha2.h" #include "net/base/test_data_directory.h" #include "net/cert/ct_ev_whitelist.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verify_result.h" #include "net/cert/x509_certificate.h" #include "net/test/cert_test_util.h" @@ -65,6 +66,8 @@ class CTPolicyEnforcerTest : public ::testing::Test { non_google_log_id_.assign(crypto::kSHA256Length, 'A'); } + // TODO(eranm): Remove the use of CTVerifyResult in this file and just + // use lists of verified SCTs. https://crbug.com/587921 void FillResultWithSCTsOfOrigin( ct::SignedCertificateTimestamp::Origin desired_origin, size_t num_scts, @@ -123,15 +126,17 @@ class CTPolicyEnforcerTest : public ::testing::Test { for (size_t i = 0; i < required_scts - 1; ++i) { FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, std::vector<std::string>(), false, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - cert.get(), nullptr, result, BoundNetLog())) + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + cert.get(), nullptr, result.verified_scts, BoundNetLog())) << " for: " << (end - start).InDays() << " and " << required_scts << " scts=" << result.verified_scts.size() << " i=" << i; } FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, std::vector<std::string>(), false, &result); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy( - cert.get(), nullptr, result, BoundNetLog())) + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + cert.get(), nullptr, result.verified_scts, BoundNetLog())) << " for: " << (end - start).InDays() << " and " << required_scts << " scts=" << result.verified_scts.size(); } @@ -148,8 +153,9 @@ TEST_F(CTPolicyEnforcerTest, ct::CTVerifyResult result; FillResultWithRepeatedLogID(google_log_id_, 2, true, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), nullptr, result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, @@ -157,16 +163,18 @@ TEST_F(CTPolicyEnforcerTest, ct::CTVerifyResult result; FillResultWithRepeatedLogID(non_google_log_id_, 2, true, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), nullptr, result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyIfSCTBeforeEnforcementDate) { ct::CTVerifyResult result; FillResultWithRepeatedLogID(non_google_log_id_, 2, false, &result); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, - result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) { @@ -174,8 +182,9 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) { FillResultWithSCTsOfOrigin( ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, 2, &result); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, - result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) { @@ -184,8 +193,9 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) { FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5, &result); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, - result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) { @@ -198,14 +208,18 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) { FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), non_including_whitelist.get(), result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), non_including_whitelist.get(), + result.verified_scts, BoundNetLog())); // ... but should be OK if whitelisted. scoped_refptr<ct::EVCertsWhitelist> whitelist( new DummyEVCertsWhitelist(true, true)); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), whitelist.get(), result, BoundNetLog())); + EXPECT_EQ( + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, DoesNotConformToPolicyInvalidDates) { @@ -214,13 +228,17 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToPolicyInvalidDates) { ct::CTVerifyResult result; FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - no_valid_dates_cert.get(), nullptr, result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + no_valid_dates_cert.get(), nullptr, result.verified_scts, + BoundNetLog())); // ... but should be OK if whitelisted. scoped_refptr<ct::EVCertsWhitelist> whitelist( new DummyEVCertsWhitelist(true, true)); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), whitelist.get(), result, BoundNetLog())); + EXPECT_EQ( + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, @@ -274,8 +292,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToPolicyByEVWhitelistPresence) { ct::CTVerifyResult result; FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, &result); - EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), whitelist.get(), result, BoundNetLog())); + EXPECT_EQ( + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, IgnoresInvalidEVWhitelist) { @@ -285,16 +305,19 @@ TEST_F(CTPolicyEnforcerTest, IgnoresInvalidEVWhitelist) { ct::CTVerifyResult result; FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), whitelist.get(), result, BoundNetLog())); + EXPECT_EQ( + ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog())); } TEST_F(CTPolicyEnforcerTest, IgnoresNullEVWhitelist) { ct::CTVerifyResult result; FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1, &result); - EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy( - chain_.get(), nullptr, result, BoundNetLog())); + EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS, + policy_enforcer_->DoesConformToCTEVPolicy( + chain_.get(), nullptr, result.verified_scts, BoundNetLog())); } } // namespace diff --git a/net/cert/ct_policy_status.h b/net/cert/ct_policy_status.h new file mode 100644 index 0000000..e234cb7 --- /dev/null +++ b/net/cert/ct_policy_status.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_CERT_CT_POLICY_STATUS_H +#define NET_CERT_CT_POLICY_STATUS_H + +namespace net { + +namespace ct { + +// Information about a connection's compliance with the CT EV +// certificate policy. +enum class EVPolicyCompliance { + // The certificate was not EV, so the EV policy doesn't apply. + EV_POLICY_DOES_NOT_APPLY, + // The connection complied with the EV certificate policy by being + // included on the EV whitelist. + EV_POLICY_COMPLIES_VIA_WHITELIST, + // The connection complied with the EV certificate policy by + // including SCTs that satisfy the policy. + EV_POLICY_COMPLIES_VIA_SCTS, + // The connection did not have enough SCTs to retain its EV + // status. + EV_POLICY_NOT_ENOUGH_SCTS, + // The connection did not have diverse enough SCTs to retain its + // EV status. + EV_POLICY_NOT_DIVERSE_SCTS, + // The connection cannot be considered compliant because the build + // isn't timely and therefore log information might be out of date + // (for example a log might no longer be considered trustworthy). + EV_POLICY_BUILD_NOT_TIMELY, +}; + +} // namespace ct + +} // namespace net + +#endif // NET_CERT_CT_POLICY_STATUS_H diff --git a/net/cert/ct_verify_result.cc b/net/cert/ct_verify_result.cc index c62a18a..5e89b8f 100644 --- a/net/cert/ct_verify_result.cc +++ b/net/cert/ct_verify_result.cc @@ -4,11 +4,15 @@ #include "net/cert/ct_verify_result.h" +#include "net/cert/ct_policy_status.h" + namespace net { namespace ct { -CTVerifyResult::CTVerifyResult() {} +CTVerifyResult::CTVerifyResult() + : ct_policies_applied(false), + ev_policy_compliance(ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY) {} CTVerifyResult::~CTVerifyResult() {} diff --git a/net/cert/ct_verify_result.h b/net/cert/ct_verify_result.h index aa90164..e434fb8 100644 --- a/net/cert/ct_verify_result.h +++ b/net/cert/ct_verify_result.h @@ -7,17 +7,20 @@ #include <vector> +#include "net/cert/ct_policy_enforcer.h" #include "net/cert/signed_certificate_timestamp.h" namespace net { namespace ct { +enum class EVPolicyCompliance; + typedef std::vector<scoped_refptr<SignedCertificateTimestamp> > SCTList; -// Holds Signed Certificate Timestamps, depending on their verification results. -// More information could be tracked here about SCTs, but for the current UI -// this categorization is enough. +// Holds Signed Certificate Timestamps, depending on their verification +// results, and information about CT policies that were applied on the +// connection. struct NET_EXPORT CTVerifyResult { CTVerifyResult(); ~CTVerifyResult(); @@ -28,6 +31,12 @@ struct NET_EXPORT CTVerifyResult { SCTList invalid_scts; // SCTs from unknown logs and as such are unverifiable. SCTList unknown_logs_scts; + + // True if any CT policies were applied on this connection. + bool ct_policies_applied; + // The result of evaluating whether the connection complies with the + // EV CT policy. + EVPolicyCompliance ev_policy_compliance; }; } // namespace ct diff --git a/net/net.gypi b/net/net.gypi index c95a6cb..15f12c5 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -88,6 +88,7 @@ 'cert/ct_known_logs_static.h', 'cert/ct_policy_enforcer.cc', 'cert/ct_policy_enforcer.h', + 'cert/ct_policy_status.h', 'cert/ct_verifier.h', 'cert/ct_verify_result.cc', 'cert/ct_verify_result.h', diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc index e9191a7..9e3b2ec 100644 --- a/net/quic/crypto/proof_verifier_chromium.cc +++ b/net/quic/crypto/proof_verifier_chromium.cc @@ -23,6 +23,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/cert_verify_result.h" #include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verifier.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" @@ -284,12 +285,25 @@ int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) { const CertVerifyResult& cert_verify_result = verify_details_->cert_verify_result; const CertStatus cert_status = cert_verify_result.cert_status; + verify_details_->ct_verify_result.ct_policies_applied = + (result == OK && policy_enforcer_ != nullptr); + verify_details_->ct_verify_result.ev_policy_compliance = + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; if (result == OK && policy_enforcer_ && (cert_verify_result.cert_status & CERT_STATUS_IS_EV)) { - if (!policy_enforcer_->DoesConformToCTEVPolicy( + ct::EVPolicyCompliance ev_policy_compliance = + policy_enforcer_->DoesConformToCTEVPolicy( cert_verify_result.verified_cert.get(), SSLConfigService::GetEVCertsWhitelist().get(), - verify_details_->ct_verify_result, net_log_)) { + verify_details_->ct_verify_result.verified_scts, net_log_); + verify_details_->ct_verify_result.ev_policy_compliance = + ev_policy_compliance; + if (ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) { verify_details_->cert_verify_result.cert_status |= CERT_STATUS_CT_COMPLIANCE_FAILED; verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV; diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc index ddd4c94..19ccdef 100644 --- a/net/quic/crypto/proof_verifier_chromium_test.cc +++ b/net/quic/crypto/proof_verifier_chromium_test.cc @@ -12,6 +12,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/ct_log_verifier.h" #include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_serialization.h" #include "net/cert/ct_verify_result.h" #include "net/cert/mock_cert_verifier.h" @@ -56,13 +57,14 @@ class FailsTestCTPolicyEnforcer : public CTPolicyEnforcer { FailsTestCTPolicyEnforcer() {} ~FailsTestCTPolicyEnforcer() override {} - bool DoesConformToCTEVPolicy(X509Certificate* cert, - const ct::EVCertsWhitelist* ev_whitelist, - const ct::CTVerifyResult& ct_result, - const BoundNetLog& net_log) override { + ct::EVPolicyCompliance DoesConformToCTEVPolicy( + X509Certificate* cert, + const ct::EVCertsWhitelist* ev_whitelist, + const ct::SCTList& verified_scts, + const BoundNetLog& net_log) override { ADD_FAILURE() << "CTPolicyEnforcer::DoesConformToCTEVPolicy() should " << "not be called"; - return false; + return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; } }; @@ -73,11 +75,13 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer { MockCTPolicyEnforcer(bool is_ev) : is_ev_(is_ev) {} ~MockCTPolicyEnforcer() override {} - bool DoesConformToCTEVPolicy(X509Certificate* cert, - const ct::EVCertsWhitelist* ev_whitelist, - const ct::CTVerifyResult& ct_result, - const BoundNetLog& net_log) override { - return is_ev_; + ct::EVPolicyCompliance DoesConformToCTEVPolicy( + X509Certificate* cert, + const ct::EVCertsWhitelist* ev_whitelist, + const ct::SCTList& verified_scts, + const BoundNetLog& net_log) override { + return is_ev_ ? ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS + : ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS; } private: diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index d68f3bb..cb4f5ae 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc @@ -510,7 +510,7 @@ bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const { ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL; ssl_info->pinning_failure_log = pinning_failure_log_; - ssl_info->UpdateSignedCertificateTimestamps(*ct_verify_result_); + ssl_info->UpdateCertificateTransparencyInfo(*ct_verify_result_); return true; } diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 5619247..9526c1c 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -95,6 +95,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/ct_ev_whitelist.h" #include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verifier.h" #include "net/cert/ct_verify_result.h" #include "net/cert/scoped_nss_types.h" @@ -2410,7 +2411,7 @@ bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { ssl_info->cert = server_cert_verify_result_.verified_cert; ssl_info->unverified_cert = core_->state().server_cert; - AddSCTInfoToSSLInfo(ssl_info); + AddCTInfoToSSLInfo(ssl_info); ssl_info->connection_status = core_->state().ssl_connection_status; @@ -3126,13 +3127,24 @@ void SSLClientSocketNSS::VerifyCT() { // TODO(ekasper): wipe stapled_ocsp_response and sct_list_from_tls_extension // from the state after verification is complete, to conserve memory. + ct_verify_result_.ct_policies_applied = (policy_enforcer_ != nullptr); + ct_verify_result_.ev_policy_compliance = + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; if (policy_enforcer_ && (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV)) { scoped_refptr<ct::EVCertsWhitelist> ev_whitelist = SSLConfigService::GetEVCertsWhitelist(); - if (!policy_enforcer_->DoesConformToCTEVPolicy( + ct::EVPolicyCompliance ev_policy_compliance = + policy_enforcer_->DoesConformToCTEVPolicy( server_cert_verify_result_.verified_cert.get(), ev_whitelist.get(), - ct_verify_result_, net_log_)) { + ct_verify_result_.verified_scts, net_log_); + ct_verify_result_.ev_policy_compliance = ev_policy_compliance; + if (ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) { // TODO(eranm): Log via the BoundNetLog, see crbug.com/437766 VLOG(1) << "EV certificate for " << server_cert_verify_result_.verified_cert->subject() @@ -3158,8 +3170,8 @@ bool SSLClientSocketNSS::CalledOnValidThread() const { return valid_thread_id_ == base::PlatformThread::CurrentId(); } -void SSLClientSocketNSS::AddSCTInfoToSSLInfo(SSLInfo* ssl_info) const { - ssl_info->UpdateSignedCertificateTimestamps(ct_verify_result_); +void SSLClientSocketNSS::AddCTInfoToSSLInfo(SSLInfo* ssl_info) const { + ssl_info->UpdateCertificateTransparencyInfo(ct_verify_result_); } // static diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index d8a1549..0df9d4f 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -146,7 +146,7 @@ class SSLClientSocketNSS : public SSLClientSocket { // vetor representing a particular verification state, this method associates // each of the SCTs with the corresponding SCTVerifyStatus as it adds it to // the |ssl_info|.signed_certificate_timestamps list. - void AddSCTInfoToSSLInfo(SSLInfo* ssl_info) const; + void AddCTInfoToSSLInfo(SSLInfo* ssl_info) const; // Move last protocol to first place: SSLConfig::next_protos has protocols in // decreasing order of preference with NPN fallback protocol at the end, but diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 4b09828..b92c4a8 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -39,6 +39,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/ct_ev_whitelist.h" #include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verifier.h" #include "net/cert/x509_certificate_net_log_param.h" #include "net/cert/x509_util_openssl.h" @@ -867,7 +868,7 @@ bool SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { ssl_info->token_binding_key_param = tb_negotiated_param_; ssl_info->pinning_failure_log = pinning_failure_log_; - AddSCTInfoToSSLInfo(ssl_info); + AddCTInfoToSSLInfo(ssl_info); const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_); CHECK(cipher); @@ -1479,13 +1480,24 @@ void SSLClientSocketOpenSSL::VerifyCT() { server_cert_verify_result_.verified_cert.get(), ocsp_response, sct_list, &ct_verify_result_, net_log_); + ct_verify_result_.ct_policies_applied = (policy_enforcer_ != nullptr); + ct_verify_result_.ev_policy_compliance = + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; if (policy_enforcer_ && (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV)) { scoped_refptr<ct::EVCertsWhitelist> ev_whitelist = SSLConfigService::GetEVCertsWhitelist(); - if (!policy_enforcer_->DoesConformToCTEVPolicy( + ct::EVPolicyCompliance ev_policy_compliance = + policy_enforcer_->DoesConformToCTEVPolicy( server_cert_verify_result_.verified_cert.get(), ev_whitelist.get(), - ct_verify_result_, net_log_)) { + ct_verify_result_.verified_scts, net_log_); + ct_verify_result_.ev_policy_compliance = ev_policy_compliance; + if (ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST && + ev_policy_compliance != + ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) { // TODO(eranm): Log via the BoundNetLog, see crbug.com/437766 VLOG(1) << "EV certificate for " << server_cert_verify_result_.verified_cert->subject() @@ -2147,8 +2159,8 @@ int SSLClientSocketOpenSSL::NewSessionCallback(SSL_SESSION* session) { return 1; } -void SSLClientSocketOpenSSL::AddSCTInfoToSSLInfo(SSLInfo* ssl_info) const { - ssl_info->UpdateSignedCertificateTimestamps(ct_verify_result_); +void SSLClientSocketOpenSSL::AddCTInfoToSSLInfo(SSLInfo* ssl_info) const { + ssl_info->UpdateCertificateTransparencyInfo(ct_verify_result_); } std::string SSLClientSocketOpenSSL::GetSessionCacheKey() const { diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index 6e464d7..70d195a 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h @@ -197,12 +197,13 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { // Called from the SSL layer whenever a new session is established. int NewSessionCallback(SSL_SESSION* session); - // Adds the SignedCertificateTimestamps from ct_verify_result_ to |ssl_info|. + // Adds the Certificate Transparency info from ct_verify_result_ to + // |ssl_info|. // SCTs are held in three separate vectors in ct_verify_result, each // vetor representing a particular verification state, this method associates // each of the SCTs with the corresponding SCTVerifyStatus as it adds it to // the |ssl_info|.signed_certificate_timestamps list. - void AddSCTInfoToSSLInfo(SSLInfo* ssl_info) const; + void AddCTInfoToSSLInfo(SSLInfo* ssl_info) const; // Returns a unique key string for the SSL session cache for // this socket. diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index d225390..d54f003 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -22,6 +22,7 @@ #include "net/base/test_data_directory.h" #include "net/cert/asn1_util.h" #include "net/cert/ct_policy_enforcer.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/ct_verifier.h" #include "net/cert/mock_cert_verifier.h" #include "net/cert/test_root_certs.h" @@ -699,10 +700,10 @@ class MockCTVerifier : public CTVerifier { class MockCTPolicyEnforcer : public CTPolicyEnforcer { public: MOCK_METHOD4(DoesConformToCTEVPolicy, - bool(X509Certificate* cert, - const ct::EVCertsWhitelist*, - const ct::CTVerifyResult&, - const BoundNetLog&)); + ct::EVPolicyCompliance(X509Certificate* cert, + const ct::EVCertsWhitelist*, + const ct::SCTList&, + const BoundNetLog&)); }; class SSLClientSocketTest : public PlatformTest { @@ -2349,7 +2350,8 @@ TEST_F(SSLClientSocketTest, EVCertStatusMaintainedForCompliantCert) { MockCTPolicyEnforcer policy_enforcer; SetCTPolicyEnforcer(&policy_enforcer); EXPECT_CALL(policy_enforcer, DoesConformToCTEVPolicy(_, _, _, _)) - .WillRepeatedly(Return(true)); + .WillRepeatedly( + Return(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS)); int rv; ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); @@ -2381,7 +2383,8 @@ TEST_F(SSLClientSocketTest, EVCertStatusRemovedForNonCompliantCert) { MockCTPolicyEnforcer policy_enforcer; SetCTPolicyEnforcer(&policy_enforcer); EXPECT_CALL(policy_enforcer, DoesConformToCTEVPolicy(_, _, _, _)) - .WillRepeatedly(Return(false)); + .WillRepeatedly( + Return(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS)); int rv; ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); diff --git a/net/ssl/ssl_info.cc b/net/ssl/ssl_info.cc index 545bf7e..aca1f43 100644 --- a/net/ssl/ssl_info.cc +++ b/net/ssl/ssl_info.cc @@ -6,6 +6,7 @@ #include "base/pickle.h" #include "net/cert/cert_status_flags.h" +#include "net/cert/ct_policy_status.h" #include "net/cert/signed_certificate_timestamp.h" #include "net/cert/x509_certificate.h" @@ -36,8 +37,10 @@ SSLInfo& SSLInfo::operator=(const SSLInfo& info) { token_binding_key_param = info.token_binding_key_param; handshake_type = info.handshake_type; public_key_hashes = info.public_key_hashes; - signed_certificate_timestamps = info.signed_certificate_timestamps; pinning_failure_log = info.pinning_failure_log; + signed_certificate_timestamps = info.signed_certificate_timestamps; + ct_compliance_details_available = info.ct_compliance_details_available; + ct_ev_policy_compliance = info.ct_ev_policy_compliance; return *this; } @@ -56,15 +59,17 @@ void SSLInfo::Reset() { token_binding_key_param = TB_PARAM_ECDSAP256; handshake_type = HANDSHAKE_UNKNOWN; public_key_hashes.clear(); - signed_certificate_timestamps.clear(); pinning_failure_log.clear(); + signed_certificate_timestamps.clear(); + ct_compliance_details_available = false; + ct_ev_policy_compliance = ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; } void SSLInfo::SetCertError(int error) { cert_status |= MapNetErrorToCertStatus(error); } -void SSLInfo::UpdateSignedCertificateTimestamps( +void SSLInfo::UpdateCertificateTransparencyInfo( const ct::CTVerifyResult& ct_verify_result) { for (const auto& sct : ct_verify_result.verified_scts) { signed_certificate_timestamps.push_back( @@ -78,6 +83,9 @@ void SSLInfo::UpdateSignedCertificateTimestamps( signed_certificate_timestamps.push_back( SignedCertificateTimestampAndStatus(sct, ct::SCT_STATUS_LOG_UNKNOWN)); } + + ct_compliance_details_available = ct_verify_result.ct_policies_applied; + ct_ev_policy_compliance = ct_verify_result.ev_policy_compliance; } } // namespace net diff --git a/net/ssl/ssl_info.h b/net/ssl/ssl_info.h index 40dec28..3935369 100644 --- a/net/ssl/ssl_info.h +++ b/net/ssl/ssl_info.h @@ -18,6 +18,12 @@ namespace net { +namespace ct { + +enum class EVPolicyCompliance; + +} // namespace ct + class X509Certificate; // SSL connection info. @@ -44,12 +50,14 @@ class NET_EXPORT SSLInfo { // Adds the specified |error| to the cert status. void SetCertError(int error); - // Adds the SignedCertificateTimestamps from ct_verify_result to - // |signed_certificate_timestamps|. SCTs are held in three separate vectors - // in ct_verify_result, each vetor representing a particular verification - // state, this method associates each of the SCTs with the corresponding - // SCTVerifyStatus as it adds it to the |signed_certificate_timestamps| list. - void UpdateSignedCertificateTimestamps( + // Adds the SignedCertificateTimestamps and policy compliance details + // from ct_verify_result to |signed_certificate_timestamps| and + // |ct_policy_compliance_details|. SCTs are held in three separate + // vectors in ct_verify_result, each vetor representing a particular + // verification state, this method associates each of the SCTs with + // the corresponding SCTVerifyStatus as it adds it to the + // |signed_certificate_timestamps| list. + void UpdateCertificateTransparencyInfo( const ct::CTVerifyResult& ct_verify_result); // The SSL certificate. @@ -115,6 +123,18 @@ class NET_EXPORT SSLInfo { // List of SignedCertificateTimestamps and their corresponding validation // status. SignedCertificateTimestampAndStatusList signed_certificate_timestamps; + + // True if Certificate Transparency policies were applied on this + // connection and results are available. If true, the field below + // (|ev_policy_compliance|) will contain information about whether + // the connection complied with the policy and why the connection + // was considered non-compliant, if applicable. + bool ct_compliance_details_available; + + // Whether the connection complied with the CT EV policy, and if not, + // why not. Only meaningful if |ct_compliance_details_available| is + // true. + ct::EVPolicyCompliance ct_ev_policy_compliance; }; } // namespace net |