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