OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/cert/internal/path_builder.h" | |
6 | |
7 #include <set> | |
8 #include <unordered_set> | |
9 | |
10 #include "base/callback_helpers.h" | |
11 #include "base/memory/ptr_util.h" | |
12 #include "net/base/net_errors.h" | |
13 #include "net/cert/internal/cert_issuer_source.h" | |
14 #include "net/cert/internal/parse_certificate.h" | |
15 #include "net/cert/internal/parse_name.h" // For CertDebugString. | |
16 #include "net/cert/internal/parsed_certificate.h" | |
17 #include "net/cert/internal/signature_policy.h" | |
18 #include "net/cert/internal/trust_store.h" | |
19 #include "net/cert/internal/verify_certificate_chain.h" | |
20 #include "net/cert/internal/verify_name_match.h" | |
21 #include "net/der/parser.h" | |
22 #include "net/der/tag.h" | |
23 | |
24 namespace net { | |
25 | |
26 namespace { | |
27 | |
28 using CertIssuerSources = std::vector<CertIssuerSource*>; | |
29 using CertVector = std::vector<scoped_refptr<ParsedCertificate>>; | |
30 | |
31 // TODO(mattm): decide how much debug logging to keep. | |
32 std::string CertDebugString(const ParsedCertificate* cert) { | |
33 RDNSequence subject, issuer; | |
34 std::string subject_str, issuer_str; | |
35 if (!ParseName(cert->tbs().subject_tlv, &subject) || | |
36 !ConvertToRFC2253(subject, &subject_str)) | |
37 subject_str = "???"; | |
38 if (!ParseName(cert->tbs().issuer_tlv, &issuer) || | |
39 !ConvertToRFC2253(issuer, &issuer_str)) | |
40 issuer_str = "???"; | |
41 | |
42 return subject_str + "(" + issuer_str + ")"; | |
43 } | |
44 | |
45 // LoopChecker tracks which certs are present in the path and prevents paths | |
46 // from being built which repeat any certs (including different versions of the | |
47 // same cert, based on Subject+SubjectAltName+SPKI). | |
48 class LoopChecker { | |
49 public: | |
50 using Key = | |
51 std::tuple<base::StringPiece, base::StringPiece, base::StringPiece>; | |
52 // Attempts to add |cert| to the list of certs to check. If it has not already | |
53 // been added, true is returned and |cert| is added, such that any future | |
54 // attempts will return false. | |
55 // The |cert| data is not copied, Remove must be called before the |cert| data | |
eroman
2016/06/27 19:58:52
These interdependencies are really hard to underst
mattm
2016/06/27 23:45:45
I gave it a shot. Changed this class to also manag
| |
56 // is destroyed. | |
57 bool Insert(const ParsedCertificate* cert) { | |
58 Key key = GetKey(cert); | |
59 if (present_certs_.find(key) != present_certs_.end()) | |
eroman
2016/06/27 19:58:52
Don't think the .find() is needed here, set insert
mattm
2016/06/27 23:45:45
Acknowledged. (Bit different in new code.)
| |
60 return false; | |
61 present_certs_.insert(key); | |
62 return true; | |
63 } | |
64 // Removes a cert from being disallowed. | |
65 void Remove(const ParsedCertificate* cert) { | |
66 present_certs_.erase(GetKey(cert)); | |
67 } | |
68 | |
69 private: | |
70 static Key GetKey(const ParsedCertificate* cert) { | |
71 // TODO(mattm): ideally this would use a normalized version of | |
72 // SubjectAltName, but it's not that important just for LoopChecker. | |
73 // | |
74 // Note that subject_alt_names_extension().value will be empty if the cert | |
75 // had no SubjectAltName extension, so there is no need for a condition on | |
76 // has_subject_alt_names(). | |
77 return Key(cert->normalized_subject().AsStringPiece(), | |
78 cert->subject_alt_names_extension().value.AsStringPiece(), | |
79 cert->tbs().spki_tlv.AsStringPiece()); | |
80 } | |
81 | |
82 // TODO(mattm): use unordered_set. Requires making a hash function for Key. | |
83 std::set<Key> present_certs_; | |
84 }; | |
85 | |
86 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | |
87 // which may be issuers of |cert|. | |
88 class CertIssuersIter { | |
89 public: | |
90 // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for | |
91 // the lifetime of the CertIssuersIter. | |
92 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | |
93 CertIssuerSources* cert_issuer_sources, | |
94 const TrustStore& trust_store); | |
95 | |
96 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC | |
97 // is returned and the cert is stored in |*out_cert|. If an issuer is not | |
98 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has | |
99 // been set. If |callback| is null, always completes synchronously. | |
100 // | |
101 // In either case, if all issuers have been exhausted, |*out_cert| is cleared. | |
102 CompletionStatus GetNextIssuer(scoped_refptr<ParsedCertificate>* out_cert, | |
103 const base::Closure& callback); | |
104 | |
105 // Returns the |cert| for which issuers are being retrieved. | |
106 const ParsedCertificate* cert() const { return cert_.get(); } | |
107 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | |
108 | |
109 private: | |
110 void GotAsyncCerts(CertIssuerSource::Request* request); | |
111 | |
112 scoped_refptr<ParsedCertificate> cert_; | |
113 CertIssuerSources* cert_issuer_sources_; | |
114 | |
115 // The list of issuers for |cert_|. This is added to incrementally (first | |
116 // synchronous results, then possibly multiple times as asynchronous results | |
117 // arrive.) The issuers may be re-sorted each time new issuers are added, but | |
118 // only the results from |cur_| onwards should be sorted, since the earlier | |
119 // results were already returned. | |
120 // Elements should not be removed from |issuers_| once added, since | |
121 // |present_issuers_| will point to data owned by the certs. | |
122 CertVector issuers_; | |
123 // The index of the next cert in |issuers_| to return. | |
124 size_t cur_ = 0; | |
125 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | |
126 // duplicates. This is based on the full DER of the cert to allow different | |
127 // versions of the same certificate to be tried in different candidate paths. | |
128 // This points to data owned by |issuers_|. | |
129 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | |
130 | |
131 // Tracks whether asynchronous requests have been made yet. | |
132 bool did_async_query_ = false; | |
133 // If asynchronous requests were made, how many of them are still outstanding? | |
134 size_t pending_async_results_; | |
135 // Owns the Request objects for any asynchronous requests so that they will be | |
136 // cancelled if CertIssuersIter is destroyed. | |
137 std::vector<std::unique_ptr<CertIssuerSource::Request>> | |
138 pending_async_requests_; | |
139 | |
140 // When GetNextIssuer was called and returned asynchronously, |*out_cert_| is | |
141 // where the result will be stored, and |callback_| will be run when the | |
142 // result is ready. | |
143 scoped_refptr<ParsedCertificate>* out_cert_; | |
144 base::Closure callback_; | |
145 | |
146 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | |
147 }; | |
148 | |
149 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | |
150 CertIssuerSources* cert_issuer_sources, | |
151 const TrustStore& trust_store) | |
152 : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) { | |
153 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | |
154 trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), | |
155 &issuers_); | |
156 // Insert matching roots into |present_issuers_| in case they also are | |
157 // returned by a CertIssuerSource. It is assumed | |
158 // FindTrustAnchorsByNormalizedName does not itself return dupes. | |
159 for (const auto& root : issuers_) | |
160 present_issuers_.insert(root->der_cert().AsStringPiece()); | |
161 | |
162 for (auto* cert_issuer_source : *cert_issuer_sources_) { | |
163 CertVector new_issuers; | |
164 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | |
165 for (scoped_refptr<ParsedCertificate>& issuer : 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 } | |
173 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | |
174 // anchor subject (or is a trust anchor), that should be sorted higher too. | |
175 // See big list of possible sorting hints in RFC 4158.) | |
176 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | |
177 // is done) | |
178 } | |
179 | |
180 CompletionStatus CertIssuersIter::GetNextIssuer( | |
181 scoped_refptr<ParsedCertificate>* out_cert, | |
182 const base::Closure& callback) { | |
183 // Should not be called again while already waiting for an async result. | |
184 DCHECK(callback_.is_null()); | |
185 | |
186 if (cur_ < issuers_.size()) { | |
187 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
188 << "): returning item " << cur_ << " of " << issuers_.size(); | |
189 // Still have issuers that haven't been returned yet, return one of them. | |
190 // A reference to the returned issuer is retained, since |present_issuers_| | |
191 // points to data owned by it. | |
192 *out_cert = issuers_[cur_++]; | |
193 return CompletionStatus::SYNC; | |
194 } | |
195 if (did_async_query_) { | |
196 if (pending_async_results_ == 0) { | |
197 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
198 << ") Reached the end of all available issuers."; | |
199 // Reached the end of all available issuers. | |
200 *out_cert = nullptr; | |
201 return CompletionStatus::SYNC; | |
202 } | |
203 | |
204 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
205 << ") Still waiting for async results from other " | |
206 "CertIssuerSources."; | |
207 // Still waiting for async results from other CertIssuerSources. | |
208 out_cert_ = out_cert; | |
209 callback_ = callback; | |
210 return CompletionStatus::ASYNC; | |
211 } | |
212 // Reached the end of synchronously gathered issuers. | |
213 | |
214 if (callback.is_null()) { | |
215 // Synchronous-only mode, don't try to query async sources. | |
216 *out_cert = nullptr; | |
217 return CompletionStatus::SYNC; | |
218 } | |
219 | |
220 // Now issue request(s) for async ones (AIA, etc). | |
221 did_async_query_ = true; | |
222 pending_async_results_ = 0; | |
223 for (auto* cert_issuer_source : *cert_issuer_sources_) { | |
224 std::unique_ptr<CertIssuerSource::Request> request; | |
225 cert_issuer_source->AsyncGetIssuersOf( | |
226 cert(), | |
227 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), | |
228 &request); | |
229 if (request) { | |
230 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | |
231 << ") pending..."; | |
232 pending_async_results_++; | |
233 pending_async_requests_.push_back(std::move(request)); | |
234 } | |
235 } | |
236 | |
237 if (pending_async_results_ == 0) { | |
238 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
239 << ") No cert sources have async results."; | |
240 // No cert sources have async results. | |
241 *out_cert = nullptr; | |
242 return CompletionStatus::SYNC; | |
243 } | |
244 | |
245 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
246 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ | |
247 << ")"; | |
248 out_cert_ = out_cert; | |
249 callback_ = callback; | |
250 return CompletionStatus::ASYNC; | |
251 } | |
252 | |
253 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { | |
254 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) | |
255 << ")"; | |
256 while (true) { | |
257 scoped_refptr<ParsedCertificate> cert; | |
258 CompletionStatus status = request->GetNext(&cert); | |
259 if (!cert) { | |
260 if (status == CompletionStatus::SYNC) { | |
261 // Request is exhausted, no more results pending from that | |
262 // CertIssuerSource. | |
263 DCHECK_GT(pending_async_results_, 0U); | |
264 pending_async_results_--; | |
265 } | |
266 break; | |
267 } | |
268 DCHECK_EQ(status, CompletionStatus::SYNC); | |
269 if (present_issuers_.find(cert->der_cert().AsStringPiece()) != | |
270 present_issuers_.end()) | |
271 continue; | |
272 present_issuers_.insert(cert->der_cert().AsStringPiece()); | |
273 issuers_.push_back(std::move(cert)); | |
274 } | |
275 | |
276 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may | |
277 // be more than the ones just inserted, depending on |cur_| value). | |
278 | |
279 // Notify that more results are available, if necessary. | |
280 if (!callback_.is_null()) { | |
281 if (cur_ < issuers_.size()) { | |
282 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
283 << "): async returning item " << cur_ << " of " | |
284 << issuers_.size(); | |
285 *out_cert_ = std::move(issuers_[cur_++]); | |
286 base::ResetAndReturn(&callback_).Run(); | |
287 } else if (pending_async_results_ == 0) { | |
288 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
289 << "): async returning empty result"; | |
290 *out_cert_ = nullptr; | |
291 base::ResetAndReturn(&callback_).Run(); | |
292 } else { | |
293 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
294 << "): empty result, but other async results " | |
295 "pending, waiting.."; | |
296 } | |
297 } | |
298 } | |
299 | |
300 std::string PathDebugString( | |
301 const std::vector<std::unique_ptr<CertIssuersIter>>& cur_path) { | |
302 std::string s; | |
303 for (const auto& node : cur_path) { | |
304 if (!s.empty()) | |
305 s += " <- "; | |
306 s += CertDebugString(node->cert()); | |
307 } | |
308 return s; | |
309 } | |
310 | |
311 } // namespace | |
312 | |
313 // CertPathIter generates possible paths from |cert| to a trust anchor in | |
314 // |trust_store|, using intermediates from the |cert_issuer_source| objects if | |
315 // necessary. | |
316 class CertPathIter { | |
317 public: | |
318 CertPathIter(scoped_refptr<ParsedCertificate> cert, | |
319 const TrustStore* trust_store); | |
320 | |
321 // Adds a CertIssuerSource to provide intermediates for use in path building. | |
322 // The |*cert_issuer_source| must remain valid for the lifetime of the | |
323 // CertPathIter. | |
324 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); | |
325 | |
326 // Gets the next candidate path. If a path is ready synchronously, SYNC is | |
327 // returned and the path is stored in |*path|. If a path is not ready, | |
328 // ASYNC is returned and |async_ready_callback| will be called once | |
329 // |*path| has been set. | |
330 // In either case, if all paths have been exhausted, |*path| is cleared. | |
331 CompletionStatus GetNextPath(CertVector* path, const base::Closure& callback); | |
332 | |
333 private: | |
334 enum State { | |
335 STATE_NONE, | |
336 STATE_GET_NEXT_ISSUER, | |
337 STATE_GET_NEXT_ISSUER_COMPLETE, | |
338 STATE_RETURN_A_PATH, | |
339 STATE_BACKTRACK, | |
340 }; | |
341 | |
342 CompletionStatus DoLoop(bool allow_async); | |
343 | |
344 CompletionStatus DoGetNextIssuer(bool allow_async); | |
345 CompletionStatus DoGetNextIssuerComplete(); | |
346 CompletionStatus DoBackTrack(); | |
347 | |
348 void HandleGotNextIssuer(void); | |
349 | |
350 LoopChecker loop_checker_; | |
351 scoped_refptr<ParsedCertificate> next_cert_; | |
352 std::vector<std::unique_ptr<CertIssuersIter>> cur_path_; | |
353 CertIssuerSources cert_issuer_sources_; | |
354 const TrustStore* trust_store_; | |
355 CertVector* out_path_; | |
356 base::Closure callback_; | |
357 State next_state_; | |
358 | |
359 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | |
360 }; | |
361 | |
362 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | |
363 const TrustStore* trust_store) | |
364 : next_cert_(std::move(cert)), | |
365 trust_store_(trust_store), | |
366 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | |
367 | |
368 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | |
369 cert_issuer_sources_.push_back(cert_issuer_source); | |
370 } | |
371 | |
372 CompletionStatus CertPathIter::GetNextPath(CertVector* path, | |
373 const base::Closure& callback) { | |
374 out_path_ = path; | |
375 out_path_->clear(); | |
376 CompletionStatus rv = DoLoop(!callback.is_null()); | |
377 if (rv == CompletionStatus::ASYNC) { | |
378 callback_ = callback; | |
379 } else { | |
380 // Clear the reference to the output parameter as a precaution. | |
381 out_path_ = nullptr; | |
382 } | |
383 return rv; | |
384 } | |
385 | |
386 CompletionStatus CertPathIter::DoLoop(bool allow_async) { | |
387 CompletionStatus result = CompletionStatus::SYNC; | |
388 do { | |
389 State state = next_state_; | |
390 next_state_ = STATE_NONE; | |
391 switch (state) { | |
392 case STATE_NONE: | |
393 NOTREACHED(); | |
394 break; | |
395 case STATE_GET_NEXT_ISSUER: | |
396 result = DoGetNextIssuer(allow_async); | |
397 break; | |
398 case STATE_GET_NEXT_ISSUER_COMPLETE: | |
399 result = DoGetNextIssuerComplete(); | |
400 break; | |
401 case STATE_RETURN_A_PATH: | |
402 // If the returned path did not verify, keep looking for other paths | |
403 // (the trust root is not part of cur_path_, so don't need to | |
404 // backtrack). | |
405 next_state_ = STATE_GET_NEXT_ISSUER; | |
406 result = CompletionStatus::SYNC; | |
407 break; | |
408 case STATE_BACKTRACK: | |
409 result = DoBackTrack(); | |
410 break; | |
411 } | |
412 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && | |
413 next_state_ != STATE_RETURN_A_PATH); | |
414 | |
415 return result; | |
416 } | |
417 | |
418 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { | |
419 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | |
420 CompletionStatus rv = cur_path_.back()->GetNextIssuer( | |
421 &next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer, | |
422 base::Unretained(this)) | |
423 : base::Closure()); | |
424 return rv; | |
425 } | |
426 | |
427 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { | |
428 if (next_cert_) { | |
429 // Skip this cert if it is already in the chain. | |
430 if (!loop_checker_.Insert(next_cert_.get())) { | |
431 next_state_ = STATE_GET_NEXT_ISSUER; | |
432 return CompletionStatus::SYNC; | |
433 } | |
434 // Note that loop_checker_.Insert does not make a copy of the cert data. | |
435 // Must call loop_checker_.Remove before destroying the cert data. | |
436 | |
437 // If the cert matches a trust root, this is a (possible) complete path. | |
438 // Signal readiness. Don't add it to cur_path_, since that would cause an | |
439 // unnecessary lookup of issuers of the trust root. | |
440 if (trust_store_->IsTrustedCertificate(next_cert_.get())) { | |
441 loop_checker_.Remove(next_cert_.get()); | |
442 DVLOG(1) << "CertPathIter IsTrustedCertificate(" | |
443 << CertDebugString(next_cert_.get()) << ") = true"; | |
444 next_state_ = STATE_RETURN_A_PATH; | |
445 for (const auto& node : cur_path_) | |
446 out_path_->push_back(node->reference_cert()); | |
447 out_path_->push_back(std::move(next_cert_)); | |
448 next_cert_ = nullptr; | |
449 return CompletionStatus::SYNC; | |
450 } | |
451 | |
452 cur_path_.push_back(base::WrapUnique(new CertIssuersIter( | |
453 std::move(next_cert_), &cert_issuer_sources_, *trust_store_))); | |
454 next_cert_ = nullptr; | |
455 DVLOG(1) << "CertPathIter cur_path_ = " << PathDebugString(cur_path_); | |
456 // Continue descending the tree. | |
457 next_state_ = STATE_GET_NEXT_ISSUER; | |
458 } else { | |
459 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | |
460 // maybe with a flag to enable it. Or use a visitor pattern so the caller | |
461 // can decide what to do with any failed paths. | |
462 // No more issuers for current chain, go back up and see if there are any | |
463 // more for the previous cert. | |
464 next_state_ = STATE_BACKTRACK; | |
465 } | |
466 return CompletionStatus::SYNC; | |
467 } | |
468 | |
469 CompletionStatus CertPathIter::DoBackTrack() { | |
470 DVLOG(1) << "CertPathIter backtracking..."; | |
471 loop_checker_.Remove(cur_path_.back()->cert()); | |
472 cur_path_.pop_back(); | |
473 if (cur_path_.empty()) { | |
474 // Exhausted all paths. | |
475 next_state_ = STATE_NONE; | |
476 } else { | |
477 // Continue exploring issuers of the previous path. | |
478 next_state_ = STATE_GET_NEXT_ISSUER; | |
479 } | |
480 return CompletionStatus::SYNC; | |
481 } | |
482 | |
483 void CertPathIter::HandleGotNextIssuer(void) { | |
484 DCHECK(!callback_.is_null()); | |
485 CompletionStatus rv = DoLoop(true /* allow_async */); | |
486 if (rv == CompletionStatus::SYNC) { | |
487 // Clear the reference to the output parameter as a precaution. | |
488 out_path_ = nullptr; | |
489 base::ResetAndReturn(&callback_).Run(); | |
490 } | |
491 } | |
492 | |
493 CertPathBuilder::ResultPath::ResultPath() = default; | |
494 CertPathBuilder::ResultPath::~ResultPath() = default; | |
495 CertPathBuilder::Result::Result() = default; | |
496 CertPathBuilder::Result::~Result() = default; | |
497 | |
498 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, | |
499 const TrustStore* trust_store, | |
500 const SignaturePolicy* signature_policy, | |
501 const der::GeneralizedTime& time, | |
502 Result* result) | |
503 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), | |
504 trust_store_(trust_store), | |
505 signature_policy_(signature_policy), | |
506 time_(time), | |
507 next_state_(STATE_NONE), | |
508 out_result_(result) {} | |
509 | |
510 CertPathBuilder::~CertPathBuilder() {} | |
511 | |
512 void CertPathBuilder::AddCertIssuerSource( | |
513 CertIssuerSource* cert_issuer_source) { | |
514 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | |
515 } | |
516 | |
517 CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { | |
518 DCHECK_EQ(STATE_NONE, next_state_); | |
519 next_state_ = STATE_GET_NEXT_PATH; | |
520 CompletionStatus rv = DoLoop(!callback.is_null()); | |
521 | |
522 if (rv == CompletionStatus::ASYNC) | |
523 callback_ = callback; | |
524 | |
525 return rv; | |
526 } | |
527 | |
528 CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { | |
529 CompletionStatus result = CompletionStatus::SYNC; | |
530 | |
531 do { | |
532 State state = next_state_; | |
533 next_state_ = STATE_NONE; | |
534 switch (state) { | |
535 case STATE_NONE: | |
536 NOTREACHED(); | |
537 break; | |
538 case STATE_GET_NEXT_PATH: | |
539 result = DoGetNextPath(allow_async); | |
540 break; | |
541 case STATE_GET_NEXT_PATH_COMPLETE: | |
542 result = DoGetNextPathComplete(); | |
543 break; | |
544 } | |
545 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE); | |
546 | |
547 return result; | |
548 } | |
549 | |
550 CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) { | |
551 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; | |
552 CompletionStatus rv = cert_path_iter_->GetNextPath( | |
553 &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath, | |
554 base::Unretained(this)) | |
555 : base::Closure()); | |
556 return rv; | |
557 } | |
558 | |
559 void CertPathBuilder::HandleGotNextPath() { | |
560 DCHECK(!callback_.is_null()); | |
561 CompletionStatus rv = DoLoop(true /* allow_async */); | |
562 if (rv == CompletionStatus::SYNC) | |
563 base::ResetAndReturn(&callback_).Run(); | |
564 } | |
565 | |
566 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { | |
567 if (next_path_.empty()) { | |
568 // No more paths to check, signal completion. | |
569 next_state_ = STATE_NONE; | |
570 return CompletionStatus::SYNC; | |
571 } | |
572 | |
573 bool verify_result = VerifyCertificateChainAssumingTrustedRoot( | |
574 next_path_, *trust_store_, signature_policy_, time_); | |
575 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | |
576 << verify_result; | |
577 AddResultPath(next_path_, verify_result); | |
578 | |
579 if (verify_result) { | |
580 // Found a valid path, return immediately. | |
581 // TODO(mattm): add debug/test mode that tries all possible paths. | |
582 next_state_ = STATE_NONE; | |
583 return CompletionStatus::SYNC; | |
584 } | |
585 | |
586 // Path did not verify. Try more paths. If there are no more paths, the result | |
587 // will be returned next time DoGetNextPathComplete is called with next_path_ | |
588 // empty. | |
589 next_state_ = STATE_GET_NEXT_PATH; | |
590 return CompletionStatus::SYNC; | |
591 } | |
592 | |
593 void CertPathBuilder::AddResultPath(const CertVector& path, bool result) { | |
594 std::unique_ptr<ResultPath> rp(new ResultPath()); | |
595 // TODO(mattm): better error reporting. | |
596 rp->rv = result ? OK : ERR_CERT_AUTHORITY_INVALID; | |
597 // TODO(mattm): set best_result_index based on number or severity of errors. | |
598 if (rp->rv == OK) | |
599 out_result_->best_result_index = out_result_->paths.size(); | |
600 // TODO(mattm): add flag to only return a single path or all attempted paths? | |
601 for (const auto& cert : path) | |
602 rp->path.push_back(cert); | |
603 out_result_->paths.push_back(std::move(rp)); | |
604 } | |
605 | |
606 } // namespace net | |
OLD | NEW |