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

Unified Diff: net/cert/internal/cert_issuer_source_aia_unittest.cc

Issue 2036033002: Add CertIssuerSourceAia: authorityInfoAccess fetching for CertPathBuilder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert-parsing-path-building
Patch Set: remove orphaned kw_args change, remove g_cur_path_id change from this cl Created 4 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 | « net/cert/internal/cert_issuer_source_aia.cc ('k') | net/cert/internal/parse_certificate.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/cert/internal/cert_issuer_source_aia_unittest.cc
diff --git a/net/cert/internal/cert_issuer_source_aia_unittest.cc b/net/cert/internal/cert_issuer_source_aia_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..31b257720fb747bc6a70d1eef39fbf1b3f4d06b3
--- /dev/null
+++ b/net/cert/internal/cert_issuer_source_aia_unittest.cc
@@ -0,0 +1,920 @@
+// 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.
+
+#include "net/cert/internal/cert_issuer_source_aia.h"
+
+#include "base/bind.h"
+#include "net/cert/cert_net_fetcher.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/test_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+using ::testing::Mock;
+using ::testing::StrictMock;
+
+::testing::AssertionResult ReadTestPem(const std::string& file_name,
+ const std::string& block_name,
+ std::string* result) {
+ const PemBlockMapping mappings[] = {
+ {block_name.c_str(), result},
+ };
+
+ return ReadTestDataFromPemFile(file_name, mappings);
+}
+
+::testing::AssertionResult ReadTestCert(
+ const std::string& file_name,
+ scoped_refptr<ParsedCertificate>* result) {
+ std::string der;
+ ::testing::AssertionResult r =
+ ReadTestPem("net/data/cert_issuer_source_aia_unittest/" + file_name,
+ "CERTIFICATE", &der);
+ if (!r)
+ return r;
+ *result = ParsedCertificate::CreateFromCertificateCopy(der);
+ if (!*result)
+ return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed";
+ return ::testing::AssertionSuccess();
+}
+
+std::vector<uint8_t> CertDataVector(const ParsedCertificate* cert) {
+ std::vector<uint8_t> data(
+ cert->der_cert().UnsafeData(),
+ cert->der_cert().UnsafeData() + cert->der_cert().Length());
+ return data;
+}
+
+// Tracks a CertNetFetcher::Request that will be returned to the
+// CertIssuerSourceAia. Allows the tests to tell if the Request is still alive
+// or was deleted(cancelled) by the CertIssuerSourceAia. If the Request is still
+// alive, the test can get the FetchCallback to simulate the Request completing.
+class RequestManager {
+ public:
+ class Request : public CertNetFetcher::Request {
+ public:
+ Request(RequestManager* manager,
+ const CertNetFetcher::FetchCallback& callback)
+ : manager_(manager), callback_(callback) {}
+ ~Request() override { manager_->RequestWasDestroyed(); }
+
+ CertNetFetcher::FetchCallback get_callback() const { return callback_; }
+
+ private:
+ RequestManager* manager_;
+ CertNetFetcher::FetchCallback callback_;
+ };
+
+ ~RequestManager() { CHECK(!request_); }
+
+ std::unique_ptr<Request> CreateRequest(
+ const CertNetFetcher::FetchCallback& callback) {
+ EXPECT_FALSE(request_);
+ std::unique_ptr<Request> request(new Request(this, callback));
+ request_ = request.get();
+ return request;
+ }
+
+ bool is_request_alive() const { return request_; }
+
+ CertNetFetcher::FetchCallback get_callback() const {
+ CHECK(is_request_alive());
+ return request_->get_callback();
+ }
+
+ private:
+ void RequestWasDestroyed() {
+ EXPECT_TRUE(request_);
+ request_ = nullptr;
+ }
+
+ Request* request_;
+};
+
+// MockCertNetFetcherImpl is an implementation of CertNetFetcher for testing.
+class MockCertNetFetcherImpl : public CertNetFetcher {
+ public:
+ MockCertNetFetcherImpl() = default;
+ ~MockCertNetFetcherImpl() override = default;
+
+ RequestManager* GetRequestManagerForURL(const GURL& url) {
+ auto it = request_map_.find(url);
+ if (it == request_map_.end())
+ return nullptr;
+ return it->second.get();
+ }
+
+ WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCaIssuers(
+ const GURL& url,
+ int timeout_milliseconds,
+ int max_response_bytes,
+ const FetchCallback& callback) override {
+ EXPECT_TRUE(request_map_.find(url) == request_map_.end());
+
+ std::unique_ptr<RequestManager> request_manager(new RequestManager());
+
+ std::unique_ptr<Request> request = request_manager->CreateRequest(callback);
+
+ request_map_[url] = std::move(request_manager);
+
+ return request;
+ }
+
+ WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCrl(
+ const GURL& url,
+ int timeout_milliseconds,
+ int max_response_bytes,
+ const FetchCallback& callback) override {
+ NOTREACHED();
+ return nullptr;
+ }
+
+ WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp(
+ const GURL& url,
+ int timeout_milliseconds,
+ int max_response_bytes,
+ const FetchCallback& callback) override {
+ NOTREACHED();
+ return nullptr;
+ }
+
+ private:
+ std::map<GURL, std::unique_ptr<RequestManager>> request_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCertNetFetcherImpl);
+};
+
+class MockIssuerCallback {
+ public:
+ MOCK_METHOD1(Callback, void(CertIssuerSource::Request*));
+};
+
+void NotCalled(CertIssuerSource::Request* request) {
+ ADD_FAILURE() << "NotCalled was called";
+}
+
+// CertIssuerSourceAia does not return results for SyncGetIssuersOf.
+TEST(CertIssuerSourceAiaTest, NoSyncResults) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ aia_source.SyncGetIssuersOf(cert.get(), &issuers);
+ EXPECT_EQ(0U, issuers.size());
+}
+
+// If the AuthorityInfoAccess extension is not present, AsyncGetIssuersOf should
+// synchronously indicate no results.
+TEST(CertIssuerSourceAiaTest, NoAia) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_no_aia.pem", &cert));
+
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> request;
+ aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&NotCalled), &request);
+ EXPECT_EQ(nullptr, request);
+}
+
+// If the AuthorityInfoAccess extension only contains non-HTTP URIs,
+// AsyncGetIssuersOf should create a Request object. The URL scheme check is
+// part of the specific CertNetFetcher implementation, this tests that we handle
+// ERR_DISALLOWED_URL_SCHEME properly. If FetchCaIssuers is modified to fail
+// synchronously in that case, this test will be more interesting.
+TEST(CertIssuerSourceAiaTest, FileAia) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_file_aia.pem", &cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("file:///dev/null"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ // CertNetFetcher rejects the URL scheme.
+ req_manager->get_callback().Run(ERR_DISALLOWED_URL_SCHEME,
+ std::vector<uint8_t>());
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // No results.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// If the AuthorityInfoAccess extension contains an invalid URL,
+// AsyncGetIssuersOf should synchronously indicate no results.
+TEST(CertIssuerSourceAiaTest, OneInvalidURL) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_invalid_url_aia.pem", &cert));
+
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> request;
+ aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&NotCalled), &request);
+ EXPECT_EQ(nullptr, request);
+}
+
+// AuthorityInfoAccess with a single HTTP url pointing to a single DER cert.
+TEST(CertIssuerSourceAiaTest, OneAia) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ EXPECT_TRUE(req_manager->is_request_alive());
+ cert_source_request.reset();
+ EXPECT_FALSE(req_manager->is_request_alive());
+}
+
+// AuthorityInfoAccess with two URIs, one a FILE, the other a HTTP.
+// Simulate a ERR_DISALLOWED_URL_SCHEME for the file URL. If FetchCaIssuers is
+// modified to synchronously reject disallowed schemes, this test will be more
+// interesting.
+TEST(CertIssuerSourceAiaTest, OneFileOneHttpAia) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_file_and_http_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("file:///dev/null"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Request for file URL completes with disallowed scheme failure. Callback is
+ // NOT called.
+ req_manager->get_callback().Run(ERR_DISALLOWED_URL_SCHEME,
+ std::vector<uint8_t>());
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Request for I2.foo completes. Callback should be called now.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager2->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ EXPECT_TRUE(req_manager2->is_request_alive());
+ cert_source_request.reset();
+ EXPECT_FALSE(req_manager2->is_request_alive());
+}
+
+// AuthorityInfoAccess with two URIs, one is invalid, the other HTTP.
+TEST(CertIssuerSourceAiaTest, OneInvalidOneHttpAia) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_invalid_and_http_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ EXPECT_TRUE(req_manager->is_request_alive());
+ cert_source_request.reset();
+ EXPECT_FALSE(req_manager->is_request_alive());
+}
+
+// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert.
+// One request completes, results are retrieved, then the next request completes
+// and the results are retrieved.
+TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeries) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert2;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Request for I.cer completes first.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Results are retrieved before the other request completes.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ // The other http request is still pending, status should be ASYNC to signify
+ // the need to wait for another callback.
+ ASSERT_EQ(CompletionStatus::ASYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ // Request for I2.foo completes.
+ ASSERT_TRUE(req_manager2->is_request_alive());
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager2->get_callback().Run(OK,
+ CertDataVector(intermediate_cert2.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Results from the second http request are retrieved.
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert());
+
+ // No more results.
+ status = cert_source_request->GetNext(&result_cert);
+ ASSERT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ EXPECT_TRUE(req_manager->is_request_alive());
+ EXPECT_TRUE(req_manager2->is_request_alive());
+ cert_source_request.reset();
+ EXPECT_FALSE(req_manager->is_request_alive());
+ EXPECT_FALSE(req_manager2->is_request_alive());
+}
+
+// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert.
+// Both HTTP requests complete before the results are retrieved from the
+// CertIssuerSourceAia. There should only be a single callback since the 2nd
+// HTTP request completed before GetNext was called, so both requests can be
+// supplied to the caller in the same batch.
+TEST(CertIssuerSourceAiaTest, TwoAiaCompletedBeforeGetNext) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert2;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // First HTTP request completes. Callback is called as soon as the first
+ // request completes.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Second HTTP request completes before any results were retrieved from the
+ // CertIssuerSourceAia. The callback should not be called again.
+ ASSERT_TRUE(req_manager2->is_request_alive());
+ req_manager2->get_callback().Run(OK,
+ CertDataVector(intermediate_cert2.get()));
+
+ // Caller retrieves results. Both certs should be supplied.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ // 2nd cert is retrieved.
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert());
+
+ // All results are done, SYNC signals completion.
+ status = cert_source_request->GetNext(&result_cert);
+ ASSERT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with three HTTP urls, each pointing to a single DER cert.
+//
+// 1) Two HTTP requests complete before the results are retrieved from the
+// CertIssuerSourceAia.
+// 2) A single cert result is retrieved via GetNext.
+// 3) The third HTTP request completes.
+// 4) The remaining two certs are retrieved.
+//
+// Only one callback should occur (after the first HTTP request completed),
+// since the pending cert results weren't exhausted before the 3rd request
+// completed.
+TEST(CertIssuerSourceAiaTest, AiaRequestCompletesDuringGetNextSequence) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_three_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert2;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2));
+ scoped_refptr<ParsedCertificate> intermediate_cert3;
+ ASSERT_TRUE(ReadTestCert("i3.pem", &intermediate_cert3));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ RequestManager* req_manager3 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia3/I3.foo"));
+ ASSERT_TRUE(req_manager3);
+ ASSERT_TRUE(req_manager3->is_request_alive());
+
+ // First HTTP request completes. Callback is called as soon as the first
+ // request completes.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Second HTTP request completes before any results were retrieved from the
+ // CertIssuerSourceAia. The callback should not be called again.
+ ASSERT_TRUE(req_manager2->is_request_alive());
+ req_manager2->get_callback().Run(OK,
+ CertDataVector(intermediate_cert2.get()));
+
+ // Caller retrieves a single result.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ // Third HTTP request completes.
+ // The callback should not be called again, since the last GetNext call had
+ // indicated more results were pending still.
+ ASSERT_TRUE(req_manager3->is_request_alive());
+ req_manager3->get_callback().Run(OK,
+ CertDataVector(intermediate_cert3.get()));
+
+ // 2nd cert is retrieved.
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert());
+
+ // 3rd cert is retrieved.
+ status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert3->der_cert());
+
+ // All results are done, SYNC signals completion.
+ status = cert_source_request->GetNext(&result_cert);
+ ASSERT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with a single HTTP url pointing to a single DER cert,
+// CertNetFetcher request fails. The callback should be called to indicate the
+// request is complete, but no results should be provided.
+TEST(CertIssuerSourceAiaTest, OneAiaHttpError) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ // HTTP request returns with an error.
+ req_manager->get_callback().Run(ERR_FAILED, std::vector<uint8_t>());
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with a single HTTP url pointing to a single DER cert,
+// CertNetFetcher request completes, but the DER cert fails to parse. The
+// callback should be called to indicate the request is complete, but no results
+// should be provided.
+TEST(CertIssuerSourceAiaTest, OneAiaParseError) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ // HTTP request returns with an error.
+ req_manager->get_callback().Run(OK, std::vector<uint8_t>({1, 2, 3, 4, 5}));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert.
+// One request fails. No callback should be generated yet. Once the second
+// request completes, the callback should occur.
+TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesFirstFails) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert2;
+ ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Request for I.cer completes first, but fails. Callback is NOT called.
+ req_manager->get_callback().Run(ERR_INVALID_RESPONSE, std::vector<uint8_t>());
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Request for I2.foo completes. Callback should be called now.
+ ASSERT_TRUE(req_manager2->is_request_alive());
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager2->get_callback().Run(OK,
+ CertDataVector(intermediate_cert2.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Results from the second http request are retrieved.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert2->der_cert());
+
+ // No more results.
+ status = cert_source_request->GetNext(&result_cert);
+ ASSERT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert.
+// First request completes, result is retrieved, then the second request fails.
+// The second callback should occur to indicate that the results are exhausted,
+// even though no more results are available.
+TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesSecondFails) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Request for I.cer completes first.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Results are retrieved before the other request completes.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ // The other http request is still pending, status should be ASYNC to signify
+ // the need to wait for another callback.
+ ASSERT_EQ(CompletionStatus::ASYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ // Request for I2.foo fails. Callback should be called to indicate that
+ // results are exhausted.
+ ASSERT_TRUE(req_manager2->is_request_alive());
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager2->get_callback().Run(ERR_INVALID_RESPONSE,
+ std::vector<uint8_t>());
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // GetNext has no more results.
+ status = cert_source_request->GetNext(&result_cert);
+ ASSERT_EQ(CompletionStatus::SYNC, status);
+ EXPECT_FALSE(result_cert.get());
+}
+
+// AuthorityInfoAccess with two HTTP urls. Request is cancelled before any HTTP
+// requests finish.
+TEST(CertIssuerSourceAiaTest, CertSourceRequestCancelled) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Delete The CertIssuerSource::Request, cancelling it.
+ cert_source_request.reset();
+ // Both CertNetFetcher::Requests should be cancelled.
+ EXPECT_FALSE(req_manager->is_request_alive());
+ EXPECT_FALSE(req_manager2->is_request_alive());
+}
+
+// AuthorityInfoAccess with two HTTP urls, each pointing to a single DER cert.
+// One request completes, results are retrieved, then request is cancelled
+// before the second HTTP request completes.
+TEST(CertIssuerSourceAiaTest, TwoAiaOneCompletedThenRequestCancelled) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert));
+ scoped_refptr<ParsedCertificate> intermediate_cert;
+ ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ ASSERT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ ASSERT_TRUE(req_manager2->is_request_alive());
+
+ // Request for I.cer completes first.
+ EXPECT_CALL(mock_callback, Callback(cert_source_request.get()));
+ req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get()));
+ Mock::VerifyAndClearExpectations(&mock_callback);
+
+ // Results are retrieved before the other request completes.
+ scoped_refptr<ParsedCertificate> result_cert;
+ CompletionStatus status = cert_source_request->GetNext(&result_cert);
+ EXPECT_EQ(CompletionStatus::SYNC, status);
+ ASSERT_TRUE(result_cert.get());
+ ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert());
+
+ status = cert_source_request->GetNext(&result_cert);
+ // The other http request is still pending, status should be ASYNC to signify
+ // the need to wait for another callback.
+ ASSERT_EQ(CompletionStatus::ASYNC, status);
+ EXPECT_FALSE(result_cert.get());
+
+ // Delete The CertIssuerSource::Request, cancelling it.
+ cert_source_request.reset();
+ // Both CertNetFetcher::Requests should be cancelled.
+ EXPECT_FALSE(req_manager->is_request_alive());
+ EXPECT_FALSE(req_manager2->is_request_alive());
+}
+
+// AuthorityInfoAccess with six HTTP URLs. kMaxFetchesPerCert is 5, so the
+// sixth URL should be ignored.
+TEST(CertIssuerSourceAiaTest, MaxFetchesPerCert) {
+ scoped_refptr<ParsedCertificate> cert;
+ ASSERT_TRUE(ReadTestCert("target_six_aia.pem", &cert));
+
+ StrictMock<MockIssuerCallback> mock_callback;
+ StrictMock<MockCertNetFetcherImpl> mock_fetcher;
+ CertIssuerSourceAia aia_source(&mock_fetcher);
+ std::unique_ptr<CertIssuerSource::Request> cert_source_request;
+ aia_source.AsyncGetIssuersOf(cert.get(),
+ base::Bind(&MockIssuerCallback::Callback,
+ base::Unretained(&mock_callback)),
+ &cert_source_request);
+ ASSERT_NE(nullptr, cert_source_request);
+
+ RequestManager* req_manager =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer"));
+ ASSERT_TRUE(req_manager);
+ EXPECT_TRUE(req_manager->is_request_alive());
+
+ RequestManager* req_manager2 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo"));
+ ASSERT_TRUE(req_manager2);
+ EXPECT_TRUE(req_manager2->is_request_alive());
+
+ RequestManager* req_manager3 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia3/I3.foo"));
+ ASSERT_TRUE(req_manager3);
+ EXPECT_TRUE(req_manager3->is_request_alive());
+
+ RequestManager* req_manager4 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia4/I4.foo"));
+ ASSERT_TRUE(req_manager4);
+ EXPECT_TRUE(req_manager4->is_request_alive());
+
+ RequestManager* req_manager5 =
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia5/I5.foo"));
+ ASSERT_TRUE(req_manager5);
+ EXPECT_TRUE(req_manager5->is_request_alive());
+
+ // Sixth URL should not have created a request.
+ EXPECT_FALSE(
+ mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia6/I6.foo")));
+}
+
+} // namespace
+
+} // namespace net
« no previous file with comments | « net/cert/internal/cert_issuer_source_aia.cc ('k') | net/cert/internal/parse_certificate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698