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

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: rebase Created 4 years, 6 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 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698