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

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

Issue 2126803004: WIP: NSS trust store integration for path builder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert-command-line-path-builder-add_certpathbuilder
Patch Set: . Created 4 years, 4 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/path_builder.h ('k') | net/cert/internal/path_builder_pkits_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/cert/internal/path_builder.cc
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc
index 863d8506b22d38673eaf18db08302484d934c34f..6bee524c4744b924d6faa49d9ef0d4e24ccec61e 100644
--- a/net/cert/internal/path_builder.cc
+++ b/net/cert/internal/path_builder.cc
@@ -11,10 +11,12 @@
#include "base/memory/ptr_util.h"
#include "net/base/net_errors.h"
#include "net/cert/internal/cert_issuer_source.h"
+#include "net/cert/internal/cert_issuer_source_collection.h"
#include "net/cert/internal/parse_certificate.h"
#include "net/cert/internal/parse_name.h" // For CertDebugString.
#include "net/cert/internal/signature_policy.h"
#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/trust_store_collection.h"
#include "net/cert/internal/verify_certificate_chain.h"
#include "net/cert/internal/verify_name_match.h"
#include "net/der/parser.h"
@@ -24,8 +26,6 @@ namespace net {
namespace {
-using CertIssuerSources = std::vector<CertIssuerSource*>;
-
// TODO(mattm): decide how much debug logging to keep.
std::string CertDebugString(const ParsedCertificate* cert) {
RDNSequence subject, issuer;
@@ -40,15 +40,14 @@ std::string CertDebugString(const ParsedCertificate* cert) {
return subject_str + "(" + issuer_str + ")";
}
-// CertIssuersIter iterates through the intermediates from |cert_issuer_sources|
+// CertIssuersIter iterates through the intermediates from |cert_issuer_source|
// which may be issuers of |cert|.
class CertIssuersIter {
public:
- // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for
+ // Constructs the CertIssuersIter. |*cert_issuer_source| must be valid for
// the lifetime of the CertIssuersIter.
CertIssuersIter(scoped_refptr<ParsedCertificate> cert,
- CertIssuerSources* cert_issuer_sources,
- const TrustStore& trust_store);
+ CertIssuerSource* cert_issuer_source);
// Gets the next candidate issuer. If an issuer is ready synchronously, SYNC
// is returned and the cert is stored in |*out_cert|. If an issuer is not
@@ -67,7 +66,7 @@ class CertIssuersIter {
void GotAsyncCerts(CertIssuerSource::Request* request);
scoped_refptr<ParsedCertificate> cert_;
- CertIssuerSources* cert_issuer_sources_;
+ CertIssuerSource* cert_issuer_source_;
// The list of issuers for |cert_|. This is added to incrementally (first
// synchronous results, then possibly multiple times as asynchronous results
@@ -87,12 +86,9 @@ class CertIssuersIter {
// Tracks whether asynchronous requests have been made yet.
bool did_async_query_ = false;
- // If asynchronous requests were made, how many of them are still outstanding?
- size_t pending_async_results_;
- // Owns the Request objects for any asynchronous requests so that they will be
+ // Owns the Request object for any asynchronous request so that it will be
// cancelled if CertIssuersIter is destroyed.
- std::vector<std::unique_ptr<CertIssuerSource::Request>>
- pending_async_requests_;
+ std::unique_ptr<CertIssuerSource::Request> pending_async_request_;
// When GetNextIssuer was called and returned asynchronously, |*out_cert_| is
// where the result will be stored, and |callback_| will be run when the
@@ -104,28 +100,17 @@ class CertIssuersIter {
};
CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert,
- CertIssuerSources* cert_issuer_sources,
- const TrustStore& trust_store)
- : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) {
+ CertIssuerSource* cert_issuer_source)
+ : cert_(in_cert), cert_issuer_source_(cert_issuer_source) {
DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created";
- trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(),
- &issuers_);
- // Insert matching roots into |present_issuers_| in case they also are
- // returned by a CertIssuerSource. It is assumed
- // FindTrustAnchorsByNormalizedName does not itself return dupes.
- for (const auto& root : issuers_)
- present_issuers_.insert(root->der_cert().AsStringPiece());
-
- for (auto* cert_issuer_source : *cert_issuer_sources_) {
- ParsedCertificateList new_issuers;
- cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
- for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
- if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
- present_issuers_.end())
- continue;
- present_issuers_.insert(issuer->der_cert().AsStringPiece());
- issuers_.push_back(std::move(issuer));
- }
+ ParsedCertificateList new_issuers;
+ cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
+ for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
+ if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
+ present_issuers_.end())
+ continue;
+ present_issuers_.insert(issuer->der_cert().AsStringPiece());
+ issuers_.push_back(std::move(issuer));
}
// TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust
// anchor subject (or is a trust anchor), that should be sorted higher too.
@@ -150,7 +135,7 @@ CompletionStatus CertIssuersIter::GetNextIssuer(
return CompletionStatus::SYNC;
}
if (did_async_query_) {
- if (pending_async_results_ == 0) {
+ if (!pending_async_request_) {
DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
<< ") Reached the end of all available issuers.";
// Reached the end of all available issuers.
@@ -159,8 +144,7 @@ CompletionStatus CertIssuersIter::GetNextIssuer(
}
DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
- << ") Still waiting for async results from other "
- "CertIssuerSources.";
+ << ") Still waiting for more async results.";
// Still waiting for async results from other CertIssuerSources.
out_cert_ = out_cert;
callback_ = callback;
@@ -176,22 +160,18 @@ CompletionStatus CertIssuersIter::GetNextIssuer(
// Now issue request(s) for async ones (AIA, etc).
did_async_query_ = true;
- pending_async_results_ = 0;
- for (auto* cert_issuer_source : *cert_issuer_sources_) {
- std::unique_ptr<CertIssuerSource::Request> request;
- cert_issuer_source->AsyncGetIssuersOf(
- cert(),
- base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)),
- &request);
- if (request) {
- DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert())
- << ") pending...";
- pending_async_results_++;
- pending_async_requests_.push_back(std::move(request));
- }
+ std::unique_ptr<CertIssuerSource::Request> request;
+ cert_issuer_source_->AsyncGetIssuersOf(
+ reference_cert(),
+ base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)),
+ &request);
+ if (request) {
+ DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert())
+ << ") pending...";
+ pending_async_request_ = std::move(request);
}
- if (pending_async_results_ == 0) {
+ if (!pending_async_request_) {
DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
<< ") No cert sources have async results.";
// No cert sources have async results.
@@ -199,9 +179,6 @@ CompletionStatus CertIssuersIter::GetNextIssuer(
return CompletionStatus::SYNC;
}
- DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
- << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_
- << ")";
out_cert_ = out_cert;
callback_ = callback;
return CompletionStatus::ASYNC;
@@ -210,15 +187,15 @@ CompletionStatus CertIssuersIter::GetNextIssuer(
void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert())
<< ")";
+ DCHECK_EQ(pending_async_request_.get(), request);
while (true) {
scoped_refptr<ParsedCertificate> cert;
CompletionStatus status = request->GetNext(&cert);
if (!cert) {
if (status == CompletionStatus::SYNC) {
- // Request is exhausted, no more results pending from that
+ // Request is exhausted, no more results pending from the
// CertIssuerSource.
- DCHECK_GT(pending_async_results_, 0U);
- pending_async_results_--;
+ pending_async_request_.reset();
}
break;
}
@@ -241,7 +218,7 @@ void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
<< issuers_.size();
*out_cert_ = std::move(issuers_[cur_++]);
base::ResetAndReturn(&callback_).Run();
- } else if (pending_async_results_ == 0) {
+ } else if (!pending_async_request_) {
DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
<< "): async returning empty result";
*out_cert_ = nullptr;
@@ -333,8 +310,12 @@ class CertIssuerIterPath {
// necessary.
class CertPathIter {
public:
- CertPathIter(scoped_refptr<ParsedCertificate> cert,
- const TrustStore* trust_store);
+ explicit CertPathIter(scoped_refptr<ParsedCertificate> cert);
+
+ // Adds a TrustStore to check if certificates are trust anchors during path
+ // building. The |*trust_store| must remain valid for the lifetime of the
+ // CertPathIter.
+ void AddTrustStore(TrustStore* trust_store);
// Adds a CertIssuerSource to provide intermediates for use in path building.
// The |*cert_issuer_source| must remain valid for the lifetime of the
@@ -353,6 +334,7 @@ class CertPathIter {
STATE_NONE,
STATE_GET_NEXT_ISSUER,
STATE_GET_NEXT_ISSUER_COMPLETE,
+ STATE_IS_NEXT_CERT_TRUSTED_COMPLETE,
STATE_RETURN_A_PATH,
STATE_BACKTRACK,
};
@@ -360,10 +342,12 @@ class CertPathIter {
CompletionStatus DoLoop(bool allow_async);
CompletionStatus DoGetNextIssuer(bool allow_async);
- CompletionStatus DoGetNextIssuerComplete();
+ CompletionStatus DoGetNextIssuerComplete(bool allow_async);
+ CompletionStatus DoIsNextCertTrustedComplete();
CompletionStatus DoBackTrack();
void HandleGotNextIssuer(void);
+ void HandleIsTrustedCertificate(bool is_trusted);
// Stores the next candidate issuer certificate, until it is used during the
// STATE_GET_NEXT_ISSUER_COMPLETE step.
@@ -373,9 +357,14 @@ class CertPathIter {
// when backtracking it can resume the search where it left off.
CertIssuerIterPath cur_path_;
// The CertIssuerSources for retrieving candidate issuers.
- CertIssuerSources cert_issuer_sources_;
- // The TrustStore for checking if a path ends in a trust anchor.
- const TrustStore* trust_store_;
+ CertIssuerSourceCollection cert_issuer_source_collection_;
+ // The TrustStores for checking if a path ends in a trust anchor.
+ TrustStoreCollection trust_store_collection_;
+ // Request handle for querying the TrustStoreCollection.
+ std::unique_ptr<TrustStore::Request> trust_request_;
+ // Stores the result of trust query for use in the
+ // STATE_IS_NEXT_CERT_TRUSTED_COMPLETE state.
+ bool is_pending_cert_trusted_;
// The output variable for storing the next candidate path, which the client
// passes in to GetNextPath. Only used for a single path output.
ParsedCertificateList* out_path_;
@@ -387,14 +376,17 @@ class CertPathIter {
DISALLOW_COPY_AND_ASSIGN(CertPathIter);
};
-CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert,
- const TrustStore* trust_store)
+CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert)
: next_cert_(std::move(cert)),
- trust_store_(trust_store),
next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {}
+void CertPathIter::AddTrustStore(TrustStore* trust_store) {
+ trust_store_collection_.AddStore(trust_store);
+ cert_issuer_source_collection_.AddSource(trust_store);
+}
+
void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) {
- cert_issuer_sources_.push_back(cert_issuer_source);
+ cert_issuer_source_collection_.AddSource(cert_issuer_source);
}
CompletionStatus CertPathIter::GetNextPath(ParsedCertificateList* path,
@@ -424,7 +416,10 @@ CompletionStatus CertPathIter::DoLoop(bool allow_async) {
result = DoGetNextIssuer(allow_async);
break;
case STATE_GET_NEXT_ISSUER_COMPLETE:
- result = DoGetNextIssuerComplete();
+ result = DoGetNextIssuerComplete(allow_async);
+ break;
+ case STATE_IS_NEXT_CERT_TRUSTED_COMPLETE:
+ result = DoIsNextCertTrustedComplete();
break;
case STATE_RETURN_A_PATH:
// If the returned path did not verify, keep looking for other paths
@@ -444,6 +439,12 @@ CompletionStatus CertPathIter::DoLoop(bool allow_async) {
}
CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) {
+ if (cur_path_.Empty()) {
+ // If the target cert matched a trust root, but did not verify
+ // successfully, cur_path_ will be empty.
+ next_state_ = STATE_NONE;
+ return CompletionStatus::SYNC;
+ }
next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE;
CompletionStatus rv = cur_path_.back()->GetNextIssuer(
&next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer,
@@ -452,32 +453,21 @@ CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) {
return rv;
}
-CompletionStatus CertPathIter::DoGetNextIssuerComplete() {
+CompletionStatus CertPathIter::DoGetNextIssuerComplete(bool allow_async) {
if (next_cert_) {
// Skip this cert if it is already in the chain.
if (cur_path_.IsPresent(next_cert_.get())) {
next_state_ = STATE_GET_NEXT_ISSUER;
return CompletionStatus::SYNC;
}
- // If the cert matches a trust root, this is a (possibly) complete path.
- // Signal readiness. Don't add it to cur_path_, since that would cause an
- // unnecessary lookup of issuers of the trust root.
- if (trust_store_->IsTrustedCertificate(next_cert_.get())) {
- DVLOG(1) << "CertPathIter IsTrustedCertificate("
- << CertDebugString(next_cert_.get()) << ") = true";
- next_state_ = STATE_RETURN_A_PATH;
- cur_path_.CopyPath(out_path_);
- out_path_->push_back(std::move(next_cert_));
- next_cert_ = nullptr;
- return CompletionStatus::SYNC;
- }
-
- cur_path_.Append(base::WrapUnique(new CertIssuersIter(
- std::move(next_cert_), &cert_issuer_sources_, *trust_store_)));
- next_cert_ = nullptr;
- DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString();
- // Continue descending the tree.
- next_state_ = STATE_GET_NEXT_ISSUER;
+ next_state_ = STATE_IS_NEXT_CERT_TRUSTED_COMPLETE;
+ trust_store_collection_.IsTrustedCertificate(
+ next_cert_.get(),
+ allow_async ? base::Bind(&CertPathIter::HandleIsTrustedCertificate,
+ base::Unretained(this))
+ : TrustStore::TrustCallback(),
+ &is_pending_cert_trusted_, &trust_request_);
+ return trust_request_ ? CompletionStatus::ASYNC : CompletionStatus::SYNC;
} else {
// TODO(mattm): should also include such paths in CertPathBuilder::Result,
// maybe with a flag to enable it. Or use a visitor pattern so the caller
@@ -489,6 +479,29 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() {
return CompletionStatus::SYNC;
}
+CompletionStatus CertPathIter::DoIsNextCertTrustedComplete() {
+ // If the cert matches a trust root, this is a (possibly) complete path.
+ // Signal readiness. Don't add it to cur_path_, since that would cause an
+ // unnecessary lookup of issuers of the trust root.
+ if (is_pending_cert_trusted_) {
+ DVLOG(1) << "CertPathIter IsTrustedCertificate("
+ << CertDebugString(next_cert_.get()) << ") = true";
+ next_state_ = STATE_RETURN_A_PATH;
+ cur_path_.CopyPath(out_path_);
+ out_path_->push_back(std::move(next_cert_));
+ next_cert_ = nullptr;
+ return CompletionStatus::SYNC;
+ }
+
+ cur_path_.Append(base::WrapUnique(new CertIssuersIter(
+ std::move(next_cert_), &cert_issuer_source_collection_)));
+ next_cert_ = nullptr;
+ DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString();
+ // Continue descending the tree.
+ next_state_ = STATE_GET_NEXT_ISSUER;
+ return CompletionStatus::SYNC;
+}
+
CompletionStatus CertPathIter::DoBackTrack() {
DVLOG(1) << "CertPathIter backtracking...";
cur_path_.Pop();
@@ -512,18 +525,24 @@ void CertPathIter::HandleGotNextIssuer(void) {
}
}
+void CertPathIter::HandleIsTrustedCertificate(bool is_trusted) {
+ DCHECK(!callback_.is_null());
+ is_pending_cert_trusted_ = is_trusted;
+ CompletionStatus rv = DoLoop(true /* allow_async */);
+ if (rv == CompletionStatus::SYNC)
+ base::ResetAndReturn(&callback_).Run();
+}
+
CertPathBuilder::ResultPath::ResultPath() = default;
CertPathBuilder::ResultPath::~ResultPath() = default;
CertPathBuilder::Result::Result() = default;
CertPathBuilder::Result::~Result() = default;
CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
- const TrustStore* trust_store,
const SignaturePolicy* signature_policy,
const der::GeneralizedTime& time,
Result* result)
- : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)),
- trust_store_(trust_store),
+ : cert_path_iter_(new CertPathIter(std::move(cert))),
signature_policy_(signature_policy),
time_(time),
next_state_(STATE_NONE),
@@ -531,6 +550,10 @@ CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
CertPathBuilder::~CertPathBuilder() {}
+void CertPathBuilder::AddTrustStore(TrustStore* trust_store) {
+ cert_path_iter_->AddTrustStore(trust_store);
+}
+
void CertPathBuilder::AddCertIssuerSource(
CertIssuerSource* cert_issuer_source) {
cert_path_iter_->AddCertIssuerSource(cert_issuer_source);
@@ -593,7 +616,7 @@ CompletionStatus CertPathBuilder::DoGetNextPathComplete() {
}
bool verify_result = VerifyCertificateChainAssumingTrustedRoot(
- next_path_, *trust_store_, signature_policy_, time_);
+ next_path_, signature_policy_, time_);
DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
<< verify_result;
AddResultPath(next_path_, verify_result);
« no previous file with comments | « net/cert/internal/path_builder.h ('k') | net/cert/internal/path_builder_pkits_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698