summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h
blob: 9195e3add82fb02a0a014eb31dc1789ab4843744 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Some helpers for quic crypto

#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_
#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_

#include <cstddef>
#include <cstdint>
#include <string>

#include "absl/strings/string_view.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_crypter.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"

namespace quic {

class QuicRandom;

class QUIC_EXPORT_PRIVATE CryptoUtils {
 public:
  CryptoUtils() = delete;

  // Diversification is a utility class that's used to act like a union type.
  // Values can be created by calling the functions like |NoDiversification|,
  // below.
  class QUIC_EXPORT_PRIVATE Diversification {
   public:
    enum Mode {
      NEVER,  // Key diversification will never be used. Forward secure
              // crypters will always use this mode.

      PENDING,  // Key diversification will happen when a nonce is later
                // received. This should only be used by clients initial
                // decrypters which are waiting on the divesification nonce
                // from the server.

      NOW,  // Key diversification will happen immediate based on the nonce.
            // This should only be used by servers initial encrypters.
    };

    Diversification(const Diversification& diversification) = default;

    static Diversification Never() { return Diversification(NEVER, nullptr); }
    static Diversification Pending() {
      return Diversification(PENDING, nullptr);
    }
    static Diversification Now(DiversificationNonce* nonce) {
      return Diversification(NOW, nonce);
    }

    Mode mode() const { return mode_; }
    DiversificationNonce* nonce() const {
      DCHECK_EQ(mode_, NOW);
      return nonce_;
    }

   private:
    Diversification(Mode mode, DiversificationNonce* nonce)
        : mode_(mode), nonce_(nonce) {}

    Mode mode_;
    DiversificationNonce* nonce_;
  };

  // InitializeCrypterSecrets derives the key and IV and header protection key
  // from the given packet protection secret |pp_secret| and sets those fields
  // on the given QuicCrypter |*crypter|.
  // This follows the derivation described in section 7.3 of RFC 8446, except
  // with the label prefix in HKDF-Expand-Label changed from "tls13 " to "quic "
  // as described in draft-ietf-quic-tls-14, section 5.1.
  static void InitializeCrypterSecrets(const EVP_MD* prf,
                                       const std::vector<uint8_t>& pp_secret,
                                       QuicCrypter* crypter);

  // Derives the key and IV from the packet protection secret and sets those
  // fields on the given QuicCrypter |*crypter|, but does not set the header
  // protection key. GenerateHeaderProtectionKey/SetHeaderProtectionKey must be
  // called before using |crypter|.
  static void SetKeyAndIV(const EVP_MD* prf,
                          const std::vector<uint8_t>& pp_secret,
                          QuicCrypter* crypter);

  // Derives the header protection key from the packet protection secret.
  static std::vector<uint8_t> GenerateHeaderProtectionKey(
      const EVP_MD* prf,
      const std::vector<uint8_t>& pp_secret,
      size_t out_len);

  // Given a secret for key phase n, return the secret for phase n+1.
  static std::vector<uint8_t> GenerateNextKeyPhaseSecret(
      const EVP_MD* prf,
      const std::vector<uint8_t>& current_secret);

  // IETF QUIC encrypts ENCRYPTION_INITIAL messages with a version-specific key
  // (to prevent network observers that are not aware of that QUIC version from
  // making decisions based on the TLS handshake). This packet protection secret
  // is derived from the connection ID in the client's Initial packet.
  //
  // This function takes that |connection_id| and creates the encrypter and
  // decrypter (put in |*crypters|) to use for this packet protection, as well
  // as setting the key and IV on those crypters. For older versions of QUIC
  // that do not use the new IETF style ENCRYPTION_INITIAL obfuscators, this
  // function puts a NullEncrypter and NullDecrypter in |*crypters|.
  static void CreateInitialObfuscators(Perspective perspective,
                                       ParsedQuicVersion version,
                                       QuicConnectionId connection_id,
                                       CrypterPair* crypters);

  // IETF QUIC Retry packets carry a retry integrity tag to detect packet
  // corruption and make it harder for an attacker to spoof. This function
  // checks whether a given retry packet is valid.
  static bool ValidateRetryIntegrityTag(ParsedQuicVersion version,
                                        QuicConnectionId original_connection_id,
                                        absl::string_view retry_without_tag,
                                        absl::string_view integrity_tag);

  // Generates the connection nonce. The nonce is formed as:
  //   <4 bytes> current time
  //   <8 bytes> |orbit| (or random if |orbit| is empty)
  //   <20 bytes> random
  static void GenerateNonce(QuicWallTime now,
                            QuicRandom* random_generator,
                            absl::string_view orbit,
                            std::string* nonce);

  // DeriveKeys populates |crypters->encrypter|, |crypters->decrypter|, and
  // |subkey_secret| (optional -- may be null) given the contents of
  // |premaster_secret|, |client_nonce|, |server_nonce| and |hkdf_input|. |aead|
  // determines which cipher will be used. |perspective| controls whether the
  // server's keys are assigned to |encrypter| or |decrypter|. |server_nonce| is
  // optional and, if non-empty, is mixed into the key derivation.
  // |subkey_secret| will have the same length as |premaster_secret|.
  //
  // If |pre_shared_key| is non-empty, it is incorporated into the key
  // derivation parameters.  If it is empty, the key derivation is unaltered.
  //
  // If the mode of |diversification| is NEVER, the the crypters will be
  // configured to never perform key diversification. If the mode is
  // NOW (which is only for servers, then the encrypter will be keyed via a
  // two-step process that uses the nonce from |diversification|.
  // If the mode is PENDING (which is only for servres), then the
  // decrypter will only be keyed to a preliminary state: a call to
  // |SetDiversificationNonce| with a diversification nonce will be needed to
  // complete keying.
  static bool 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);

  // Performs key extraction to derive a new secret of |result_len| bytes
  // dependent on |subkey_secret|, |label|, and |context|. Returns false if the
  // parameters are invalid (e.g. |label| contains null bytes); returns true on
  // success.
  static bool ExportKeyingMaterial(absl::string_view subkey_secret,
                                   absl::string_view label,
                                   absl::string_view context,
                                   size_t result_len,
                                   std::string* result);

  // Computes the FNV-1a hash of the provided DER-encoded cert for use in the
  // XLCT tag.
  static uint64_t ComputeLeafCertHash(absl::string_view cert);

  // Validates that |server_hello| is actually an SHLO message and that it is
  // not part of a downgrade attack.
  //
  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
  // code and sets |error_details|.
  static QuicErrorCode ValidateServerHello(
      const CryptoHandshakeMessage& server_hello,
      const ParsedQuicVersionVector& negotiated_versions,
      std::string* error_details);

  // Validates that the |server_versions| received do not indicate that the
  // ServerHello is part of a downgrade attack. |negotiated_versions| must
  // contain the list of versions received in the server's version negotiation
  // packet (or be empty if no such packet was received).
  //
  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
  // code and sets |error_details|.
  static QuicErrorCode ValidateServerHelloVersions(
      const QuicVersionLabelVector& server_versions,
      const ParsedQuicVersionVector& negotiated_versions,
      std::string* error_details);

  // Validates that |client_hello| is actually a CHLO and that this is not part
  // of a downgrade attack.
  // This includes verifiying versions and detecting downgrade attacks.
  //
  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
  // code and sets |error_details|.
  static QuicErrorCode ValidateClientHello(
      const CryptoHandshakeMessage& client_hello,
      ParsedQuicVersion version,
      const ParsedQuicVersionVector& supported_versions,
      std::string* error_details);

  // Validates that the |client_version| received does not indicate that a
  // downgrade attack has occurred. |connection_version| is the version of the
  // QuicConnection, and |supported_versions| is all versions that that
  // QuicConnection supports.
  //
  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
  // code and sets |error_details|.
  static QuicErrorCode ValidateClientHelloVersion(
      QuicVersionLabel client_version,
      ParsedQuicVersion connection_version,
      const ParsedQuicVersionVector& supported_versions,
      std::string* error_details);

  // Returns the name of the HandshakeFailureReason as a char*
  static const char* HandshakeFailureReasonToString(
      HandshakeFailureReason reason);

  // Returns the name of an ssl_early_data_reason_t as a char*
  static std::string EarlyDataReasonToString(ssl_early_data_reason_t reason);

  // Returns a hash of the serialized |message|.
  static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message,
                                          Perspective perspective);
};

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_