xref: /aosp_15_r20/external/cronet/net/tools/cert_verify_tool/cert_verify_tool_util.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/cert_verify_tool_util.h"
6 
7 #include <iostream>
8 
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "build/build_config.h"
14 #include "net/cert/x509_certificate.h"
15 #include "net/cert/x509_util.h"
16 #include "third_party/boringssl/src/pki/pem.h"
17 
18 namespace {
19 
20 // The PEM block header used for PEM-encoded DER certificates.
21 const char kCertificateHeader[] = "CERTIFICATE";
22 
23 // Parses |data_string| as a single DER cert or a PEM certificate list.
24 // This is an alternative to X509Certificate::CreateFrom[...] which
25 // is designed to decouple the file input and decoding from the DER Certificate
26 // parsing.
ExtractCertificatesFromData(const std::string & data_string,const base::FilePath & file_path,std::vector<CertInput> * certs)27 void ExtractCertificatesFromData(const std::string& data_string,
28                                  const base::FilePath& file_path,
29                                  std::vector<CertInput>* certs) {
30   bssl::PEMTokenizer pem_tokenizer(data_string, {kCertificateHeader});
31   int block = 0;
32   while (pem_tokenizer.GetNext()) {
33     CertInput cert;
34     cert.der_cert = pem_tokenizer.data();
35     cert.source_file_path = file_path;
36     cert.source_details =
37         base::StringPrintf("%s block %i", kCertificateHeader, block);
38     certs->push_back(cert);
39     ++block;
40   }
41 
42   // If it was a PEM file, return the extracted results.
43   if (block)
44     return;
45 
46   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> pkcs7_cert_buffers;
47   if (net::x509_util::CreateCertBuffersFromPKCS7Bytes(
48           base::as_byte_span(data_string), &pkcs7_cert_buffers)) {
49     int n = 0;
50     for (const auto& cert_buffer : pkcs7_cert_buffers) {
51       CertInput cert;
52       cert.der_cert = std::string(
53           net::x509_util::CryptoBufferAsStringPiece(cert_buffer.get()));
54       cert.source_file_path = file_path;
55       cert.source_details = base::StringPrintf("PKCS #7 cert %i", n);
56       certs->push_back(cert);
57       ++n;
58     }
59     return;
60   }
61 
62   // Otherwise, assume it is a single DER cert.
63   CertInput cert;
64   cert.der_cert = data_string;
65   cert.source_file_path = file_path;
66   certs->push_back(cert);
67 }
68 
69 }  // namespace
70 
ReadCertificatesFromFile(const base::FilePath & file_path,std::vector<CertInput> * certs)71 bool ReadCertificatesFromFile(const base::FilePath& file_path,
72                               std::vector<CertInput>* certs) {
73   std::string file_data;
74   if (!ReadFromFile(file_path, &file_data))
75     return false;
76   ExtractCertificatesFromData(file_data, file_path, certs);
77   return true;
78 }
79 
ReadChainFromFile(const base::FilePath & file_path,CertInput * target,std::vector<CertInput> * intermediates)80 bool ReadChainFromFile(const base::FilePath& file_path,
81                        CertInput* target,
82                        std::vector<CertInput>* intermediates) {
83   std::vector<CertInput> tmp_certs;
84   if (!ReadCertificatesFromFile(file_path, &tmp_certs))
85     return false;
86 
87   if (tmp_certs.empty())
88     return true;
89 
90   *target = tmp_certs.front();
91 
92   intermediates->insert(intermediates->end(), ++tmp_certs.begin(),
93                         tmp_certs.end());
94   return true;
95 }
96 
ReadFromFile(const base::FilePath & file_path,std::string * file_data)97 bool ReadFromFile(const base::FilePath& file_path, std::string* file_data) {
98   if (!base::ReadFileToString(file_path, file_data)) {
99     std::cerr << "ERROR: ReadFileToString " << file_path.value() << ": "
100               << strerror(errno) << "\n";
101     return false;
102   }
103   return true;
104 }
105 
WriteToFile(const base::FilePath & file_path,const std::string & data)106 bool WriteToFile(const base::FilePath& file_path, const std::string& data) {
107   if (!base::WriteFile(file_path, data)) {
108     std::cerr << "ERROR: WriteFile " << file_path.value() << ": "
109               << strerror(errno) << "\n";
110     return false;
111   }
112   return true;
113 }
114 
PrintCertError(const std::string & error,const CertInput & cert)115 void PrintCertError(const std::string& error, const CertInput& cert) {
116   std::cerr << error << " " << cert.source_file_path.value();
117   if (!cert.source_details.empty())
118     std::cerr << " (" << cert.source_details << ")";
119   std::cerr << "\n";
120 }
121 
FingerPrintCryptoBuffer(const CRYPTO_BUFFER * cert_handle)122 std::string FingerPrintCryptoBuffer(const CRYPTO_BUFFER* cert_handle) {
123   net::SHA256HashValue hash =
124       net::X509Certificate::CalculateFingerprint256(cert_handle);
125   return base::HexEncode(hash.data);
126 }
127 
SubjectFromX509Certificate(const net::X509Certificate * cert)128 std::string SubjectFromX509Certificate(const net::X509Certificate* cert) {
129   return cert->subject().GetDisplayName();
130 }
131 
SubjectFromCryptoBuffer(CRYPTO_BUFFER * cert_handle)132 std::string SubjectFromCryptoBuffer(CRYPTO_BUFFER* cert_handle) {
133   scoped_refptr<net::X509Certificate> cert =
134       net::X509Certificate::CreateFromBuffer(bssl::UpRef(cert_handle), {});
135   if (!cert)
136     return std::string();
137   return SubjectFromX509Certificate(cert.get());
138 }
139