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

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

Powered by Google App Engine
This is Rietveld 408576698