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

Side by Side Diff: net/cert/internal/path_builder.cc

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

Powered by Google App Engine
This is Rietveld 408576698