// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/at_exit.h" #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_split.h" #include "base/synchronization/waitable_event.h" #include "base/task/task_scheduler/task_scheduler.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "build/build_config.h" #include "net/cert/cert_net_fetcher.h" #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_proc_builtin.h" #include "net/cert/crl_set.h" #include "net/cert_net/cert_net_fetcher_impl.h" #include "net/tools/cert_verify_tool/cert_verify_tool_util.h" #include "net/tools/cert_verify_tool/verify_using_cert_verify_proc.h" #include "net/tools/cert_verify_tool/verify_using_path_builder.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_context_getter.h" #if defined(OS_LINUX) #include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_config_service_fixed.h" #endif #if defined(USE_NSS_CERTS) #include "net/cert_net/nss_ocsp.h" #endif namespace { std::string GetUserAgent() { return "cert_verify_tool/0.1"; } void SetUpOnNetworkThread(std::unique_ptr* context, base::WaitableEvent* initialization_complete_event) { net::URLRequestContextBuilder url_request_context_builder; url_request_context_builder.set_user_agent(GetUserAgent()); #if defined(OS_LINUX) // On Linux, use a fixed ProxyConfigService, since the default one // depends on glib. // // TODO(akalin): Remove this once http://crbug.com/146421 is fixed. url_request_context_builder.set_proxy_config_service( std::make_unique( net::ProxyConfigWithAnnotation())); #endif *context = url_request_context_builder.Build(); #if defined(USE_NSS_CERTS) net::SetURLRequestContextForNSSHttpIO(context->get()); #endif net::SetGlobalCertNetFetcher(net::CreateCertNetFetcher(context->get())); initialization_complete_event->Signal(); } void ShutdownOnNetworkThread(std::unique_ptr* context) { net::ShutdownGlobalCertNetFetcher(); context->reset(); } // Base class to abstract running a particular implementation of certificate // verification. class CertVerifyImpl { public: virtual ~CertVerifyImpl() = default; virtual std::string GetName() const = 0; // Does certificate verification. // // Note that |hostname| may be empty to indicate that no name validation is // requested, and a null value of |verify_time| means to use the current time. virtual bool VerifyCert(const CertInput& target_der_cert, const std::string& hostname, const std::vector& intermediate_der_certs, const std::vector& root_der_certs, base::Time verify_time, net::CRLSet* crl_set, const base::FilePath& dump_prefix_path) = 0; }; // Runs certificate verification using a particular CertVerifyProc. class CertVerifyImplUsingProc : public CertVerifyImpl { public: CertVerifyImplUsingProc(const std::string& name, scoped_refptr proc) : name_(name), proc_(std::move(proc)) {} std::string GetName() const override { return name_; } bool VerifyCert(const CertInput& target_der_cert, const std::string& hostname, const std::vector& intermediate_der_certs, const std::vector& root_der_certs, base::Time verify_time, net::CRLSet* crl_set, const base::FilePath& dump_prefix_path) override { if (!verify_time.is_null()) { std::cerr << "WARNING: --time is not supported by " << GetName() << ", will use current time.\n"; } if (hostname.empty()) { std::cerr << "ERROR: --hostname is required for " << GetName() << ", skipping\n"; return true; // "skipping" is considered a successful return. } base::FilePath dump_path; if (!dump_prefix_path.empty()) { dump_path = dump_prefix_path.AddExtension(FILE_PATH_LITERAL(".pem")) .InsertBeforeExtensionASCII("." + GetName()); } return VerifyUsingCertVerifyProc(proc_.get(), target_der_cert, hostname, intermediate_der_certs, root_der_certs, crl_set, dump_path); } private: const std::string name_; scoped_refptr proc_; }; // Runs certificate verification using CertPathBuilder. class CertVerifyImplUsingPathBuilder : public CertVerifyImpl { public: std::string GetName() const override { return "CertPathBuilder"; } bool VerifyCert(const CertInput& target_der_cert, const std::string& hostname, const std::vector& intermediate_der_certs, const std::vector& root_der_certs, base::Time verify_time, net::CRLSet* crl_set, const base::FilePath& dump_prefix_path) override { if (!hostname.empty()) { std::cerr << "WARNING: --hostname is not verified with CertPathBuilder\n"; } if (verify_time.is_null()) { verify_time = base::Time::Now(); } return VerifyUsingPathBuilder(target_der_cert, intermediate_der_certs, root_der_certs, verify_time, dump_prefix_path); } }; // Creates an subclass of CertVerifyImpl based on its name, or returns nullptr. std::unique_ptr CreateCertVerifyImplFromName( base::StringPiece impl_name) { if (impl_name == "platform") return std::make_unique( "CertVerifyProc (default)", net::CertVerifyProc::CreateDefault()); if (impl_name == "builtin") { return std::make_unique( "CertVerifyProcBuiltin", net::CreateCertVerifyProcBuiltin()); } if (impl_name == "pathbuilder") return std::make_unique(); std::cerr << "WARNING: Unrecognized impl: " << impl_name << "\n"; return nullptr; } const char kUsage[] = " [flags] \n" "\n" " is a file containing certificates [1]. Minimally it\n" " contains the target certificate. Optionally it may subsequently list\n" " additional certificates needed to build a chain (this is equivalent to\n" " specifying them through --intermediates)\n" "\n" "Flags:\n" "\n" " --hostname=\n" " The hostname required to match the end-entity certificate.\n" " Required for the CertVerifyProc implementation.\n" "\n" " --roots=\n" " is a file containing certificates [1] to interpret as\n" " trust anchors (without any anchor constraints).\n" "\n" " --intermediates=\n" " is a file containing certificates [1] for use when\n" " path building is looking for intermediates.\n" "\n" " --impls=\n" " Ordered list of the verifier implementations to run. If omitted,\n" " will default to: \"platform,builtin,pathbuilder\".\n" " Changing this can lead to different results in cases where the\n" " platform verifier affects global caches (as in the case of NSS).\n" "\n" " --trust-last-cert\n" " Removes the final intermediate from the chain and instead adds it\n" " as a root. This is useful when providing a \n" " parameter whose final certificate is a trust anchor.\n" "\n" " --time=