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