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