Chromium Code Reviews| Index: net/cert/internal/path_builder.cc |
| diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc |
| index 10b507bc594c3849d63aa2af78c35ad8a1c5d08a..03791a8a17c76c551daf17bba9b4255147c4644e 100644 |
| --- a/net/cert/internal/path_builder.cc |
| +++ b/net/cert/internal/path_builder.cc |
| @@ -65,11 +65,11 @@ struct CertificateOrTrustAnchor { |
| // which may be issuers of |cert|. |
| class CertIssuersIter { |
| public: |
| - // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for |
| - // the lifetime of the CertIssuersIter. |
| + // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| |
| + // must be valid for the lifetime of the CertIssuersIter. |
| CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
| CertIssuerSources* cert_issuer_sources, |
| - const TrustStore& trust_store); |
| + const TrustStore* trust_store); |
| // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC |
| // is returned and the cert is stored in |*cert|. If an issuer is not |
| @@ -85,10 +85,14 @@ class CertIssuersIter { |
| scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
| private: |
| + void DoAsyncIssuerQuery(); |
| + void GotAsyncAnchors(TrustAnchors anchors); |
| void GotAsyncCerts(CertIssuerSource::Request* request); |
| + void NotifyIfNecessary(); |
| scoped_refptr<ParsedCertificate> cert_; |
| CertIssuerSources* cert_issuer_sources_; |
| + const TrustStore* trust_store_; |
| // The list of trust anchors that match the issuer name for |cert_|. |
| TrustAnchors anchors_; |
| @@ -112,14 +116,16 @@ class CertIssuersIter { |
| // This points to data owned by |issuers_|. |
| std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
| - // Tracks whether asynchronous requests have been made yet. |
| - bool did_async_query_ = false; |
| + // Tracks which requests have been made yet. |
| + bool did_initial_query_ = false; |
| + bool did_async_issuer_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 |
| // cancelled if CertIssuersIter is destroyed. |
| std::vector<std::unique_ptr<CertIssuerSource::Request>> |
| pending_async_requests_; |
| + std::unique_ptr<TrustStore::Request> pending_anchor_request_; |
| // When GetNextIssuer was called and returned asynchronously, |*out_| is |
| // where the result will be stored, and |callback_| will be run when the |
| @@ -132,28 +138,11 @@ 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) { |
| + const TrustStore* trust_store) |
| + : cert_(in_cert), |
| + cert_issuer_sources_(cert_issuer_sources), |
| + trust_store_(trust_store) { |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
| - trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), |
| - &anchors_); |
| - |
| - 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)); |
| - } |
| - } |
| - // 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. |
| - // See big list of possible sorting hints in RFC 4158.) |
| - // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| - // is done) |
| } |
| CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| @@ -161,6 +150,35 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| // Should not be called again while already waiting for an async result. |
| DCHECK(callback_.is_null()); |
| + if (!did_initial_query_) { |
| + did_initial_query_ = true; |
| + trust_store_->FindTrustAnchorsForCert( |
| + cert_.get(), |
| + callback.is_null() ? TrustStore::TrustAnchorsCallback() |
| + : base::Bind(&CertIssuersIter::GotAsyncAnchors, |
| + base::Unretained(this)), |
| + &anchors_, &pending_anchor_request_); |
| + |
| + 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)); |
| + } |
| + } |
| + DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() |
| + << " sync issuers"; |
| + // 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. |
| + // See big list of possible sorting hints in RFC 4158.) |
| + // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| + // is done) |
| + } |
| + |
| // Return possible trust anchors first. |
| if (cur_anchor_ < anchors_.size()) { |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| @@ -171,6 +189,14 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| return CompletionStatus::SYNC; |
| } |
| + if (pending_anchor_request_) { |
| + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| + << ") Still waiting for async trust anchor results."; |
| + out_ = out; |
| + callback_ = callback; |
| + return CompletionStatus::ASYNC; |
| + } |
| + |
| if (cur_issuer_ < issuers_.size()) { |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| << "): returning issuer " << cur_issuer_ << " of " |
| @@ -181,7 +207,8 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); |
| return CompletionStatus::SYNC; |
| } |
| - if (did_async_query_) { |
| + |
| + if (did_async_issuer_query_) { |
| if (pending_async_results_ == 0) { |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| << ") Reached the end of all available issuers."; |
| @@ -207,7 +234,27 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| } |
| // Now issue request(s) for async ones (AIA, etc). |
| - did_async_query_ = true; |
| + DoAsyncIssuerQuery(); |
| + |
| + if (pending_async_results_ == 0) { |
| + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| + << ") No cert sources have async results."; |
| + // No cert sources have async results. |
| + *out = CertificateOrTrustAnchor(); |
| + return CompletionStatus::SYNC; |
| + } |
| + |
| + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| + << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ |
| + << ")"; |
| + out_ = out; |
| + callback_ = callback; |
| + return CompletionStatus::ASYNC; |
| +} |
| + |
| +void CertIssuersIter::DoAsyncIssuerQuery() { |
| + DCHECK(!did_async_issuer_query_); |
| + did_async_issuer_query_ = true; |
| pending_async_results_ = 0; |
| for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| std::unique_ptr<CertIssuerSource::Request> request; |
| @@ -222,21 +269,16 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| pending_async_requests_.push_back(std::move(request)); |
| } |
| } |
| +} |
| - if (pending_async_results_ == 0) { |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << ") No cert sources have async results."; |
| - // No cert sources have async results. |
| - *out = CertificateOrTrustAnchor(); |
| - return CompletionStatus::SYNC; |
| - } |
| +void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) { |
| + DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert()) |
| + << "): " << anchors.size() << " anchors"; |
| + for (scoped_refptr<TrustAnchor>& anchor : anchors) |
| + anchors_.push_back(std::move(anchor)); |
| + pending_anchor_request_.reset(); |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ |
| - << ")"; |
| - out_ = out; |
| - callback_ = callback; |
| - return CompletionStatus::ASYNC; |
| + NotifyIfNecessary(); |
| } |
| void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { |
| @@ -265,25 +307,43 @@ void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { |
| // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may |
| // be more than the ones just inserted, depending on |cur_| value). |
| + NotifyIfNecessary(); |
| +} |
| + |
| +void CertIssuersIter::NotifyIfNecessary() { |
| // Notify that more results are available, if necessary. |
| if (!callback_.is_null()) { |
| - DCHECK_GE(cur_anchor_, anchors_.size()); |
| + if (cur_anchor_ < anchors_.size()) { |
| + DVLOG(1) << "CertanchorsIter(" << CertDebugString(cert()) |
|
eroman
2016/08/26 18:19:31
typo?
mattm
2016/08/26 22:14:18
Done.
|
| + << "): async returning anchor " << cur_anchor_ << " of " |
| + << anchors_.size(); |
| + *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++])); |
| + base::ResetAndReturn(&callback_).Run(); |
| + return; |
| + } |
| if (cur_issuer_ < issuers_.size()) { |
| + DCHECK(!pending_anchor_request_); |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << "): async returning item " << cur_issuer_ << " of " |
| + << "): async returning issuer " << cur_issuer_ << " of " |
| << issuers_.size(); |
| *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); |
| base::ResetAndReturn(&callback_).Run(); |
| - } else if (pending_async_results_ == 0) { |
| + return; |
| + } |
| + |
| + if (!did_async_issuer_query_) |
| + DoAsyncIssuerQuery(); |
| + |
| + if (pending_async_results_ == 0) { |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| << "): async returning empty result"; |
| *out_ = CertificateOrTrustAnchor(); |
| base::ResetAndReturn(&callback_).Run(); |
| - } else { |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << "): empty result, but other async results " |
| - "pending, waiting.."; |
| + return; |
| } |
| + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| + << "): empty result, but other async results " |
| + "pending, waiting.."; |
| } |
| } |
| @@ -517,7 +577,7 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() { |
| } |
| cur_path_.Append(base::WrapUnique(new CertIssuersIter( |
| - std::move(next_issuer_.cert), &cert_issuer_sources_, *trust_store_))); |
| + std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_))); |
| next_issuer_ = CertificateOrTrustAnchor(); |
| DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
| // Continue descending the tree. |