1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 "quiche/quic/core/crypto/proof_source_x509.h"
6
7 #include <memory>
8 #include <optional>
9
10 #include "absl/strings/str_cat.h"
11 #include "absl/strings/string_view.h"
12 #include "openssl/ssl.h"
13 #include "quiche/quic/core/crypto/certificate_view.h"
14 #include "quiche/quic/core/crypto/crypto_protocol.h"
15 #include "quiche/quic/core/crypto/crypto_utils.h"
16 #include "quiche/quic/core/quic_data_writer.h"
17 #include "quiche/quic/platform/api/quic_bug_tracker.h"
18 #include "quiche/common/quiche_endian.h"
19
20 namespace quic {
21
ProofSourceX509(quiche::QuicheReferenceCountedPointer<Chain> default_chain,CertificatePrivateKey default_key)22 ProofSourceX509::ProofSourceX509(
23 quiche::QuicheReferenceCountedPointer<Chain> default_chain,
24 CertificatePrivateKey default_key) {
25 if (!AddCertificateChain(default_chain, std::move(default_key))) {
26 return;
27 }
28 default_certificate_ = &certificates_.front();
29 }
30
Create(quiche::QuicheReferenceCountedPointer<Chain> default_chain,CertificatePrivateKey default_key)31 std::unique_ptr<ProofSourceX509> ProofSourceX509::Create(
32 quiche::QuicheReferenceCountedPointer<Chain> default_chain,
33 CertificatePrivateKey default_key) {
34 std::unique_ptr<ProofSourceX509> result(
35 new ProofSourceX509(default_chain, std::move(default_key)));
36 if (!result->valid()) {
37 return nullptr;
38 }
39 return result;
40 }
41
GetProof(const QuicSocketAddress &,const QuicSocketAddress &,const std::string & hostname,const std::string & server_config,QuicTransportVersion,absl::string_view chlo_hash,std::unique_ptr<ProofSource::Callback> callback)42 void ProofSourceX509::GetProof(
43 const QuicSocketAddress& /*server_address*/,
44 const QuicSocketAddress& /*client_address*/, const std::string& hostname,
45 const std::string& server_config,
46 QuicTransportVersion /*transport_version*/, absl::string_view chlo_hash,
47 std::unique_ptr<ProofSource::Callback> callback) {
48 QuicCryptoProof proof;
49
50 if (!valid()) {
51 QUIC_BUG(ProofSourceX509::GetProof called in invalid state)
52 << "ProofSourceX509::GetProof called while the object is not valid";
53 callback->Run(/*ok=*/false, nullptr, proof, nullptr);
54 return;
55 }
56
57 std::optional<std::string> payload =
58 CryptoUtils::GenerateProofPayloadToBeSigned(chlo_hash, server_config);
59 if (!payload.has_value()) {
60 callback->Run(/*ok=*/false, nullptr, proof, nullptr);
61 return;
62 }
63
64 Certificate* certificate = GetCertificate(hostname, &proof.cert_matched_sni);
65 proof.signature =
66 certificate->key.Sign(*payload, SSL_SIGN_RSA_PSS_RSAE_SHA256);
67 MaybeAddSctsForHostname(hostname, proof.leaf_cert_scts);
68 callback->Run(/*ok=*/!proof.signature.empty(), certificate->chain, proof,
69 nullptr);
70 }
71
72 quiche::QuicheReferenceCountedPointer<ProofSource::Chain>
GetCertChain(const QuicSocketAddress &,const QuicSocketAddress &,const std::string & hostname,bool * cert_matched_sni)73 ProofSourceX509::GetCertChain(const QuicSocketAddress& /*server_address*/,
74 const QuicSocketAddress& /*client_address*/,
75 const std::string& hostname,
76 bool* cert_matched_sni) {
77 if (!valid()) {
78 QUIC_BUG(ProofSourceX509::GetCertChain called in invalid state)
79 << "ProofSourceX509::GetCertChain called while the object is not "
80 "valid";
81 return nullptr;
82 }
83
84 return GetCertificate(hostname, cert_matched_sni)->chain;
85 }
86
ComputeTlsSignature(const QuicSocketAddress &,const QuicSocketAddress &,const std::string & hostname,uint16_t signature_algorithm,absl::string_view in,std::unique_ptr<ProofSource::SignatureCallback> callback)87 void ProofSourceX509::ComputeTlsSignature(
88 const QuicSocketAddress& /*server_address*/,
89 const QuicSocketAddress& /*client_address*/, const std::string& hostname,
90 uint16_t signature_algorithm, absl::string_view in,
91 std::unique_ptr<ProofSource::SignatureCallback> callback) {
92 if (!valid()) {
93 QUIC_BUG(ProofSourceX509::ComputeTlsSignature called in invalid state)
94 << "ProofSourceX509::ComputeTlsSignature called while the object is "
95 "not valid";
96 callback->Run(/*ok=*/false, "", nullptr);
97 return;
98 }
99
100 bool cert_matched_sni;
101 std::string signature = GetCertificate(hostname, &cert_matched_sni)
102 ->key.Sign(in, signature_algorithm);
103 callback->Run(/*ok=*/!signature.empty(), signature, nullptr);
104 }
105
SupportedTlsSignatureAlgorithms() const106 QuicSignatureAlgorithmVector ProofSourceX509::SupportedTlsSignatureAlgorithms()
107 const {
108 return SupportedSignatureAlgorithmsForQuic();
109 }
110
GetTicketCrypter()111 ProofSource::TicketCrypter* ProofSourceX509::GetTicketCrypter() {
112 return nullptr;
113 }
114
AddCertificateChain(quiche::QuicheReferenceCountedPointer<Chain> chain,CertificatePrivateKey key)115 bool ProofSourceX509::AddCertificateChain(
116 quiche::QuicheReferenceCountedPointer<Chain> chain,
117 CertificatePrivateKey key) {
118 if (chain->certs.empty()) {
119 QUIC_BUG(quic_bug_10644_1) << "Empty certificate chain supplied.";
120 return false;
121 }
122
123 std::unique_ptr<CertificateView> leaf =
124 CertificateView::ParseSingleCertificate(chain->certs[0]);
125 if (leaf == nullptr) {
126 QUIC_BUG(quic_bug_10644_2)
127 << "Unable to parse X.509 leaf certificate in the supplied chain.";
128 return false;
129 }
130 if (!key.MatchesPublicKey(*leaf)) {
131 QUIC_BUG(quic_bug_10644_3)
132 << "Private key does not match the leaf certificate.";
133 return false;
134 }
135
136 certificates_.push_front(Certificate{
137 chain,
138 std::move(key),
139 });
140 Certificate* certificate = &certificates_.front();
141
142 for (absl::string_view host : leaf->subject_alt_name_domains()) {
143 certificate_map_[std::string(host)] = certificate;
144 }
145 return true;
146 }
147
GetCertificate(const std::string & hostname,bool * cert_matched_sni) const148 ProofSourceX509::Certificate* ProofSourceX509::GetCertificate(
149 const std::string& hostname, bool* cert_matched_sni) const {
150 QUICHE_DCHECK(valid());
151 auto it = certificate_map_.find(hostname);
152 if (it != certificate_map_.end()) {
153 *cert_matched_sni = true;
154 return it->second;
155 }
156 auto dot_pos = hostname.find('.');
157 if (dot_pos != std::string::npos) {
158 std::string wildcard = absl::StrCat("*", hostname.substr(dot_pos));
159 it = certificate_map_.find(wildcard);
160 if (it != certificate_map_.end()) {
161 *cert_matched_sni = true;
162 return it->second;
163 }
164 }
165 *cert_matched_sni = false;
166 return default_certificate_;
167 }
168
169 } // namespace quic
170