| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/certificate_reporting/error_report.h" | 5 #include "components/certificate_reporting/error_report.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "components/certificate_reporting/cert_logger.pb.h" | 13 #include "components/certificate_reporting/cert_logger.pb.h" |
| 14 #include "net/cert/cert_status_flags.h" | 14 #include "net/cert/cert_status_flags.h" |
| 15 #include "net/ssl/ssl_info.h" | 15 #include "net/ssl/ssl_info.h" |
| 16 #include "net/test/cert_test_util.h" | 16 #include "net/test/cert_test_util.h" |
| 17 #include "net/test/test_data_directory.h" | 17 #include "net/test/test_data_directory.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 using net::SSLInfo; | 21 using net::SSLInfo; |
| 22 using testing::UnorderedElementsAre; | 22 using testing::UnorderedElementsAre; |
| 23 using testing::UnorderedElementsAreArray; |
| 23 | 24 |
| 24 namespace certificate_reporting { | 25 namespace certificate_reporting { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 const char kDummyHostname[] = "dummy.hostname.com"; | 29 const char kDummyHostname[] = "dummy.hostname.com"; |
| 29 const char kDummyFailureLog[] = "dummy failure log"; | 30 const char kDummyFailureLog[] = "dummy failure log"; |
| 30 const char kTestCertFilename[] = "test_mail_google_com.pem"; | 31 const char kTestCertFilename[] = "test_mail_google_com.pem"; |
| 31 | 32 |
| 32 const net::CertStatus kCertStatus = | 33 const net::CertStatus kCertStatus = |
| 33 net::CERT_STATUS_COMMON_NAME_INVALID | net::CERT_STATUS_REVOKED; | 34 net::CERT_STATUS_COMMON_NAME_INVALID | net::CERT_STATUS_REVOKED; |
| 34 | 35 |
| 35 const CertLoggerRequest::CertError kFirstReportedCertError = | 36 const CertLoggerRequest::CertError kFirstReportedCertError = |
| 36 CertLoggerRequest::ERR_CERT_COMMON_NAME_INVALID; | 37 CertLoggerRequest::ERR_CERT_COMMON_NAME_INVALID; |
| 37 const CertLoggerRequest::CertError kSecondReportedCertError = | 38 const CertLoggerRequest::CertError kSecondReportedCertError = |
| 38 CertLoggerRequest::ERR_CERT_REVOKED; | 39 CertLoggerRequest::ERR_CERT_REVOKED; |
| 39 | 40 |
| 40 // Whether to include an unverified certificate chain in the test | 41 // Whether to include an unverified certificate chain in the test |
| 41 // SSLInfo. In production code, an unverified cert chain will not be | 42 // SSLInfo. In production code, an unverified cert chain will not be |
| 42 // present if the resource was loaded from cache. | 43 // present if the resource was loaded from cache. |
| 43 enum UnverifiedCertChainStatus { | 44 enum UnverifiedCertChainStatus { |
| 44 INCLUDE_UNVERIFIED_CERT_CHAIN, | 45 INCLUDE_UNVERIFIED_CERT_CHAIN, |
| 45 EXCLUDE_UNVERIFIED_CERT_CHAIN | 46 EXCLUDE_UNVERIFIED_CERT_CHAIN |
| 46 }; | 47 }; |
| 47 | 48 |
| 48 void GetTestSSLInfo(UnverifiedCertChainStatus unverified_cert_chain_status, | 49 void GetTestSSLInfo(UnverifiedCertChainStatus unverified_cert_chain_status, |
| 49 SSLInfo* info) { | 50 SSLInfo* info, |
| 51 net::CertStatus cert_status) { |
| 50 info->cert = | 52 info->cert = |
| 51 net::ImportCertFromFile(net::GetTestCertsDirectory(), kTestCertFilename); | 53 net::ImportCertFromFile(net::GetTestCertsDirectory(), kTestCertFilename); |
| 52 ASSERT_TRUE(info->cert); | 54 ASSERT_TRUE(info->cert); |
| 53 if (unverified_cert_chain_status == INCLUDE_UNVERIFIED_CERT_CHAIN) { | 55 if (unverified_cert_chain_status == INCLUDE_UNVERIFIED_CERT_CHAIN) { |
| 54 info->unverified_cert = net::ImportCertFromFile( | 56 info->unverified_cert = net::ImportCertFromFile( |
| 55 net::GetTestCertsDirectory(), kTestCertFilename); | 57 net::GetTestCertsDirectory(), kTestCertFilename); |
| 56 ASSERT_TRUE(info->unverified_cert); | 58 ASSERT_TRUE(info->unverified_cert); |
| 57 } | 59 } |
| 58 info->is_issued_by_known_root = true; | 60 info->is_issued_by_known_root = true; |
| 59 info->cert_status = kCertStatus; | 61 info->cert_status = cert_status; |
| 60 info->pinning_failure_log = kDummyFailureLog; | 62 info->pinning_failure_log = kDummyFailureLog; |
| 61 } | 63 } |
| 62 | 64 |
| 63 std::string GetPEMEncodedChain() { | 65 std::string GetPEMEncodedChain() { |
| 64 base::FilePath cert_path = | 66 base::FilePath cert_path = |
| 65 net::GetTestCertsDirectory().AppendASCII(kTestCertFilename); | 67 net::GetTestCertsDirectory().AppendASCII(kTestCertFilename); |
| 66 std::string cert_data; | 68 std::string cert_data; |
| 67 EXPECT_TRUE(base::ReadFileToString(cert_path, &cert_data)); | 69 EXPECT_TRUE(base::ReadFileToString(cert_path, &cert_data)); |
| 68 return cert_data; | 70 return cert_data; |
| 69 } | 71 } |
| 70 | 72 |
| 71 void VerifyErrorReportSerialization(const ErrorReport& report, | 73 void VerifyErrorReportSerialization( |
| 72 const SSLInfo& ssl_info) { | 74 const ErrorReport& report, |
| 75 const SSLInfo& ssl_info, |
| 76 std::vector<CertLoggerRequest::CertError> cert_errors) { |
| 73 std::string serialized_report; | 77 std::string serialized_report; |
| 74 ASSERT_TRUE(report.Serialize(&serialized_report)); | 78 ASSERT_TRUE(report.Serialize(&serialized_report)); |
| 75 | 79 |
| 76 CertLoggerRequest deserialized_report; | 80 CertLoggerRequest deserialized_report; |
| 77 ASSERT_TRUE(deserialized_report.ParseFromString(serialized_report)); | 81 ASSERT_TRUE(deserialized_report.ParseFromString(serialized_report)); |
| 78 EXPECT_EQ(kDummyHostname, deserialized_report.hostname()); | 82 EXPECT_EQ(kDummyHostname, deserialized_report.hostname()); |
| 79 EXPECT_EQ(GetPEMEncodedChain(), deserialized_report.cert_chain()); | 83 EXPECT_EQ(GetPEMEncodedChain(), deserialized_report.cert_chain()); |
| 80 EXPECT_EQ(GetPEMEncodedChain(), deserialized_report.unverified_cert_chain()); | 84 EXPECT_EQ(GetPEMEncodedChain(), deserialized_report.unverified_cert_chain()); |
| 81 EXPECT_EQ(1, deserialized_report.pin().size()); | 85 EXPECT_EQ(1, deserialized_report.pin().size()); |
| 82 EXPECT_EQ(kDummyFailureLog, deserialized_report.pin().Get(0)); | 86 EXPECT_EQ(kDummyFailureLog, deserialized_report.pin().Get(0)); |
| 83 EXPECT_EQ( | 87 EXPECT_EQ( |
| 84 ssl_info.is_issued_by_known_root, | 88 ssl_info.is_issued_by_known_root, |
| 85 deserialized_report.is_issued_by_known_root()); | 89 deserialized_report.is_issued_by_known_root()); |
| 86 EXPECT_THAT( | 90 EXPECT_THAT(deserialized_report.cert_error(), |
| 87 deserialized_report.cert_error(), | 91 UnorderedElementsAreArray(cert_errors)); |
| 88 UnorderedElementsAre(kFirstReportedCertError, kSecondReportedCertError)); | |
| 89 } | 92 } |
| 90 | 93 |
| 91 // Test that a serialized ErrorReport can be deserialized as | 94 // Test that a serialized ErrorReport can be deserialized as |
| 92 // a CertLoggerRequest protobuf (which is the format that the receiving | 95 // a CertLoggerRequest protobuf (which is the format that the receiving |
| 93 // server expects it in) with the right data in it. | 96 // server expects it in) with the right data in it. |
| 94 TEST(ErrorReportTest, SerializedReportAsProtobuf) { | 97 TEST(ErrorReportTest, SerializedReportAsProtobuf) { |
| 95 SSLInfo ssl_info; | 98 SSLInfo ssl_info; |
| 96 ASSERT_NO_FATAL_FAILURE( | 99 ASSERT_NO_FATAL_FAILURE( |
| 97 GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info)); | 100 GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, kCertStatus)); |
| 98 ErrorReport report_known(kDummyHostname, ssl_info); | 101 ErrorReport report_known(kDummyHostname, ssl_info); |
| 102 std::vector<CertLoggerRequest::CertError> cert_errors; |
| 103 cert_errors.push_back(kFirstReportedCertError); |
| 104 cert_errors.push_back(kSecondReportedCertError); |
| 99 ASSERT_NO_FATAL_FAILURE( | 105 ASSERT_NO_FATAL_FAILURE( |
| 100 VerifyErrorReportSerialization(report_known, ssl_info)); | 106 VerifyErrorReportSerialization(report_known, ssl_info, cert_errors)); |
| 101 // Test that both values for |is_issued_by_known_root| are serialized | 107 // Test that both values for |is_issued_by_known_root| are serialized |
| 102 // correctly. | 108 // correctly. |
| 103 ssl_info.is_issued_by_known_root = false; | 109 ssl_info.is_issued_by_known_root = false; |
| 104 ErrorReport report_unknown(kDummyHostname, ssl_info); | 110 ErrorReport report_unknown(kDummyHostname, ssl_info); |
| 105 ASSERT_NO_FATAL_FAILURE( | 111 ASSERT_NO_FATAL_FAILURE( |
| 106 VerifyErrorReportSerialization(report_unknown, ssl_info)); | 112 VerifyErrorReportSerialization(report_unknown, ssl_info, cert_errors)); |
| 107 } | 113 } |
| 108 | 114 |
| 109 TEST(ErrorReportTest, SerializedReportAsProtobufWithInterstitialInfo) { | 115 TEST(ErrorReportTest, SerializedReportAsProtobufWithInterstitialInfo) { |
| 110 std::string serialized_report; | 116 std::string serialized_report; |
| 111 SSLInfo ssl_info; | 117 SSLInfo ssl_info; |
| 112 // Use EXCLUDE_UNVERIFIED_CERT_CHAIN here to exercise the code path | 118 // Use EXCLUDE_UNVERIFIED_CERT_CHAIN here to exercise the code path |
| 113 // where SSLInfo does not contain the unverified cert chain. (The test | 119 // where SSLInfo does not contain the unverified cert chain. (The test |
| 114 // above exercises the path where it does.) | 120 // above exercises the path where it does.) |
| 115 ASSERT_NO_FATAL_FAILURE( | 121 ASSERT_NO_FATAL_FAILURE( |
| 116 GetTestSSLInfo(EXCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info)); | 122 GetTestSSLInfo(EXCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, kCertStatus)); |
| 117 ErrorReport report(kDummyHostname, ssl_info); | 123 ErrorReport report(kDummyHostname, ssl_info); |
| 118 | 124 |
| 119 report.SetInterstitialInfo(ErrorReport::INTERSTITIAL_CLOCK, | 125 report.SetInterstitialInfo(ErrorReport::INTERSTITIAL_CLOCK, |
| 120 ErrorReport::USER_PROCEEDED, | 126 ErrorReport::USER_PROCEEDED, |
| 121 ErrorReport::INTERSTITIAL_OVERRIDABLE); | 127 ErrorReport::INTERSTITIAL_OVERRIDABLE); |
| 122 | 128 |
| 123 ASSERT_TRUE(report.Serialize(&serialized_report)); | 129 ASSERT_TRUE(report.Serialize(&serialized_report)); |
| 124 | 130 |
| 125 CertLoggerRequest deserialized_report; | 131 CertLoggerRequest deserialized_report; |
| 126 ASSERT_TRUE(deserialized_report.ParseFromString(serialized_report)); | 132 ASSERT_TRUE(deserialized_report.ParseFromString(serialized_report)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 141 EXPECT_THAT( | 147 EXPECT_THAT( |
| 142 deserialized_report.cert_error(), | 148 deserialized_report.cert_error(), |
| 143 UnorderedElementsAre(kFirstReportedCertError, kSecondReportedCertError)); | 149 UnorderedElementsAre(kFirstReportedCertError, kSecondReportedCertError)); |
| 144 } | 150 } |
| 145 | 151 |
| 146 // Test that a serialized report can be parsed. | 152 // Test that a serialized report can be parsed. |
| 147 TEST(ErrorReportTest, ParseSerializedReport) { | 153 TEST(ErrorReportTest, ParseSerializedReport) { |
| 148 std::string serialized_report; | 154 std::string serialized_report; |
| 149 SSLInfo ssl_info; | 155 SSLInfo ssl_info; |
| 150 ASSERT_NO_FATAL_FAILURE( | 156 ASSERT_NO_FATAL_FAILURE( |
| 151 GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info)); | 157 GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, kCertStatus)); |
| 152 ErrorReport report(kDummyHostname, ssl_info); | 158 ErrorReport report(kDummyHostname, ssl_info); |
| 153 EXPECT_EQ(kDummyHostname, report.hostname()); | 159 EXPECT_EQ(kDummyHostname, report.hostname()); |
| 154 ASSERT_TRUE(report.Serialize(&serialized_report)); | 160 ASSERT_TRUE(report.Serialize(&serialized_report)); |
| 155 | 161 |
| 156 ErrorReport parsed; | 162 ErrorReport parsed; |
| 157 ASSERT_TRUE(parsed.InitializeFromString(serialized_report)); | 163 ASSERT_TRUE(parsed.InitializeFromString(serialized_report)); |
| 158 EXPECT_EQ(report.hostname(), parsed.hostname()); | 164 EXPECT_EQ(report.hostname(), parsed.hostname()); |
| 159 } | 165 } |
| 160 | 166 |
| 167 // Check that CT errors are handled correctly. |
| 168 TEST(ErrorReportTest, CertificateTransparencyError) { |
| 169 SSLInfo ssl_info; |
| 170 ASSERT_NO_FATAL_FAILURE( |
| 171 GetTestSSLInfo(INCLUDE_UNVERIFIED_CERT_CHAIN, &ssl_info, |
| 172 net::CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED)); |
| 173 ErrorReport report_known(kDummyHostname, ssl_info); |
| 174 std::vector<CertLoggerRequest::CertError> cert_errors; |
| 175 cert_errors.push_back( |
| 176 CertLoggerRequest::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED); |
| 177 ASSERT_NO_FATAL_FAILURE( |
| 178 VerifyErrorReportSerialization(report_known, ssl_info, cert_errors)); |
| 179 } |
| 180 |
| 161 } // namespace | 181 } // namespace |
| 162 | 182 |
| 163 } // namespace certificate_reporting | 183 } // namespace certificate_reporting |
| OLD | NEW |