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 | |
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 | |
OLD | NEW |