| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/caching_cert_verifier.h" | 5 #include "net/cert/caching_cert_verifier.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 13 #include "net/base/test_completion_callback.h" | 13 #include "net/base/test_completion_callback.h" |
| 14 #include "net/base/test_data_directory.h" | 14 #include "net/base/test_data_directory.h" |
| 15 #include "net/cert/cert_trust_anchor_provider.h" | 15 #include "net/cert/cert_trust_anchor_provider.h" |
| 16 #include "net/cert/cert_verifier.h" | 16 #include "net/cert/cert_verifier.h" |
| 17 #include "net/cert/cert_verify_result.h" | 17 #include "net/cert/cert_verify_result.h" |
| 18 #include "net/cert/mock_cert_verifier.h" | 18 #include "net/cert/mock_cert_verifier.h" |
| 19 #include "net/cert/x509_certificate.h" | 19 #include "net/cert/x509_certificate.h" |
| 20 #include "net/log/net_log.h" | 20 #include "net/log/net_log.h" |
| 21 #include "net/test/cert_test_util.h" | 21 #include "net/test/cert_test_util.h" |
| 22 #include "testing/gmock/include/gmock/gmock.h" | 22 #include "testing/gmock/include/gmock/gmock.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 24 | 24 |
| 25 using testing::_; |
| 25 using testing::Mock; | 26 using testing::Mock; |
| 27 using testing::Return; |
| 26 using testing::ReturnRef; | 28 using testing::ReturnRef; |
| 27 | 29 |
| 28 namespace net { | 30 namespace net { |
| 29 | 31 |
| 30 namespace { | 32 namespace { |
| 31 | 33 |
| 32 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider { | 34 class MockCertTrustAnchorProvider : public CertTrustAnchorProvider { |
| 33 public: | 35 public: |
| 34 MockCertTrustAnchorProvider() {} | 36 MockCertTrustAnchorProvider() {} |
| 35 virtual ~MockCertTrustAnchorProvider() {} | 37 virtual ~MockCertTrustAnchorProvider() {} |
| 36 | 38 |
| 37 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&()); | 39 MOCK_METHOD0(GetAdditionalTrustAnchors, const CertificateList&()); |
| 38 }; | 40 }; |
| 39 | 41 |
| 42 class MockCacheVisitor : public CachingCertVerifier::CacheVisitor { |
| 43 public: |
| 44 MockCacheVisitor() {} |
| 45 ~MockCacheVisitor() override {} |
| 46 |
| 47 MOCK_METHOD5(VisitEntry, |
| 48 bool(const CachingCertVerifier::RequestParams& params, |
| 49 int error, |
| 50 const CertVerifyResult& result, |
| 51 base::Time verification_time, |
| 52 base::Time expiration_time)); |
| 53 }; |
| 54 |
| 40 } // namespace | 55 } // namespace |
| 41 | 56 |
| 42 class CachingCertVerifierTest : public ::testing::Test { | 57 class CachingCertVerifierTest : public ::testing::Test { |
| 43 public: | 58 public: |
| 44 CachingCertVerifierTest() : verifier_(base::MakeUnique<MockCertVerifier>()) {} | 59 CachingCertVerifierTest() : verifier_(base::MakeUnique<MockCertVerifier>()) {} |
| 45 ~CachingCertVerifierTest() override {} | 60 ~CachingCertVerifierTest() override {} |
| 46 | 61 |
| 47 protected: | 62 protected: |
| 48 CachingCertVerifier verifier_; | 63 CachingCertVerifier verifier_; |
| 49 }; | 64 }; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 74 nullptr, &verify_result, callback.callback(), &request, BoundNetLog()); | 89 nullptr, &verify_result, callback.callback(), &request, BoundNetLog()); |
| 75 // Synchronous completion. | 90 // Synchronous completion. |
| 76 ASSERT_NE(ERR_IO_PENDING, error); | 91 ASSERT_NE(ERR_IO_PENDING, error); |
| 77 ASSERT_TRUE(IsCertificateError(error)); | 92 ASSERT_TRUE(IsCertificateError(error)); |
| 78 ASSERT_FALSE(request); | 93 ASSERT_FALSE(request); |
| 79 ASSERT_EQ(2u, verifier_.requests()); | 94 ASSERT_EQ(2u, verifier_.requests()); |
| 80 ASSERT_EQ(1u, verifier_.cache_hits()); | 95 ASSERT_EQ(1u, verifier_.cache_hits()); |
| 81 ASSERT_EQ(1u, verifier_.GetCacheSize()); | 96 ASSERT_EQ(1u, verifier_.GetCacheSize()); |
| 82 } | 97 } |
| 83 | 98 |
| 99 TEST_F(CachingCertVerifierTest, Visitor) { |
| 100 base::FilePath certs_dir = GetTestCertsDirectory(); |
| 101 scoped_refptr<X509Certificate> test_cert( |
| 102 ImportCertFromFile(certs_dir, "ok_cert.pem")); |
| 103 ASSERT_TRUE(test_cert.get()); |
| 104 |
| 105 TestCompletionCallback callback; |
| 106 std::unique_ptr<CertVerifier::Request> request; |
| 107 |
| 108 // Add some entries to the cache |
| 109 CertVerifier::RequestParams params1(test_cert, "www.example.com", 0, |
| 110 std::string(), CertificateList()); |
| 111 CertVerifyResult result1; |
| 112 int error1 = callback.GetResult(verifier_.Verify(params1, nullptr, &result1, |
| 113 callback.callback(), |
| 114 &request, BoundNetLog())); |
| 115 ASSERT_TRUE(IsCertificateError(error1)); |
| 116 ASSERT_EQ(1u, verifier_.requests()); |
| 117 ASSERT_EQ(0u, verifier_.cache_hits()); |
| 118 ASSERT_EQ(1u, verifier_.GetCacheSize()); |
| 119 |
| 120 CertVerifier::RequestParams params2(test_cert, "www.example.net", 0, |
| 121 std::string(), CertificateList()); |
| 122 CertVerifyResult result2; |
| 123 int error2 = callback.GetResult(verifier_.Verify(params2, nullptr, &result2, |
| 124 callback.callback(), |
| 125 &request, BoundNetLog())); |
| 126 ASSERT_TRUE(IsCertificateError(error2)); |
| 127 ASSERT_EQ(2u, verifier_.requests()); |
| 128 ASSERT_EQ(0u, verifier_.cache_hits()); |
| 129 ASSERT_EQ(2u, verifier_.GetCacheSize()); |
| 130 |
| 131 CertVerifier::RequestParams params3(test_cert, "www.example.org", 0, |
| 132 std::string(), CertificateList()); |
| 133 CertVerifyResult result3; |
| 134 int error3 = callback.GetResult(verifier_.Verify(params3, nullptr, &result3, |
| 135 callback.callback(), |
| 136 &request, BoundNetLog())); |
| 137 ASSERT_TRUE(IsCertificateError(error3)); |
| 138 ASSERT_EQ(3u, verifier_.requests()); |
| 139 ASSERT_EQ(0u, verifier_.cache_hits()); |
| 140 ASSERT_EQ(3u, verifier_.GetCacheSize()); |
| 141 |
| 142 // Iterate through all entries. |
| 143 { |
| 144 MockCacheVisitor mock_visitor; |
| 145 EXPECT_CALL(mock_visitor, VisitEntry(params1, error1, _, _, _)) |
| 146 .WillOnce(Return(true)); |
| 147 EXPECT_CALL(mock_visitor, VisitEntry(params2, error2, _, _, _)) |
| 148 .WillOnce(Return(true)); |
| 149 EXPECT_CALL(mock_visitor, VisitEntry(params3, error3, _, _, _)) |
| 150 .WillOnce(Return(true)); |
| 151 verifier_.VisitEntries(&mock_visitor); |
| 152 } |
| 153 |
| 154 // Now perform partial iteration |
| 155 { |
| 156 MockCacheVisitor mock_visitor; |
| 157 ::testing::InSequence sequence; |
| 158 EXPECT_CALL(mock_visitor, VisitEntry(_, _, _, _, _)).WillOnce(Return(true)); |
| 159 EXPECT_CALL(mock_visitor, VisitEntry(_, _, _, _, _)) |
| 160 .WillOnce(Return(false)); |
| 161 verifier_.VisitEntries(&mock_visitor); |
| 162 } |
| 163 } |
| 164 |
| 165 TEST_F(CachingCertVerifierTest, AddsEntries) { |
| 166 base::FilePath certs_dir = GetTestCertsDirectory(); |
| 167 scoped_refptr<X509Certificate> test_cert( |
| 168 ImportCertFromFile(certs_dir, "ok_cert.pem")); |
| 169 ASSERT_TRUE(test_cert.get()); |
| 170 |
| 171 CertVerifyResult result_1; |
| 172 result_1.verified_cert = test_cert; |
| 173 result_1.cert_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; |
| 174 result_1.has_md2 = true; |
| 175 result_1.is_issued_by_known_root = false; |
| 176 |
| 177 CertVerifyResult result_2; |
| 178 result_2.verified_cert = test_cert; |
| 179 result_2.cert_status = CERT_STATUS_IS_EV; |
| 180 result_2.is_issued_by_known_root = true; |
| 181 |
| 182 CertVerifier::RequestParams params(test_cert, "www.example.com", 0, |
| 183 std::string(), CertificateList()); |
| 184 |
| 185 base::Time now = base::Time::Now(); |
| 186 |
| 187 // On an empty cache, it should be fine to add an entry. |
| 188 EXPECT_TRUE(verifier_.AddEntry(params, ERR_CERT_WEAK_KEY, result_1, now)); |
| 189 ASSERT_EQ(0u, verifier_.requests()); |
| 190 ASSERT_EQ(0u, verifier_.cache_hits()); |
| 191 ASSERT_EQ(1u, verifier_.GetCacheSize()); |
| 192 |
| 193 TestCompletionCallback callback; |
| 194 std::unique_ptr<CertVerifier::Request> request; |
| 195 |
| 196 CertVerifyResult cached_result; |
| 197 int error = callback.GetResult( |
| 198 verifier_.Verify(params, nullptr, &cached_result, callback.callback(), |
| 199 &request, BoundNetLog())); |
| 200 ASSERT_EQ(ERR_CERT_WEAK_KEY, error); |
| 201 EXPECT_TRUE(cached_result.has_md2); |
| 202 EXPECT_FALSE(cached_result.is_issued_by_known_root); |
| 203 |
| 204 ASSERT_EQ(1u, verifier_.requests()); |
| 205 ASSERT_EQ(1u, verifier_.cache_hits()); |
| 206 ASSERT_EQ(1u, verifier_.GetCacheSize()); |
| 207 |
| 208 // But it should not be fine to replace it with an existing entry, even |
| 209 // if that entry is 'newer'. |
| 210 EXPECT_FALSE(verifier_.AddEntry(params, OK, result_2, |
| 211 now + base::TimeDelta::FromMinutes(1))); |
| 212 |
| 213 error = callback.GetResult(verifier_.Verify(params, nullptr, &cached_result, |
| 214 callback.callback(), &request, |
| 215 BoundNetLog())); |
| 216 ASSERT_EQ(ERR_CERT_WEAK_KEY, error); |
| 217 EXPECT_TRUE(cached_result.has_md2); |
| 218 EXPECT_FALSE(cached_result.is_issued_by_known_root); |
| 219 |
| 220 ASSERT_EQ(2u, verifier_.requests()); |
| 221 ASSERT_EQ(2u, verifier_.cache_hits()); |
| 222 ASSERT_EQ(1u, verifier_.GetCacheSize()); |
| 223 } |
| 224 |
| 84 // Tests the same server certificate with different intermediate CA | 225 // Tests the same server certificate with different intermediate CA |
| 85 // certificates. These should be treated as different certificate chains even | 226 // certificates. These should be treated as different certificate chains even |
| 86 // though the two X509Certificate objects contain the same server certificate. | 227 // though the two X509Certificate objects contain the same server certificate. |
| 87 TEST_F(CachingCertVerifierTest, DifferentCACerts) { | 228 TEST_F(CachingCertVerifierTest, DifferentCACerts) { |
| 88 base::FilePath certs_dir = GetTestCertsDirectory(); | 229 base::FilePath certs_dir = GetTestCertsDirectory(); |
| 89 | 230 |
| 90 scoped_refptr<X509Certificate> server_cert = | 231 scoped_refptr<X509Certificate> server_cert = |
| 91 ImportCertFromFile(certs_dir, "salesforce_com_test.pem"); | 232 ImportCertFromFile(certs_dir, "salesforce_com_test.pem"); |
| 92 ASSERT_TRUE(server_cert); | 233 ASSERT_TRUE(server_cert); |
| 93 | 234 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 CertVerifier::RequestParams(test_cert, "www.example.com", 0, | 327 CertVerifier::RequestParams(test_cert, "www.example.com", 0, |
| 187 std::string(), CertificateList()), | 328 std::string(), CertificateList()), |
| 188 nullptr, &verify_result, callback.callback(), &request, BoundNetLog())); | 329 nullptr, &verify_result, callback.callback(), &request, BoundNetLog())); |
| 189 Mock::VerifyAndClearExpectations(&trust_provider); | 330 Mock::VerifyAndClearExpectations(&trust_provider); |
| 190 EXPECT_TRUE(IsCertificateError(error)); | 331 EXPECT_TRUE(IsCertificateError(error)); |
| 191 ASSERT_EQ(3u, verifier_.requests()); | 332 ASSERT_EQ(3u, verifier_.requests()); |
| 192 ASSERT_EQ(1u, verifier_.cache_hits()); | 333 ASSERT_EQ(1u, verifier_.cache_hits()); |
| 193 } | 334 } |
| 194 | 335 |
| 195 } // namespace net | 336 } // namespace net |
| OLD | NEW |