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