• 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 #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_bytes(base::make_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,absl::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     absl::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: "
126           << base::HexEncode(proof->signature.data(), proof->signature.size());
127   proof->leaf_cert_scts = signed_certificate_timestamp_;
128   return true;
129 }
130 
GetProof(const quic::QuicSocketAddress & server_addr,const quic::QuicSocketAddress & client_addr,const std::string & hostname,const std::string & server_config,quic::QuicTransportVersion quic_version,absl::string_view chlo_hash,std::unique_ptr<Callback> callback)131 void ProofSourceChromium::GetProof(const quic::QuicSocketAddress& server_addr,
132                                    const quic::QuicSocketAddress& client_addr,
133                                    const std::string& hostname,
134                                    const std::string& server_config,
135                                    quic::QuicTransportVersion quic_version,
136                                    absl::string_view chlo_hash,
137                                    std::unique_ptr<Callback> callback) {
138   // As a transitional implementation, just call the synchronous version of
139   // GetProof, then invoke the callback with the results and destroy it.
140   quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> chain;
141   string signature;
142   string leaf_cert_sct;
143   quic::QuicCryptoProof out_proof;
144 
145   const bool ok = GetProofInner(server_addr, hostname, server_config,
146                                 quic_version, chlo_hash, &chain, &out_proof);
147   callback->Run(ok, chain, out_proof, nullptr /* details */);
148 }
149 
150 quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>
GetCertChain(const quic::QuicSocketAddress & server_address,const quic::QuicSocketAddress & client_address,const std::string & hostname,bool * cert_matched_sni)151 ProofSourceChromium::GetCertChain(const quic::QuicSocketAddress& server_address,
152                                   const quic::QuicSocketAddress& client_address,
153                                   const std::string& hostname,
154                                   bool* cert_matched_sni) {
155   *cert_matched_sni = false;
156   if (!hostname.empty()) {
157     for (const scoped_refptr<X509Certificate>& cert : certs_in_file_) {
158       if (cert->VerifyNameMatch(hostname)) {
159         *cert_matched_sni = true;
160         break;
161       }
162     }
163   }
164   return chain_;
165 }
166 
ComputeTlsSignature(const quic::QuicSocketAddress & server_address,const quic::QuicSocketAddress & client_address,const std::string & hostname,uint16_t signature_algorithm,absl::string_view in,std::unique_ptr<SignatureCallback> callback)167 void ProofSourceChromium::ComputeTlsSignature(
168     const quic::QuicSocketAddress& server_address,
169     const quic::QuicSocketAddress& client_address,
170     const std::string& hostname,
171     uint16_t signature_algorithm,
172     absl::string_view in,
173     std::unique_ptr<SignatureCallback> callback) {
174   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
175   bssl::ScopedEVP_MD_CTX sign_context;
176   EVP_PKEY_CTX* pkey_ctx;
177 
178   size_t siglen;
179   string sig;
180   if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(), nullptr,
181                           private_key_->key()) ||
182       !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
183       !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
184       !EVP_DigestSignUpdate(sign_context.get(),
185                             reinterpret_cast<const uint8_t*>(in.data()),
186                             in.size()) ||
187       !EVP_DigestSignFinal(sign_context.get(), nullptr, &siglen)) {
188     callback->Run(false, sig, nullptr);
189     return;
190   }
191   sig.resize(siglen);
192   if (!EVP_DigestSignFinal(
193           sign_context.get(),
194           reinterpret_cast<uint8_t*>(const_cast<char*>(sig.data())), &siglen)) {
195     callback->Run(false, sig, nullptr);
196     return;
197   }
198   sig.resize(siglen);
199 
200   callback->Run(true, sig, nullptr);
201 }
202 
203 absl::InlinedVector<uint16_t, 8>
SupportedTlsSignatureAlgorithms() const204 ProofSourceChromium::SupportedTlsSignatureAlgorithms() const {
205   // Allow all signature algorithms that BoringSSL allows.
206   return {};
207 }
208 
GetTicketCrypter()209 quic::ProofSource::TicketCrypter* ProofSourceChromium::GetTicketCrypter() {
210   return ticket_crypter_.get();
211 }
212 
SetTicketCrypter(std::unique_ptr<quic::ProofSource::TicketCrypter> ticket_crypter)213 void ProofSourceChromium::SetTicketCrypter(
214     std::unique_ptr<quic::ProofSource::TicketCrypter> ticket_crypter) {
215   ticket_crypter_ = std::move(ticket_crypter);
216 }
217 
218 }  // namespace net
219