Index: net/cert/multi_threaded_cert_verifier_unittest.cc |
diff --git a/net/cert/multi_threaded_cert_verifier_unittest.cc b/net/cert/multi_threaded_cert_verifier_unittest.cc |
index aa01511448fa48c2e70d093362d9121bc3c998bf..0877f155f15e5b1efbccbe2a9895b35a55ee07f2 100644 |
--- a/net/cert/multi_threaded_cert_verifier_unittest.cc |
+++ b/net/cert/multi_threaded_cert_verifier_unittest.cc |
@@ -379,6 +379,41 @@ TEST_F(MultiThreadedCertVerifierTest, RequestParamsComparators) { |
} |
} |
+TEST_F(MultiThreadedCertVerifierTest, PersistRequestParams) { |
+ SHA1HashValue a_key; |
+ memset(a_key.data, 'a', sizeof(a_key.data)); |
+ |
+ const CertificateList empty_list; |
+ CertificateList test_list; |
+ test_list.push_back( |
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); |
+ |
+ // Key to test. |
+ MultiThreadedCertVerifier::RequestParams key(a_key, a_key, "www.example.test", |
+ std::string(), 0, test_list); |
+ |
+ // Restoring invalid pickled data should fail. |
+ base::Pickle pickle; |
+ EXPECT_TRUE(pickle.WriteString(std::string())); |
+ base::PickleIterator corrupt_iter(pickle); |
+ MultiThreadedCertVerifier::RequestParams key1; |
+ EXPECT_FALSE(MultiThreadedCertVerifier::RequestParams::CreateFromPickle( |
+ &corrupt_iter, &key1)); |
+ |
+ // Persisting and restoring valid object should succeed. |
+ base::Pickle pickle1; |
+ EXPECT_TRUE(key.Persist(&pickle1)); |
+ base::PickleIterator iter(pickle1); |
+ EXPECT_TRUE( |
+ MultiThreadedCertVerifier::RequestParams::CreateFromPickle(&iter, &key1)); |
+ |
+ EXPECT_EQ(key.hostname, key1.hostname); |
+ EXPECT_EQ(key.flags, key1.flags); |
+ EXPECT_EQ(key.hash_values.size(), key1.hash_values.size()); |
+ for (size_t i = 0; i < key.hash_values.size(); ++i) |
+ EXPECT_TRUE(key.hash_values[i].Equals(key1.hash_values[i])); |
+} |
+ |
TEST_F(MultiThreadedCertVerifierTest, CertTrustAnchorProvider) { |
MockCertTrustAnchorProvider trust_provider; |
verifier_.SetCertTrustAnchorProvider(&trust_provider); |
@@ -512,4 +547,158 @@ TEST_F(MultiThreadedCertVerifierTest, MultipleInflightJoin) { |
ASSERT_EQ(2u, verifier_.inflight_joins()); |
} |
+TEST_F(MultiThreadedCertVerifierTest, PersistCache) { |
+ base::FilePath certs_dir = GetTestCertsDirectory(); |
+ scoped_refptr<X509Certificate> test_cert( |
+ ImportCertFromFile(certs_dir, "ok_cert.pem")); |
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get()); |
+ |
+ std::string example_hostname("www.example.com"); |
+ std::string ocsp_response; |
+ int flags = 0; |
+ CRLSet* crl_set = NULL; |
+ int error; |
+ CertVerifyResult verify_result; |
+ TestCompletionCallback callback; |
+ scoped_ptr<CertVerifier::Request> request; |
+ |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ ASSERT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request); |
+ error = callback.WaitForResult(); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_EQ(1u, verifier_.requests()); |
+ ASSERT_EQ(0u, verifier_.cache_hits()); |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ // Synchronous completion. |
+ ASSERT_NE(ERR_IO_PENDING, error); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_FALSE(request); |
+ ASSERT_EQ(2u, verifier_.requests()); |
+ ASSERT_EQ(1u, verifier_.cache_hits()); |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ base::Pickle pickle(sizeof(base::Pickle::Header)); |
+ EXPECT_TRUE(verifier_.SerializeCache(&pickle)); |
+ |
+ // Clear the cache. |
+ verifier_.ClearCache(); |
+ ASSERT_EQ(0u, verifier_.GetCacheSize()); |
+ |
+ // Restore the cache from the pickled data. |
+ base::PickleIterator iter(pickle); |
+ EXPECT_TRUE(MultiThreadedCertVerifier::CreateFromPickle(&iter, &verifier_)); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ // Synchronous completion. |
+ ASSERT_NE(ERR_IO_PENDING, error); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_FALSE(request); |
+ ASSERT_EQ(3u, verifier_.requests()); |
+ ASSERT_EQ(2u, verifier_.cache_hits()); |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+} |
+ |
+TEST_F(MultiThreadedCertVerifierTest, PersistCacheExpiredEntry) { |
+ base::FilePath certs_dir = GetTestCertsDirectory(); |
+ scoped_refptr<X509Certificate> test_cert( |
+ ImportCertFromFile(certs_dir, "ok_cert.pem")); |
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get()); |
+ |
+ std::string example_hostname("www.example.com"); |
+ std::string ocsp_response; |
+ int flags = 0; |
+ CRLSet* crl_set = NULL; |
+ int error; |
+ CertVerifyResult verify_result; |
+ TestCompletionCallback callback; |
+ scoped_ptr<CertVerifier::Request> request; |
+ |
+ // Verify that there is no cache hit. |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ ASSERT_EQ(ERR_IO_PENDING, error); |
+ EXPECT_TRUE(request); |
+ error = callback.WaitForResult(); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_EQ(1u, verifier_.requests()); |
+ ASSERT_EQ(0u, verifier_.cache_hits()); |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ // Synchronous completion and verify that there is a cache hit. |
+ ASSERT_NE(ERR_IO_PENDING, error); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_FALSE(request); |
+ ASSERT_EQ(2u, verifier_.requests()); |
+ ASSERT_EQ(1u, verifier_.cache_hits()); // cache hit. |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ // Test cache expiration, by adding expired data. |
+ const CertificateList empty_cert_list; |
+ const CertificateList& additional_trust_anchors = |
+ verifier_.trust_anchor_provider_ |
+ ? verifier_.trust_anchor_provider_->GetAdditionalTrustAnchors() |
+ : empty_cert_list; |
+ const MultiThreadedCertVerifier::RequestParams key( |
+ test_cert->fingerprint(), test_cert->ca_fingerprint(), example_hostname, |
+ ocsp_response, flags, additional_trust_anchors); |
+ const MultiThreadedCertVerifier::CertVerifierCache::value_type* cached_entry = |
+ verifier_.cache_.Get(key, MultiThreadedCertVerifier::CacheValidityPeriod( |
+ base::Time::Now())); |
+ // TODO(rtenneti): use |kTTLSecs| instead of hardcoded 1800ms. |
+ base::Time start_time = |
+ base::Time::Now() - base::TimeDelta::FromSeconds(3600); |
+ verifier_.cache_.Put( |
+ key, *cached_entry, |
+ MultiThreadedCertVerifier::CacheValidityPeriod(start_time), |
+ MultiThreadedCertVerifier::CacheValidityPeriod( |
+ start_time, start_time + base::TimeDelta::FromSeconds(1800))); |
+ |
+ // Persist the data. |
+ base::Pickle pickle(sizeof(base::Pickle::Header)); |
+ EXPECT_TRUE(verifier_.SerializeCache(&pickle)); |
+ |
+ // Clear the cache. |
+ verifier_.ClearCache(); |
+ ASSERT_EQ(0u, verifier_.GetCacheSize()); |
+ |
+ // Restore the persisted data. |
+ base::PickleIterator iter(pickle); |
+ EXPECT_TRUE(MultiThreadedCertVerifier::CreateFromPickle(&iter, &verifier_)); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+ |
+ error = verifier_.Verify(test_cert.get(), example_hostname, ocsp_response, |
+ flags, crl_set, &verify_result, callback.callback(), |
+ &request, BoundNetLog()); |
+ ASSERT_EQ(ERR_IO_PENDING, error); |
+ // Verify the entry is evicted from the cache. |
+ ASSERT_EQ(0u, verifier_.GetCacheSize()); |
+ ASSERT_TRUE(request); |
+ error = callback.WaitForResult(); |
+ ASSERT_TRUE(IsCertificateError(error)); |
+ ASSERT_EQ(3u, verifier_.requests()); |
+ // Verify number of cache hits hasn't increased. |
+ ASSERT_EQ(1u, verifier_.cache_hits()); |
+ ASSERT_EQ(0u, verifier_.inflight_joins()); |
+ ASSERT_EQ(1u, verifier_.GetCacheSize()); |
+} |
+ |
} // namespace net |