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 <iostream> | 5 #include <iostream> |
| 6 | 6 |
| 7 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
| 12 #include "net/tools/cert_verify_tool/cert_verify_tool_util.h" | 12 #include "net/tools/cert_verify_tool/cert_verify_tool_util.h" |
| 13 #include "net/tools/cert_verify_tool/verify_using_cert_verify_proc.h" | 13 #include "net/tools/cert_verify_tool/verify_using_cert_verify_proc.h" |
| 14 #include "net/tools/cert_verify_tool/verify_using_path_builder.h" | 14 #include "net/tools/cert_verify_tool/verify_using_path_builder.h" |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 | 17 |
| 18 const char kUsage[] = | |
| 19 " [flags] <target/intermediates>\n" | |
|
eroman
2016/09/02 21:32:28
If you don't like these changes I can revert them.
mattm
2016/09/02 22:39:21
"target/intermediates" seems a little misleading t
eroman
2016/09/02 22:53:30
Did some rewording, what do you think now?
| |
| 20 "\n" | |
| 21 " <target+chain> is a file containing certificates [1], with the target \n" | |
| 22 " certificate listed first, and possible intermediates next (in no\n" | |
| 23 " particular order).\n" | |
| 24 "\n" | |
| 25 "Flags:\n" | |
| 26 "\n" | |
| 27 " --hostname=<hostname>\n" | |
| 28 " The hostname required to match the end-entity certificat. Required\n" | |
| 29 " for the CertVerifyProc implementation.\n" | |
| 30 "\n" | |
| 31 " --roots=<certs path>\n" | |
| 32 " <certs path> is a file containing certificates [1] to interpret as\n" | |
| 33 " trust anchors (without any anchor constraints).\n" | |
| 34 "\n" | |
| 35 " --intermediates=<certs path>\n" | |
| 36 " <certs path> is a file containing certificates [1] for use when\n" | |
| 37 " path building is looking for intermediates. These are in addition\n" | |
| 38 " to any intermediates provided by the main certificate file.\n" | |
| 39 "\n" | |
| 40 " --time=<time>\n" | |
| 41 " Use <time> instead of the current system time. <time> is\n" | |
| 42 " interpreted in local time if a timezone is not specified.\n" | |
| 43 " Many common formats are supported, including:\n" | |
| 44 " 1994-11-15 12:45:26 GMT\n" | |
| 45 " Tue, 15 Nov 1994 12:45:26 GMT\n" | |
| 46 " Nov 15 12:45:26 1994 GMT\n" | |
| 47 "\n" | |
| 48 " --dump=<file prefix>\n" | |
| 49 " Dumps the verified chain to PEM files starting with\n" | |
| 50 " <file prefix>.\n" | |
| 51 "\n" | |
| 52 "\n" | |
| 53 "[1] A \"file containing certificates\" means a path to a file that can\n" | |
| 54 " either be:\n" | |
| 55 " * A binary file containing a single DER-encoded RFC 5280 Certificate\n" | |
| 56 " * A PEM file containing one or more CERTIFICATE blocks (DER-encoded\n" | |
| 57 " RFC 5280 Certificate)\n"; | |
| 58 | |
| 18 void PrintUsage(const char* argv0) { | 59 void PrintUsage(const char* argv0) { |
| 19 std::cerr << "Usage: " << argv0 << " [flags] <target/chain>\n"; | 60 std::cerr << "Usage: " << argv0 << kUsage; |
| 20 std::cerr << " <target/chain> should be a file containing a single DER cert " | 61 |
| 21 "or a PEM certificate chain (target first).\n"; | |
| 22 std::cerr << "Flags:\n"; | |
| 23 std::cerr << " --hostname=<hostname>\n"; | |
| 24 std::cerr << " --roots=<certs path>\n"; | |
| 25 std::cerr << " --intermediates=<certs path>\n"; | |
| 26 std::cerr << " <certs path> should be a file containing a single DER cert or " | |
| 27 "one or more PEM CERTIFICATE blocks.\n"; | |
| 28 std::cerr << " --time=<time>\n"; | |
| 29 std::cerr << " Use <time> instead of the current system time. <time> is " | |
| 30 "interpreted in local time if a timezone is not specified.\n"; | |
| 31 std::cerr << " Many common formats are supported, such as:\n"; | |
| 32 std::cerr << " 1994-11-15 12:45:26 GMT\n"; | |
| 33 std::cerr << " Tue, 15 Nov 1994 12:45:26 GMT\n"; | |
| 34 std::cerr << " Nov 15 12:45:26 1994 GMT\n"; | |
| 35 std::cerr << " --dump=<file prefix>\n"; | |
| 36 std::cerr << " Dumps the verified chain to PEM files starting with <file " | |
| 37 "prefix>.\n"; | |
| 38 // TODO(mattm): allow <certs path> to be a directory containing DER/PEM files? | 62 // TODO(mattm): allow <certs path> to be a directory containing DER/PEM files? |
| 39 // TODO(mattm): allow target to specify an HTTPS URL to check the cert of? | 63 // TODO(mattm): allow target to specify an HTTPS URL to check the cert of? |
| 40 // TODO(mattm): allow target to be a verify_certificate_chain_unittest PEM | 64 // TODO(mattm): allow target to be a verify_certificate_chain_unittest PEM |
| 41 // file? | 65 // file? |
| 42 } | 66 } |
| 43 | 67 |
| 44 } // namespace | 68 } // namespace |
| 45 | 69 |
| 46 int main(int argc, char** argv) { | 70 int main(int argc, char** argv) { |
| 47 base::AtExitManager at_exit_manager; | 71 base::AtExitManager at_exit_manager; |
| 48 base::MessageLoopForIO message_loop; | 72 base::MessageLoopForIO message_loop; |
| 49 if (!base::CommandLine::Init(argc, argv)) { | 73 if (!base::CommandLine::Init(argc, argv)) { |
| 50 std::cerr << "ERROR in CommandLine::Init\n"; | 74 std::cerr << "ERROR in CommandLine::Init\n"; |
| 51 return 1; | 75 return 1; |
| 52 } | 76 } |
| 53 base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); | 77 base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); |
| 54 logging::LoggingSettings settings; | 78 logging::LoggingSettings settings; |
| 55 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | 79 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; |
| 56 logging::InitLogging(settings); | 80 logging::InitLogging(settings); |
| 57 | 81 |
| 58 base::CommandLine::StringVector args = command_line.GetArgs(); | 82 base::CommandLine::StringVector args = command_line.GetArgs(); |
| 59 if (args.size() != 1U || command_line.HasSwitch("help")) { | 83 if (args.size() != 1U || command_line.HasSwitch("help")) { |
| 60 PrintUsage(argv[0]); | 84 PrintUsage(argv[0]); |
| 61 return 1; | 85 return 1; |
| 62 } | 86 } |
| 63 | 87 |
| 64 std::string hostname = command_line.GetSwitchValueASCII("hostname"); | 88 std::string hostname = command_line.GetSwitchValueASCII("hostname"); |
| 65 if (hostname.empty()) { | |
| 66 std::cerr << "ERROR: --hostname is required\n"; | |
|
eroman
2016/09/02 21:32:28
Mostly just a convenience, since I find myself mos
| |
| 67 return 1; | |
| 68 } | |
| 69 | 89 |
| 70 base::Time verify_time; | 90 base::Time verify_time; |
| 71 std::string time_flag = command_line.GetSwitchValueASCII("time"); | 91 std::string time_flag = command_line.GetSwitchValueASCII("time"); |
| 72 if (!time_flag.empty()) { | 92 if (!time_flag.empty()) { |
| 73 if (!base::Time::FromString(time_flag.c_str(), &verify_time)) { | 93 if (!base::Time::FromString(time_flag.c_str(), &verify_time)) { |
| 74 std::cerr << "Error parsing --time flag\n"; | 94 std::cerr << "Error parsing --time flag\n"; |
| 75 return 1; | 95 return 1; |
| 76 } | 96 } |
| 77 } else { | 97 } else { |
| 78 verify_time = base::Time::Now(); | 98 verify_time = base::Time::Now(); |
| 79 } | 99 } |
| 80 | 100 |
| 81 base::FilePath roots_path = command_line.GetSwitchValuePath("roots"); | 101 base::FilePath roots_path = command_line.GetSwitchValuePath("roots"); |
| 82 base::FilePath intermediates_path = | 102 base::FilePath intermediates_path = |
| 83 command_line.GetSwitchValuePath("intermediates"); | 103 command_line.GetSwitchValuePath("intermediates"); |
| 84 base::FilePath target_path = base::FilePath(args[0]); | 104 base::FilePath target_path = base::FilePath(args[0]); |
| 85 | 105 |
| 86 base::FilePath dump_prefix_path = command_line.GetSwitchValuePath("dump"); | 106 base::FilePath dump_prefix_path = command_line.GetSwitchValuePath("dump"); |
| 87 | 107 |
| 88 std::vector<CertInput> root_der_certs; | 108 std::vector<CertInput> root_der_certs; |
| 89 std::vector<CertInput> intermediate_der_certs; | 109 std::vector<CertInput> intermediate_der_certs; |
| 90 CertInput target_der_cert; | 110 CertInput target_der_cert; |
| 91 | 111 |
| 92 if (!roots_path.empty()) | 112 if (!roots_path.empty()) |
| 93 ReadCertificatesFromFile(roots_path, &root_der_certs); | 113 ReadCertificatesFromFile(roots_path, &root_der_certs); |
| 94 if (!intermediates_path.empty()) | 114 if (!intermediates_path.empty()) |
| 95 ReadCertificatesFromFile(intermediates_path, &intermediate_der_certs); | 115 ReadCertificatesFromFile(intermediates_path, &intermediate_der_certs); |
| 96 ReadChainFromFile(target_path, &target_der_cert, &intermediate_der_certs); | 116 |
| 117 if (!ReadChainFromFile(target_path, &target_der_cert, | |
| 118 &intermediate_der_certs)) { | |
| 119 std::cerr << "ERROR: Couldn't read certifcate chain\n"; | |
|
mattm
2016/09/02 22:39:21
certifcate
eroman
2016/09/02 22:53:30
Done.
| |
| 120 return 1; | |
| 121 } | |
| 97 | 122 |
| 98 if (target_der_cert.der_cert.empty()) { | 123 if (target_der_cert.der_cert.empty()) { |
| 99 std::cerr << "ERROR: no target cert\n"; | 124 std::cerr << "ERROR: no target cert\n"; |
| 100 return 1; | 125 return 1; |
| 101 } | 126 } |
| 102 | 127 |
| 103 std::cout << "CertVerifyProc:\n"; | 128 std::cout << "CertVerifyProc:\n"; |
| 104 bool cert_verify_proc_ok = true; | 129 bool cert_verify_proc_ok = true; |
| 105 if (!time_flag.empty()) { | 130 if (!time_flag.empty()) { |
| 106 std::cerr << "ERROR: --time is not supported with CertVerifyProc, " | 131 std::cerr << "ERROR: --time is not supported with CertVerifyProc, " |
| 107 "skipping.\n"; | 132 "skipping.\n"; |
| 133 } else if (hostname.empty()) { | |
| 134 std::cerr << "ERROR: --hostname is required for CertVerifyProc, skipping\n"; | |
| 108 } else { | 135 } else { |
| 109 cert_verify_proc_ok = VerifyUsingCertVerifyProc( | 136 cert_verify_proc_ok = VerifyUsingCertVerifyProc( |
| 110 target_der_cert, hostname, intermediate_der_certs, root_der_certs, | 137 target_der_cert, hostname, intermediate_der_certs, root_der_certs, |
| 111 dump_prefix_path); | 138 dump_prefix_path); |
| 112 } | 139 } |
| 113 | 140 |
| 114 std::cout << "\nCertPathBuilder:\n"; | 141 std::cout << "\nCertPathBuilder:\n"; |
| 142 | |
| 143 if (hostname.empty()) { | |
|
mattm
2016/09/02 22:39:21
should be !empty ?
eroman
2016/09/02 22:53:30
Done.
| |
| 144 std::cerr | |
| 145 << "WARNING: --hostname is not yet verified with CertPathBuilder\n"; | |
| 146 } | |
| 147 | |
| 148 if (root_der_certs.empty()) { | |
| 149 std::cerr << "ERROR: --roots is required for CertPathBuilder to succeed " | |
| 150 "(as it doesn't use the OS trust store).\n"; | |
| 151 } else { | |
| 152 std::cout << "NOTE: CertPathBuilder does not currently use OS trust " | |
| 153 "settings (only --roots will be used)\n"; | |
| 154 } | |
|
mattm
2016/09/02 22:39:21
I think it's better to leave the trust store warni
eroman
2016/09/02 22:53:30
Done.
| |
| 155 | |
| 115 bool path_builder_ok = | 156 bool path_builder_ok = |
| 116 VerifyUsingPathBuilder(target_der_cert, intermediate_der_certs, | 157 VerifyUsingPathBuilder(target_der_cert, intermediate_der_certs, |
| 117 root_der_certs, verify_time, dump_prefix_path); | 158 root_der_certs, verify_time, dump_prefix_path); |
| 118 | 159 |
| 119 return (cert_verify_proc_ok && path_builder_ok) ? 0 : 1; | 160 return (cert_verify_proc_ok && path_builder_ok) ? 0 : 1; |
| 120 } | 161 } |
| OLD | NEW |