Commit 994db999 authored by eroman's avatar eroman Committed by Commit bot

Remove dependence on a message loop for net::PathBuilder.

 * Path building now can only complete synchronously
 * Access to trust store is done synchronously
 * The network dependencies (AIA fetching) will block the thread

BUG=649017

Review-Url: https://codereview.chromium.org/2453093004
Cr-Commit-Position: refs/heads/master@{#434769}
parent 51bd8627
......@@ -310,8 +310,7 @@ bool VerifyDeviceCertUsingCustomTrustStore(
signature_policy.get(), verification_time,
&result);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
net::CompletionStatus rv = path_builder.Run(base::Closure());
DCHECK_EQ(rv, net::CompletionStatus::SYNC);
path_builder.Run();
if (!result.HasValidPath()) {
// TODO(crbug.com/634443): Log error information.
return false;
......
......@@ -145,8 +145,7 @@ bool VerifyCRL(const Crl& crl,
net::CertPathBuilder path_builder(parsed_cert.get(), trust_store,
signature_policy.get(), verification_time,
&result);
net::CompletionStatus rv = path_builder.Run(base::Closure());
DCHECK_EQ(rv, net::CompletionStatus::SYNC);
path_builder.Run();
if (!result.HasValidPath()) {
VLOG(2) << "CRL - Issuer certificate verification failed.";
// TODO(crbug.com/634443): Log the error information.
......
......@@ -19,59 +19,38 @@ class GURL;
namespace net {
class URLRequestContext;
// CertNetFetcher is an asynchronous interface for fetching AIA URLs and CRL
// CertNetFetcher is a synchronous interface for fetching AIA URLs and CRL
// URLs.
//
// -------------------------
// Cancellation of requests
// -------------------------
//
// * Network requests started by the CertNetFetcher can be cancelled by
// deleting the Request object. Cancellation means the request's callback
// will no longer be invoked.
//
// * If the CertNetFetcher is deleted then any outstanding
// requests are automatically cancelled.
//
// * Cancelling a request within the execution of a callback is allowed.
// A Request object is returned when starting a fetch. The consumer can
// use this as a handle for aborting the request (by freeing it), or reading
// the result of the request (WaitForResult)
//
// * Deleting the CertNetFetcher from within the execution of a callback is
// allowed.
// This interface is expected to be operated from a single thread.
//
// -------------------------
// Threading
// -------------------------
//
// The CertNetFetcher is expected to be operated from a single thread, which has
// an IO message loop. The URLRequestContext will be accessed from this same
// thread, and callbacks will be posted to this message loop.
//
// For more details see the design document:
// https://docs.google.com/a/chromium.org/document/d/1CdS9YOnPdAyVZBJqHY7ZJ6tUlU71OCvX8kHnaVhf144/edit
// The CertNetFetcher must outlive all Request objects it creates.
class NET_EXPORT CertNetFetcher {
public:
class Request {
public:
virtual ~Request() {}
};
// Callback invoked on request completion. If the Error is OK, then the
// vector contains the response bytes.
using FetchCallback =
base::Callback<void(Error, const std::vector<uint8_t>&)>;
// WaitForResult() can be called at most once.
//
// It will block and wait for the (network) request to complete, and
// then write the result into the provided out-parameters.
virtual void WaitForResult(Error* error, std::vector<uint8_t>* bytes) = 0;
};
// This value can be used in place of timeout or max size limits.
enum { DEFAULT = -1 };
CertNetFetcher() {}
// Deletion implicitly cancels any outstanding requests.
virtual ~CertNetFetcher() {}
// The Fetch*() methods start an asynchronous request which can be cancelled
// by deleting the returned Request. Here is the meaning of the common
// The Fetch*() methods start a request which can be cancelled by
// deleting the returned Request. Here is the meaning of the common
// parameters:
//
// * url -- The http:// URL to fetch.
......@@ -81,25 +60,21 @@ class NET_EXPORT CertNetFetcher {
// * max_response_bytes -- The maximum size of the response body. If this
// size is exceeded then the request will fail. To use a default timeout
// pass DEFAULT.
// * callback -- The callback that will be invoked on completion of the job.
virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCaIssuers(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) = 0;
int max_response_bytes) = 0;
virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCrl(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) = 0;
int max_response_bytes) = 0;
virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) = 0;
int max_response_bytes) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CertNetFetcher);
......
......@@ -8,9 +8,7 @@
#include <memory>
#include <vector>
#include "base/callback.h"
#include "net/base/net_export.h"
#include "net/cert/internal/completion_status.h"
#include "net/cert/internal/parsed_certificate.h"
namespace net {
......@@ -30,27 +28,19 @@ class NET_EXPORT CertIssuerSource {
// Destruction of the Request cancels it.
virtual ~Request() = default;
// Retrieves the next issuer.
// Retrieves issuers and appends them to |issuers|.
//
// If one is available it will be stored in |out_cert| and SYNC will be
// returned. GetNext should be called again to retrieve any remaining
// issuers.
// GetNext should be called again to retrieve any remaining issuers.
//
// If no issuers are currently available, |out_cert| will be cleared and the
// return value will indicate if the Request is exhausted. If the return
// value is ASYNC, the |issuers_callback| that was passed to
// AsyncGetIssuersOf will be called again (unless the Request is destroyed
// first). If the return value is SYNC, the Request is complete and the
// |issuers_callback| will not be called again.
virtual CompletionStatus GetNext(
scoped_refptr<ParsedCertificate>* out_cert) = 0;
// If no issuers are left then |issuers| will not be modified. This
// indicates that the issuers have been exhausted and GetNext() should
// not be called again.
virtual void GetNext(ParsedCertificateList* issuers) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Request);
};
using IssuerCallback = base::Callback<void(Request*)>;
virtual ~CertIssuerSource() = default;
// Finds certificates whose Subject matches |cert|'s Issuer.
......@@ -61,18 +51,13 @@ class NET_EXPORT CertIssuerSource {
ParsedCertificateList* issuers) = 0;
// Finds certificates whose Subject matches |cert|'s Issuer.
// If an async callback will be made |*out_req| is filled with a Request
// object which may be destroyed to cancel the callback. If the implementation
// does not support asynchronous lookups or can determine synchronously that
// it would return no results, |*out_req| will be set to nullptr.
// If the implementation does not support asynchronous lookups or can
// determine synchronously that it would return no results, |*out_req|
// will be set to nullptr.
//
// When matches are available or the request is complete, |issuers_callback|
// will be called with a pointer to the same Request. The Request::GetNext
// method may then be used to iterate through the retrieved issuers. Note that
// |issuers_callback| may be called multiple times. See the documentation for
// Request::GetNext for more details.
// Otherwise a request is started and saved to |out_req|. The results can be
// read through the Request interface.
virtual void AsyncGetIssuersOf(const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) = 0;
};
......
......@@ -20,88 +20,75 @@ const int kMaxFetchesPerCert = 5;
class AiaRequest : public CertIssuerSource::Request {
public:
explicit AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback);
AiaRequest() {}
~AiaRequest() override;
// CertIssuerSource::Request implementation.
CompletionStatus GetNext(scoped_refptr<ParsedCertificate>* out_cert) override;
void GetNext(ParsedCertificateList* issuers) override;
void AddCertFetcherRequest(
std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request);
void OnFetchCompleted(Error error, const std::vector<uint8_t>& fetched_bytes);
bool AddCompletedFetchToResults(Error error,
std::vector<uint8_t> fetched_bytes,
ParsedCertificateList* results);
private:
bool HasNext() const { return current_result_ < results_.size(); }
CertIssuerSource::IssuerCallback issuers_callback_;
std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_;
size_t pending_requests_ = 0;
ParsedCertificateList results_;
size_t current_result_ = 0;
size_t current_request_ = 0;
DISALLOW_COPY_AND_ASSIGN(AiaRequest);
};
AiaRequest::AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback)
: issuers_callback_(issuers_callback) {}
AiaRequest::~AiaRequest() = default;
CompletionStatus AiaRequest::GetNext(
scoped_refptr<ParsedCertificate>* out_cert) {
if (HasNext()) {
*out_cert = std::move(results_[current_result_++]);
return CompletionStatus::SYNC;
void AiaRequest::GetNext(ParsedCertificateList* out_certs) {
// TODO(eroman): Rather than blocking in FIFO order, select the one that
// completes first.
while (current_request_ < cert_fetcher_requests_.size()) {
Error error;
std::vector<uint8_t> bytes;
auto req = std::move(cert_fetcher_requests_[current_request_++]);
req->WaitForResult(&error, &bytes);
if (AddCompletedFetchToResults(error, std::move(bytes), out_certs))
return;
}
*out_cert = nullptr;
if (pending_requests_)
return CompletionStatus::ASYNC;
return CompletionStatus::SYNC;
}
void AiaRequest::AddCertFetcherRequest(
std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request) {
DCHECK(cert_fetcher_request);
cert_fetcher_requests_.push_back(std::move(cert_fetcher_request));
pending_requests_++;
}
void AiaRequest::OnFetchCompleted(Error error,
const std::vector<uint8_t>& fetched_bytes) {
DCHECK_GT(pending_requests_, 0U);
pending_requests_--;
bool client_waiting_for_callback = !HasNext();
bool AiaRequest::AddCompletedFetchToResults(Error error,
std::vector<uint8_t> fetched_bytes,
ParsedCertificateList* results) {
if (error != OK) {
// TODO(mattm): propagate error info.
LOG(ERROR) << "AiaRequest::OnFetchCompleted got error " << error;
} else {
// RFC 5280 section 4.2.2.1:
//
// Conforming applications that support HTTP or FTP for accessing
// certificates MUST be able to accept individual DER encoded
// certificates and SHOULD be able to accept "certs-only" CMS messages.
//
// TODO(mattm): Is supporting CMS message format important?
//
// TODO(mattm): Avoid copying bytes. Change the CertNetFetcher and
// ParsedCertificate interface to allow passing through ownership of the
// bytes.
CertErrors errors;
if (!ParsedCertificate::CreateAndAddToVector(fetched_bytes.data(),
fetched_bytes.size(), {},
&results_, &errors)) {
// TODO(crbug.com/634443): propagate error info.
LOG(ERROR) << "Error parsing cert retrieved from AIA:\n"
<< errors.ToDebugString();
}
return false;
}
// If the client is waiting for results, need to run callback if:
// * Some are available now.
// * The last fetch finished, even with no results. (Client needs to know to
// stop waiting.)
if (client_waiting_for_callback && (HasNext() || pending_requests_ == 0))
issuers_callback_.Run(this);
// RFC 5280 section 4.2.2.1:
//
// Conforming applications that support HTTP or FTP for accessing
// certificates MUST be able to accept individual DER encoded
// certificates and SHOULD be able to accept "certs-only" CMS messages.
//
// TODO(mattm): Is supporting CMS message format important?
//
// TODO(eroman): Avoid copying bytes in the certificate?
CertErrors errors;
if (!ParsedCertificate::CreateAndAddToVector(
fetched_bytes.data(), fetched_bytes.size(), {}, results, &errors)) {
// TODO(crbug.com/634443): propagate error info.
LOG(ERROR) << "Error parsing cert retrieved from AIA:\n"
<< errors.ToDebugString();
return false;
}
return true;
}
} // namespace
......@@ -116,10 +103,8 @@ void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert,
// CertIssuerSourceAia never returns synchronous results.
}
void CertIssuerSourceAia::AsyncGetIssuersOf(
const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) {
void CertIssuerSourceAia::AsyncGetIssuersOf(const ParsedCertificate* cert,
std::unique_ptr<Request>* out_req) {
out_req->reset();
if (!cert->has_authority_info_access())
......@@ -152,16 +137,14 @@ void CertIssuerSourceAia::AsyncGetIssuersOf(
if (urls.empty())
return;
std::unique_ptr<AiaRequest> aia_request(new AiaRequest(issuers_callback));
std::unique_ptr<AiaRequest> aia_request(new AiaRequest());
for (const auto& url : urls) {
// TODO(mattm): add synchronous failure mode to FetchCaIssuers interface so
// that this doesn't need to wait for async callback just to tell that an
// URL has an unsupported scheme?
aia_request->AddCertFetcherRequest(cert_fetcher_->FetchCaIssuers(
url, kTimeoutMilliseconds, kMaxResponseBytes,
base::Bind(&AiaRequest::OnFetchCompleted,
base::Unretained(aia_request.get()))));
url, kTimeoutMilliseconds, kMaxResponseBytes));
}
*out_req = std::move(aia_request);
......
......@@ -26,7 +26,6 @@ class NET_EXPORT CertIssuerSourceAia : public CertIssuerSource {
void SyncGetIssuersOf(const ParsedCertificate* cert,
ParsedCertificateList* issuers) override;
void AsyncGetIssuersOf(const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) override;
private:
......
......@@ -24,7 +24,6 @@ void CertIssuerSourceStatic::SyncGetIssuersOf(const ParsedCertificate* cert,
void CertIssuerSourceStatic::AsyncGetIssuersOf(
const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) {
// CertIssuerSourceStatic never returns asynchronous results.
out_req->reset();
......
......@@ -27,7 +27,6 @@ class NET_EXPORT CertIssuerSourceStatic : public CertIssuerSource {
void SyncGetIssuersOf(const ParsedCertificate* cert,
ParsedCertificateList* issuers) override;
void AsyncGetIssuersOf(const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) override;
private:
......
......@@ -14,10 +14,6 @@ namespace net {
namespace {
void NotCalled(CertIssuerSource::Request* req) {
ADD_FAILURE() << "NotCalled was called";
}
::testing::AssertionResult ReadTestPem(const std::string& file_name,
const std::string& block_name,
std::string* result) {
......@@ -137,7 +133,7 @@ TEST_F(CertIssuerSourceStaticTest, IsNotAsync) {
CertIssuerSourceStatic source;
source.AddCert(i1_1_);
std::unique_ptr<CertIssuerSource::Request> request;
source.AsyncGetIssuersOf(c1_.get(), base::Bind(&NotCalled), &request);
source.AsyncGetIssuersOf(c1_.get(), &request);
EXPECT_EQ(nullptr, request);
}
......
// 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_INTERNAL_COMPLETION_STATUS_H_
#define NET_CERT_INTERNAL_COMPLETION_STATUS_H_
namespace net {
enum class CompletionStatus {
SYNC,
ASYNC,
};
} // namespace net
#endif // NET_CERT_INTERNAL_COMPLETION_STATUS_H_
This diff is collapsed.
......@@ -9,11 +9,8 @@
#include <string>
#include <vector>
#include "base/callback.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/completion_status.h"
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/trust_store.h"
#include "net/der/input.h"
......@@ -107,6 +104,9 @@ class NET_EXPORT CertPathBuilder {
// TODO(mattm): allow caller specified hook/callback to extend path
// verification.
//
// TODO(eroman): The assumption is that |result| is default initialized. Can
// probably just internalize |result| into CertPathBuilder.
//
// Creates a CertPathBuilder that attempts to find a path from |cert| to a
// trust anchor in |trust_store|, which satisfies |signature_policy| and is
// valid at |time|. Details of attempted path(s) are stored in |*result|.
......@@ -129,24 +129,12 @@ class NET_EXPORT CertPathBuilder {
// it is a trust anchor or is directly signed by a trust anchor.)
void AddCertIssuerSource(CertIssuerSource* cert_issuer_source);
// Begins verification of the target certificate.
//
// If the return value is SYNC then the verification is complete and the
// |result| value can be inspected for the status, and |callback| will not be
// called.
// If the return value is ASYNC, the |callback| will be called asynchronously
// once the verification is complete. |result| should not be examined or
// modified until the |callback| is run.
//
// If |callback| is null, verification always completes synchronously, even if
// it fails to find a valid path and one could have been found asynchronously.
// Executes verification of the target certificate.
//
// The CertPathBuilder may be deleted while an ASYNC verification is pending,
// in which case the verification is cancelled, |callback| will not be called,
// and the output Result will be in an undefined state.
// It is safe to delete the CertPathBuilder during the |callback|.
// Run must not be called more than once on each CertPathBuilder instance.
CompletionStatus Run(const base::Closure& callback);
// Upon return results are written to the |result| object passed into the
// constructor. Run must not be called more than once on each CertPathBuilder
// instance.
void Run();
private:
enum State {
......@@ -155,16 +143,11 @@ class NET_EXPORT CertPathBuilder {
STATE_GET_NEXT_PATH_COMPLETE,
};
CompletionStatus DoLoop(bool allow_async);
CompletionStatus DoGetNextPath(bool allow_async);
void HandleGotNextPath();
CompletionStatus DoGetNextPathComplete();
void DoGetNextPath();
void DoGetNextPathComplete();
void AddResultPath(std::unique_ptr<ResultPath> result_path);
base::Closure callback_;
std::unique_ptr<CertPathIter> cert_path_iter_;
const SignaturePolicy* signature_policy_;
const der::GeneralizedTime time_;
......
......@@ -90,8 +90,7 @@ class PathBuilderPkitsTestDelegate {
&signature_policy, time, &result);
path_builder.AddCertIssuerSource(&cert_issuer_source);
CompletionStatus rv = path_builder.Run(base::Closure());
EXPECT_EQ(CompletionStatus::SYNC, rv);
path_builder.Run();
return result.HasValidPath();
}
......
This diff is collapsed.
......@@ -37,9 +37,7 @@ class PathBuilderDelegate {
time, &result);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
CompletionStatus rv = path_builder.Run(base::Closure());
EXPECT_EQ(CompletionStatus::SYNC, rv);
path_builder.Run();
EXPECT_EQ(expected_result, result.HasValidPath());
}
};
......
......@@ -36,9 +36,6 @@ TrustAnchor::TrustAnchor(scoped_refptr<ParsedCertificate> cert,
TrustAnchor::~TrustAnchor() = default;
TrustStore::Request::Request() = default;
TrustStore::Request::~Request() = default;
TrustStore::TrustStore() = default;
TrustStore::~TrustStore() = default;
......
......@@ -7,7 +7,6 @@
#include <vector>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
#include "net/cert/internal/parsed_certificate.h"
......@@ -115,35 +114,14 @@ using TrustAnchors = std::vector<scoped_refptr<TrustAnchor>>;
// Interface for finding trust anchors.
class NET_EXPORT TrustStore {
public:
class NET_EXPORT Request {
public:
Request();
// Destruction of the Request cancels it.
virtual ~Request();
};
TrustStore();
virtual ~TrustStore();
using TrustAnchorsCallback = base::Callback<void(TrustAnchors)>;
// Returns the trust anchors that match |cert|'s issuer name in
// |*synchronous_matches| and/or through |callback|. |cert| and
// |synchronous_matches| must not be null.
//
// If results are available synchronously, they will be appended to
// |*synchronous_matches|. |*synchronous_matches| will not be modified
// asynchronously.
//
// If |callback| is not null and results may be available asynchronously,
// |*out_req| will be filled with a Request, and |callback| will be called
// when results are available. The Request may be destroyed to cancel
// the callback if it has not occurred yet.
// Appends the trust anchors that match |cert|'s issuer name to |*matches|.
// |cert| and |matches| must not be null.
virtual void FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const = 0;
TrustAnchors* matches) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(TrustStore);
......
......@@ -9,29 +9,16 @@ namespace net {
TrustStoreCollection::TrustStoreCollection() = default;
TrustStoreCollection::~TrustStoreCollection() = default;
void TrustStoreCollection::SetPrimaryTrustStore(TrustStore* store) {
DCHECK(!primary_store_);
void TrustStoreCollection::AddTrustStore(TrustStore* store) {
DCHECK(store);
primary_store_ = store;
}
void TrustStoreCollection::AddTrustStoreSynchronousOnly(TrustStore* store) {
DCHECK(store);
sync_only_stores_.push_back(store);
stores_.push_back(store);
}
void TrustStoreCollection::FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const {
if (primary_store_)
primary_store_->FindTrustAnchorsForCert(cert, callback, synchronous_matches,
out_req);
for (auto* store : sync_only_stores_) {
store->FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
synchronous_matches, nullptr);
TrustAnchors* matches) const {
for (auto* store : stores_) {
store->FindTrustAnchorsForCert(cert, matches);
}
}
......
......@@ -18,41 +18,23 @@ namespace net {
// TrustStoreCollection is an implementation of TrustStore which combines the
// results from multiple TrustStores.
//
// The synchronous matches will be in order from the primary store, and then
// from the secondary stores in the order they were added to the
// TrustStoreCollection.
//
// Currently only one "primary" store can be added that supports async queries,
// any number of additional, synchronous-only stores can be used. (The
// assumption is that the async one would be useful for OS integration, while
// the sync only stores can be used for supplying additional anchors. If
// multiple async stores are desired, it might be worth changing the
// FindTrustAnchorsForCert interface so that it can return async results in
// multiple batches.)
// The order of the matches will correspond to a concatenation of matches in
// the order the stores were added.
class NET_EXPORT TrustStoreCollection : public TrustStore {
public:
TrustStoreCollection();
~TrustStoreCollection() override;
// Includes results from |store| in the combined output. Both sync and async
// queries to |store| will be allowed. |store| must outlive the
// TrustStoreCollection.
void SetPrimaryTrustStore(TrustStore* store);
// Includes results from |store| in the combined output. |store| will only be
// queried synchronously. |store| must outlive the TrustStoreCollection.
void AddTrustStoreSynchronousOnly(TrustStore* store);
// Includes results from |store| in the combined output. |store| must
// outlive the TrustStoreCollection.
void AddTrustStore(TrustStore* store);
// TrustStore implementation:
void FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const override;
void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert,
TrustAnchors* matches) const override;
private:
TrustStore* primary_store_ = nullptr;
std::vector<TrustStore*> sync_only_stores_;
std::vector<TrustStore*> stores_;
DISALLOW_COPY_AND_ASSIGN(TrustStoreCollection);
};
......
......@@ -4,33 +4,14 @@
#include "net/cert/internal/trust_store_collection.h"
#include "base/bind.h"
#include "net/cert/internal/test_helpers.h"
#include "net/cert/internal/trust_store_test_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
using ::testing::_;
using ::testing::Property;
using ::testing::StrictMock;
void NotCalled(TrustAnchors anchors) {
ADD_FAILURE() << "NotCalled was called";
}
class MockTrustStore : public TrustStore {
public:
MOCK_CONST_METHOD4(FindTrustAnchorsForCert,
void(const scoped_refptr<ParsedCertificate>&,
const TrustAnchorsCallback&,
TrustAnchors*,
std::unique_ptr<Request>*));
};
class TrustStoreCollectionTest : public testing::Test {
public:
void SetUp() override {
......@@ -75,155 +56,46 @@ class TrustStoreCollectionTest : public testing::Test {
scoped_refptr<ParsedCertificate> newintermediate_;
};
// Collection contains no stores, should return no results and complete
// synchronously.
// Collection contains no stores, should return no results.
TEST_F(TrustStoreCollectionTest, NoStores) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
TrustAnchors matches;
TrustStoreCollection collection;
collection.FindTrustAnchorsForCert(target_, base::Bind(&NotCalled),
&sync_matches, &req);
collection.FindTrustAnchorsForCert(target_, &matches);
EXPECT_FALSE(req);
EXPECT_TRUE(sync_matches.empty());
EXPECT_TRUE(matches.empty());
}
// Collection contains only one synchronous store, should complete
// synchronously.
TEST_F(TrustStoreCollectionTest, NoPrimaryStoreOneSyncStore) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
// Collection contains only one store.
TEST_F(TrustStoreCollectionTest, OneStore) {
TrustAnchors matches;
TrustStoreCollection collection;
TrustStoreInMemory in_memory;
in_memory.AddTrustAnchor(newroot_);
collection.AddTrustStoreSynchronousOnly(&in_memory);
collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
&sync_matches, &req);
EXPECT_FALSE(req);
ASSERT_EQ(1U, sync_matches.size());
EXPECT_EQ(newroot_, sync_matches[0]);
}
// Collection contains two synchronous stores, should complete synchronously.
TEST_F(TrustStoreCollectionTest, NoPrimaryStoreTwoSyncStores) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
TrustStoreCollection collection;
TrustStoreInMemory in_memory1;
TrustStoreInMemory in_memory2;
in_memory1.AddTrustAnchor(newroot_);
in_memory2.AddTrustAnchor(oldroot_);
collection.AddTrustStoreSynchronousOnly(&in_memory1);
collection.AddTrustStoreSynchronousOnly(&in_memory2);
collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
&sync_matches, &req);
EXPECT_FALSE(req);
ASSERT_EQ(2U, sync_matches.size());
EXPECT_EQ(newroot_, sync_matches[0]);
EXPECT_EQ(oldroot_, sync_matches[1]);
}
// The secondary stores in the collection should not be passed a callback to
// their FindTrustAnchorsForCert call.
TEST_F(TrustStoreCollectionTest, SyncStoresAreQueriedSynchronously) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
TrustStoreCollection collection;
StrictMock<MockTrustStore> store;
collection.AddTrustStoreSynchronousOnly(&store);
collection.AddTrustStore(&in_memory);
collection.FindTrustAnchorsForCert(newintermediate_, &matches);
EXPECT_CALL(
store,
FindTrustAnchorsForCert(
_, Property(&TrustStore::TrustAnchorsCallback::is_null, true), _, _));
collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
&sync_matches, &req);
EXPECT_FALSE(req);
EXPECT_TRUE(sync_matches.empty());
ASSERT_EQ(1U, matches.size());
EXPECT_EQ(newroot_, matches[0]);
}
// If the primary store completes synchronously, TrustStoreCollection should
// complete synchronously also.
TEST_F(TrustStoreCollectionTest, AllStoresAreSynchronous) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
// Collection contains two stores.
TEST_F(TrustStoreCollectionTest, TwoStores) {
TrustAnchors matches;
TrustStoreCollection collection;
TrustStoreInMemory in_memory1;
TrustStoreInMemory in_memory2;
in_memory1.AddTrustAnchor(newroot_);
in_memory2.AddTrustAnchor(oldroot_);
collection.SetPrimaryTrustStore(&in_memory1);
collection.AddTrustStoreSynchronousOnly(&in_memory2);
collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
&sync_matches, &req);
EXPECT_FALSE(req);
ASSERT_EQ(2U, sync_matches.size());
EXPECT_EQ(newroot_, sync_matches[0]);
EXPECT_EQ(oldroot_, sync_matches[1]);
}
// Primary store returns results asynchronously. No secondary stores registered.
TEST_F(TrustStoreCollectionTest, AsyncPrimaryStore) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
TrustStoreInMemoryAsync in_memory_async;
in_memory_async.AddAsyncTrustAnchor(newroot_);
TrustStoreCollection collection;
collection.SetPrimaryTrustStore(&in_memory_async);
TrustAnchorResultRecorder anchor_results;
collection.FindTrustAnchorsForCert(
newintermediate_, anchor_results.Callback(), &sync_matches, &req);
ASSERT_TRUE(req);
EXPECT_TRUE(sync_matches.empty());
anchor_results.Run();
ASSERT_EQ(1U, anchor_results.matches().size());
EXPECT_EQ(newroot_, anchor_results.matches()[0]);
}
// Primary store returns results both synchronously and asynchronously, and
// a secondary store returns results synchronously as well.
TEST_F(TrustStoreCollectionTest, SyncAndAsyncPrimaryStoreAndSyncStore) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
TrustStoreInMemoryAsync in_memory_async;
in_memory_async.AddAsyncTrustAnchor(newroot_);
in_memory_async.AddSyncTrustAnchor(newrootrollover_);
TrustStoreInMemory in_memory;
in_memory.AddTrustAnchor(oldroot_);
TrustStoreCollection collection;
collection.SetPrimaryTrustStore(&in_memory_async);
collection.AddTrustStoreSynchronousOnly(&in_memory);
TrustAnchorResultRecorder anchor_results;
collection.FindTrustAnchorsForCert(
newintermediate_, anchor_results.Callback(), &sync_matches, &req);
ASSERT_TRUE(req);
ASSERT_EQ(2U, sync_matches.size());
EXPECT_EQ(newrootrollover_, sync_matches[0]);
EXPECT_EQ(oldroot_, sync_matches[1]);
collection.AddTrustStore(&in_memory1);
collection.AddTrustStore(&in_memory2);
collection.FindTrustAnchorsForCert(newintermediate_, &matches);
anchor_results.Run();
ASSERT_EQ(1U, anchor_results.matches().size());
EXPECT_EQ(newroot_, anchor_results.matches()[0]);
ASSERT_EQ(2U, matches.size());
EXPECT_EQ(newroot_, matches[0]);
EXPECT_EQ(oldroot_, matches[1]);
}
} // namespace
......
......@@ -21,12 +21,10 @@ void TrustStoreInMemory::AddTrustAnchor(scoped_refptr<TrustAnchor> anchor) {
void TrustStoreInMemory::FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const {
TrustAnchors* matches) const {
auto range = anchors_.equal_range(cert->normalized_issuer().AsStringPiece());
for (auto it = range.first; it != range.second; ++it)
synchronous_matches->push_back(it->second);
matches->push_back(it->second);
}
} // namespace net
......@@ -31,11 +31,8 @@ class NET_EXPORT TrustStoreInMemory : public TrustStore {
void AddTrustAnchor(scoped_refptr<TrustAnchor> anchor);
// TrustStore implementation:
void FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const override;
void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert,
TrustAnchors* matches) const override;
private:
// Multimap from normalized subject -> TrustAnchor.
......
......@@ -7,11 +7,7 @@
#include <cert.h>
#include <certdb.h>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/task_runner.h"
#include "crypto/nss_util.h"
#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parsed_certificate.h"
......@@ -22,13 +18,14 @@
namespace net {
namespace {
TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type)
: trust_type_(trust_type) {}
// Get all certs in NSS which have a subject matching |der_name| and which are
// marked as a trusted CA.
void GetAnchors(const scoped_refptr<ParsedCertificate>& cert,
SECTrustType trust_type,
TrustAnchors* out_anchors) {
TrustStoreNSS::~TrustStoreNSS() = default;
void TrustStoreNSS::FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
TrustAnchors* out_anchors) const {
crypto::EnsureNSSInit();
SECItem name;
......@@ -54,7 +51,7 @@ void GetAnchors(const scoped_refptr<ParsedCertificate>& cert,
// TODO(mattm): handle explicit distrust (blacklisting)?
const int ca_trust = CERTDB_TRUSTED_CA;
if ((SEC_GET_TRUST_FLAGS(&trust, trust_type) & ca_trust) != ca_trust)
if ((SEC_GET_TRUST_FLAGS(&trust, trust_type_) & ca_trust) != ca_trust)
continue;
CertErrors errors;
......@@ -73,65 +70,4 @@ void GetAnchors(const scoped_refptr<ParsedCertificate>& cert,
CERT_DestroyCertList(found_certs);
}
class GetAnchorsRequest : public TrustStore::Request {
public:
explicit GetAnchorsRequest(const TrustStore::TrustAnchorsCallback& callback);
// Destruction of the Request cancels it. GetAnchors will still run, but the
// callback will not be called since the WeakPtr will be invalidated.
~GetAnchorsRequest() override = default;
void Start(const scoped_refptr<ParsedCertificate>& cert,
SECTrustType trust_type,
base::TaskRunner* task_runner);
private:
void HandleGetAnchors(std::unique_ptr<TrustAnchors> anchors);
TrustStore::TrustAnchorsCallback callback_;
base::WeakPtrFactory<GetAnchorsRequest> weak_ptr_factory_;
};
GetAnchorsRequest::GetAnchorsRequest(
const TrustStore::TrustAnchorsCallback& callback)
: callback_(callback), weak_ptr_factory_(this) {}
void GetAnchorsRequest::Start(const scoped_refptr<ParsedCertificate>& cert,
SECTrustType trust_type,
base::TaskRunner* task_runner) {
auto anchors = base::MakeUnique<TrustAnchors>();
auto* anchors_ptr = anchors.get();
task_runner->PostTaskAndReply(
FROM_HERE, base::Bind(&GetAnchors, cert, trust_type, anchors_ptr),
base::Bind(&GetAnchorsRequest::HandleGetAnchors,
weak_ptr_factory_.GetWeakPtr(), base::Passed(&anchors)));
}
void GetAnchorsRequest::HandleGetAnchors(
std::unique_ptr<TrustAnchors> anchors) {
base::ResetAndReturn(&callback_).Run(std::move(*anchors));
// |this| may be deleted here.
}
} // namespace
TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type,
scoped_refptr<base::TaskRunner> nss_task_runner)
: trust_type_(trust_type), nss_task_runner_(std::move(nss_task_runner)) {}
TrustStoreNSS::~TrustStoreNSS() = default;
void TrustStoreNSS::FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const {
if (callback.is_null())
return;
auto req = base::MakeUnique<GetAnchorsRequest>(callback);
req->Start(cert, trust_type_, nss_task_runner_.get());
*out_req = std::move(req);
}
} // namespace net
......@@ -11,10 +11,6 @@
#include "net/base/net_export.h"
#include "net/cert/internal/trust_store.h"
namespace base {
class TaskRunner;
}
namespace net {
// TrustStoreNSS is an implementation of TrustStore which uses NSS to find trust
......@@ -26,21 +22,16 @@ namespace net {
class NET_EXPORT TrustStoreNSS : public TrustStore {
public:
// Creates a TrustStoreNSS which will find anchors that are trusted for
// |trust_type|. All NSS calls will be done on |nss_task_runner|.
TrustStoreNSS(SECTrustType trust_type,
scoped_refptr<base::TaskRunner> nss_task_runner);
// |trust_type|.
explicit TrustStoreNSS(SECTrustType trust_type);
~TrustStoreNSS() override;
// TrustStore implementation:
void FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const override;
void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert,
TrustAnchors* matches) const override;
private:
SECTrustType trust_type_;
scoped_refptr<base::TaskRunner> nss_task_runner_;
DISALLOW_COPY_AND_ASSIGN(TrustStoreNSS);
};
......
......@@ -7,14 +7,10 @@
#include <cert.h>
#include <certdb.h>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "crypto/scoped_test_nss_db.h"
#include "net/cert/internal/test_helpers.h"
#include "net/cert/internal/trust_store_test_helpers.h"
#include "net/cert/scoped_nss_types.h"
#include "net/cert/x509_certificate.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -23,10 +19,6 @@ namespace net {
namespace {
void NotCalled(TrustAnchors anchors) {
ADD_FAILURE() << "NotCalled was called";
}
class TrustStoreNSSTest : public testing::Test {
public:
void SetUp() override {
......@@ -61,8 +53,7 @@ class TrustStoreNSSTest : public testing::Test {
ASSERT_TRUE(newroot_);
ASSERT_TRUE(newrootrollover_);
trust_store_nss_.reset(
new TrustStoreNSS(trustSSL, base::ThreadTaskRunnerHandle::Get()));
trust_store_nss_.reset(new TrustStoreNSS(trustSSL));
}
std::string GetUniqueNickname() {
......@@ -112,31 +103,27 @@ class TrustStoreNSSTest : public testing::Test {
}
protected:
void ExpectTrustStoreContains(tracked_objects::Location loc,
scoped_refptr<ParsedCertificate> cert,
TrustAnchors expected_async_matches) {
SCOPED_TRACE(loc.ToString());
TrustAnchors sync_matches;
TrustAnchorResultRecorder anchor_results;
std::unique_ptr<TrustStore::Request> req;
trust_store_nss_->FindTrustAnchorsForCert(cert, anchor_results.Callback(),
&sync_matches, &req);
ASSERT_TRUE(req);
EXPECT_TRUE(sync_matches.empty());
anchor_results.Run();
bool TrustStoreContains(scoped_refptr<ParsedCertificate> cert,
TrustAnchors expected_matches) {
TrustAnchors matches;
trust_store_nss_->FindTrustAnchorsForCert(cert, &matches);
std::vector<der::Input> der_result_matches;
for (const auto& it : anchor_results.matches())
for (const auto& it : matches)
der_result_matches.push_back(it->cert()->der_cert());
std::sort(der_result_matches.begin(), der_result_matches.end());
std::vector<der::Input> der_expected_matches;
for (const auto& it : expected_async_matches)
for (const auto& it : expected_matches)
der_expected_matches.push_back(it->cert()->der_cert());
std::sort(der_expected_matches.begin(), der_expected_matches.end());
if (der_expected_matches == der_result_matches)
return true;
// Print some extra information for debugging.
EXPECT_EQ(der_expected_matches, der_result_matches);
return false;
}
scoped_refptr<TrustAnchor> oldroot_;
......@@ -154,19 +141,19 @@ class TrustStoreNSSTest : public testing::Test {
// Without adding any certs to the NSS DB, should get no anchor results for any
// of the test certs.
TEST_F(TrustStoreNSSTest, CertsNotPresent) {
ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors()));
}
// If certs are present in NSS DB but aren't marked as trusted, should get no
// anchor results for any of the test certs.
TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) {
AddCertsToNSS();
ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors()));
}
// A self-signed CA certificate is trusted. FindTrustAnchorsForCert should
......@@ -175,12 +162,12 @@ TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) {
TEST_F(TrustStoreNSSTest, TrustedCA) {
AddCertsToNSS();
TrustCert(newroot_.get());
ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_});
ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_});
ExpectTrustStoreContains(FROM_HERE, newrootrollover_, {newroot_});
ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_});
ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), {newroot_});
EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newintermediate_, {newroot_}));
EXPECT_TRUE(TrustStoreContains(oldintermediate_, {newroot_}));
EXPECT_TRUE(TrustStoreContains(newrootrollover_, {newroot_}));
EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), {newroot_}));
EXPECT_TRUE(TrustStoreContains(newroot_->cert(), {newroot_}));
}
// When an intermediate certificate is trusted, FindTrustAnchorsForCert should
......@@ -189,14 +176,14 @@ TEST_F(TrustStoreNSSTest, TrustedCA) {
TEST_F(TrustStoreNSSTest, TrustedIntermediate) {
AddCertsToNSS();
TrustCert(newintermediate_.get());
ExpectTrustStoreContains(
FROM_HERE, target_,
{TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)});
ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, oldintermediate_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newrootrollover_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
EXPECT_TRUE(TrustStoreContains(
target_,
{TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)}));
EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(oldintermediate_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newrootrollover_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors()));
}
// Multiple self-signed CA certificates with the same name are trusted.
......@@ -206,41 +193,10 @@ TEST_F(TrustStoreNSSTest, MultipleTrustedCAWithSameSubject) {
AddCertsToNSS();
TrustCert(oldroot_.get());
TrustCert(newroot_.get());
ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_, oldroot_});
ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_, oldroot_});
ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_, oldroot_});
}
// Cancel a FindTrustAnchorsForCert request before it has returned any results.
// Callback should not be called.
TEST_F(TrustStoreNSSTest, CancelRequest) {
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
trust_store_nss_->FindTrustAnchorsForCert(target_, base::Bind(&NotCalled),
&sync_matches, &req);
ASSERT_TRUE(req);
req.reset();
base::RunLoop().RunUntilIdle();
}
// Cancel a FindTrustAnchorsForCert request during the callback. Should not
// crash.
TEST_F(TrustStoreNSSTest, CancelRequestDuringCallback) {
AddCertsToNSS();
TrustCert(newroot_.get());
base::RunLoop run_loop;
std::unique_ptr<TrustStore::Request> req;
TrustAnchors sync_matches;
trust_store_nss_->FindTrustAnchorsForCert(
newintermediate_,
base::Bind(&TrustStoreRequestDeleter, &req, run_loop.QuitClosure()),
&sync_matches, &req);
ASSERT_TRUE(req);
run_loop.Run();
ASSERT_FALSE(req);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors()));
EXPECT_TRUE(TrustStoreContains(newintermediate_, {newroot_, oldroot_}));
EXPECT_TRUE(TrustStoreContains(oldintermediate_, {newroot_, oldroot_}));
EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), {newroot_, oldroot_}));
}
} // namespace
......
// 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/trust_store_test_helpers.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
namespace net {
namespace {
class TrustStoreInMemoryAsyncRequest : public TrustStore::Request {
public:
explicit TrustStoreInMemoryAsyncRequest(
const TrustStore::TrustAnchorsCallback& callback)
: callback_(callback), weak_ptr_factory_(this) {}
void PostTrustCallback(TrustAnchors anchors) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&TrustStoreInMemoryAsyncRequest::DoTrustCallback,
weak_ptr_factory_.GetWeakPtr(), std::move(anchors)));
}
private:
void DoTrustCallback(TrustAnchors anchors) {
base::ResetAndReturn(&callback_).Run(std::move(anchors));
// |this| may be deleted here.
}
TrustStore::TrustAnchorsCallback callback_;
base::WeakPtrFactory<TrustStoreInMemoryAsyncRequest> weak_ptr_factory_;
};
} // namespace
void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner,
const base::Closure& done_callback,
TrustAnchors anchors) {
req_owner->reset();
done_callback.Run();
}
TrustAnchorResultRecorder::TrustAnchorResultRecorder() = default;
TrustAnchorResultRecorder::~TrustAnchorResultRecorder() = default;
TrustStore::TrustAnchorsCallback TrustAnchorResultRecorder::Callback() {
return base::Bind(&TrustAnchorResultRecorder::OnGotAnchors,
base::Unretained(this));
}
void TrustAnchorResultRecorder::OnGotAnchors(TrustAnchors anchors) {
anchors_ = std::move(anchors);
run_loop_.Quit();
}
TrustStoreInMemoryAsync::TrustStoreInMemoryAsync() = default;
TrustStoreInMemoryAsync::~TrustStoreInMemoryAsync() = default;
void TrustStoreInMemoryAsync::AddSyncTrustAnchor(
scoped_refptr<TrustAnchor> anchor) {
sync_store_.AddTrustAnchor(std::move(anchor));
}
void TrustStoreInMemoryAsync::AddAsyncTrustAnchor(
scoped_refptr<TrustAnchor> anchor) {
async_store_.AddTrustAnchor(std::move(anchor));
}
void TrustStoreInMemoryAsync::FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const {
sync_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
synchronous_matches, nullptr);
if (!callback.is_null()) {
TrustAnchors async_matches;
async_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
&async_matches, nullptr);
std::unique_ptr<TrustStoreInMemoryAsyncRequest> req(
base::MakeUnique<TrustStoreInMemoryAsyncRequest>(callback));
req->PostTrustCallback(std::move(async_matches));
*out_req = std::move(req);
}
}
} // namespace net
// 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_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
#define NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
#include "base/callback.h"
#include "base/run_loop.h"
#include "net/cert/internal/trust_store.h"
#include "net/cert/internal/trust_store_in_memory.h"
namespace net {
// Deletes the Request owned by |*req_owner|, then calls done_callback. Intended
// to be passed as the TrustAnchorsCallback to FindTrustAnchorsForCert to test
// deleting the Request during the request callback.
void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner,
const base::Closure& done_callback,
TrustAnchors anchors);
// Helper to record async results from a FindTrustAnchorsForCert call.
class TrustAnchorResultRecorder {
public:
TrustAnchorResultRecorder();
~TrustAnchorResultRecorder();
TrustStore::TrustAnchorsCallback Callback();
void Run() { run_loop_.Run(); }
const TrustAnchors& matches() const { return anchors_; }
private:
void OnGotAnchors(TrustAnchors anchors);
base::RunLoop run_loop_;
TrustAnchors anchors_;
};
// In-memory TrustStore that can return results synchronously, asynchronously,
// or both.
class TrustStoreInMemoryAsync : public TrustStore {
public:
TrustStoreInMemoryAsync();
~TrustStoreInMemoryAsync() override;
// Adds |anchor| to the set of results that will be returned synchronously.
void AddSyncTrustAnchor(scoped_refptr<TrustAnchor> anchor);
// Adds |anchor| to the set of results that will be returned asynchronously.
void AddAsyncTrustAnchor(scoped_refptr<TrustAnchor> anchor);
// TrustStore implementation:
void FindTrustAnchorsForCert(
const scoped_refptr<ParsedCertificate>& cert,
const TrustAnchorsCallback& callback,
TrustAnchors* synchronous_matches,
std::unique_ptr<Request>* out_req) const override;
private:
TrustStoreInMemory sync_store_;
TrustStoreInMemory async_store_;
};
} // namespace net
#endif // NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
This diff is collapsed.
......@@ -5,105 +5,23 @@
#ifndef NET_CERT_NET_CERT_NET_FETCHER_H_
#define NET_CERT_NET_CERT_NET_FETCHER_H_
#include <map>
#include <memory>
#include "base/callback.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/cert/cert_net_fetcher.h"
namespace net {
class URLRequestContext;
class CertNetFetcher;
class URLRequestContextGetter;
// CertNetFetcherImpl is an implementation of CertNetFetcher that uses the
// network stack.
// Creates a CertNetFetcher that issues requests through the provided
// URLRequestContext.
//
// For more details refer to the documentation for the interface.
class NET_EXPORT CertNetFetcherImpl : public CertNetFetcher {
public:
// Initializes CertNetFetcherImpl using the specified URLRequestContext for
// issuing requests. |context| must remain valid for the entire lifetime of
// the CertNetFetcherImpl.
explicit CertNetFetcherImpl(URLRequestContext* context);
// Deletion implicitly cancels any outstanding requests.
~CertNetFetcherImpl() override;
WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCaIssuers(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) override;
WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCrl(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) override;
WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp(
const GURL& url,
int timeout_milliseconds,
int max_response_bytes,
const FetchCallback& callback) override;
private:
class RequestImpl;
class Job;
struct JobToRequestParamsComparator;
struct RequestParams;
struct JobComparator {
bool operator()(const Job* job1, const Job* job2) const;
};
// Would be a set<unique_ptr> but extraction of owned objects from a set of
// owned types doesn't come until C++17.
using JobSet = std::map<Job*, std::unique_ptr<Job>, JobComparator>;
// Starts an asynchronous request to fetch the given URL. On completion
// |callback| will be invoked.
//
// Completion of the request will never occur synchronously. In other words it
// is guaranteed that |callback| will only be invoked once the Fetch*() method
// has returned.
WARN_UNUSED_RESULT std::unique_ptr<Request> Fetch(
std::unique_ptr<RequestParams> request_params,
const FetchCallback& callback);
// Finds a job with a matching RequestPararms or returns nullptr if there was
// no match.
Job* FindJob(const RequestParams& params);
// Removes |job| from the in progress jobs and transfers ownership to the
// caller.
std::unique_ptr<Job> RemoveJob(Job* job);
// Indicates which Job is currently executing inside of OnJobCompleted().
void SetCurrentlyCompletingJob(Job* job);
void ClearCurrentlyCompletingJob(Job* job);
bool IsCurrentlyCompletingJob(Job* job);
// The in-progress jobs. This set does not contain the job which is actively
// invoking callbacks (OnJobCompleted). Instead that is tracked by
// |currently_completing_job_|.
JobSet jobs_;
// The Job that is currently executing OnJobCompleted(). There can be at most
// one such job. This pointer is not owned.
Job* currently_completing_job_;
// Not owned. CertNetFetcherImpl must outlive the URLRequestContext.
URLRequestContext* context_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(CertNetFetcherImpl);
};
// The returned CertNetFetcher is to be operated on a thread *other* than the
// thread used for the URLRequestContext (since it gives a blocking interface
// to URL fetching).
NET_EXPORT std::unique_ptr<CertNetFetcher> CreateCertNetFetcher(
URLRequestContextGetter* context_getter);
} // namespace net
......
......@@ -1502,8 +1502,6 @@
'cert/internal/test_helpers.h',
'cert/internal/trust_store_collection_unittest.cc',
'cert/internal/trust_store_nss_unittest.cc',
'cert/internal/trust_store_test_helpers.cc',
'cert/internal/trust_store_test_helpers.h',
'cert/internal/verify_certificate_chain_pkits_unittest.cc',
'cert/internal/verify_certificate_chain_typed_unittest.h',
'cert/internal/verify_certificate_chain_unittest.cc',
......
......@@ -69,6 +69,7 @@ void PrintUsage(const char* argv0) {
int main(int argc, char** argv) {
base::AtExitManager at_exit_manager;
// TODO(eroman): Is this needed?
base::MessageLoopForIO message_loop;
if (!base::CommandLine::Init(argc, argv)) {
std::cerr << "ERROR in CommandLine::Init\n";
......
......@@ -9,8 +9,9 @@
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread.h"
#include "crypto/sha2.h"
#include "net/base/test_completion_callback.h"
#include "net/cert/cert_net_fetcher.h"
#include "net/cert/internal/cert_issuer_source_aia.h"
#include "net/cert/internal/cert_issuer_source_static.h"
#include "net/cert/internal/parse_name.h"
......@@ -23,6 +24,7 @@
#include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_context_getter.h"
#if defined(USE_NSS_CERTS)
#include "base/threading/thread_task_runner_handle.h"
......@@ -167,6 +169,57 @@ scoped_refptr<net::ParsedCertificate> ParseCertificate(const CertInput& input) {
return cert;
}
class URLRequestContextGetterForAia : public net::URLRequestContextGetter {
public:
URLRequestContextGetterForAia(
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: task_runner_(std::move(task_runner)) {}
net::URLRequestContext* GetURLRequestContext() override {
DCHECK(task_runner_->BelongsToCurrentThread());
if (!context_) {
// TODO(mattm): add command line flags to configure using
// CertIssuerSourceAia
// (similar to VERIFY_CERT_IO_ENABLED flag for CertVerifyProc).
net::URLRequestContextBuilder url_request_context_builder;
url_request_context_builder.set_user_agent(GetUserAgent());
#if defined(OS_LINUX)
// On Linux, use a fixed ProxyConfigService, since the default one
// depends on glib.
//
// TODO(akalin): Remove this once http://crbug.com/146421 is fixed.
url_request_context_builder.set_proxy_config_service(
base::MakeUnique<net::ProxyConfigServiceFixed>(net::ProxyConfig()));
#endif
context_ = url_request_context_builder.Build();
}
return context_.get();
}
void ShutDown() {
GetNetworkTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&URLRequestContextGetterForAia::ShutdownOnNetworkThread,
this));
}
scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
const override {
return task_runner_;
}
private:
~URLRequestContextGetterForAia() override { DCHECK(!context_); }
void ShutdownOnNetworkThread() { context_.release(); }
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::unique_ptr<net::URLRequestContext> context_;
};
} // namespace
// Verifies |target_der_cert| using CertPathBuilder.
......@@ -183,7 +236,7 @@ bool VerifyUsingPathBuilder(
net::TrustStoreCollection trust_store;
net::TrustStoreInMemory trust_store_in_memory;
trust_store.AddTrustStoreSynchronousOnly(&trust_store_in_memory);
trust_store.AddTrustStore(&trust_store_in_memory);
for (const auto& der_cert : root_der_certs) {
scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert);
if (cert) {
......@@ -193,9 +246,8 @@ bool VerifyUsingPathBuilder(
}
#if defined(USE_NSS_CERTS)
net::TrustStoreNSS trust_store_nss(trustSSL,
base::ThreadTaskRunnerHandle::Get());
trust_store.SetPrimaryTrustStore(&trust_store_nss);
net::TrustStoreNSS trust_store_nss(trustSSL);
trust_store.AddTrustStore(&trust_store_nss);
#else
if (root_der_certs.empty()) {
std::cerr << "NOTE: CertPathBuilder does not currently use OS trust "
......@@ -222,32 +274,24 @@ bool VerifyUsingPathBuilder(
&signature_policy, time, &result);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
// TODO(mattm): add command line flags to configure using CertIssuerSourceAia
// (similar to VERIFY_CERT_IO_ENABLED flag for CertVerifyProc).
net::URLRequestContextBuilder url_request_context_builder;
url_request_context_builder.set_user_agent(GetUserAgent());
#if defined(OS_LINUX)
// On Linux, use a fixed ProxyConfigService, since the default one
// depends on glib.
//
// TODO(akalin): Remove this once http://crbug.com/146421 is fixed.
url_request_context_builder.set_proxy_config_service(
base::MakeUnique<net::ProxyConfigServiceFixed>(net::ProxyConfig()));
#endif
std::unique_ptr<net::URLRequestContext> url_request_context =
url_request_context_builder.Build();
net::CertNetFetcherImpl cert_net_fetcher(url_request_context.get());
net::CertIssuerSourceAia aia_cert_issuer_source(&cert_net_fetcher);
// Initialize an AIA fetcher, that uses a separate thread for running the
// networking message loop.
base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
base::Thread thread("network_thread");
CHECK(thread.StartWithOptions(options));
scoped_refptr<URLRequestContextGetterForAia> url_request_context_getter(
new URLRequestContextGetterForAia(thread.task_runner()));
auto cert_net_fetcher =
CreateCertNetFetcher(url_request_context_getter.get());
net::CertIssuerSourceAia aia_cert_issuer_source(cert_net_fetcher.get());
path_builder.AddCertIssuerSource(&aia_cert_issuer_source);
net::TestClosure callback;
net::CompletionStatus rv = path_builder.Run(callback.closure());
// Run the path builder.
path_builder.Run();
if (rv == net::CompletionStatus::ASYNC) {
DVLOG(1) << "waiting for async completion...";
callback.WaitForResult();
DVLOG(1) << "async completed.";
}
// Stop the temporary network thread..
url_request_context_getter->ShutDown();
thread.Stop();
// TODO(crbug.com/634443): Display any errors/warnings associated with path
// building that were not part of a particular
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment