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
|
// 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 "third_party/boringssl/src/include/openssl/evp.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_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.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_;
};
// SetKeyAndIV derives the key and IV 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 SetKeyAndIV(const EVP_MD* prf,
const std::vector<uint8_t>& pp_secret,
QuicCrypter* crypter);
// 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);
// 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,
QuicStringPiece 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,
QuicStringPiece premaster_secret,
QuicTag aead,
QuicStringPiece client_nonce,
QuicStringPiece server_nonce,
QuicStringPiece 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(QuicStringPiece subkey_secret,
QuicStringPiece label,
QuicStringPiece 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(QuicStringPiece 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 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_
|