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 <unordered_set> |
| 8 #include <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/parse_certificate.h" |
| 14 #include "net/cert/internal/parse_name.h" // XXX for DumpPath. Remove. |
| 15 #include "net/cert/internal/verify_name_match.h" |
| 16 #include "net/der/parser.h" |
| 17 #include "net/der/tag.h" |
| 18 |
| 19 namespace net { |
| 20 |
| 21 namespace { |
| 22 |
| 23 // LoopChecker tracks which certs are present in the path and prevents paths |
| 24 // from being built which repeat any certs. |
| 25 class LoopChecker { |
| 26 public: |
| 27 using Key = |
| 28 std::tuple<base::StringPiece, base::StringPiece, base::StringPiece>; |
| 29 // Attempts to add |cert| to the list of certs to check. If it has not already |
| 30 // been added, true is returned and |cert| is added, such that any future |
| 31 // attempts will return false. |
| 32 // The |cert| data is not copied, Remove must be called before the |cert| data |
| 33 // is destroyed. |
| 34 bool Insert(const CertThing* cert) { |
| 35 Key key = GetKey(cert); |
| 36 if (present_certs_.find(key) != present_certs_.end()) |
| 37 return false; |
| 38 present_certs_.insert(key); |
| 39 return true; |
| 40 } |
| 41 // Removes a cert from being disallowed. |
| 42 void Remove(const CertThing* cert) { present_certs_.erase(GetKey(cert)); } |
| 43 |
| 44 private: |
| 45 static Key GetKey(const CertThing* cert) { |
| 46 // TODO(mattm): ideally this would use a normalized version of |
| 47 // SubjectAltName, but it's not that important just for LoopChecker. |
| 48 // |
| 49 // Note that subject_alt_names_extension().value will be empty if the cert |
| 50 // had no SubjectAltName extension, so there is no need for a condition on |
| 51 // has_subject_alt_names(). |
| 52 return std::make_tuple( |
| 53 cert->normalized_subject(), |
| 54 cert->subject_alt_names_extension().value.AsStringPiece(), |
| 55 cert->parsed_tbs().spki_tlv.AsStringPiece()); |
| 56 } |
| 57 |
| 58 // TODO: use unordered_set. Requires making a hash function for Key. |
| 59 std::set<Key> present_certs_; |
| 60 }; |
| 61 |
| 62 // CertIssuersIter iterates through the intermediates from |cert_sources| which |
| 63 // may be issuers of |cert|. |
| 64 // TODO: It should return the issuers in order most likely to succeed. |
| 65 // TODO: deduping of certs in case multiple certsources return the same cert |
| 66 class CertIssuersIter { |
| 67 public: |
| 68 // Constructs the CertIssuersIter. Takes ownership of |cert|. |*cert_sources| |
| 69 // must be valid for the lifetime of the CertIssuersIter. |
| 70 CertIssuersIter(scoped_refptr<CertThing> cert, |
| 71 CertPathBuilder::CertSources* cert_sources, |
| 72 const TrustStore& trust_store); |
| 73 |
| 74 // Gets the next candidate issuer for |cert_|. If one is not ready |
| 75 // synchronously, the return value ERR_IO_PENDING is returned and |callback| |
| 76 // will be called once an issuer is ready. |
| 77 // In either case, the next issuer will be set in |*out_cert|, or if there are |
| 78 // no |
| 79 // more issuers available, |*out_cert| will be cleared. |
| 80 // and it will have been stored in |*out_cert| |
| 81 // it. If an issuer is ready, OK is returned and the cert is stored in |
| 82 // |*out_cert|. |
| 83 // If all issuers have been exhausted, OK is returned and |*out_cert| is |
| 84 // cleared. |
| 85 int GetNextIssuer(scoped_refptr<CertThing>* out_cert, |
| 86 const base::Closure& callback); |
| 87 |
| 88 // Returns the |cert| for which issuers are being retrieved. |
| 89 const CertThing* cert() const { return cert_.get(); } |
| 90 scoped_refptr<CertThing> reference_cert() const { return cert_; } |
| 91 |
| 92 private: |
| 93 void GotAsyncCerts(CertVector certs); |
| 94 |
| 95 scoped_refptr<CertThing> cert_; |
| 96 CertPathBuilder::CertSources* cert_sources_; |
| 97 |
| 98 // The list of issuers for |cert_|. This is added to incrementally (first |
| 99 // synchronous, results, then possibly multiple times as asynchronous results |
| 100 // arrive.) The issuers may be re-sorted each time new issuers are added, but |
| 101 // only the results from |cur_| onwards should be sorted, since the earlier |
| 102 // results were already returned. |
| 103 CertVector issuers_; |
| 104 // The index of the next cert in |issuers_| to return. |
| 105 size_t cur_ = 0; |
| 106 |
| 107 // Tracks whether asynchronous requests have been made yet. |
| 108 bool did_async_query_ = false; |
| 109 // If asynchronous requests were made, how many of them are still outstanding? |
| 110 int pending_async_results_; |
| 111 // Owns the Request objects for any asynchronous requests so that they will be |
| 112 // cancelled if CertIssuersIter is destroyed. |
| 113 std::vector<std::unique_ptr<CertSource::Request>> pending_async_requests_; |
| 114 |
| 115 // When GetNextIssuer was called and returned asynchronously, |out_cert_| is |
| 116 // where the result will be stored, and |callback_| will be run when the |
| 117 // result is ready. |
| 118 scoped_refptr<CertThing>* out_cert_; |
| 119 base::Closure callback_; |
| 120 |
| 121 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
| 122 }; |
| 123 |
| 124 CertIssuersIter::CertIssuersIter(scoped_refptr<CertThing> in_cert, |
| 125 CertPathBuilder::CertSources* cert_sources, |
| 126 const TrustStore& trust_store) |
| 127 : cert_(in_cert), cert_sources_(cert_sources) { |
| 128 trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), |
| 129 &issuers_); |
| 130 for (auto* cert_source : *cert_sources_) |
| 131 cert_source->SyncGetIssuersOf(cert(), &issuers_); |
| 132 // TODO: sort by notbefore, etc (eg if cert issuer matches a trust anchor |
| 133 // subject (or is a trust anchor), that should be sorted higher too. See big |
| 134 // list of possible sorting hints in RFC 4158.) |
| 135 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| 136 // is done) |
| 137 } |
| 138 |
| 139 int CertIssuersIter::GetNextIssuer(scoped_refptr<CertThing>* 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: returning item " << cur_ << " of " |
| 146 << issuers_.size(); |
| 147 // Still have issuers that haven't been returned yet, return one of them. |
| 148 *out_cert = std::move(issuers_[cur_++]); |
| 149 return OK; |
| 150 } |
| 151 if (did_async_query_) { |
| 152 if (pending_async_results_ == 0) { |
| 153 DVLOG(1) << "CertIssuersIter Reached the end of all available issuers."; |
| 154 // Reached the end of all available issuers. |
| 155 *out_cert = nullptr; |
| 156 return OK; |
| 157 } |
| 158 |
| 159 DVLOG(1) << "CertIssuersIter Still waiting for async results from other " |
| 160 "CertSources."; |
| 161 // Still waiting for async results from other CertSources. |
| 162 out_cert_ = out_cert; |
| 163 callback_ = callback; |
| 164 return ERR_IO_PENDING; |
| 165 } |
| 166 |
| 167 // Reached the end of synchronously gathered issuers, now issue request(s) for |
| 168 // async ones (AIA, etc). |
| 169 |
| 170 did_async_query_ = true; |
| 171 pending_async_results_ = 0; |
| 172 for (auto* cert_source : *cert_sources_) { |
| 173 std::unique_ptr<CertSource::Request> request; |
| 174 int rv = cert_source->AsyncGetIssuersOf( |
| 175 cert(), |
| 176 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), |
| 177 &request); |
| 178 DVLOG(1) << "AsyncGetIssuersOf v=" << rv; |
| 179 // XXX any other error handling here? |
| 180 if (rv == ERR_IO_PENDING) |
| 181 pending_async_results_++; |
| 182 if (request) |
| 183 pending_async_requests_.push_back(std::move(request)); |
| 184 } |
| 185 |
| 186 if (pending_async_results_ == 0) { |
| 187 DVLOG(1) << "CertIssuersIter No cert sources have async results."; |
| 188 // No cert sources have async results. |
| 189 *out_cert = nullptr; |
| 190 return OK; |
| 191 } |
| 192 |
| 193 DVLOG(1) << "CertIssuersIter issued AsyncGetIssuersOf call(s) (n=" |
| 194 << pending_async_results_ << ")"; |
| 195 out_cert_ = out_cert; |
| 196 callback_ = callback; |
| 197 return ERR_IO_PENDING; |
| 198 } |
| 199 |
| 200 void CertIssuersIter::GotAsyncCerts(CertVector certs) { |
| 201 DVLOG(1) << "CertIssuersIter::GotAsyncCerts n=" << certs.size(); |
| 202 pending_async_results_--; |
| 203 for (auto& c : certs) |
| 204 issuers_.push_back(std::move(c)); |
| 205 |
| 206 // TODO: re-sort remaining elements of issuers_ (remaining elements may be |
| 207 // more than the ones just inserted, depending on |cur_| value). |
| 208 |
| 209 // Notify that more results are available, if necessary. |
| 210 if (!callback_.is_null()) { |
| 211 if (cur_ < issuers_.size()) { |
| 212 DVLOG(1) << "CertIssuersIter: async returning item " << cur_ << " of " |
| 213 << issuers_.size(); |
| 214 *out_cert_ = std::move(issuers_[cur_++]); |
| 215 base::ResetAndReturn(&callback_).Run(); |
| 216 } else if (pending_async_results_ == 0) { |
| 217 DVLOG(1) << "CertIssuersIter: async returning empty result"; |
| 218 *out_cert_ = nullptr; |
| 219 base::ResetAndReturn(&callback_).Run(); |
| 220 } else { |
| 221 DVLOG(1) << "CertIssuersIter: empty result, but other async results " |
| 222 "pending, waiting.."; |
| 223 } |
| 224 } |
| 225 } |
| 226 |
| 227 } // namespace |
| 228 |
| 229 StaticCertSource::StaticCertSource(const CertVector& certs) { |
| 230 for (const auto& cert : certs) { |
| 231 intermediates_.insert( |
| 232 std::make_pair(cert->normalized_subject(), std::move(cert))); |
| 233 } |
| 234 } |
| 235 StaticCertSource::~StaticCertSource() {} |
| 236 |
| 237 void StaticCertSource::SyncGetIssuersOf(const CertThing* cert, |
| 238 CertVector* issuers) { |
| 239 auto range = intermediates_.equal_range(cert->normalized_issuer()); |
| 240 for (auto it = range.first; it != range.second; ++it) |
| 241 issuers->push_back(it->second); |
| 242 } |
| 243 |
| 244 int StaticCertSource::AsyncGetIssuersOf(const CertThing* cert, |
| 245 const IssuerCallback& issuers_callback, |
| 246 std::unique_ptr<Request>* out_req) { |
| 247 // StaticCertSource never returns asynchronous results. |
| 248 return OK; |
| 249 } |
| 250 |
| 251 // CertPathIter generates possible paths from |cert| to a trust anchor in |
| 252 // |trust_store|, using intermediates from |cert_sources| if necessary. |
| 253 class CertPathIter { |
| 254 public: |
| 255 CertPathIter(scoped_refptr<CertThing> cert, |
| 256 const CertPathBuilder::CertSources& cert_sources, |
| 257 const TrustStore& trust_store); |
| 258 |
| 259 // Gets the next candidate path. If a path is ready synchronously, OK is |
| 260 // returned and the path is stored in |*path|. If a path is not ready, |
| 261 // ERR_IO_PENDING is returned and |async_ready_callback| will be called once |
| 262 // |*path| has been set. |
| 263 // In either case, if all paths have been exhausted, OK result is returned and |
| 264 // |*path| is cleared. |
| 265 // The cert data referred to in |*path| is only valid until the next |
| 266 // GetNextPath call or until the CertPathIter is destroyed. |
| 267 int GetNextPath(CertVector* path, const CompletionCallback& callback); |
| 268 |
| 269 private: |
| 270 enum State { |
| 271 STATE_NONE, |
| 272 STATE_GET_NEXT_ISSUER, |
| 273 STATE_GET_NEXT_ISSUER_COMPLETE, |
| 274 STATE_RETURN_A_PATH, |
| 275 STATE_BACKTRACK, |
| 276 }; |
| 277 |
| 278 int DoLoop(); |
| 279 |
| 280 int DoGetNextIssuer(); |
| 281 int DoGetNextIssuerComplete(); |
| 282 int DoBackTrack(); |
| 283 |
| 284 void HandleGotNextIssuer(void); |
| 285 |
| 286 LoopChecker loop_checker_; |
| 287 scoped_refptr<CertThing> next_cert_; |
| 288 std::vector<std::unique_ptr<CertIssuersIter>> cur_path_; |
| 289 CertPathBuilder::CertSources cert_sources_; |
| 290 const TrustStore& trust_store_; |
| 291 CertVector* out_path_; |
| 292 CompletionCallback callback_; |
| 293 State next_state_; |
| 294 |
| 295 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
| 296 }; |
| 297 |
| 298 CertPathIter::CertPathIter(scoped_refptr<CertThing> cert, |
| 299 const CertPathBuilder::CertSources& cert_sources, |
| 300 const TrustStore& trust_store) |
| 301 : next_cert_(std::move(cert)), |
| 302 cert_sources_(cert_sources), |
| 303 trust_store_(trust_store), |
| 304 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} |
| 305 |
| 306 int CertPathIter::GetNextPath(CertVector* path, |
| 307 const CompletionCallback& callback) { |
| 308 out_path_ = path; |
| 309 out_path_->clear(); |
| 310 int rv = DoLoop(); |
| 311 if (rv == ERR_IO_PENDING) |
| 312 callback_ = callback; |
| 313 return rv; |
| 314 } |
| 315 |
| 316 int CertPathIter::DoLoop() { |
| 317 int result; |
| 318 do { |
| 319 State state = next_state_; |
| 320 next_state_ = STATE_NONE; |
| 321 switch (state) { |
| 322 case STATE_NONE: |
| 323 NOTREACHED(); |
| 324 break; |
| 325 case STATE_GET_NEXT_ISSUER: |
| 326 result = DoGetNextIssuer(); |
| 327 break; |
| 328 case STATE_GET_NEXT_ISSUER_COMPLETE: |
| 329 result = DoGetNextIssuerComplete(); |
| 330 break; |
| 331 case STATE_RETURN_A_PATH: |
| 332 // If the returned path did not verify, then backtrack and keep |
| 333 // looking. |
| 334 next_state_ = STATE_BACKTRACK; |
| 335 break; |
| 336 case STATE_BACKTRACK: |
| 337 result = DoBackTrack(); |
| 338 break; |
| 339 } |
| 340 } while (result != ERR_IO_PENDING && next_state_ != STATE_NONE && |
| 341 next_state_ != STATE_RETURN_A_PATH); |
| 342 |
| 343 return result; |
| 344 } |
| 345 |
| 346 int CertPathIter::DoGetNextIssuer() { |
| 347 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
| 348 int rv = cur_path_.back()->GetNextIssuer( |
| 349 &next_cert_, |
| 350 base::Bind(&CertPathIter::HandleGotNextIssuer, base::Unretained(this))); |
| 351 return rv; |
| 352 } |
| 353 |
| 354 std::string DumpPath( |
| 355 const std::vector<std::unique_ptr<CertIssuersIter>>& cur_path) { |
| 356 std::string s; |
| 357 for (const auto& node : cur_path) { |
| 358 const CertThing* cert = node->cert(); |
| 359 |
| 360 RDNSequence subject, issuer; |
| 361 if (!ParseName(cert->parsed_tbs().subject_tlv, &subject)) |
| 362 return std::string(); |
| 363 if (!ParseName(cert->parsed_tbs().issuer_tlv, &issuer)) |
| 364 return std::string(); |
| 365 |
| 366 std::string subject_str, issuer_str; |
| 367 |
| 368 if (!ConvertToRFC2253(subject, &subject_str)) |
| 369 return std::string(); |
| 370 if (!ConvertToRFC2253(issuer, &issuer_str)) |
| 371 return std::string(); |
| 372 if (!s.empty()) |
| 373 s += " -> "; |
| 374 s += subject_str + "(" + issuer_str + ")"; |
| 375 } |
| 376 return s; |
| 377 } |
| 378 |
| 379 // Should we include trust anchors as a CertSource, or handle them separately? |
| 380 // |
| 381 // Pros/cons for handling them as a CertSource: |
| 382 // + CertPathIter will automatically try each one as a separate path |
| 383 // ? Could this cause LoopChecker issues? (preventing finding a trust anchor if |
| 384 // it has same Name+SAN+SPKI as the last cert in chain. Or would there always be |
| 385 // a better path by just removing that last cert and going directly to the trust |
| 386 // anchor?) |
| 387 // - Need special logic to not try to descend past a trust anchor (No reason |
| 388 // to). |
| 389 // - CertIssuersIter would need prioritization logic to put trust anchors first. |
| 390 // + Automatically handles the case where the trust anchor is the end-entity. |
| 391 // (Do we care about that?) |
| 392 // |
| 393 // Not as a Certsource, but Loop through trust anchors separately in |
| 394 // CertPathIter: |
| 395 // - requires another layer of logic to return the sequence of paths. bleh. |
| 396 // |
| 397 // Loop through trust anchors separately in CertPathBuilder: |
| 398 // + pretty straightforward |
| 399 // + doesn't require any special cases in CertPathIter for handling anchors. |
| 400 // ? maybe requires little extra work to make a separate path/result for each? |
| 401 // ? may want to sort/prioritize the anchors before trying them - but could |
| 402 // probably re-use whatever sort function CertIssuersIter uses. |
| 403 // - need to check TrustStore twice, unless CertPathIter returns the list of |
| 404 // matching anchors. |
| 405 // - means we can't just return a const-reference to the cur_path_, instead have |
| 406 // to clone all the entries a new CertVector, since the CertPathBuilder will |
| 407 // need to append the trust anchor to it. |
| 408 // |
| 409 // Old Conclusion: Loop through trust anchors separately in CertPathBuilder |
| 410 // looks nice, except for having to clone the entries.. |
| 411 // New Conclusion: Handle them similar to a CertSource. |
| 412 |
| 413 int CertPathIter::DoGetNextIssuerComplete() { |
| 414 if (next_cert_) { |
| 415 // Skip this cert if it is already in the chain. |
| 416 if (!loop_checker_.Insert(next_cert_.get())) { |
| 417 next_state_ = STATE_GET_NEXT_ISSUER; |
| 418 return OK; |
| 419 } |
| 420 // Note that loop_checker_.Insert does not make a copy of the cert data. |
| 421 // Must call loop_checker_.Remove before destroying the cert data. |
| 422 |
| 423 cur_path_.push_back(base::WrapUnique(new CertIssuersIter( |
| 424 std::move(next_cert_), &cert_sources_, trust_store_))); |
| 425 next_cert_ = nullptr; |
| 426 DVLOG(1) << "CertPathIter cur_path_ = " << DumpPath(cur_path_); |
| 427 // If the cert matches a trust root, this is a (possible) complete path. |
| 428 // Signal readiness. |
| 429 if (trust_store_.IsTrustedCertificate(cur_path_.back()->cert())) { |
| 430 DVLOG(1) << "CertPathIter IsTrustedCertificate = true"; |
| 431 next_state_ = STATE_RETURN_A_PATH; |
| 432 for (const auto& node : cur_path_) |
| 433 out_path_->push_back(node->reference_cert()); |
| 434 return OK; |
| 435 } |
| 436 // Continue descending the tree. |
| 437 next_state_ = STATE_GET_NEXT_ISSUER; |
| 438 } else { |
| 439 // XXX should also include such paths in CertPathBuilder::Result? |
| 440 // No more issuers for current chain, go back up and see if there are any |
| 441 // more for the previous cert. |
| 442 next_state_ = STATE_BACKTRACK; |
| 443 } |
| 444 return OK; |
| 445 } |
| 446 |
| 447 int CertPathIter::DoBackTrack() { |
| 448 DVLOG(1) << "CertPathIter backtracking..."; |
| 449 loop_checker_.Remove(cur_path_.back()->cert()); |
| 450 cur_path_.pop_back(); |
| 451 if (cur_path_.empty()) { |
| 452 // Exhausted all paths. |
| 453 next_state_ = STATE_NONE; |
| 454 } else { |
| 455 next_state_ = STATE_GET_NEXT_ISSUER; |
| 456 } |
| 457 return OK; |
| 458 } |
| 459 |
| 460 void CertPathIter::HandleGotNextIssuer(void) { |
| 461 DCHECK(!callback_.is_null()); |
| 462 int rv = DoLoop(); |
| 463 if (rv != ERR_IO_PENDING) |
| 464 base::ResetAndReturn(&callback_).Run(rv); |
| 465 } |
| 466 |
| 467 CertPathBuilder::ResultPath::ResultPath() {} |
| 468 CertPathBuilder::ResultPath::~ResultPath() {} |
| 469 CertPathBuilder::Result::Result() {} |
| 470 CertPathBuilder::Result::~Result() {} |
| 471 |
| 472 CertPathBuilder::CertPathBuilder(scoped_refptr<CertThing> cert, |
| 473 const CertSources& cert_sources, |
| 474 const TrustStore& trust_store, |
| 475 const SignaturePolicy* signature_policy, |
| 476 const der::GeneralizedTime& time, |
| 477 Result* result) |
| 478 : cert_path_iter_( |
| 479 new CertPathIter(std::move(cert), cert_sources, trust_store)), |
| 480 trust_store_(trust_store), |
| 481 signature_policy_(signature_policy), |
| 482 time_(time), |
| 483 next_state_(STATE_NONE), |
| 484 out_result_(result) {} |
| 485 |
| 486 CertPathBuilder::~CertPathBuilder() {} |
| 487 |
| 488 int CertPathBuilder::Run(const CompletionCallback& callback) { |
| 489 DCHECK_EQ(STATE_NONE, next_state_); |
| 490 next_state_ = STATE_GET_NEXT_PATH; |
| 491 int rv = DoLoop(OK); |
| 492 |
| 493 if (rv == ERR_IO_PENDING) |
| 494 callback_ = callback; |
| 495 |
| 496 return rv; |
| 497 } |
| 498 |
| 499 int CertPathBuilder::DoLoop(int result) { |
| 500 do { |
| 501 State state = next_state_; |
| 502 next_state_ = STATE_NONE; |
| 503 switch (state) { |
| 504 case STATE_NONE: |
| 505 NOTREACHED(); |
| 506 break; |
| 507 case STATE_GET_NEXT_PATH: |
| 508 DCHECK_EQ(OK, result); |
| 509 result = DoGetNextPath(); |
| 510 break; |
| 511 case STATE_GET_NEXT_PATH_COMPLETE: |
| 512 result = DoGetNextPathComplete(result); |
| 513 break; |
| 514 } |
| 515 } while (result != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 516 |
| 517 return result; |
| 518 } |
| 519 |
| 520 int CertPathBuilder::DoGetNextPath() { |
| 521 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; |
| 522 int rv = cert_path_iter_->GetNextPath( |
| 523 &next_path_, |
| 524 base::Bind(&CertPathBuilder::HandleGotNextPath, base::Unretained(this))); |
| 525 return rv; |
| 526 } |
| 527 |
| 528 void CertPathBuilder::HandleGotNextPath(int result) { |
| 529 DCHECK(!callback_.is_null()); |
| 530 int rv = DoLoop(result); |
| 531 if (rv != ERR_IO_PENDING) |
| 532 base::ResetAndReturn(&callback_).Run(rv); |
| 533 } |
| 534 |
| 535 int CertPathBuilder::DoGetNextPathComplete(int result) { |
| 536 if (next_path_.empty()) { |
| 537 // No more paths to check, cert failed to verify. Return the result code for |
| 538 // the best path that was found. |
| 539 next_state_ = STATE_NONE; |
| 540 return out_result_->result(); |
| 541 } |
| 542 |
| 543 bool verify_result = VerifyCertificateChainAssumingTrustedRoot( |
| 544 next_path_, trust_store_, signature_policy_, time_); |
| 545 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
| 546 << verify_result; |
| 547 AddResultPath(next_path_, verify_result); |
| 548 |
| 549 if (verify_result) { |
| 550 // Found a valid path, return immediately. |
| 551 // XXX add debug/test mode that tries all possible paths. |
| 552 next_state_ = STATE_NONE; |
| 553 return out_result_->result(); |
| 554 } |
| 555 |
| 556 // Path did not verify. Try more paths. If there are no more paths, the result |
| 557 // will be returned next time DoGetNextPathComplete is called with next_path_ |
| 558 // empty. |
| 559 next_state_ = STATE_GET_NEXT_PATH; |
| 560 return OK; |
| 561 } |
| 562 |
| 563 void CertPathBuilder::AddResultPath(const CertVector& path, bool result) { |
| 564 std::unique_ptr<ResultPath> rp(new ResultPath()); |
| 565 // XXX do better error mapping from VerifyCertificateChain results |
| 566 rp->rv = result ? OK : ERR_CERT_AUTHORITY_INVALID; |
| 567 // XXX set best_path_ if #errors(this) < #errors(best): |
| 568 if (rp->rv == OK) |
| 569 out_result_->best_result_index = out_result_->paths.size(); |
| 570 // XXX only return a single path except in debug/test mode. |
| 571 for (const auto& cert : path) |
| 572 rp->path.push_back(cert); |
| 573 out_result_->paths.push_back(std::move(rp)); |
| 574 } |
| 575 |
| 576 } // namespace net |
OLD | NEW |