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