Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/cert_verify_tool/verify_using_path_builder.h" | 5 #include "net/tools/cert_verify_tool/verify_using_path_builder.h" |
| 6 | 6 |
| 7 #include <iostream> | 7 #include <iostream> |
| 8 | 8 |
| 9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/run_loop.h" | |
| 10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 12 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
| 13 #include "crypto/sha2.h" | 14 #include "crypto/sha2.h" |
| 14 #include "net/cert/cert_net_fetcher.h" | 15 #include "net/cert/cert_net_fetcher.h" |
| 15 #include "net/cert/internal/cert_issuer_source_aia.h" | 16 #include "net/cert/internal/cert_issuer_source_aia.h" |
| 16 #include "net/cert/internal/cert_issuer_source_static.h" | 17 #include "net/cert/internal/cert_issuer_source_static.h" |
| 17 #include "net/cert/internal/parse_name.h" | 18 #include "net/cert/internal/parse_name.h" |
| 18 #include "net/cert/internal/parsed_certificate.h" | 19 #include "net/cert/internal/parsed_certificate.h" |
| 19 #include "net/cert/internal/path_builder.h" | 20 #include "net/cert/internal/path_builder.h" |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 private: | 215 private: |
| 215 ~URLRequestContextGetterForAia() override { DCHECK(!context_); } | 216 ~URLRequestContextGetterForAia() override { DCHECK(!context_); } |
| 216 | 217 |
| 217 void ShutdownOnNetworkThread() { context_.release(); } | 218 void ShutdownOnNetworkThread() { context_.release(); } |
| 218 | 219 |
| 219 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 220 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 220 | 221 |
| 221 std::unique_ptr<net::URLRequestContext> context_; | 222 std::unique_ptr<net::URLRequestContext> context_; |
| 222 }; | 223 }; |
| 223 | 224 |
| 224 } // namespace | 225 void ShutDownCertNetFetcher( |
| 226 const scoped_refptr<net::CertNetFetcher>& cert_net_fetcher, | |
| 227 const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, | |
| 228 const base::Closure& callback) { | |
| 229 network_task_runner->PostTaskAndReply( | |
| 230 FROM_HERE, base::Bind(&net::CertNetFetcher::Shutdown, cert_net_fetcher), | |
| 231 callback); | |
| 232 } | |
| 225 | 233 |
| 226 // Verifies |target_der_cert| using CertPathBuilder. | 234 // Performs the actual certificate verification using CertPathBuilder. When |
| 227 bool VerifyUsingPathBuilder( | 235 // completed, it sets |result| to true if verification was successful and false |
| 236 // otherwise. Then it shuts down |cert_net_fetcher| on the network thread and | |
| 237 // calls |callback| when all this is complete. | |
| 238 void DoVerifyOnWorkerThread( | |
| 239 scoped_refptr<net::CertNetFetcher> cert_net_fetcher, | |
| 240 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | |
| 228 const CertInput& target_der_cert, | 241 const CertInput& target_der_cert, |
| 229 const std::vector<CertInput>& intermediate_der_certs, | 242 const std::vector<CertInput>& intermediate_der_certs, |
| 230 const std::vector<CertInput>& root_der_certs, | 243 const std::vector<CertInput>& root_der_certs, |
| 231 const base::Time at_time, | 244 const base::Time at_time, |
| 232 const base::FilePath& dump_prefix_path) { | 245 const base::FilePath& dump_prefix_path, |
| 246 const base::Closure& callback, | |
| 247 bool* result) { | |
| 233 base::Time::Exploded exploded_time; | 248 base::Time::Exploded exploded_time; |
| 234 at_time.UTCExplode(&exploded_time); | 249 at_time.UTCExplode(&exploded_time); |
| 235 net::der::GeneralizedTime time = ConvertExplodedTime(exploded_time); | 250 net::der::GeneralizedTime time = ConvertExplodedTime(exploded_time); |
| 236 | 251 |
| 237 net::TrustStoreCollection trust_store; | 252 net::TrustStoreCollection trust_store; |
| 238 | 253 |
| 239 net::TrustStoreInMemory trust_store_in_memory; | 254 net::TrustStoreInMemory trust_store_in_memory; |
| 240 trust_store.AddTrustStore(&trust_store_in_memory); | 255 trust_store.AddTrustStore(&trust_store_in_memory); |
| 241 for (const auto& der_cert : root_der_certs) { | 256 for (const auto& der_cert : root_der_certs) { |
| 242 scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert); | 257 scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 258 | 273 |
| 259 net::CertIssuerSourceStatic intermediate_cert_issuer_source; | 274 net::CertIssuerSourceStatic intermediate_cert_issuer_source; |
| 260 for (const auto& der_cert : intermediate_der_certs) { | 275 for (const auto& der_cert : intermediate_der_certs) { |
| 261 scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert); | 276 scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert); |
| 262 if (cert) | 277 if (cert) |
| 263 intermediate_cert_issuer_source.AddCert(cert); | 278 intermediate_cert_issuer_source.AddCert(cert); |
| 264 } | 279 } |
| 265 | 280 |
| 266 scoped_refptr<net::ParsedCertificate> target_cert = | 281 scoped_refptr<net::ParsedCertificate> target_cert = |
| 267 ParseCertificate(target_der_cert); | 282 ParseCertificate(target_der_cert); |
| 268 if (!target_cert) | 283 if (!target_cert) { |
| 269 return false; | 284 *result = false; |
| 285 ShutDownCertNetFetcher(cert_net_fetcher, network_task_runner, callback); | |
| 286 return; | |
| 287 } | |
| 270 | 288 |
| 271 // Verify the chain. | 289 // Verify the chain. |
| 272 net::SimpleSignaturePolicy signature_policy(2048); | 290 net::SimpleSignaturePolicy signature_policy(2048); |
| 273 net::CertPathBuilder::Result result; | 291 net::CertPathBuilder::Result verify_result; |
| 274 net::CertPathBuilder path_builder(target_cert, &trust_store, | 292 net::CertPathBuilder path_builder(target_cert, &trust_store, |
| 275 &signature_policy, time, &result); | 293 &signature_policy, time, &verify_result); |
| 276 path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source); | 294 path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source); |
| 277 #if defined(USE_NSS_CERTS) | 295 #if defined(USE_NSS_CERTS) |
| 278 net::CertIssuerSourceNSS cert_issuer_source_nss; | 296 net::CertIssuerSourceNSS cert_issuer_source_nss; |
| 279 path_builder.AddCertIssuerSource(&cert_issuer_source_nss); | 297 path_builder.AddCertIssuerSource(&cert_issuer_source_nss); |
| 280 #endif | 298 #endif |
| 281 | 299 |
| 282 // Initialize an AIA fetcher, that uses a separate thread for running the | 300 net::CertIssuerSourceAia aia_cert_issuer_source(cert_net_fetcher); |
| 283 // networking message loop. | |
| 284 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); | |
| 285 base::Thread thread("network_thread"); | |
| 286 CHECK(thread.StartWithOptions(options)); | |
| 287 scoped_refptr<URLRequestContextGetterForAia> url_request_context_getter( | |
| 288 new URLRequestContextGetterForAia(thread.task_runner())); | |
| 289 auto cert_net_fetcher = | |
| 290 CreateCertNetFetcher(url_request_context_getter.get()); | |
| 291 net::CertIssuerSourceAia aia_cert_issuer_source(cert_net_fetcher.get()); | |
| 292 path_builder.AddCertIssuerSource(&aia_cert_issuer_source); | 301 path_builder.AddCertIssuerSource(&aia_cert_issuer_source); |
| 293 | 302 |
| 294 // Run the path builder. | 303 // Run the path builder. |
| 295 path_builder.Run(); | 304 path_builder.Run(); |
| 296 | 305 |
| 297 // Stop the temporary network thread.. | |
| 298 url_request_context_getter->ShutDown(); | |
| 299 thread.Stop(); | |
| 300 | |
| 301 // TODO(crbug.com/634443): Display any errors/warnings associated with path | 306 // TODO(crbug.com/634443): Display any errors/warnings associated with path |
| 302 // building that were not part of a particular | 307 // building that were not part of a particular |
| 303 // PathResult. | 308 // PathResult. |
| 304 std::cout << "CertPathBuilder result: " | 309 std::cout << "CertPathBuilder result: " |
| 305 << (result.HasValidPath() ? "SUCCESS" : "FAILURE") << "\n"; | 310 << (verify_result.HasValidPath() ? "SUCCESS" : "FAILURE") << "\n"; |
| 306 | 311 |
| 307 for (size_t i = 0; i < result.paths.size(); ++i) { | 312 for (size_t i = 0; i < verify_result.paths.size(); ++i) { |
| 308 PrintResultPath(result.paths[i].get(), i, i == result.best_result_index); | 313 PrintResultPath(verify_result.paths[i].get(), i, |
| 314 i == verify_result.best_result_index); | |
| 309 } | 315 } |
| 310 | 316 |
| 311 // TODO(mattm): add flag to dump all paths, not just the final one? | 317 // TODO(mattm): add flag to dump all paths, not just the final one? |
| 312 if (!dump_prefix_path.empty() && result.paths.size()) { | 318 if (!dump_prefix_path.empty() && verify_result.paths.size()) { |
| 313 if (!DumpParsedCertificateChain( | 319 if (!DumpParsedCertificateChain( |
| 314 dump_prefix_path.AddExtension( | 320 dump_prefix_path.AddExtension( |
| 315 FILE_PATH_LITERAL(".CertPathBuilder.pem")), | 321 FILE_PATH_LITERAL(".CertPathBuilder.pem")), |
| 316 result.paths[result.best_result_index]->path)) { | 322 verify_result.paths[verify_result.best_result_index]->path)) { |
| 317 return false; | 323 *result = false; |
| 324 ShutDownCertNetFetcher(cert_net_fetcher, network_task_runner, callback); | |
| 325 return; | |
| 318 } | 326 } |
| 319 } | 327 } |
| 320 | 328 |
| 321 return result.HasValidPath(); | 329 *result = verify_result.HasValidPath(); |
| 330 ShutDownCertNetFetcher(cert_net_fetcher, network_task_runner, callback); | |
| 322 } | 331 } |
| 332 | |
| 333 // Creates a CertNetFetcher and passes a reference to the worker thread to | |
| 334 // perform the verification using that CertNetFetcher. | |
| 335 void StartVerifyOnNetworkThread( | |
| 336 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | |
| 337 scoped_refptr<URLRequestContextGetterForAia> context_getter, | |
| 338 const CertInput& target_der_cert, | |
| 339 const std::vector<CertInput>& intermediate_der_certs, | |
| 340 const std::vector<CertInput>& root_der_certs, | |
| 341 const base::Time at_time, | |
| 342 const base::FilePath& dump_prefix_path, | |
| 343 const base::Closure& callback, | |
| 344 bool* result) { | |
| 345 scoped_refptr<net::CertNetFetcher> cert_net_fetcher = | |
| 346 net::CreateCertNetFetcher(context_getter->GetURLRequestContext()); | |
| 347 worker_task_runner->PostTask( | |
| 348 FROM_HERE, | |
| 349 base::Bind(&DoVerifyOnWorkerThread, cert_net_fetcher, | |
| 350 base::ThreadTaskRunnerHandle::Get(), target_der_cert, | |
| 351 intermediate_der_certs, root_der_certs, at_time, | |
| 352 dump_prefix_path, callback, result)); | |
| 353 } | |
| 354 | |
| 355 } // namespace | |
| 356 | |
| 357 // Verifies |target_der_cert| using CertPathBuilder. | |
| 358 bool VerifyUsingPathBuilder( | |
| 359 const CertInput& target_der_cert, | |
| 360 const std::vector<CertInput>& intermediate_der_certs, | |
| 361 const std::vector<CertInput>& root_der_certs, | |
| 362 const base::Time at_time, | |
| 363 const base::FilePath& dump_prefix_path) { | |
| 364 // Create a network thread for AIA fetching operations. A CertNetFetcher will | |
| 365 // be created and shutdown on this thread. | |
| 366 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); | |
| 367 base::Thread thread("network_thread"); | |
| 368 CHECK(thread.StartWithOptions(options)); | |
| 369 | |
| 370 bool result = false; | |
| 371 base::RunLoop run_loop; | |
|
eroman
2017/01/11 01:57:00
I don't think we should have a message loop on the
estark
2017/01/12 01:06:31
Thanks. I #if'd it out for now. I'm happy to come
eroman
2017/01/12 02:11:37
Sure, sounds good.
(The tool is just used by mattm
| |
| 372 scoped_refptr<URLRequestContextGetterForAia> url_request_context_getter( | |
| 373 new URLRequestContextGetterForAia(thread.task_runner())); | |
| 374 | |
| 375 // A CertNetFetcher must be created on the network thread before verification | |
| 376 // can proceed on the main thread (and the fetcher must be shutdown on the | |
| 377 // network thread when verification completes). Thus, the flow is as follows. | |
| 378 // | |
| 379 // The StartVerifyOnNetworkThread task runs on the network thread and creates | |
| 380 // a CertNetFetcher using the URLRequestContext managed by | |
| 381 // |url_request_context_getter|. When the CertNetFetcher is created, a | |
| 382 // reference to it is posted back to this thread to run | |
| 383 // DoVerifyOnWorkerThread using the created CertNetFetcher. When the | |
| 384 // verification is completed, DoVerifyOnWorkerThread writes the result to | |
| 385 // |result|, shuts down the CertNetFetcher on the network thread, and then | |
| 386 // quits |run_loop|. | |
| 387 thread.task_runner()->PostTask( | |
| 388 FROM_HERE, base::Bind(&StartVerifyOnNetworkThread, | |
| 389 base::ThreadTaskRunnerHandle::Get(), | |
| 390 url_request_context_getter, target_der_cert, | |
| 391 intermediate_der_certs, root_der_certs, at_time, | |
| 392 dump_prefix_path, run_loop.QuitClosure(), &result)); | |
| 393 run_loop.Run(); | |
| 394 | |
| 395 // Stop the temporary network thread. | |
| 396 url_request_context_getter->ShutDown(); | |
| 397 thread.Stop(); | |
| 398 | |
| 399 return result; | |
| 400 } | |
| OLD | NEW |