Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/internal/path_builder.h" | 5 #include "net/cert/internal/path_builder.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <unordered_set> | 8 #include <unordered_set> |
| 9 | 9 |
| 10 #include "base/callback_helpers.h" | |
| 11 #include "base/logging.h" | 10 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 13 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 14 #include "net/cert/internal/cert_issuer_source.h" | 13 #include "net/cert/internal/cert_issuer_source.h" |
| 15 #include "net/cert/internal/parse_certificate.h" | 14 #include "net/cert/internal/parse_certificate.h" |
| 16 #include "net/cert/internal/parse_name.h" // For CertDebugString. | 15 #include "net/cert/internal/parse_name.h" // For CertDebugString. |
| 17 #include "net/cert/internal/signature_policy.h" | 16 #include "net/cert/internal/signature_policy.h" |
| 18 #include "net/cert/internal/trust_store.h" | 17 #include "net/cert/internal/trust_store.h" |
| 19 #include "net/cert/internal/verify_certificate_chain.h" | 18 #include "net/cert/internal/verify_certificate_chain.h" |
| 20 #include "net/cert/internal/verify_name_match.h" | 19 #include "net/cert/internal/verify_name_match.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | 63 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| |
| 65 // which may be issuers of |cert|. | 64 // which may be issuers of |cert|. |
| 66 class CertIssuersIter { | 65 class CertIssuersIter { |
| 67 public: | 66 public: |
| 68 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| | 67 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| |
| 69 // must be valid for the lifetime of the CertIssuersIter. | 68 // must be valid for the lifetime of the CertIssuersIter. |
| 70 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | 69 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
| 71 CertIssuerSources* cert_issuer_sources, | 70 CertIssuerSources* cert_issuer_sources, |
| 72 const TrustStore* trust_store); | 71 const TrustStore* trust_store); |
| 73 | 72 |
| 74 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC | 73 // Gets the next candidate issuer, or clears |*out| when all issuers have been |
| 75 // is returned and the cert is stored in |*cert|. If an issuer is not | 74 // exhausted. |
| 76 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has | 75 void GetNextIssuer(CertificateOrTrustAnchor* out); |
| 77 // been set. If |callback| is null, always completes synchronously. | |
| 78 // | |
| 79 // In either case, if all issuers have been exhausted, |*out| is cleared. | |
| 80 CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out, | |
| 81 const base::Closure& callback); | |
| 82 | 76 |
| 83 // Returns the |cert| for which issuers are being retrieved. | 77 // Returns the |cert| for which issuers are being retrieved. |
| 84 const ParsedCertificate* cert() const { return cert_.get(); } | 78 const ParsedCertificate* cert() const { return cert_.get(); } |
| 85 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | 79 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
| 86 | 80 |
| 87 private: | 81 private: |
| 82 void AddIssuers(ParsedCertificateList issuers); | |
| 88 void DoAsyncIssuerQuery(); | 83 void DoAsyncIssuerQuery(); |
| 89 void GotAsyncAnchors(TrustAnchors anchors); | |
| 90 void GotAsyncCerts(CertIssuerSource::Request* request); | |
| 91 void NotifyIfNecessary(); | |
| 92 | 84 |
| 93 scoped_refptr<ParsedCertificate> cert_; | 85 scoped_refptr<ParsedCertificate> cert_; |
| 94 CertIssuerSources* cert_issuer_sources_; | 86 CertIssuerSources* cert_issuer_sources_; |
| 95 const TrustStore* trust_store_; | 87 const TrustStore* trust_store_; |
| 96 | 88 |
| 97 // The list of trust anchors that match the issuer name for |cert_|. | 89 // The list of trust anchors that match the issuer name for |cert_|. |
| 98 TrustAnchors anchors_; | 90 TrustAnchors anchors_; |
| 99 // The index of the next trust anchor in |anchors_| to return. | 91 // The index of the next trust anchor in |anchors_| to return. |
| 100 size_t cur_anchor_ = 0; | 92 size_t cur_anchor_ = 0; |
| 101 | 93 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 112 | 104 |
| 113 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | 105 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent |
| 114 // duplicates. This is based on the full DER of the cert to allow different | 106 // duplicates. This is based on the full DER of the cert to allow different |
| 115 // versions of the same certificate to be tried in different candidate paths. | 107 // versions of the same certificate to be tried in different candidate paths. |
| 116 // This points to data owned by |issuers_|. | 108 // This points to data owned by |issuers_|. |
| 117 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | 109 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
| 118 | 110 |
| 119 // Tracks which requests have been made yet. | 111 // Tracks which requests have been made yet. |
| 120 bool did_initial_query_ = false; | 112 bool did_initial_query_ = false; |
| 121 bool did_async_issuer_query_ = false; | 113 bool did_async_issuer_query_ = false; |
| 122 // If asynchronous requests were made, how many of them are still outstanding? | 114 // If asynchronous requests were made, which ones are still outstanding? |
|
mattm
2016/10/28 02:11:55
comment is a bit confusing / indirect. maybe menti
eroman
2016/11/23 22:10:21
Done.
| |
| 123 size_t pending_async_results_; | 115 size_t cur_async_request_ = 0; |
| 124 // Owns the Request objects for any asynchronous requests so that they will be | 116 // Owns the Request objects for any asynchronous requests so that they will be |
| 125 // cancelled if CertIssuersIter is destroyed. | 117 // cancelled if CertIssuersIter is destroyed. |
| 126 std::vector<std::unique_ptr<CertIssuerSource::Request>> | 118 std::vector<std::unique_ptr<CertIssuerSource::Request>> |
| 127 pending_async_requests_; | 119 pending_async_requests_; |
| 128 std::unique_ptr<TrustStore::Request> pending_anchor_request_; | |
| 129 | |
| 130 // When GetNextIssuer was called and returned asynchronously, |*out_| is | |
| 131 // where the result will be stored, and |callback_| will be run when the | |
| 132 // result is ready. | |
| 133 CertificateOrTrustAnchor* out_; | |
| 134 base::Closure callback_; | |
| 135 | 120 |
| 136 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | 121 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
| 137 }; | 122 }; |
| 138 | 123 |
| 139 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | 124 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
| 140 CertIssuerSources* cert_issuer_sources, | 125 CertIssuerSources* cert_issuer_sources, |
| 141 const TrustStore* trust_store) | 126 const TrustStore* trust_store) |
| 142 : cert_(in_cert), | 127 : cert_(in_cert), |
| 143 cert_issuer_sources_(cert_issuer_sources), | 128 cert_issuer_sources_(cert_issuer_sources), |
| 144 trust_store_(trust_store) { | 129 trust_store_(trust_store) { |
| 145 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | 130 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
| 146 } | 131 } |
| 147 | 132 |
| 148 CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, | 133 void CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out) { |
| 149 const base::Closure& callback) { | |
| 150 // Should not be called again while already waiting for an async result. | |
| 151 DCHECK(callback_.is_null()); | |
| 152 | |
| 153 if (!did_initial_query_) { | 134 if (!did_initial_query_) { |
| 154 did_initial_query_ = true; | 135 did_initial_query_ = true; |
| 155 trust_store_->FindTrustAnchorsForCert( | 136 trust_store_->FindTrustAnchorsForCert(cert_, &anchors_); |
| 156 cert_, | |
| 157 callback.is_null() ? TrustStore::TrustAnchorsCallback() | |
| 158 : base::Bind(&CertIssuersIter::GotAsyncAnchors, | |
| 159 base::Unretained(this)), | |
| 160 &anchors_, &pending_anchor_request_); | |
| 161 | 137 |
| 162 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 138 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| 163 ParsedCertificateList new_issuers; | 139 ParsedCertificateList new_issuers; |
| 164 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | 140 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); |
| 165 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | 141 AddIssuers(std::move(new_issuers)); |
| 166 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | |
| 167 present_issuers_.end()) | |
| 168 continue; | |
| 169 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | |
| 170 issuers_.push_back(std::move(issuer)); | |
| 171 } | |
| 172 } | 142 } |
| 173 DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() | 143 DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() |
| 174 << " sync issuers"; | 144 << " sync issuers"; |
| 175 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | 145 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust |
| 176 // anchor subject (or is a trust anchor), that should be sorted higher too. | 146 // anchor subject (or is a trust anchor), that should be sorted higher too. |
| 177 // See big list of possible sorting hints in RFC 4158.) | 147 // See big list of possible sorting hints in RFC 4158.) |
| 178 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | 148 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| 179 // is done) | 149 // is done) |
| 180 } | 150 } |
| 181 | 151 |
| 182 // Return possible trust anchors first. | 152 // Return possible trust anchors first. |
| 183 if (cur_anchor_ < anchors_.size()) { | 153 if (cur_anchor_ < anchors_.size()) { |
| 184 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 154 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 185 << "): returning anchor " << cur_anchor_ << " of " | 155 << "): returning anchor " << cur_anchor_ << " of " |
| 186 << anchors_.size(); | 156 << anchors_.size(); |
| 187 // Still have anchors that haven't been returned yet, return one of them. | 157 // Still have anchors that haven't been returned yet, return one of them. |
| 188 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); | 158 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); |
| 189 return CompletionStatus::SYNC; | 159 return; |
| 190 } | 160 } |
| 191 | 161 |
| 192 if (pending_anchor_request_) { | 162 // If there aren't any issuers left, block until async results are ready. |
| 193 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 163 if (cur_issuer_ >= issuers_.size()) { |
| 194 << ") Still waiting for async trust anchor results."; | 164 if (!did_async_issuer_query_) { |
| 195 out_ = out; | 165 // Now issue request(s) for async ones (AIA, etc). |
| 196 callback_ = callback; | 166 DoAsyncIssuerQuery(); |
| 197 return CompletionStatus::ASYNC; | 167 } |
| 168 | |
| 169 // TODO(eroman): Rather than blocking on the async requests in FIFO order, | |
| 170 // consume in the order they become ready. | |
| 171 while (cur_async_request_ < pending_async_requests_.size()) { | |
| 172 ParsedCertificateList new_issuers; | |
| 173 pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); | |
| 174 if (new_issuers.empty()) { | |
| 175 // Request is exhausted, no more results pending from that | |
| 176 // CertIssuerSource. | |
| 177 pending_async_requests_[cur_async_request_++].reset(); | |
| 178 continue; | |
| 179 } | |
| 180 | |
| 181 AddIssuers(std::move(new_issuers)); | |
| 182 break; | |
| 183 } | |
| 198 } | 184 } |
| 199 | 185 |
| 200 if (cur_issuer_ < issuers_.size()) { | 186 if (cur_issuer_ < issuers_.size()) { |
| 201 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 187 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 202 << "): returning issuer " << cur_issuer_ << " of " | 188 << "): returning issuer " << cur_issuer_ << " of " |
| 203 << issuers_.size(); | 189 << issuers_.size(); |
| 204 // Still have issuers that haven't been returned yet, return one of them. | 190 // Still have issuers that haven't been returned yet, return one of them. |
| 205 // A reference to the returned issuer is retained, since |present_issuers_| | 191 // A reference to the returned issuer is retained, since |present_issuers_| |
| 206 // points to data owned by it. | 192 // points to data owned by it. |
| 207 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); | 193 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); |
| 208 return CompletionStatus::SYNC; | 194 return; |
| 209 } | |
| 210 | |
| 211 if (did_async_issuer_query_) { | |
| 212 if (pending_async_results_ == 0) { | |
| 213 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 214 << ") Reached the end of all available issuers."; | |
| 215 // Reached the end of all available issuers. | |
| 216 *out = CertificateOrTrustAnchor(); | |
| 217 return CompletionStatus::SYNC; | |
| 218 } | |
| 219 | |
| 220 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 221 << ") Still waiting for async results from other " | |
| 222 "CertIssuerSources."; | |
| 223 // Still waiting for async results from other CertIssuerSources. | |
| 224 out_ = out; | |
| 225 callback_ = callback; | |
| 226 return CompletionStatus::ASYNC; | |
| 227 } | |
| 228 // Reached the end of synchronously gathered issuers. | |
| 229 | |
| 230 if (callback.is_null()) { | |
| 231 // Synchronous-only mode, don't try to query async sources. | |
| 232 *out = CertificateOrTrustAnchor(); | |
| 233 return CompletionStatus::SYNC; | |
| 234 } | |
| 235 | |
| 236 // Now issue request(s) for async ones (AIA, etc). | |
| 237 DoAsyncIssuerQuery(); | |
| 238 | |
| 239 if (pending_async_results_ == 0) { | |
| 240 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 241 << ") No cert sources have async results."; | |
| 242 // No cert sources have async results. | |
| 243 *out = CertificateOrTrustAnchor(); | |
| 244 return CompletionStatus::SYNC; | |
| 245 } | 195 } |
| 246 | 196 |
| 247 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 197 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 248 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ | 198 << ") Reached the end of all available issuers."; |
| 249 << ")"; | 199 // Reached the end of all available issuers. |
| 250 out_ = out; | 200 *out = CertificateOrTrustAnchor(); |
| 251 callback_ = callback; | 201 } |
| 252 return CompletionStatus::ASYNC; | 202 |
| 203 void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) { | |
| 204 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | |
| 205 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | |
| 206 present_issuers_.end()) | |
| 207 continue; | |
| 208 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | |
| 209 issuers_.push_back(std::move(issuer)); | |
| 210 } | |
| 253 } | 211 } |
| 254 | 212 |
| 255 void CertIssuersIter::DoAsyncIssuerQuery() { | 213 void CertIssuersIter::DoAsyncIssuerQuery() { |
| 256 DCHECK(!did_async_issuer_query_); | 214 DCHECK(!did_async_issuer_query_); |
| 257 did_async_issuer_query_ = true; | 215 did_async_issuer_query_ = true; |
| 258 pending_async_results_ = 0; | 216 cur_async_request_ = 0; |
| 259 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 217 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| 260 std::unique_ptr<CertIssuerSource::Request> request; | 218 std::unique_ptr<CertIssuerSource::Request> request; |
| 261 cert_issuer_source->AsyncGetIssuersOf( | 219 cert_issuer_source->AsyncGetIssuersOf(cert(), &request); |
| 262 cert(), | |
| 263 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), | |
| 264 &request); | |
| 265 if (request) { | 220 if (request) { |
| 266 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | 221 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
| 267 << ") pending..."; | 222 << ") pending..."; |
| 268 pending_async_results_++; | |
| 269 pending_async_requests_.push_back(std::move(request)); | 223 pending_async_requests_.push_back(std::move(request)); |
| 270 } | 224 } |
| 271 } | 225 } |
| 272 } | 226 } |
| 273 | 227 |
| 274 void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) { | |
| 275 DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert()) | |
| 276 << "): " << anchors.size() << " anchors"; | |
| 277 for (scoped_refptr<TrustAnchor>& anchor : anchors) | |
| 278 anchors_.push_back(std::move(anchor)); | |
| 279 pending_anchor_request_.reset(); | |
| 280 | |
| 281 NotifyIfNecessary(); | |
| 282 } | |
| 283 | |
| 284 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { | |
| 285 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) | |
| 286 << ")"; | |
| 287 while (true) { | |
| 288 scoped_refptr<ParsedCertificate> cert; | |
| 289 CompletionStatus status = request->GetNext(&cert); | |
| 290 if (!cert) { | |
| 291 if (status == CompletionStatus::SYNC) { | |
| 292 // Request is exhausted, no more results pending from that | |
| 293 // CertIssuerSource. | |
| 294 DCHECK_GT(pending_async_results_, 0U); | |
| 295 pending_async_results_--; | |
| 296 } | |
| 297 break; | |
| 298 } | |
| 299 DCHECK_EQ(status, CompletionStatus::SYNC); | |
| 300 if (present_issuers_.find(cert->der_cert().AsStringPiece()) != | |
| 301 present_issuers_.end()) | |
| 302 continue; | |
| 303 present_issuers_.insert(cert->der_cert().AsStringPiece()); | |
| 304 issuers_.push_back(std::move(cert)); | |
| 305 } | |
| 306 | |
| 307 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may | |
| 308 // be more than the ones just inserted, depending on |cur_| value). | |
| 309 | |
| 310 NotifyIfNecessary(); | |
| 311 } | |
| 312 | |
| 313 void CertIssuersIter::NotifyIfNecessary() { | |
| 314 // Notify that more results are available, if necessary. | |
| 315 if (!callback_.is_null()) { | |
| 316 if (cur_anchor_ < anchors_.size()) { | |
| 317 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 318 << "): async returning anchor " << cur_anchor_ << " of " | |
| 319 << anchors_.size(); | |
| 320 *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++])); | |
| 321 base::ResetAndReturn(&callback_).Run(); | |
| 322 return; | |
| 323 } | |
| 324 if (cur_issuer_ < issuers_.size()) { | |
| 325 DCHECK(!pending_anchor_request_); | |
| 326 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 327 << "): async returning issuer " << cur_issuer_ << " of " | |
| 328 << issuers_.size(); | |
| 329 *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); | |
| 330 base::ResetAndReturn(&callback_).Run(); | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 if (!did_async_issuer_query_) | |
| 335 DoAsyncIssuerQuery(); | |
| 336 | |
| 337 if (pending_async_results_ == 0) { | |
| 338 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 339 << "): async returning empty result"; | |
| 340 *out_ = CertificateOrTrustAnchor(); | |
| 341 base::ResetAndReturn(&callback_).Run(); | |
| 342 return; | |
| 343 } | |
| 344 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 345 << "): empty result, but other async results " | |
| 346 "pending, waiting.."; | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 // CertIssuerIterPath tracks which certs are present in the path and prevents | 228 // CertIssuerIterPath tracks which certs are present in the path and prevents |
| 351 // paths from being built which repeat any certs (including different versions | 229 // paths from being built which repeat any certs (including different versions |
| 352 // of the same cert, based on Subject+SubjectAltName+SPKI). | 230 // of the same cert, based on Subject+SubjectAltName+SPKI). |
| 353 class CertIssuerIterPath { | 231 class CertIssuerIterPath { |
| 354 public: | 232 public: |
| 355 // Returns true if |cert| is already present in the path. | 233 // Returns true if |cert| is already present in the path. |
| 356 bool IsPresent(const ParsedCertificate* cert) const { | 234 bool IsPresent(const ParsedCertificate* cert) const { |
| 357 return present_certs_.find(GetKey(cert)) != present_certs_.end(); | 235 return present_certs_.find(GetKey(cert)) != present_certs_.end(); |
| 358 } | 236 } |
| 359 | 237 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 class CertPathIter { | 317 class CertPathIter { |
| 440 public: | 318 public: |
| 441 CertPathIter(scoped_refptr<ParsedCertificate> cert, | 319 CertPathIter(scoped_refptr<ParsedCertificate> cert, |
| 442 const TrustStore* trust_store); | 320 const TrustStore* trust_store); |
| 443 | 321 |
| 444 // Adds a CertIssuerSource to provide intermediates for use in path building. | 322 // Adds a CertIssuerSource to provide intermediates for use in path building. |
| 445 // The |*cert_issuer_source| must remain valid for the lifetime of the | 323 // The |*cert_issuer_source| must remain valid for the lifetime of the |
| 446 // CertPathIter. | 324 // CertPathIter. |
| 447 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); | 325 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); |
| 448 | 326 |
| 449 // Gets the next candidate path. If a path is ready synchronously, SYNC is | 327 // Gets the next candidate path, or clears |*path| when all paths have been |
| 450 // returned and the path is stored in |*path|. If a path is not ready, | 328 // exhausted. |
| 451 // ASYNC is returned and |callback| will be called once |*path| has been set. | 329 void GetNextPath(CertPath* path); |
| 452 // In either case, if all paths have been exhausted, |*path| is cleared. | |
| 453 CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback); | |
| 454 | 330 |
| 455 private: | 331 private: |
| 456 enum State { | 332 enum State { |
| 457 STATE_NONE, | 333 STATE_NONE, |
| 458 STATE_GET_NEXT_ISSUER, | 334 STATE_GET_NEXT_ISSUER, |
| 459 STATE_GET_NEXT_ISSUER_COMPLETE, | 335 STATE_GET_NEXT_ISSUER_COMPLETE, |
| 460 STATE_RETURN_A_PATH, | 336 STATE_RETURN_A_PATH, |
| 461 STATE_BACKTRACK, | 337 STATE_BACKTRACK, |
| 462 }; | 338 }; |
| 463 | 339 |
| 464 CompletionStatus DoLoop(bool allow_async); | 340 void DoGetNextIssuer(); |
| 465 | 341 void DoGetNextIssuerComplete(); |
| 466 CompletionStatus DoGetNextIssuer(bool allow_async); | 342 void DoBackTrack(); |
| 467 CompletionStatus DoGetNextIssuerComplete(); | |
| 468 CompletionStatus DoBackTrack(); | |
| 469 | |
| 470 void HandleGotNextIssuer(void); | |
| 471 | 343 |
| 472 // Stores the next candidate issuer, until it is used during the | 344 // Stores the next candidate issuer, until it is used during the |
| 473 // STATE_GET_NEXT_ISSUER_COMPLETE step. | 345 // STATE_GET_NEXT_ISSUER_COMPLETE step. |
| 474 CertificateOrTrustAnchor next_issuer_; | 346 CertificateOrTrustAnchor next_issuer_; |
| 475 // The current path being explored, made up of CertIssuerIters. Each node | 347 // The current path being explored, made up of CertIssuerIters. Each node |
| 476 // keeps track of the state of searching for issuers of that cert, so that | 348 // keeps track of the state of searching for issuers of that cert, so that |
| 477 // when backtracking it can resume the search where it left off. | 349 // when backtracking it can resume the search where it left off. |
| 478 CertIssuerIterPath cur_path_; | 350 CertIssuerIterPath cur_path_; |
| 479 // The CertIssuerSources for retrieving candidate issuers. | 351 // The CertIssuerSources for retrieving candidate issuers. |
| 480 CertIssuerSources cert_issuer_sources_; | 352 CertIssuerSources cert_issuer_sources_; |
| 481 // The TrustStore for checking if a path ends in a trust anchor. | 353 // The TrustStore for checking if a path ends in a trust anchor. |
| 482 const TrustStore* trust_store_; | 354 const TrustStore* trust_store_; |
| 483 // The output variable for storing the next candidate path, which the client | 355 // The output variable for storing the next candidate path, which the client |
| 484 // passes in to GetNextPath. Only used for a single path output. | 356 // passes in to GetNextPath. Only used for a single path output. |
| 485 CertPath* out_path_; | 357 CertPath* out_path_; |
| 486 // The callback to be called if an async lookup generated a candidate path. | |
| 487 base::Closure callback_; | |
| 488 // Current state of the state machine. | 358 // Current state of the state machine. |
| 489 State next_state_; | 359 State next_state_; |
| 490 | 360 |
| 491 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | 361 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
| 492 }; | 362 }; |
| 493 | 363 |
| 494 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | 364 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, |
| 495 const TrustStore* trust_store) | 365 const TrustStore* trust_store) |
| 496 : next_issuer_(std::move(cert)), | 366 : next_issuer_(std::move(cert)), |
| 497 trust_store_(trust_store), | 367 trust_store_(trust_store), |
| 498 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | 368 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} |
| 499 | 369 |
| 500 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | 370 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
| 501 cert_issuer_sources_.push_back(cert_issuer_source); | 371 cert_issuer_sources_.push_back(cert_issuer_source); |
| 502 } | 372 } |
| 503 | 373 |
| 504 CompletionStatus CertPathIter::GetNextPath(CertPath* path, | 374 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
| 505 const base::Closure& callback) { | 375 void CertPathIter::GetNextPath(CertPath* path) { |
| 506 out_path_ = path; | 376 out_path_ = path; |
| 507 out_path_->Clear(); | 377 out_path_->Clear(); |
| 508 CompletionStatus rv = DoLoop(!callback.is_null()); | |
| 509 if (rv == CompletionStatus::ASYNC) { | |
| 510 callback_ = callback; | |
| 511 } else { | |
| 512 // Clear the reference to the output parameter as a precaution. | |
| 513 out_path_ = nullptr; | |
| 514 } | |
| 515 return rv; | |
| 516 } | |
| 517 | |
| 518 CompletionStatus CertPathIter::DoLoop(bool allow_async) { | |
| 519 CompletionStatus result = CompletionStatus::SYNC; | |
| 520 do { | 378 do { |
| 521 State state = next_state_; | 379 State state = next_state_; |
| 522 next_state_ = STATE_NONE; | 380 next_state_ = STATE_NONE; |
| 523 switch (state) { | 381 switch (state) { |
| 524 case STATE_NONE: | 382 case STATE_NONE: |
| 525 NOTREACHED(); | 383 NOTREACHED(); |
| 526 break; | 384 break; |
| 527 case STATE_GET_NEXT_ISSUER: | 385 case STATE_GET_NEXT_ISSUER: |
| 528 result = DoGetNextIssuer(allow_async); | 386 DoGetNextIssuer(); |
| 529 break; | 387 break; |
| 530 case STATE_GET_NEXT_ISSUER_COMPLETE: | 388 case STATE_GET_NEXT_ISSUER_COMPLETE: |
| 531 result = DoGetNextIssuerComplete(); | 389 DoGetNextIssuerComplete(); |
| 532 break; | 390 break; |
| 533 case STATE_RETURN_A_PATH: | 391 case STATE_RETURN_A_PATH: |
| 534 // If the returned path did not verify, keep looking for other paths | 392 // If the returned path did not verify, keep looking for other paths |
| 535 // (the trust root is not part of cur_path_, so don't need to | 393 // (the trust root is not part of cur_path_, so don't need to |
| 536 // backtrack). | 394 // backtrack). |
| 537 next_state_ = STATE_GET_NEXT_ISSUER; | 395 next_state_ = STATE_GET_NEXT_ISSUER; |
| 538 result = CompletionStatus::SYNC; | |
| 539 break; | 396 break; |
| 540 case STATE_BACKTRACK: | 397 case STATE_BACKTRACK: |
| 541 result = DoBackTrack(); | 398 DoBackTrack(); |
| 542 break; | 399 break; |
| 543 } | 400 } |
| 544 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && | 401 } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); |
| 545 next_state_ != STATE_RETURN_A_PATH); | |
| 546 | 402 |
| 547 return result; | 403 out_path_ = nullptr; |
| 548 } | 404 } |
| 549 | 405 |
| 550 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { | 406 void CertPathIter::DoGetNextIssuer() { |
| 551 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | 407 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
| 552 CompletionStatus rv = cur_path_.back()->GetNextIssuer( | 408 cur_path_.back()->GetNextIssuer(&next_issuer_); |
| 553 &next_issuer_, allow_async | |
| 554 ? base::Bind(&CertPathIter::HandleGotNextIssuer, | |
| 555 base::Unretained(this)) | |
| 556 : base::Closure()); | |
| 557 return rv; | |
| 558 } | 409 } |
| 559 | 410 |
| 560 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { | 411 void CertPathIter::DoGetNextIssuerComplete() { |
| 561 // If the issuer is a trust anchor signal readiness. | 412 // If the issuer is a trust anchor signal readiness. |
| 562 if (next_issuer_.IsTrustAnchor()) { | 413 if (next_issuer_.IsTrustAnchor()) { |
| 563 DVLOG(1) << "CertPathIter got anchor(" | 414 DVLOG(1) << "CertPathIter got anchor(" |
| 564 << CertDebugString(next_issuer_.anchor->cert().get()); | 415 << CertDebugString(next_issuer_.anchor->cert().get()); |
| 565 next_state_ = STATE_RETURN_A_PATH; | 416 next_state_ = STATE_RETURN_A_PATH; |
| 566 cur_path_.CopyPath(&out_path_->certs); | 417 cur_path_.CopyPath(&out_path_->certs); |
| 567 out_path_->trust_anchor = std::move(next_issuer_.anchor); | 418 out_path_->trust_anchor = std::move(next_issuer_.anchor); |
| 568 next_issuer_ = CertificateOrTrustAnchor(); | 419 next_issuer_ = CertificateOrTrustAnchor(); |
| 569 return CompletionStatus::SYNC; | 420 return; |
| 570 } | 421 } |
| 571 | 422 |
| 572 if (next_issuer_.IsCertificate()) { | 423 if (next_issuer_.IsCertificate()) { |
| 573 // Skip this cert if it is already in the chain. | 424 // Skip this cert if it is already in the chain. |
| 574 if (cur_path_.IsPresent(next_issuer_.cert.get())) { | 425 if (cur_path_.IsPresent(next_issuer_.cert.get())) { |
| 575 next_state_ = STATE_GET_NEXT_ISSUER; | 426 next_state_ = STATE_GET_NEXT_ISSUER; |
| 576 return CompletionStatus::SYNC; | 427 return; |
| 577 } | 428 } |
| 578 | 429 |
| 579 cur_path_.Append(base::MakeUnique<CertIssuersIter>( | 430 cur_path_.Append(base::MakeUnique<CertIssuersIter>( |
| 580 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); | 431 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); |
| 581 next_issuer_ = CertificateOrTrustAnchor(); | 432 next_issuer_ = CertificateOrTrustAnchor(); |
| 582 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); | 433 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
| 583 // Continue descending the tree. | 434 // Continue descending the tree. |
| 584 next_state_ = STATE_GET_NEXT_ISSUER; | 435 next_state_ = STATE_GET_NEXT_ISSUER; |
| 585 } else { | 436 } else { |
| 586 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | 437 // TODO(mattm): should also include such paths in CertPathBuilder::Result, |
| 587 // maybe with a flag to enable it. Or use a visitor pattern so the caller | 438 // maybe with a flag to enable it. Or use a visitor pattern so the caller |
| 588 // can decide what to do with any failed paths. | 439 // can decide what to do with any failed paths. |
| 589 // No more issuers for current chain, go back up and see if there are any | 440 // No more issuers for current chain, go back up and see if there are any |
| 590 // more for the previous cert. | 441 // more for the previous cert. |
| 591 next_state_ = STATE_BACKTRACK; | 442 next_state_ = STATE_BACKTRACK; |
| 592 } | 443 } |
| 593 return CompletionStatus::SYNC; | |
| 594 } | 444 } |
| 595 | 445 |
| 596 CompletionStatus CertPathIter::DoBackTrack() { | 446 void CertPathIter::DoBackTrack() { |
| 597 DVLOG(1) << "CertPathIter backtracking..."; | 447 DVLOG(1) << "CertPathIter backtracking..."; |
| 598 cur_path_.Pop(); | 448 cur_path_.Pop(); |
| 599 if (cur_path_.Empty()) { | 449 if (cur_path_.Empty()) { |
| 600 // Exhausted all paths. | 450 // Exhausted all paths. |
| 601 next_state_ = STATE_NONE; | 451 next_state_ = STATE_NONE; |
| 602 } else { | 452 } else { |
| 603 // Continue exploring issuers of the previous path. | 453 // Continue exploring issuers of the previous path. |
| 604 next_state_ = STATE_GET_NEXT_ISSUER; | 454 next_state_ = STATE_GET_NEXT_ISSUER; |
| 605 } | 455 } |
| 606 return CompletionStatus::SYNC; | |
| 607 } | |
| 608 | |
| 609 void CertPathIter::HandleGotNextIssuer(void) { | |
| 610 DCHECK(!callback_.is_null()); | |
| 611 CompletionStatus rv = DoLoop(true /* allow_async */); | |
| 612 if (rv == CompletionStatus::SYNC) { | |
| 613 // Clear the reference to the output parameter as a precaution. | |
| 614 out_path_ = nullptr; | |
| 615 base::ResetAndReturn(&callback_).Run(); | |
| 616 } | |
| 617 } | 456 } |
| 618 | 457 |
| 619 CertPathBuilder::ResultPath::ResultPath() = default; | 458 CertPathBuilder::ResultPath::ResultPath() = default; |
| 620 CertPathBuilder::ResultPath::~ResultPath() = default; | 459 CertPathBuilder::ResultPath::~ResultPath() = default; |
| 621 CertPathBuilder::Result::Result() = default; | 460 CertPathBuilder::Result::Result() = default; |
| 622 CertPathBuilder::Result::~Result() = default; | 461 CertPathBuilder::Result::~Result() = default; |
| 623 | 462 |
| 624 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() | 463 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() |
| 625 const { | 464 const { |
| 626 DCHECK((paths.empty() && best_result_index == 0) || | 465 DCHECK((paths.empty() && best_result_index == 0) || |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 651 next_state_(STATE_NONE), | 490 next_state_(STATE_NONE), |
| 652 out_result_(result) {} | 491 out_result_(result) {} |
| 653 | 492 |
| 654 CertPathBuilder::~CertPathBuilder() {} | 493 CertPathBuilder::~CertPathBuilder() {} |
| 655 | 494 |
| 656 void CertPathBuilder::AddCertIssuerSource( | 495 void CertPathBuilder::AddCertIssuerSource( |
| 657 CertIssuerSource* cert_issuer_source) { | 496 CertIssuerSource* cert_issuer_source) { |
| 658 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | 497 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
| 659 } | 498 } |
| 660 | 499 |
| 661 CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { | 500 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
| 501 void CertPathBuilder::Run() { | |
| 662 DCHECK_EQ(STATE_NONE, next_state_); | 502 DCHECK_EQ(STATE_NONE, next_state_); |
| 663 next_state_ = STATE_GET_NEXT_PATH; | 503 next_state_ = STATE_GET_NEXT_PATH; |
| 664 CompletionStatus rv = DoLoop(!callback.is_null()); | |
| 665 | |
| 666 if (rv == CompletionStatus::ASYNC) | |
| 667 callback_ = callback; | |
| 668 | |
| 669 return rv; | |
| 670 } | |
| 671 | |
| 672 CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { | |
| 673 CompletionStatus result = CompletionStatus::SYNC; | |
| 674 | 504 |
| 675 do { | 505 do { |
| 676 State state = next_state_; | 506 State state = next_state_; |
| 677 next_state_ = STATE_NONE; | 507 next_state_ = STATE_NONE; |
| 678 switch (state) { | 508 switch (state) { |
| 679 case STATE_NONE: | 509 case STATE_NONE: |
| 680 NOTREACHED(); | 510 NOTREACHED(); |
| 681 break; | 511 break; |
| 682 case STATE_GET_NEXT_PATH: | 512 case STATE_GET_NEXT_PATH: |
| 683 result = DoGetNextPath(allow_async); | 513 DoGetNextPath(); |
| 684 break; | 514 break; |
| 685 case STATE_GET_NEXT_PATH_COMPLETE: | 515 case STATE_GET_NEXT_PATH_COMPLETE: |
| 686 result = DoGetNextPathComplete(); | 516 DoGetNextPathComplete(); |
| 687 break; | 517 break; |
| 688 } | 518 } |
| 689 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE); | 519 } while (next_state_ != STATE_NONE); |
| 690 | |
| 691 return result; | |
| 692 } | 520 } |
| 693 | 521 |
| 694 CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) { | 522 void CertPathBuilder::DoGetNextPath() { |
| 695 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; | 523 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; |
| 696 CompletionStatus rv = cert_path_iter_->GetNextPath( | 524 cert_path_iter_->GetNextPath(&next_path_); |
| 697 &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath, | |
| 698 base::Unretained(this)) | |
| 699 : base::Closure()); | |
| 700 return rv; | |
| 701 } | 525 } |
| 702 | 526 |
| 703 void CertPathBuilder::HandleGotNextPath() { | 527 void CertPathBuilder::DoGetNextPathComplete() { |
| 704 DCHECK(!callback_.is_null()); | |
| 705 CompletionStatus rv = DoLoop(true /* allow_async */); | |
| 706 if (rv == CompletionStatus::SYNC) | |
| 707 base::ResetAndReturn(&callback_).Run(); | |
| 708 } | |
| 709 | |
| 710 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { | |
| 711 if (next_path_.IsEmpty()) { | 528 if (next_path_.IsEmpty()) { |
| 712 // No more paths to check, signal completion. | 529 // No more paths to check, signal completion. |
| 713 next_state_ = STATE_NONE; | 530 next_state_ = STATE_NONE; |
| 714 return CompletionStatus::SYNC; | 531 return; |
| 715 } | 532 } |
| 716 | 533 |
| 717 // Verify the entire certificate chain. | 534 // Verify the entire certificate chain. |
| 718 auto result_path = base::MakeUnique<ResultPath>(); | 535 auto result_path = base::MakeUnique<ResultPath>(); |
| 719 bool verify_result = | 536 bool verify_result = |
| 720 VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(), | 537 VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(), |
| 721 signature_policy_, time_, &result_path->errors); | 538 signature_policy_, time_, &result_path->errors); |
| 722 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | 539 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
| 723 << result_path->valid; | 540 << result_path->valid; |
| 724 result_path->path = next_path_; | 541 result_path->path = next_path_; |
| 725 result_path->valid = verify_result; | 542 result_path->valid = verify_result; |
| 726 AddResultPath(std::move(result_path)); | 543 AddResultPath(std::move(result_path)); |
| 727 | 544 |
| 728 if (verify_result) { | 545 if (verify_result) { |
| 729 // Found a valid path, return immediately. | 546 // Found a valid path, return immediately. |
| 730 // TODO(mattm): add debug/test mode that tries all possible paths. | 547 // TODO(mattm): add debug/test mode that tries all possible paths. |
| 731 next_state_ = STATE_NONE; | 548 next_state_ = STATE_NONE; |
| 732 return CompletionStatus::SYNC; | 549 return; |
| 733 } | 550 } |
| 734 | 551 |
| 735 // Path did not verify. Try more paths. If there are no more paths, the result | 552 // Path did not verify. Try more paths. If there are no more paths, the result |
| 736 // will be returned next time DoGetNextPathComplete is called with next_path_ | 553 // will be returned next time DoGetNextPathComplete is called with next_path_ |
| 737 // empty. | 554 // empty. |
| 738 next_state_ = STATE_GET_NEXT_PATH; | 555 next_state_ = STATE_GET_NEXT_PATH; |
| 739 return CompletionStatus::SYNC; | |
| 740 } | 556 } |
| 741 | 557 |
| 742 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { | 558 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { |
| 743 // TODO(mattm): set best_result_index based on number or severity of errors. | 559 // TODO(mattm): set best_result_index based on number or severity of errors. |
| 744 if (result_path->valid) | 560 if (result_path->valid) |
| 745 out_result_->best_result_index = out_result_->paths.size(); | 561 out_result_->best_result_index = out_result_->paths.size(); |
| 746 // TODO(mattm): add flag to only return a single path or all attempted paths? | 562 // TODO(mattm): add flag to only return a single path or all attempted paths? |
| 747 out_result_->paths.push_back(std::move(result_path)); | 563 out_result_->paths.push_back(std::move(result_path)); |
| 748 } | 564 } |
| 749 | 565 |
| 750 } // namespace net | 566 } // namespace net |
| OLD | NEW |