xref: /aosp_15_r20/external/cronet/net/quic/crypto/proof_source_chromium.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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/quic/crypto/proof_source_chromium.h"
6 
7 #include "base/strings/string_number_conversions.h"
8 #include "crypto/openssl_util.h"
9 #include "net/cert/x509_util.h"
10 #include "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_protocol.h"
11 #include "third_party/boringssl/src/include/openssl/digest.h"
12 #include "third_party/boringssl/src/include/openssl/evp.h"
13 #include "third_party/boringssl/src/include/openssl/rsa.h"
14 
15 using std::string;
16 
17 namespace net {
18 
19 ProofSourceChromium::ProofSourceChromium() = default;
20 
21 ProofSourceChromium::~ProofSourceChromium() = default;
22 
Initialize(const base::FilePath & cert_path,const base::FilePath & key_path,const base::FilePath & sct_path)23 bool ProofSourceChromium::Initialize(const base::FilePath& cert_path,
24                                      const base::FilePath& key_path,
25                                      const base::FilePath& sct_path) {
26   crypto::EnsureOpenSSLInit();
27 
28   std::string cert_data;
29   if (!base::ReadFileToString(cert_path, &cert_data)) {
30     DLOG(FATAL) << "Unable to read certificates.";
31     return false;
32   }
33 
34   certs_in_file_ = X509Certificate::CreateCertificateListFromBytes(
35       base::as_byte_span(cert_data), X509Certificate::FORMAT_AUTO);
36 
37   if (certs_in_file_.empty()) {
38     DLOG(FATAL) << "No certificates.";
39     return false;
40   }
41 
42   std::vector<string> certs;
43   for (const scoped_refptr<X509Certificate>& cert : certs_in_file_) {
44     certs.emplace_back(
45         x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
46   }
47   chain_ = new quic::ProofSource::Chain(certs);
48 
49   std::string key_data;
50   if (!base::ReadFileToString(key_path, &key_data)) {
51     DLOG(FATAL) << "Unable to read key.";
52     return false;
53   }
54 
55   const uint8_t* p = reinterpret_cast<const uint8_t*>(key_data.data());
56   std::vector<uint8_t> input(p, p + key_data.size());
57   private_key_ = crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input);
58   if (!private_key_) {
59     DLOG(FATAL) << "Unable to create private key.";
60     return false;
61   }
62 
63   // Loading of the signed certificate timestamp is optional.
64   if (sct_path.empty())
65     return true;
66 
67   if (!base::ReadFileToString(sct_path, &signed_certificate_timestamp_)) {
68     DLOG(FATAL) << "Unable to read signed certificate timestamp.";
69     return false;
70   }
71 
72   return true;
73 }
74 
GetProofInner(const quic::QuicSocketAddress & server_addr,const string & hostname,const string & server_config,quic::QuicTransportVersion quic_version,std::string_view chlo_hash,quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> * out_chain,quic::QuicCryptoProof * proof)75 bool ProofSourceChromium::GetProofInner(
76     const quic::QuicSocketAddress& server_addr,
77     const string& hostname,
78     const string& server_config,
79     quic::QuicTransportVersion quic_version,
80     std::string_view chlo_hash,
81     quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>* out_chain,
82     quic::QuicCryptoProof* proof) {
83   DCHECK(proof != nullptr);
84   DCHECK(private_key_.get()) << " this: " << this;
85 
86   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
87   bssl::ScopedEVP_MD_CTX sign_context;
88   EVP_PKEY_CTX* pkey_ctx;
89 
90   uint32_t len_tmp = chlo_hash.length();
91   if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(), nullptr,
92                           private_key_->key()) ||
93       !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
94       !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
95       !EVP_DigestSignUpdate(
96           sign_context.get(),
97           reinterpret_cast<const uint8_t*>(quic::kProofSignatureLabel),
98           sizeof(quic::kProofSignatureLabel)) ||
99       !EVP_DigestSignUpdate(sign_context.get(),
100                             reinterpret_cast<const uint8_t*>(&len_tmp),
101                             sizeof(len_tmp)) ||
102       !EVP_DigestSignUpdate(sign_context.get(),
103                             reinterpret_cast<const uint8_t*>(chlo_hash.data()),
104                             len_tmp) ||
105       !EVP_DigestSignUpdate(
106           sign_context.get(),
107           reinterpret_cast<const uint8_t*>(server_config.data()),
108           server_config.size())) {
109     return false;
110   }
111   // Determine the maximum length of the signature.
112   size_t len = 0;
113   if (!EVP_DigestSignFinal(sign_context.get(), nullptr, &len)) {
114     return false;
115   }
116   std::vector<uint8_t> signature(len);
117   // Sign it.
118   if (!EVP_DigestSignFinal(sign_context.get(), signature.data(), &len)) {
119     return false;
120   }
121   signature.resize(len);
122   proof->signature.assign(reinterpret_cast<const char*>(signature.data()),
123                           signature.size());
124   *out_chain = chain_;
125   VLOG(1) << "signature: " << base::HexEncode(proof->signature);
126   proof->leaf_cert_scts = signed_certificate_timestamp_;
127   return true;
128 }
129 
GetProof(const quic::QuicSocketAddress & server_addr,const quic::QuicSocketAddress & client_addr,const std::string & hostname,const std::string & server_config,quic::QuicTransportVersion quic_version,std::string_view chlo_hash,std::unique_ptr<Callback> callback)130 void ProofSourceChromium::GetProof(const quic::QuicSocketAddress& server_addr,
131                                    const quic::QuicSocketAddress& client_addr,
132                                    const std::string& hostname,
133                                    const std::string& server_config,
134                                    quic::QuicTransportVersion quic_version,
135                                    std::string_view chlo_hash,
136                                    std::unique_ptr<Callback> callback) {
137   // As a transitional implementation, just call the synchronous version of
138   // GetProof, then invoke the callback with the results and destroy it.
139   quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> chain;
140   string signature;
141   string leaf_cert_sct;
142   quic::QuicCryptoProof out_proof;
143 
144   const bool ok = GetProofInner(server_addr, hostname, server_config,
145                                 quic_version, chlo_hash, &chain, &out_proof);
146   callback->Run(ok, chain, out_proof, nullptr /* details */);
147 }
148 
149 quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>
GetCertChain(const quic::QuicSocketAddress & server_address,const quic::QuicSocketAddress & client_address,const std::string & hostname,bool * cert_matched_sni)150 ProofSourceChromium::GetCertChain(const quic::QuicSocketAddress& server_address,
151                                   const quic::QuicSocketAddress& client_address,
152                                   const std::string& hostname,
153                                   bool* cert_matched_sni) {
154   *cert_matched_sni = false;
155   if (!hostname.empty()) {
156     for (const scoped_refptr<X509Certificate>& cert : certs_in_file_) {
157       if (cert->VerifyNameMatch(hostname)) {
158         *cert_matched_sni = true;
159         break;
160       }
161     }
162   }
163   return chain_;
164 }
165 
ComputeTlsSignature(const quic::QuicSocketAddress & server_address,const quic::QuicSocketAddress & client_address,const std::string & hostname,uint16_t signature_algorithm,std::string_view in,std::unique_ptr<SignatureCallback> callback)166 void ProofSourceChromium::ComputeTlsSignature(
167     const quic::QuicSocketAddress& server_address,
168     const quic::QuicSocketAddress& client_address,
169     const std::string& hostname,
170     uint16_t signature_algorithm,
171     std::string_view in,
172     std::unique_ptr<SignatureCallback> callback) {
173   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
174   bssl::ScopedEVP_MD_CTX sign_context;
175   EVP_PKEY_CTX* pkey_ctx;
176 
177   size_t siglen;
178   string sig;
179   if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(), nullptr,
180                           private_key_->key()) ||
181       !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
182       !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
183       !EVP_DigestSignUpdate(sign_context.get(),
184                             reinterpret_cast<const uint8_t*>(in.data()),
185                             in.size()) ||
186       !EVP_DigestSignFinal(sign_context.get(), nullptr, &siglen)) {
187     callback->Run(false, sig, nullptr);
188     return;
189   }
190   sig.resize(siglen);
191   if (!EVP_DigestSignFinal(
192           sign_context.get(),
193           reinterpret_cast<uint8_t*>(const_cast<char*>(sig.data())), &siglen)) {
194     callback->Run(false, sig, nullptr);
195     return;
196   }
197   sig.resize(siglen);
198 
199   callback->Run(true, sig, nullptr);
200 }
201 
202 absl::InlinedVector<uint16_t, 8>
SupportedTlsSignatureAlgorithms() const203 ProofSourceChromium::SupportedTlsSignatureAlgorithms() const {
204   // Allow all signature algorithms that BoringSSL allows.
205   return {};
206 }
207 
GetTicketCrypter()208 quic::ProofSource::TicketCrypter* ProofSourceChromium::GetTicketCrypter() {
209   return ticket_crypter_.get();
210 }
211 
SetTicketCrypter(std::unique_ptr<quic::ProofSource::TicketCrypter> ticket_crypter)212 void ProofSourceChromium::SetTicketCrypter(
213     std::unique_ptr<quic::ProofSource::TicketCrypter> ticket_crypter) {
214   ticket_crypter_ = std::move(ticket_crypter);
215 }
216 
217 }  // namespace net
218