xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/crypto_utils.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2013 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/crypto_utils.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "absl/base/macros.h"
12 #include "absl/strings/str_cat.h"
13 #include "absl/strings/string_view.h"
14 #include "openssl/bytestring.h"
15 #include "openssl/hkdf.h"
16 #include "openssl/mem.h"
17 #include "openssl/sha.h"
18 #include "quiche/quic/core/crypto/aes_128_gcm_12_decrypter.h"
19 #include "quiche/quic/core/crypto/aes_128_gcm_12_encrypter.h"
20 #include "quiche/quic/core/crypto/aes_128_gcm_decrypter.h"
21 #include "quiche/quic/core/crypto/aes_128_gcm_encrypter.h"
22 #include "quiche/quic/core/crypto/crypto_handshake.h"
23 #include "quiche/quic/core/crypto/crypto_protocol.h"
24 #include "quiche/quic/core/crypto/null_decrypter.h"
25 #include "quiche/quic/core/crypto/null_encrypter.h"
26 #include "quiche/quic/core/crypto/quic_decrypter.h"
27 #include "quiche/quic/core/crypto/quic_encrypter.h"
28 #include "quiche/quic/core/crypto/quic_hkdf.h"
29 #include "quiche/quic/core/crypto/quic_random.h"
30 #include "quiche/quic/core/quic_connection_id.h"
31 #include "quiche/quic/core/quic_constants.h"
32 #include "quiche/quic/core/quic_data_writer.h"
33 #include "quiche/quic/core/quic_time.h"
34 #include "quiche/quic/core/quic_utils.h"
35 #include "quiche/quic/core/quic_versions.h"
36 #include "quiche/quic/platform/api/quic_bug_tracker.h"
37 #include "quiche/quic/platform/api/quic_logging.h"
38 #include "quiche/common/quiche_endian.h"
39 
40 namespace quic {
41 
42 namespace {
43 
44 // Implements the HKDF-Expand-Label function as defined in section 7.1 of RFC
45 // 8446. The HKDF-Expand-Label function takes 4 explicit arguments (Secret,
46 // Label, Context, and Length), as well as implicit PRF which is the hash
47 // function negotiated by TLS. Its use in QUIC (as needed by the QUIC stack,
48 // instead of as used internally by the TLS stack) is only for deriving initial
49 // secrets for obfuscation, for calculating packet protection keys and IVs from
50 // the corresponding packet protection secret and key update in the same quic
51 // session. None of these uses need a Context (a zero-length context is
52 // provided), so this argument is omitted here.
53 //
54 // The implicit PRF is explicitly passed into HkdfExpandLabel as |prf|; the
55 // Secret, Label, and Length are passed in as |secret|, |label|, and
56 // |out_len|, respectively. The resulting expanded secret is returned.
HkdfExpandLabel(const EVP_MD * prf,absl::Span<const uint8_t> secret,const std::string & label,size_t out_len)57 std::vector<uint8_t> HkdfExpandLabel(const EVP_MD* prf,
58                                      absl::Span<const uint8_t> secret,
59                                      const std::string& label, size_t out_len) {
60   bssl::ScopedCBB quic_hkdf_label;
61   CBB inner_label;
62   const char label_prefix[] = "tls13 ";
63   // 20 = size(u16) + size(u8) + len("tls13 ") +
64   //      max_len("client in", "server in", "quicv2 key", ... ) +
65   //      size(u8);
66   static const size_t max_quic_hkdf_label_length = 20;
67   if (!CBB_init(quic_hkdf_label.get(), max_quic_hkdf_label_length) ||
68       !CBB_add_u16(quic_hkdf_label.get(), out_len) ||
69       !CBB_add_u8_length_prefixed(quic_hkdf_label.get(), &inner_label) ||
70       !CBB_add_bytes(&inner_label,
71                      reinterpret_cast<const uint8_t*>(label_prefix),
72                      ABSL_ARRAYSIZE(label_prefix) - 1) ||
73       !CBB_add_bytes(&inner_label,
74                      reinterpret_cast<const uint8_t*>(label.data()),
75                      label.size()) ||
76       // Zero length |Context|.
77       !CBB_add_u8(quic_hkdf_label.get(), 0) ||
78       !CBB_flush(quic_hkdf_label.get())) {
79     QUIC_LOG(ERROR) << "Building HKDF label failed";
80     return std::vector<uint8_t>();
81   }
82   std::vector<uint8_t> out;
83   out.resize(out_len);
84   if (!HKDF_expand(out.data(), out_len, prf, secret.data(), secret.size(),
85                    CBB_data(quic_hkdf_label.get()),
86                    CBB_len(quic_hkdf_label.get()))) {
87     QUIC_LOG(ERROR) << "Running HKDF-Expand-Label failed";
88     return std::vector<uint8_t>();
89   }
90   return out;
91 }
92 
93 }  // namespace
94 
getLabelForVersion(const ParsedQuicVersion & version,const absl::string_view & predicate)95 const std::string getLabelForVersion(const ParsedQuicVersion& version,
96                                      const absl::string_view& predicate) {
97   static_assert(SupportedVersions().size() == 4u,
98                 "Supported versions out of sync with HKDF labels");
99   if (version == ParsedQuicVersion::RFCv2()) {
100     return absl::StrCat("quicv2 ", predicate);
101   } else {
102     return absl::StrCat("quic ", predicate);
103   }
104 }
105 
InitializeCrypterSecrets(const EVP_MD * prf,const std::vector<uint8_t> & pp_secret,const ParsedQuicVersion & version,QuicCrypter * crypter)106 void CryptoUtils::InitializeCrypterSecrets(
107     const EVP_MD* prf, const std::vector<uint8_t>& pp_secret,
108     const ParsedQuicVersion& version, QuicCrypter* crypter) {
109   SetKeyAndIV(prf, pp_secret, version, crypter);
110   std::vector<uint8_t> header_protection_key = GenerateHeaderProtectionKey(
111       prf, pp_secret, version, crypter->GetKeySize());
112   crypter->SetHeaderProtectionKey(
113       absl::string_view(reinterpret_cast<char*>(header_protection_key.data()),
114                         header_protection_key.size()));
115 }
116 
SetKeyAndIV(const EVP_MD * prf,absl::Span<const uint8_t> pp_secret,const ParsedQuicVersion & version,QuicCrypter * crypter)117 void CryptoUtils::SetKeyAndIV(const EVP_MD* prf,
118                               absl::Span<const uint8_t> pp_secret,
119                               const ParsedQuicVersion& version,
120                               QuicCrypter* crypter) {
121   std::vector<uint8_t> key =
122       HkdfExpandLabel(prf, pp_secret, getLabelForVersion(version, "key"),
123                       crypter->GetKeySize());
124   std::vector<uint8_t> iv = HkdfExpandLabel(
125       prf, pp_secret, getLabelForVersion(version, "iv"), crypter->GetIVSize());
126   crypter->SetKey(
127       absl::string_view(reinterpret_cast<char*>(key.data()), key.size()));
128   crypter->SetIV(
129       absl::string_view(reinterpret_cast<char*>(iv.data()), iv.size()));
130 }
131 
GenerateHeaderProtectionKey(const EVP_MD * prf,absl::Span<const uint8_t> pp_secret,const ParsedQuicVersion & version,size_t out_len)132 std::vector<uint8_t> CryptoUtils::GenerateHeaderProtectionKey(
133     const EVP_MD* prf, absl::Span<const uint8_t> pp_secret,
134     const ParsedQuicVersion& version, size_t out_len) {
135   return HkdfExpandLabel(prf, pp_secret, getLabelForVersion(version, "hp"),
136                          out_len);
137 }
138 
GenerateNextKeyPhaseSecret(const EVP_MD * prf,const ParsedQuicVersion & version,const std::vector<uint8_t> & current_secret)139 std::vector<uint8_t> CryptoUtils::GenerateNextKeyPhaseSecret(
140     const EVP_MD* prf, const ParsedQuicVersion& version,
141     const std::vector<uint8_t>& current_secret) {
142   return HkdfExpandLabel(prf, current_secret, getLabelForVersion(version, "ku"),
143                          current_secret.size());
144 }
145 
146 namespace {
147 
148 // Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.2
149 const uint8_t kDraft29InitialSalt[] = {0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2,
150                                        0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
151                                        0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
152 const uint8_t kRFCv1InitialSalt[] = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34,
153                                      0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
154                                      0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
155 const uint8_t kRFCv2InitialSalt[] = {
156     0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93,
157     0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
158 };
159 
160 // Salts used by deployed versions of QUIC. When introducing a new version,
161 // generate a new salt by running `openssl rand -hex 20`.
162 
163 // Salt to use for initial obfuscators in
164 // ParsedQuicVersion::ReservedForNegotiation().
165 const uint8_t kReservedForNegotiationSalt[] = {
166     0xf9, 0x64, 0xbf, 0x45, 0x3a, 0x1f, 0x1b, 0x80, 0xa5, 0xf8,
167     0x82, 0x03, 0x77, 0xd4, 0xaf, 0xca, 0x58, 0x0e, 0xe7, 0x43};
168 
InitialSaltForVersion(const ParsedQuicVersion & version,size_t * out_len)169 const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version,
170                                      size_t* out_len) {
171   static_assert(SupportedVersions().size() == 4u,
172                 "Supported versions out of sync with initial encryption salts");
173   if (version == ParsedQuicVersion::RFCv2()) {
174     *out_len = ABSL_ARRAYSIZE(kRFCv2InitialSalt);
175     return kRFCv2InitialSalt;
176   } else if (version == ParsedQuicVersion::RFCv1()) {
177     *out_len = ABSL_ARRAYSIZE(kRFCv1InitialSalt);
178     return kRFCv1InitialSalt;
179   } else if (version == ParsedQuicVersion::Draft29()) {
180     *out_len = ABSL_ARRAYSIZE(kDraft29InitialSalt);
181     return kDraft29InitialSalt;
182   } else if (version == ParsedQuicVersion::ReservedForNegotiation()) {
183     *out_len = ABSL_ARRAYSIZE(kReservedForNegotiationSalt);
184     return kReservedForNegotiationSalt;
185   }
186   QUIC_BUG(quic_bug_10699_1)
187       << "No initial obfuscation salt for version " << version;
188   *out_len = ABSL_ARRAYSIZE(kReservedForNegotiationSalt);
189   return kReservedForNegotiationSalt;
190 }
191 
192 const char kPreSharedKeyLabel[] = "QUIC PSK";
193 
194 // Retry Integrity Protection Keys and Nonces.
195 // https://tools.ietf.org/html/draft-ietf-quic-tls-29#section-5.8
196 // When introducing a new Google version, generate a new key by running
197 // `openssl rand -hex 16`.
198 const uint8_t kDraft29RetryIntegrityKey[] = {0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a,
199                                              0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a,
200                                              0x6c, 0xb9, 0x6b, 0xe1};
201 const uint8_t kDraft29RetryIntegrityNonce[] = {
202     0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c};
203 const uint8_t kRFCv1RetryIntegrityKey[] = {0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66,
204                                            0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54,
205                                            0xe3, 0x68, 0xc8, 0x4e};
206 const uint8_t kRFCv1RetryIntegrityNonce[] = {
207     0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb};
208 const uint8_t kRFCv2RetryIntegrityKey[] = {0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac,
209                                            0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce,
210                                            0xad, 0x7c, 0xcc, 0x92};
211 const uint8_t kRFCv2RetryIntegrityNonce[] = {
212     0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a};
213 // Retry integrity key used by ParsedQuicVersion::ReservedForNegotiation().
214 const uint8_t kReservedForNegotiationRetryIntegrityKey[] = {
215     0xf2, 0xcd, 0x8f, 0xe0, 0x36, 0xd0, 0x25, 0x35,
216     0x03, 0xe6, 0x7c, 0x7b, 0xd2, 0x44, 0xca, 0xd9};
217 // When introducing a new Google version, generate a new nonce by running
218 // `openssl rand -hex 12`.
219 // Retry integrity nonce used by ParsedQuicVersion::ReservedForNegotiation().
220 const uint8_t kReservedForNegotiationRetryIntegrityNonce[] = {
221     0x35, 0x9f, 0x16, 0xd1, 0xed, 0x80, 0x90, 0x8e, 0xec, 0x85, 0xc4, 0xd6};
222 
RetryIntegrityKeysForVersion(const ParsedQuicVersion & version,absl::string_view * key,absl::string_view * nonce)223 bool RetryIntegrityKeysForVersion(const ParsedQuicVersion& version,
224                                   absl::string_view* key,
225                                   absl::string_view* nonce) {
226   static_assert(SupportedVersions().size() == 4u,
227                 "Supported versions out of sync with retry integrity keys");
228   if (!version.UsesTls()) {
229     QUIC_BUG(quic_bug_10699_2)
230         << "Attempted to get retry integrity keys for invalid version "
231         << version;
232     return false;
233   } else if (version == ParsedQuicVersion::RFCv2()) {
234     *key = absl::string_view(
235         reinterpret_cast<const char*>(kRFCv2RetryIntegrityKey),
236         ABSL_ARRAYSIZE(kRFCv2RetryIntegrityKey));
237     *nonce = absl::string_view(
238         reinterpret_cast<const char*>(kRFCv2RetryIntegrityNonce),
239         ABSL_ARRAYSIZE(kRFCv2RetryIntegrityNonce));
240     return true;
241   } else if (version == ParsedQuicVersion::RFCv1()) {
242     *key = absl::string_view(
243         reinterpret_cast<const char*>(kRFCv1RetryIntegrityKey),
244         ABSL_ARRAYSIZE(kRFCv1RetryIntegrityKey));
245     *nonce = absl::string_view(
246         reinterpret_cast<const char*>(kRFCv1RetryIntegrityNonce),
247         ABSL_ARRAYSIZE(kRFCv1RetryIntegrityNonce));
248     return true;
249   } else if (version == ParsedQuicVersion::Draft29()) {
250     *key = absl::string_view(
251         reinterpret_cast<const char*>(kDraft29RetryIntegrityKey),
252         ABSL_ARRAYSIZE(kDraft29RetryIntegrityKey));
253     *nonce = absl::string_view(
254         reinterpret_cast<const char*>(kDraft29RetryIntegrityNonce),
255         ABSL_ARRAYSIZE(kDraft29RetryIntegrityNonce));
256     return true;
257   } else if (version == ParsedQuicVersion::ReservedForNegotiation()) {
258     *key = absl::string_view(
259         reinterpret_cast<const char*>(kReservedForNegotiationRetryIntegrityKey),
260         ABSL_ARRAYSIZE(kReservedForNegotiationRetryIntegrityKey));
261     *nonce = absl::string_view(
262         reinterpret_cast<const char*>(
263             kReservedForNegotiationRetryIntegrityNonce),
264         ABSL_ARRAYSIZE(kReservedForNegotiationRetryIntegrityNonce));
265     return true;
266   }
267   QUIC_BUG(quic_bug_10699_3)
268       << "Attempted to get retry integrity keys for version " << version;
269   return false;
270 }
271 
272 }  // namespace
273 
274 // static
CreateInitialObfuscators(Perspective perspective,ParsedQuicVersion version,QuicConnectionId connection_id,CrypterPair * crypters)275 void CryptoUtils::CreateInitialObfuscators(Perspective perspective,
276                                            ParsedQuicVersion version,
277                                            QuicConnectionId connection_id,
278                                            CrypterPair* crypters) {
279   QUIC_DLOG(INFO) << "Creating "
280                   << (perspective == Perspective::IS_CLIENT ? "client"
281                                                             : "server")
282                   << " crypters for version " << version << " with CID "
283                   << connection_id;
284   if (!version.UsesInitialObfuscators()) {
285     crypters->encrypter = std::make_unique<NullEncrypter>(perspective);
286     crypters->decrypter = std::make_unique<NullDecrypter>(perspective);
287     return;
288   }
289   QUIC_BUG_IF(quic_bug_12871_1, !QuicUtils::IsConnectionIdValidForVersion(
290                                     connection_id, version.transport_version))
291       << "CreateTlsInitialCrypters: attempted to use connection ID "
292       << connection_id << " which is invalid with version " << version;
293   const EVP_MD* hash = EVP_sha256();
294 
295   size_t salt_len;
296   const uint8_t* salt = InitialSaltForVersion(version, &salt_len);
297   std::vector<uint8_t> handshake_secret;
298   handshake_secret.resize(EVP_MAX_MD_SIZE);
299   size_t handshake_secret_len;
300   const bool hkdf_extract_success =
301       HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash,
302                    reinterpret_cast<const uint8_t*>(connection_id.data()),
303                    connection_id.length(), salt, salt_len);
304   QUIC_BUG_IF(quic_bug_12871_2, !hkdf_extract_success)
305       << "HKDF_extract failed when creating initial crypters";
306   handshake_secret.resize(handshake_secret_len);
307 
308   const std::string client_label = "client in";
309   const std::string server_label = "server in";
310   std::string encryption_label, decryption_label;
311   if (perspective == Perspective::IS_CLIENT) {
312     encryption_label = client_label;
313     decryption_label = server_label;
314   } else {
315     encryption_label = server_label;
316     decryption_label = client_label;
317   }
318   std::vector<uint8_t> encryption_secret = HkdfExpandLabel(
319       hash, handshake_secret, encryption_label, EVP_MD_size(hash));
320   crypters->encrypter = std::make_unique<Aes128GcmEncrypter>();
321   InitializeCrypterSecrets(hash, encryption_secret, version,
322                            crypters->encrypter.get());
323 
324   std::vector<uint8_t> decryption_secret = HkdfExpandLabel(
325       hash, handshake_secret, decryption_label, EVP_MD_size(hash));
326   crypters->decrypter = std::make_unique<Aes128GcmDecrypter>();
327   InitializeCrypterSecrets(hash, decryption_secret, version,
328                            crypters->decrypter.get());
329 }
330 
331 // static
ValidateRetryIntegrityTag(ParsedQuicVersion version,QuicConnectionId original_connection_id,absl::string_view retry_without_tag,absl::string_view integrity_tag)332 bool CryptoUtils::ValidateRetryIntegrityTag(
333     ParsedQuicVersion version, QuicConnectionId original_connection_id,
334     absl::string_view retry_without_tag, absl::string_view integrity_tag) {
335   unsigned char computed_integrity_tag[kRetryIntegrityTagLength];
336   if (integrity_tag.length() != ABSL_ARRAYSIZE(computed_integrity_tag)) {
337     QUIC_BUG(quic_bug_10699_4)
338         << "Invalid retry integrity tag length " << integrity_tag.length();
339     return false;
340   }
341   char retry_pseudo_packet[kMaxIncomingPacketSize + 256];
342   QuicDataWriter writer(ABSL_ARRAYSIZE(retry_pseudo_packet),
343                         retry_pseudo_packet);
344   if (!writer.WriteLengthPrefixedConnectionId(original_connection_id)) {
345     QUIC_BUG(quic_bug_10699_5)
346         << "Failed to write original connection ID in retry pseudo packet";
347     return false;
348   }
349   if (!writer.WriteStringPiece(retry_without_tag)) {
350     QUIC_BUG(quic_bug_10699_6)
351         << "Failed to write retry without tag in retry pseudo packet";
352     return false;
353   }
354   absl::string_view key;
355   absl::string_view nonce;
356   if (!RetryIntegrityKeysForVersion(version, &key, &nonce)) {
357     // RetryIntegrityKeysForVersion already logs failures.
358     return false;
359   }
360   Aes128GcmEncrypter crypter;
361   crypter.SetKey(key);
362   absl::string_view associated_data(writer.data(), writer.length());
363   absl::string_view plaintext;  // Plaintext is empty.
364   if (!crypter.Encrypt(nonce, associated_data, plaintext,
365                        computed_integrity_tag)) {
366     QUIC_BUG(quic_bug_10699_7) << "Failed to compute retry integrity tag";
367     return false;
368   }
369   if (CRYPTO_memcmp(computed_integrity_tag, integrity_tag.data(),
370                     ABSL_ARRAYSIZE(computed_integrity_tag)) != 0) {
371     QUIC_DLOG(ERROR) << "Failed to validate retry integrity tag";
372     return false;
373   }
374   return true;
375 }
376 
377 // static
GenerateNonce(QuicWallTime now,QuicRandom * random_generator,absl::string_view orbit,std::string * nonce)378 void CryptoUtils::GenerateNonce(QuicWallTime now, QuicRandom* random_generator,
379                                 absl::string_view orbit, std::string* nonce) {
380   // a 4-byte timestamp + 28 random bytes.
381   nonce->reserve(kNonceSize);
382   nonce->resize(kNonceSize);
383 
384   uint32_t gmt_unix_time = static_cast<uint32_t>(now.ToUNIXSeconds());
385   // The time in the nonce must be encoded in big-endian because the
386   // strike-register depends on the nonces being ordered by time.
387   (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24);
388   (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16);
389   (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8);
390   (*nonce)[3] = static_cast<char>(gmt_unix_time);
391   size_t bytes_written = 4;
392 
393   if (orbit.size() == 8) {
394     memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size());
395     bytes_written += orbit.size();
396   }
397 
398   random_generator->RandBytes(&(*nonce)[bytes_written],
399                               kNonceSize - bytes_written);
400 }
401 
402 // static
DeriveKeys(const ParsedQuicVersion & version,absl::string_view premaster_secret,QuicTag aead,absl::string_view client_nonce,absl::string_view server_nonce,absl::string_view pre_shared_key,const std::string & hkdf_input,Perspective perspective,Diversification diversification,CrypterPair * crypters,std::string * subkey_secret)403 bool CryptoUtils::DeriveKeys(
404     const ParsedQuicVersion& version, absl::string_view premaster_secret,
405     QuicTag aead, absl::string_view client_nonce,
406     absl::string_view server_nonce, absl::string_view pre_shared_key,
407     const std::string& hkdf_input, Perspective perspective,
408     Diversification diversification, CrypterPair* crypters,
409     std::string* subkey_secret) {
410   // If the connection is using PSK, concatenate it with the pre-master secret.
411   std::unique_ptr<char[]> psk_premaster_secret;
412   if (!pre_shared_key.empty()) {
413     const absl::string_view label(kPreSharedKeyLabel);
414     const size_t psk_premaster_secret_size = label.size() + 1 +
415                                              pre_shared_key.size() + 8 +
416                                              premaster_secret.size() + 8;
417 
418     psk_premaster_secret = std::make_unique<char[]>(psk_premaster_secret_size);
419     QuicDataWriter writer(psk_premaster_secret_size, psk_premaster_secret.get(),
420                           quiche::HOST_BYTE_ORDER);
421 
422     if (!writer.WriteStringPiece(label) || !writer.WriteUInt8(0) ||
423         !writer.WriteStringPiece(pre_shared_key) ||
424         !writer.WriteUInt64(pre_shared_key.size()) ||
425         !writer.WriteStringPiece(premaster_secret) ||
426         !writer.WriteUInt64(premaster_secret.size()) ||
427         writer.remaining() != 0) {
428       return false;
429     }
430 
431     premaster_secret = absl::string_view(psk_premaster_secret.get(),
432                                          psk_premaster_secret_size);
433   }
434 
435   crypters->encrypter = QuicEncrypter::Create(version, aead);
436   crypters->decrypter = QuicDecrypter::Create(version, aead);
437 
438   size_t key_bytes = crypters->encrypter->GetKeySize();
439   size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize();
440   if (version.UsesInitialObfuscators()) {
441     nonce_prefix_bytes = crypters->encrypter->GetIVSize();
442   }
443   size_t subkey_secret_bytes =
444       subkey_secret == nullptr ? 0 : premaster_secret.length();
445 
446   absl::string_view nonce = client_nonce;
447   std::string nonce_storage;
448   if (!server_nonce.empty()) {
449     nonce_storage = std::string(client_nonce) + std::string(server_nonce);
450     nonce = nonce_storage;
451   }
452 
453   QuicHKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes,
454                 nonce_prefix_bytes, subkey_secret_bytes);
455 
456   // Key derivation depends on the key diversification method being employed.
457   // both the client and the server support never doing key diversification.
458   // The server also supports immediate diversification, and the client
459   // supports pending diversification.
460   switch (diversification.mode()) {
461     case Diversification::NEVER: {
462       if (perspective == Perspective::IS_SERVER) {
463         if (!crypters->encrypter->SetKey(hkdf.server_write_key()) ||
464             !crypters->encrypter->SetNoncePrefixOrIV(version,
465                                                      hkdf.server_write_iv()) ||
466             !crypters->encrypter->SetHeaderProtectionKey(
467                 hkdf.server_hp_key()) ||
468             !crypters->decrypter->SetKey(hkdf.client_write_key()) ||
469             !crypters->decrypter->SetNoncePrefixOrIV(version,
470                                                      hkdf.client_write_iv()) ||
471             !crypters->decrypter->SetHeaderProtectionKey(
472                 hkdf.client_hp_key())) {
473           return false;
474         }
475       } else {
476         if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
477             !crypters->encrypter->SetNoncePrefixOrIV(version,
478                                                      hkdf.client_write_iv()) ||
479             !crypters->encrypter->SetHeaderProtectionKey(
480                 hkdf.client_hp_key()) ||
481             !crypters->decrypter->SetKey(hkdf.server_write_key()) ||
482             !crypters->decrypter->SetNoncePrefixOrIV(version,
483                                                      hkdf.server_write_iv()) ||
484             !crypters->decrypter->SetHeaderProtectionKey(
485                 hkdf.server_hp_key())) {
486           return false;
487         }
488       }
489       break;
490     }
491     case Diversification::PENDING: {
492       if (perspective == Perspective::IS_SERVER) {
493         QUIC_BUG(quic_bug_10699_8)
494             << "Pending diversification is only for clients.";
495         return false;
496       }
497 
498       if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
499           !crypters->encrypter->SetNoncePrefixOrIV(version,
500                                                    hkdf.client_write_iv()) ||
501           !crypters->encrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) ||
502           !crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) ||
503           !crypters->decrypter->SetNoncePrefixOrIV(version,
504                                                    hkdf.server_write_iv()) ||
505           !crypters->decrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) {
506         return false;
507       }
508       break;
509     }
510     case Diversification::NOW: {
511       if (perspective == Perspective::IS_CLIENT) {
512         QUIC_BUG(quic_bug_10699_9)
513             << "Immediate diversification is only for servers.";
514         return false;
515       }
516 
517       std::string key, nonce_prefix;
518       QuicDecrypter::DiversifyPreliminaryKey(
519           hkdf.server_write_key(), hkdf.server_write_iv(),
520           *diversification.nonce(), key_bytes, nonce_prefix_bytes, &key,
521           &nonce_prefix);
522       if (!crypters->decrypter->SetKey(hkdf.client_write_key()) ||
523           !crypters->decrypter->SetNoncePrefixOrIV(version,
524                                                    hkdf.client_write_iv()) ||
525           !crypters->decrypter->SetHeaderProtectionKey(hkdf.client_hp_key()) ||
526           !crypters->encrypter->SetKey(key) ||
527           !crypters->encrypter->SetNoncePrefixOrIV(version, nonce_prefix) ||
528           !crypters->encrypter->SetHeaderProtectionKey(hkdf.server_hp_key())) {
529         return false;
530       }
531       break;
532     }
533     default:
534       QUICHE_DCHECK(false);
535   }
536 
537   if (subkey_secret != nullptr) {
538     *subkey_secret = std::string(hkdf.subkey_secret());
539   }
540 
541   return true;
542 }
543 
544 // static
ComputeLeafCertHash(absl::string_view cert)545 uint64_t CryptoUtils::ComputeLeafCertHash(absl::string_view cert) {
546   return QuicUtils::FNV1a_64_Hash(cert);
547 }
548 
ValidateServerHello(const CryptoHandshakeMessage & server_hello,const ParsedQuicVersionVector & negotiated_versions,std::string * error_details)549 QuicErrorCode CryptoUtils::ValidateServerHello(
550     const CryptoHandshakeMessage& server_hello,
551     const ParsedQuicVersionVector& negotiated_versions,
552     std::string* error_details) {
553   QUICHE_DCHECK(error_details != nullptr);
554 
555   if (server_hello.tag() != kSHLO) {
556     *error_details = "Bad tag";
557     return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
558   }
559 
560   QuicVersionLabelVector supported_version_labels;
561   if (server_hello.GetVersionLabelList(kVER, &supported_version_labels) !=
562       QUIC_NO_ERROR) {
563     *error_details = "server hello missing version list";
564     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
565   }
566 
567   return ValidateServerHelloVersions(supported_version_labels,
568                                      negotiated_versions, error_details);
569 }
570 
ValidateServerHelloVersions(const QuicVersionLabelVector & server_versions,const ParsedQuicVersionVector & negotiated_versions,std::string * error_details)571 QuicErrorCode CryptoUtils::ValidateServerHelloVersions(
572     const QuicVersionLabelVector& server_versions,
573     const ParsedQuicVersionVector& negotiated_versions,
574     std::string* error_details) {
575   if (!negotiated_versions.empty()) {
576     bool mismatch = server_versions.size() != negotiated_versions.size();
577     for (size_t i = 0; i < server_versions.size() && !mismatch; ++i) {
578       mismatch =
579           server_versions[i] != CreateQuicVersionLabel(negotiated_versions[i]);
580     }
581     // The server sent a list of supported versions, and the connection
582     // reports that there was a version negotiation during the handshake.
583     // Ensure that these two lists are identical.
584     if (mismatch) {
585       *error_details = absl::StrCat(
586           "Downgrade attack detected: ServerVersions(", server_versions.size(),
587           ")[", QuicVersionLabelVectorToString(server_versions, ",", 30),
588           "] NegotiatedVersions(", negotiated_versions.size(), ")[",
589           ParsedQuicVersionVectorToString(negotiated_versions, ",", 30), "]");
590       return QUIC_VERSION_NEGOTIATION_MISMATCH;
591     }
592   }
593   return QUIC_NO_ERROR;
594 }
595 
ValidateClientHello(const CryptoHandshakeMessage & client_hello,ParsedQuicVersion version,const ParsedQuicVersionVector & supported_versions,std::string * error_details)596 QuicErrorCode CryptoUtils::ValidateClientHello(
597     const CryptoHandshakeMessage& client_hello, ParsedQuicVersion version,
598     const ParsedQuicVersionVector& supported_versions,
599     std::string* error_details) {
600   if (client_hello.tag() != kCHLO) {
601     *error_details = "Bad tag";
602     return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
603   }
604 
605   // If the client's preferred version is not the version we are currently
606   // speaking, then the client went through a version negotiation.  In this
607   // case, we need to make sure that we actually do not support this version
608   // and that it wasn't a downgrade attack.
609   QuicVersionLabel client_version_label;
610   if (client_hello.GetVersionLabel(kVER, &client_version_label) !=
611       QUIC_NO_ERROR) {
612     *error_details = "client hello missing version list";
613     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
614   }
615   return ValidateClientHelloVersion(client_version_label, version,
616                                     supported_versions, error_details);
617 }
618 
ValidateClientHelloVersion(QuicVersionLabel client_version,ParsedQuicVersion connection_version,const ParsedQuicVersionVector & supported_versions,std::string * error_details)619 QuicErrorCode CryptoUtils::ValidateClientHelloVersion(
620     QuicVersionLabel client_version, ParsedQuicVersion connection_version,
621     const ParsedQuicVersionVector& supported_versions,
622     std::string* error_details) {
623   if (client_version != CreateQuicVersionLabel(connection_version)) {
624     // Check to see if |client_version| is actually on the supported versions
625     // list. If not, the server doesn't support that version and it's not a
626     // downgrade attack.
627     for (size_t i = 0; i < supported_versions.size(); ++i) {
628       if (client_version == CreateQuicVersionLabel(supported_versions[i])) {
629         *error_details = absl::StrCat(
630             "Downgrade attack detected: ClientVersion[",
631             QuicVersionLabelToString(client_version), "] ConnectionVersion[",
632             ParsedQuicVersionToString(connection_version),
633             "] SupportedVersions(", supported_versions.size(), ")[",
634             ParsedQuicVersionVectorToString(supported_versions, ",", 30), "]");
635         return QUIC_VERSION_NEGOTIATION_MISMATCH;
636       }
637     }
638   }
639   return QUIC_NO_ERROR;
640 }
641 
642 // static
ValidateChosenVersion(const QuicVersionLabel & version_information_chosen_version,const ParsedQuicVersion & session_version,std::string * error_details)643 bool CryptoUtils::ValidateChosenVersion(
644     const QuicVersionLabel& version_information_chosen_version,
645     const ParsedQuicVersion& session_version, std::string* error_details) {
646   if (version_information_chosen_version !=
647       CreateQuicVersionLabel(session_version)) {
648     *error_details = absl::StrCat(
649         "Detected version mismatch: version_information contained ",
650         QuicVersionLabelToString(version_information_chosen_version),
651         " instead of ", ParsedQuicVersionToString(session_version));
652     return false;
653   }
654   return true;
655 }
656 
657 // static
ValidateServerVersions(const QuicVersionLabelVector & version_information_other_versions,const ParsedQuicVersion & session_version,const ParsedQuicVersionVector & client_original_supported_versions,std::string * error_details)658 bool CryptoUtils::ValidateServerVersions(
659     const QuicVersionLabelVector& version_information_other_versions,
660     const ParsedQuicVersion& session_version,
661     const ParsedQuicVersionVector& client_original_supported_versions,
662     std::string* error_details) {
663   if (client_original_supported_versions.empty()) {
664     // We did not receive a version negotiation packet.
665     return true;
666   }
667   // Parse the server's other versions.
668   ParsedQuicVersionVector parsed_other_versions =
669       ParseQuicVersionLabelVector(version_information_other_versions);
670   // Find the first version that we originally supported that is listed in the
671   // server's other versions.
672   ParsedQuicVersion expected_version = ParsedQuicVersion::Unsupported();
673   for (const ParsedQuicVersion& client_version :
674        client_original_supported_versions) {
675     if (std::find(parsed_other_versions.begin(), parsed_other_versions.end(),
676                   client_version) != parsed_other_versions.end()) {
677       expected_version = client_version;
678       break;
679     }
680   }
681   if (expected_version != session_version) {
682     *error_details = absl::StrCat(
683         "Downgrade attack detected: used ",
684         ParsedQuicVersionToString(session_version), " but ServerVersions(",
685         version_information_other_versions.size(), ")[",
686         QuicVersionLabelVectorToString(version_information_other_versions, ",",
687                                        30),
688         "] ClientOriginalVersions(", client_original_supported_versions.size(),
689         ")[",
690         ParsedQuicVersionVectorToString(client_original_supported_versions, ",",
691                                         30),
692         "]");
693     return false;
694   }
695   return true;
696 }
697 
698 #define RETURN_STRING_LITERAL(x) \
699   case x:                        \
700     return #x
701 
702 // Returns the name of the HandshakeFailureReason as a char*
703 // static
HandshakeFailureReasonToString(HandshakeFailureReason reason)704 const char* CryptoUtils::HandshakeFailureReasonToString(
705     HandshakeFailureReason reason) {
706   switch (reason) {
707     RETURN_STRING_LITERAL(HANDSHAKE_OK);
708     RETURN_STRING_LITERAL(CLIENT_NONCE_UNKNOWN_FAILURE);
709     RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_FAILURE);
710     RETURN_STRING_LITERAL(CLIENT_NONCE_NOT_UNIQUE_FAILURE);
711     RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_ORBIT_FAILURE);
712     RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_TIME_FAILURE);
713     RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT);
714     RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_FAILURE);
715 
716     RETURN_STRING_LITERAL(SERVER_NONCE_DECRYPTION_FAILURE);
717     RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_FAILURE);
718     RETURN_STRING_LITERAL(SERVER_NONCE_NOT_UNIQUE_FAILURE);
719     RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_TIME_FAILURE);
720     RETURN_STRING_LITERAL(SERVER_NONCE_REQUIRED_FAILURE);
721 
722     RETURN_STRING_LITERAL(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
723     RETURN_STRING_LITERAL(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
724 
725     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_INVALID_FAILURE);
726     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE);
727     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_PARSE_FAILURE);
728     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE);
729     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE);
730     RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE);
731 
732     RETURN_STRING_LITERAL(INVALID_EXPECTED_LEAF_CERTIFICATE);
733     RETURN_STRING_LITERAL(MAX_FAILURE_REASON);
734   }
735   // Return a default value so that we return this when |reason| doesn't match
736   // any HandshakeFailureReason.. This can happen when the message by the peer
737   // (attacker) has invalid reason.
738   return "INVALID_HANDSHAKE_FAILURE_REASON";
739 }
740 
741 #undef RETURN_STRING_LITERAL  // undef for jumbo builds
742 
743 // static
EarlyDataReasonToString(ssl_early_data_reason_t reason)744 std::string CryptoUtils::EarlyDataReasonToString(
745     ssl_early_data_reason_t reason) {
746   const char* reason_string = SSL_early_data_reason_string(reason);
747   if (reason_string != nullptr) {
748     return std::string("ssl_early_data_") + reason_string;
749   }
750   QUIC_BUG_IF(quic_bug_12871_3,
751               reason < 0 || reason > ssl_early_data_reason_max_value)
752       << "Unknown ssl_early_data_reason_t " << reason;
753   return "unknown ssl_early_data_reason_t";
754 }
755 
756 // static
HashHandshakeMessage(const CryptoHandshakeMessage & message,Perspective)757 std::string CryptoUtils::HashHandshakeMessage(
758     const CryptoHandshakeMessage& message, Perspective /*perspective*/) {
759   std::string output;
760   const QuicData& serialized = message.GetSerialized();
761   uint8_t digest[SHA256_DIGEST_LENGTH];
762   SHA256(reinterpret_cast<const uint8_t*>(serialized.data()),
763          serialized.length(), digest);
764   output.assign(reinterpret_cast<const char*>(digest), sizeof(digest));
765   return output;
766 }
767 
768 // static
GetSSLCapabilities(const SSL * ssl,bssl::UniquePtr<uint8_t> * capabilities,size_t * capabilities_len)769 bool CryptoUtils::GetSSLCapabilities(const SSL* ssl,
770                                      bssl::UniquePtr<uint8_t>* capabilities,
771                                      size_t* capabilities_len) {
772   uint8_t* buffer;
773   bssl::ScopedCBB cbb;
774 
775   if (!CBB_init(cbb.get(), 128) ||
776       !SSL_serialize_capabilities(ssl, cbb.get()) ||
777       !CBB_finish(cbb.get(), &buffer, capabilities_len)) {
778     return false;
779   }
780 
781   *capabilities = bssl::UniquePtr<uint8_t>(buffer);
782   return true;
783 }
784 
785 // static
GenerateProofPayloadToBeSigned(absl::string_view chlo_hash,absl::string_view server_config)786 std::optional<std::string> CryptoUtils::GenerateProofPayloadToBeSigned(
787     absl::string_view chlo_hash, absl::string_view server_config) {
788   size_t payload_size = sizeof(kProofSignatureLabel) + sizeof(uint32_t) +
789                         chlo_hash.size() + server_config.size();
790   std::string payload;
791   payload.resize(payload_size);
792   QuicDataWriter payload_writer(payload_size, payload.data(),
793                                 quiche::Endianness::HOST_BYTE_ORDER);
794   bool success = payload_writer.WriteBytes(kProofSignatureLabel,
795                                            sizeof(kProofSignatureLabel)) &&
796                  payload_writer.WriteUInt32(chlo_hash.size()) &&
797                  payload_writer.WriteStringPiece(chlo_hash) &&
798                  payload_writer.WriteStringPiece(server_config);
799   if (!success) {
800     return std::nullopt;
801   }
802   return payload;
803 }
804 
805 }  // namespace quic
806