• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
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/tools/cert_verify_tool/verify_using_cert_verify_proc.h"
6 
7 #include <algorithm>
8 #include <iostream>
9 
10 #include "base/strings/strcat.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "crypto/sha2.h"
14 #include "net/base/net_errors.h"
15 #include "net/cert/cert_verifier.h"
16 #include "net/cert/cert_verify_proc.h"
17 #include "net/cert/cert_verify_result.h"
18 #include "net/cert/test_root_certs.h"
19 #include "net/cert/x509_certificate.h"
20 #include "net/cert/x509_util.h"
21 #include "net/log/net_log_with_source.h"
22 #include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
23 
24 namespace {
25 
26 // Associates a printable name with an integer constant. Useful for providing
27 // human-readable decoding of bitmask values.
28 struct StringToConstant {
29   const char* name;
30   const int constant;
31 };
32 
33 const StringToConstant kCertStatusFlags[] = {
34 #define CERT_STATUS_FLAG(label, value) {#label, value},
35 #include "net/cert/cert_status_flags_list.h"
36 #undef CERT_STATUS_FLAG
37 };
38 
39 // Writes a PEM-encoded file of |cert| and its chain.
DumpX509CertificateChain(const base::FilePath & file_path,const net::X509Certificate * cert)40 bool DumpX509CertificateChain(const base::FilePath& file_path,
41                               const net::X509Certificate* cert) {
42   std::vector<std::string> pem_encoded;
43   if (!cert->GetPEMEncodedChain(&pem_encoded)) {
44     std::cerr << "ERROR: X509Certificate::GetPEMEncodedChain failed.\n";
45     return false;
46   }
47   return WriteToFile(file_path, base::StrCat(pem_encoded));
48 }
49 
PrintCertStatus(int cert_status)50 void PrintCertStatus(int cert_status) {
51   std::cout << base::StringPrintf("CertStatus: 0x%x\n", cert_status);
52 
53   for (const auto& flag : kCertStatusFlags) {
54     if ((cert_status & flag.constant) == flag.constant)
55       std::cout << " " << flag.name << "\n";
56   }
57 }
58 
59 }  // namespace
60 
PrintCertVerifyResult(const net::CertVerifyResult & result)61 void PrintCertVerifyResult(const net::CertVerifyResult& result) {
62   PrintCertStatus(result.cert_status);
63   if (result.has_sha1)
64     std::cout << "has_sha1\n";
65   if (result.is_issued_by_known_root)
66     std::cout << "is_issued_by_known_root\n";
67   if (result.is_issued_by_additional_trust_anchor)
68     std::cout << "is_issued_by_additional_trust_anchor\n";
69 
70   if (result.verified_cert) {
71     std::cout << "chain:\n "
72               << FingerPrintCryptoBuffer(result.verified_cert->cert_buffer())
73               << " " << SubjectFromX509Certificate(result.verified_cert.get())
74               << "\n";
75     for (const auto& intermediate :
76          result.verified_cert->intermediate_buffers()) {
77       std::cout << " " << FingerPrintCryptoBuffer(intermediate.get()) << " "
78                 << SubjectFromCryptoBuffer(intermediate.get()) << "\n";
79     }
80   }
81 }
82 
VerifyUsingCertVerifyProc(net::CertVerifyProc * cert_verify_proc,const CertInput & target_der_cert,const std::string & hostname,const std::vector<CertInput> & intermediate_der_certs,const std::vector<CertInputWithTrustSetting> & der_certs_with_trust_settings,const base::FilePath & dump_path)83 bool VerifyUsingCertVerifyProc(
84     net::CertVerifyProc* cert_verify_proc,
85     const CertInput& target_der_cert,
86     const std::string& hostname,
87     const std::vector<CertInput>& intermediate_der_certs,
88     const std::vector<CertInputWithTrustSetting>& der_certs_with_trust_settings,
89     const base::FilePath& dump_path) {
90   std::vector<base::StringPiece> der_cert_chain;
91   der_cert_chain.push_back(target_der_cert.der_cert);
92   for (const auto& cert : intermediate_der_certs)
93     der_cert_chain.push_back(cert.der_cert);
94 
95   scoped_refptr<net::X509Certificate> x509_target_and_intermediates =
96       net::X509Certificate::CreateFromDERCertChain(der_cert_chain);
97   if (!x509_target_and_intermediates) {
98     std::cerr
99         << "ERROR: X509Certificate::CreateFromDERCertChain failed on one or "
100            "more of:\n";
101     PrintCertError(" (target)", target_der_cert);
102     for (const auto& cert : intermediate_der_certs)
103       PrintCertError(" (intermediate)", cert);
104     return false;
105   }
106 
107   net::TestRootCerts* test_root_certs = net::TestRootCerts::GetInstance();
108   CHECK(test_root_certs->IsEmpty());
109 
110   std::vector<net::ScopedTestRoot> scoped_test_roots;
111   for (const auto& cert_input_with_trust : der_certs_with_trust_settings) {
112     scoped_refptr<net::X509Certificate> x509_root =
113         net::X509Certificate::CreateFromBytes(base::as_bytes(
114             base::make_span(cert_input_with_trust.cert_input.der_cert)));
115 
116     if (!x509_root) {
117       PrintCertError("ERROR: X509Certificate::CreateFromBytes failed:",
118                      cert_input_with_trust.cert_input);
119     } else {
120       scoped_test_roots.emplace_back(x509_root, cert_input_with_trust.trust);
121     }
122   }
123 
124   // TODO(mattm): add command line flags to configure VerifyFlags.
125   int flags = 0;
126 
127   // TODO(crbug.com/634484): use a real netlog and print the results?
128   net::CertVerifyResult result;
129   int rv = cert_verify_proc->Verify(
130       x509_target_and_intermediates.get(), hostname,
131       /*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
132       &result, net::NetLogWithSource());
133 
134   std::cout << "CertVerifyProc result: " << net::ErrorToShortString(rv) << "\n";
135   PrintCertVerifyResult(result);
136   if (!dump_path.empty() && result.verified_cert) {
137     if (!DumpX509CertificateChain(dump_path, result.verified_cert.get())) {
138       return false;
139     }
140   }
141 
142   return rv == net::OK;
143 }
144