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