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); |