xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/crypto_utils.h (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 // Some helpers for quic crypto
6 
7 #ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_
8 #define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_
9 
10 #include <cstddef>
11 #include <cstdint>
12 #include <string>
13 
14 #include "absl/strings/string_view.h"
15 #include "openssl/evp.h"
16 #include "openssl/ssl.h"
17 #include "quiche/quic/core/crypto/crypto_handshake.h"
18 #include "quiche/quic/core/crypto/crypto_handshake_message.h"
19 #include "quiche/quic/core/crypto/crypto_protocol.h"
20 #include "quiche/quic/core/crypto/quic_crypter.h"
21 #include "quiche/quic/core/crypto/quic_random.h"
22 #include "quiche/quic/core/quic_connection_id.h"
23 #include "quiche/quic/core/quic_packets.h"
24 #include "quiche/quic/core/quic_time.h"
25 #include "quiche/quic/core/quic_versions.h"
26 #include "quiche/quic/platform/api/quic_export.h"
27 
28 namespace quic {
29 
30 class QUICHE_EXPORT CryptoUtils {
31  public:
32   CryptoUtils() = delete;
33 
34   // Diversification is a utility class that's used to act like a union type.
35   // Values can be created by calling the functions like |NoDiversification|,
36   // below.
37   class QUICHE_EXPORT Diversification {
38    public:
39     enum Mode {
40       NEVER,  // Key diversification will never be used. Forward secure
41               // crypters will always use this mode.
42 
43       PENDING,  // Key diversification will happen when a nonce is later
44                 // received. This should only be used by clients initial
45                 // decrypters which are waiting on the divesification nonce
46                 // from the server.
47 
48       NOW,  // Key diversification will happen immediate based on the nonce.
49             // This should only be used by servers initial encrypters.
50     };
51 
52     Diversification(const Diversification& diversification) = default;
53 
Never()54     static Diversification Never() { return Diversification(NEVER, nullptr); }
Pending()55     static Diversification Pending() {
56       return Diversification(PENDING, nullptr);
57     }
Now(DiversificationNonce * nonce)58     static Diversification Now(DiversificationNonce* nonce) {
59       return Diversification(NOW, nonce);
60     }
61 
mode()62     Mode mode() const { return mode_; }
nonce()63     DiversificationNonce* nonce() const {
64       QUICHE_DCHECK_EQ(mode_, NOW);
65       return nonce_;
66     }
67 
68    private:
Diversification(Mode mode,DiversificationNonce * nonce)69     Diversification(Mode mode, DiversificationNonce* nonce)
70         : mode_(mode), nonce_(nonce) {}
71 
72     Mode mode_;
73     DiversificationNonce* nonce_;
74   };
75 
76   // InitializeCrypterSecrets derives the key and IV and header protection key
77   // from the given packet protection secret |pp_secret| and sets those fields
78   // on the given QuicCrypter |*crypter|.
79   // This follows the derivation described in section 7.3 of RFC 8446, except
80   // with the label prefix in HKDF-Expand-Label changed from "tls13 " to "quic "
81   // as described in draft-ietf-quic-tls-14, section 5.1, or "quicv2 " as
82   // described in draft-ietf-quic-v2-01.
83   static void InitializeCrypterSecrets(const EVP_MD* prf,
84                                        const std::vector<uint8_t>& pp_secret,
85                                        const ParsedQuicVersion& version,
86                                        QuicCrypter* crypter);
87 
88   // Derives the key and IV from the packet protection secret and sets those
89   // fields on the given QuicCrypter |*crypter|, but does not set the header
90   // protection key. GenerateHeaderProtectionKey/SetHeaderProtectionKey must be
91   // called before using |crypter|.
92   static void SetKeyAndIV(const EVP_MD* prf,
93                           absl::Span<const uint8_t> pp_secret,
94                           const ParsedQuicVersion& version,
95                           QuicCrypter* crypter);
96 
97   // Derives the header protection key from the packet protection secret.
98   static std::vector<uint8_t> GenerateHeaderProtectionKey(
99       const EVP_MD* prf, absl::Span<const uint8_t> pp_secret,
100       const ParsedQuicVersion& version, size_t out_len);
101 
102   // Given a secret for key phase n, return the secret for phase n+1.
103   static std::vector<uint8_t> GenerateNextKeyPhaseSecret(
104       const EVP_MD* prf, const ParsedQuicVersion& version,
105       const std::vector<uint8_t>& current_secret);
106 
107   // IETF QUIC encrypts ENCRYPTION_INITIAL messages with a version-specific key
108   // (to prevent network observers that are not aware of that QUIC version from
109   // making decisions based on the TLS handshake). This packet protection secret
110   // is derived from the connection ID in the client's Initial packet.
111   //
112   // This function takes that |connection_id| and creates the encrypter and
113   // decrypter (put in |*crypters|) to use for this packet protection, as well
114   // as setting the key and IV on those crypters. For older versions of QUIC
115   // that do not use the new IETF style ENCRYPTION_INITIAL obfuscators, this
116   // function puts a NullEncrypter and NullDecrypter in |*crypters|.
117   static void CreateInitialObfuscators(Perspective perspective,
118                                        ParsedQuicVersion version,
119                                        QuicConnectionId connection_id,
120                                        CrypterPair* crypters);
121 
122   // IETF QUIC Retry packets carry a retry integrity tag to detect packet
123   // corruption and make it harder for an attacker to spoof. This function
124   // checks whether a given retry packet is valid.
125   static bool ValidateRetryIntegrityTag(ParsedQuicVersion version,
126                                         QuicConnectionId original_connection_id,
127                                         absl::string_view retry_without_tag,
128                                         absl::string_view integrity_tag);
129 
130   // Generates the connection nonce. The nonce is formed as:
131   //   <4 bytes> current time
132   //   <8 bytes> |orbit| (or random if |orbit| is empty)
133   //   <20 bytes> random
134   static void GenerateNonce(QuicWallTime now, QuicRandom* random_generator,
135                             absl::string_view orbit, std::string* nonce);
136 
137   // DeriveKeys populates |crypters->encrypter|, |crypters->decrypter|, and
138   // |subkey_secret| (optional -- may be null) given the contents of
139   // |premaster_secret|, |client_nonce|, |server_nonce| and |hkdf_input|. |aead|
140   // determines which cipher will be used. |perspective| controls whether the
141   // server's keys are assigned to |encrypter| or |decrypter|. |server_nonce| is
142   // optional and, if non-empty, is mixed into the key derivation.
143   // |subkey_secret| will have the same length as |premaster_secret|.
144   //
145   // If |pre_shared_key| is non-empty, it is incorporated into the key
146   // derivation parameters.  If it is empty, the key derivation is unaltered.
147   //
148   // If the mode of |diversification| is NEVER, the the crypters will be
149   // configured to never perform key diversification. If the mode is
150   // NOW (which is only for servers, then the encrypter will be keyed via a
151   // two-step process that uses the nonce from |diversification|.
152   // If the mode is PENDING (which is only for servres), then the
153   // decrypter will only be keyed to a preliminary state: a call to
154   // |SetDiversificationNonce| with a diversification nonce will be needed to
155   // complete keying.
156   static bool DeriveKeys(const ParsedQuicVersion& version,
157                          absl::string_view premaster_secret, QuicTag aead,
158                          absl::string_view client_nonce,
159                          absl::string_view server_nonce,
160                          absl::string_view pre_shared_key,
161                          const std::string& hkdf_input, Perspective perspective,
162                          Diversification diversification, CrypterPair* crypters,
163                          std::string* subkey_secret);
164 
165   // Computes the FNV-1a hash of the provided DER-encoded cert for use in the
166   // XLCT tag.
167   static uint64_t ComputeLeafCertHash(absl::string_view cert);
168 
169   // Validates that |server_hello| is actually an SHLO message and that it is
170   // not part of a downgrade attack.
171   //
172   // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
173   // code and sets |error_details|.
174   static QuicErrorCode ValidateServerHello(
175       const CryptoHandshakeMessage& server_hello,
176       const ParsedQuicVersionVector& negotiated_versions,
177       std::string* error_details);
178 
179   // Validates that the |server_versions| received do not indicate that the
180   // ServerHello is part of a downgrade attack. |negotiated_versions| must
181   // contain the list of versions received in the server's version negotiation
182   // packet (or be empty if no such packet was received).
183   //
184   // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
185   // code and sets |error_details|.
186   static QuicErrorCode ValidateServerHelloVersions(
187       const QuicVersionLabelVector& server_versions,
188       const ParsedQuicVersionVector& negotiated_versions,
189       std::string* error_details);
190 
191   // Validates that |client_hello| is actually a CHLO and that this is not part
192   // of a downgrade attack.
193   // This includes verifiying versions and detecting downgrade attacks.
194   //
195   // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
196   // code and sets |error_details|.
197   static QuicErrorCode ValidateClientHello(
198       const CryptoHandshakeMessage& client_hello, ParsedQuicVersion version,
199       const ParsedQuicVersionVector& supported_versions,
200       std::string* error_details);
201 
202   // Validates that the |client_version| received does not indicate that a
203   // downgrade attack has occurred. |connection_version| is the version of the
204   // QuicConnection, and |supported_versions| is all versions that that
205   // QuicConnection supports.
206   //
207   // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
208   // code and sets |error_details|.
209   static QuicErrorCode ValidateClientHelloVersion(
210       QuicVersionLabel client_version, ParsedQuicVersion connection_version,
211       const ParsedQuicVersionVector& supported_versions,
212       std::string* error_details);
213 
214   // Validates that the chosen version from the version_information matches the
215   // version from the session. Returns true if they match, otherwise returns
216   // false and fills in |error_details|.
217   static bool ValidateChosenVersion(
218       const QuicVersionLabel& version_information_chosen_version,
219       const ParsedQuicVersion& session_version, std::string* error_details);
220 
221   // Validates that there was no downgrade attack involving a version
222   // negotiation packet. This verifies that if the client was initially
223   // configured with |client_original_supported_versions| and it had received a
224   // version negotiation packet with |version_information_other_versions|, then
225   // it would have selected |session_version|. Returns true if they match (or if
226   // |client_original_supported_versions| is empty indicating no version
227   // negotiation packet was received), otherwise returns
228   // false and fills in |error_details|.
229   static bool ValidateServerVersions(
230       const QuicVersionLabelVector& version_information_other_versions,
231       const ParsedQuicVersion& session_version,
232       const ParsedQuicVersionVector& client_original_supported_versions,
233       std::string* error_details);
234 
235   // Returns the name of the HandshakeFailureReason as a char*
236   static const char* HandshakeFailureReasonToString(
237       HandshakeFailureReason reason);
238 
239   // Returns the name of an ssl_early_data_reason_t as a char*
240   static std::string EarlyDataReasonToString(ssl_early_data_reason_t reason);
241 
242   // Returns a hash of the serialized |message|.
243   static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message,
244                                           Perspective perspective);
245 
246   // Wraps SSL_serialize_capabilities. Return nullptr if failed.
247   static bool GetSSLCapabilities(const SSL* ssl,
248                                  bssl::UniquePtr<uint8_t>* capabilities,
249                                  size_t* capabilities_len);
250 
251   // Computes the contents of a binary message that is signed inside QUIC Crypto
252   // protocol using the certificate key.
253   static std::optional<std::string> GenerateProofPayloadToBeSigned(
254       absl::string_view chlo_hash, absl::string_view server_config);
255 };
256 
257 }  // namespace quic
258 
259 #endif  // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_
260