tttls1.3 0.2.19 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,9 @@ module TTTLS13
5
5
  INITIAL = 0
6
6
  EOF = -1
7
7
 
8
+ SUPPORTED_ECHCONFIG_VERSIONS = ["\xfe\x0d"].freeze
9
+ private_constant :SUPPORTED_ECHCONFIG_VERSIONS
10
+
8
11
  # rubocop: disable Metrics/ClassLength
9
12
  class Connection
10
13
  include Logging
@@ -45,7 +45,7 @@ module TTTLS13
45
45
  # @return [String]
46
46
  def encrypt(content, type)
47
47
  cipher = reset_cipher
48
- plaintext = content + type + "\x00" * @length_of_padding
48
+ plaintext = content + type + @length_of_padding.zeros
49
49
  cipher.auth_data = additional_data(plaintext.length)
50
50
  encrypted_data = cipher.update(plaintext) + cipher.final
51
51
  @sequence_number.succ
@@ -10,7 +10,7 @@ module TTTLS13
10
10
  class ConfigError < Error; end
11
11
 
12
12
  # Raised on received Error Alerts message or invalid message.
13
- # https://tools.ietf.org/html/rfc8446#section-6.2
13
+ # https://datatracker.ietf.org/doc/html/rfc8446#section-6.2
14
14
  # Terminated the connection, so you *cannot* recover from this exception.
15
15
  class ErrorAlerts < Error
16
16
  # @return [TTTLS13::Message::Alert]
@@ -0,0 +1,91 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ # NOTE: Hpke module is the adapter for ech_config using hpke-rb.
6
+ module Hpke
7
+ module KemId
8
+ # https://www.iana.org/assignments/hpke/hpke.xhtml#hpke-kem-ids
9
+ P_256_SHA256 = 0x0010
10
+ P_384_SHA384 = 0x0011
11
+ P_521_SHA512 = 0x0012
12
+ X25519_SHA256 = 0x0020
13
+ X448_SHA512 = 0x0021
14
+ end
15
+
16
+ def self.kem_id2dhkem(kem_id)
17
+ case kem_id
18
+ when KemId::P_256_SHA256
19
+ %i[p_256 sha256]
20
+ when KemId::P_384_SHA384
21
+ %i[p_384 sha384]
22
+ when KemId::P_521_SHA512
23
+ %i[p_521 sha512]
24
+ when KemId::X25519_SHA256
25
+ %i[x25519 sha256]
26
+ when KemId::X448_SHA512
27
+ %i[x448 sha512]
28
+ end
29
+ end
30
+
31
+ def self.kem_curve_name2dhkem(kem_curve_name)
32
+ case kem_curve_name
33
+ when :p_256
34
+ HPKE::DHKEM::EC::P_256
35
+ when :p_384
36
+ HPKE::DHKEM::EC::P_384
37
+ when :p_521
38
+ HPKE::DHKEM::EC::P_521
39
+ when :x25519
40
+ HPKE::DHKEM::X25519
41
+ when :x448
42
+ HPKE::DHKEM::X448
43
+ end
44
+ end
45
+
46
+ module KdfId
47
+ # https://www.iana.org/assignments/hpke/hpke.xhtml#hpke-kdf-ids
48
+ HKDF_SHA256 = 0x0001
49
+ HKDF_SHA384 = 0x0002
50
+ HKDF_SHA512 = 0x0003
51
+ end
52
+
53
+ def self.kdf_id2kdf_hash(kdf_id)
54
+ case kdf_id
55
+ when KdfId::HKDF_SHA256
56
+ :sha256
57
+ when KdfId::HKDF_SHA384
58
+ :sha384
59
+ when KdfId::HKDF_SHA512
60
+ :sha512
61
+ end
62
+ end
63
+
64
+ module AeadId
65
+ # https://www.iana.org/assignments/hpke/hpke.xhtml#hpke-aead-ids
66
+ AES_128_GCM = 0x0001
67
+ AES_256_GCM = 0x0002
68
+ CHACHA20_POLY1305 = 0x0003
69
+ end
70
+
71
+ def self.aead_id2overhead_len(aead_id)
72
+ case aead_id
73
+ when AeadId::AES_128_GCM, AeadId::CHACHA20_POLY1305
74
+ 16
75
+ when AeadId::AES_256_GCM
76
+ 32
77
+ end
78
+ end
79
+
80
+ def self.aead_id2aead_cipher(aead_id)
81
+ case aead_id
82
+ when AeadId::AES_128_GCM
83
+ :aes_128_gcm
84
+ when AeadId::AES_256_GCM
85
+ :aes_256_gcm
86
+ when AeadId::CHACHA20_POLY1305
87
+ :chacha20_poly1305
88
+ end
89
+ end
90
+ end
91
+ end
@@ -14,14 +14,14 @@ module TTTLS13
14
14
  @hash_len = CipherSuite.hash_len(cipher_suite)
15
15
  @key_len = CipherSuite.key_len(cipher_suite)
16
16
  @iv_len = CipherSuite.iv_len(cipher_suite)
17
- @psk = psk || "\x00" * @hash_len
17
+ @psk = psk || @hash_len.zeros
18
18
  @shared_secret = shared_secret
19
19
  @transcript = transcript
20
20
  end
21
21
 
22
22
  # @return [String]
23
23
  def early_salt
24
- "\x00" * @hash_len
24
+ @hash_len.zeros
25
25
  end
26
26
 
27
27
  # @return [String]
@@ -155,7 +155,7 @@ module TTTLS13
155
155
 
156
156
  # @return [String]
157
157
  def main_secret
158
- ikm = "\x00" * @hash_len
158
+ ikm = @hash_len.zeros
159
159
  hkdf_extract(ikm, main_salt)
160
160
  end
161
161
 
@@ -273,6 +273,74 @@ module TTTLS13
273
273
  def derive_secret(secret, label, context)
274
274
  self.class.hkdf_expand_label(secret, label, context, @hash_len, @digest)
275
275
  end
276
+
277
+ # @return [String]
278
+ def accept_confirmation
279
+ ch_inner_random = @transcript[CH].first.random
280
+ sh = @transcript[SH].first
281
+ sh = Message::ServerHello.new(
282
+ random: sh.random[...-8] + 8.zeros,
283
+ legacy_session_id_echo: sh.legacy_session_id_echo,
284
+ cipher_suite: sh.cipher_suite,
285
+ extensions: sh.extensions
286
+ )
287
+ transcript = @transcript.clone
288
+ transcript[SH] = [sh, sh.serialize]
289
+ transcript_ech_conf = transcript.hash(@digest, SH)
290
+
291
+ self.class.hkdf_expand_label(
292
+ hkdf_extract(ch_inner_random, ''),
293
+ 'ech accept confirmation',
294
+ transcript_ech_conf,
295
+ 8,
296
+ @digest
297
+ )
298
+ end
299
+
300
+ # @return [Boolean]
301
+ def accept_ech?
302
+ accept_confirmation == @transcript[SH].first.random[-8..]
303
+ end
304
+
305
+ # @return [String]
306
+ def hrr_accept_confirmation
307
+ ch1_inner_random = @transcript[CH1].first.random
308
+ hrr = @transcript[HRR].first
309
+ ech = Message::Extension::ECHHelloRetryRequest.new("\x00" * 8)
310
+ hrr = Message::ServerHello.new(
311
+ random: hrr.random,
312
+ legacy_session_id_echo: hrr.legacy_session_id_echo,
313
+ cipher_suite: hrr.cipher_suite,
314
+ extensions: hrr.extensions.merge(
315
+ Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => ech
316
+ )
317
+ )
318
+
319
+ # It then computes the transcript hash for the first ClientHelloInner,
320
+ # denoted ClientHelloInner1, up to and including the modified
321
+ # HelloRetryRequest.
322
+ #
323
+ # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-7.2.1-2
324
+ transcript = @transcript.clone
325
+ transcript[HRR] = [hrr, hrr.serialize]
326
+ transcript_hrr_ech_conf = transcript.hash(@digest, HRR)
327
+
328
+ self.class.hkdf_expand_label(
329
+ hkdf_extract(ch1_inner_random, ''),
330
+ 'hrr ech accept confirmation',
331
+ transcript_hrr_ech_conf,
332
+ 8,
333
+ @digest
334
+ )
335
+ end
336
+
337
+ # @return [Boolean]
338
+ def hrr_accept_ech?
339
+ hrr_ech = @transcript[HRR]
340
+ .first
341
+ .extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO]
342
+ hrr_accept_confirmation == hrr_ech.confirmation
343
+ end
276
344
  end
277
345
  # rubocop: enable Metrics/ClassLength
278
346
  end
@@ -36,7 +36,8 @@ module TTTLS13
36
36
  bad_certificate_status_response: "\x71",
37
37
  unknown_psk_identity: "\x73",
38
38
  certificate_required: "\x74",
39
- no_application_protocol: "\x78"
39
+ no_application_protocol: "\x78",
40
+ ech_required: "\x79"
40
41
  }.freeze
41
42
  # rubocop: enable Layout/HashAlignment
42
43
 
@@ -31,7 +31,8 @@ module TTTLS13
31
31
  ExtensionType::CERTIFICATE_AUTHORITIES,
32
32
  ExtensionType::POST_HANDSHAKE_AUTH,
33
33
  ExtensionType::SIGNATURE_ALGORITHMS_CERT,
34
- ExtensionType::KEY_SHARE
34
+ ExtensionType::KEY_SHARE,
35
+ ExtensionType::ENCRYPTED_CLIENT_HELLO
35
36
  ].freeze
36
37
  private_constant :APPEARABLE_CH_EXTENSIONS
37
38
 
@@ -15,7 +15,8 @@ module TTTLS13
15
15
  ExtensionType::CLIENT_CERTIFICATE_TYPE,
16
16
  ExtensionType::SERVER_CERTIFICATE_TYPE,
17
17
  ExtensionType::RECORD_SIZE_LIMIT,
18
- ExtensionType::EARLY_DATA
18
+ ExtensionType::EARLY_DATA,
19
+ ExtensionType::ENCRYPTED_CLIENT_HELLO
19
20
  ].freeze
20
21
  private_constant :APPEARABLE_EE_EXTENSIONS
21
22
 
@@ -19,7 +19,7 @@ module TTTLS13
19
19
  # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
20
20
  def initialize(protocol_name_list)
21
21
  @extension_type \
22
- = ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
22
+ = ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
23
23
  @protocol_name_list = protocol_name_list || []
24
24
  raise Error::ErrorAlerts, :internal_error \
25
25
  if @protocol_name_list.empty?
@@ -27,10 +27,9 @@ module TTTLS13
27
27
 
28
28
  # @return [String]
29
29
  def serialize
30
- binary = @protocol_name_list
31
- .map(&:prefix_uint8_length)
32
- .join
33
- .prefix_uint16_length
30
+ binary = @protocol_name_list.map(&:prefix_uint8_length)
31
+ .join
32
+ .prefix_uint16_length
34
33
 
35
34
  @extension_type + binary.prefix_uint16_length
36
35
  end
@@ -11,7 +11,7 @@ module TTTLS13
11
11
  # ZSTD = "\x00\x03" # UNSUPPORTED
12
12
  end
13
13
 
14
- # https://tools.ietf.org/html/rfc8879
14
+ # https://datatracker.ietf.org/doc/html/rfc8879
15
15
  class CompressCertificate
16
16
  attr_reader :extension_type
17
17
  attr_reader :algorithms
@@ -0,0 +1,241 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ HpkeSymmetricCipherSuite = \
7
+ ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite
8
+ module Message
9
+ module Extension
10
+ module ECHClientHelloType
11
+ OUTER = "\x00"
12
+ INNER = "\x01"
13
+ end
14
+
15
+ # NOTE:
16
+ # struct {
17
+ # ECHClientHelloType type;
18
+ # select (ECHClientHello.type) {
19
+ # case outer:
20
+ # HpkeSymmetricCipherSuite cipher_suite;
21
+ # uint8 config_id;
22
+ # opaque enc<0..2^16-1>;
23
+ # opaque payload<1..2^16-1>;
24
+ # case inner:
25
+ # Empty;
26
+ # };
27
+ # } ECHClientHello;
28
+ class ECHClientHello
29
+ attr_accessor :extension_type
30
+ attr_accessor :type
31
+ attr_accessor :cipher_suite
32
+ attr_accessor :config_id
33
+ attr_accessor :enc
34
+ attr_accessor :payload
35
+
36
+ # @param type [TTTLS13::Message::Extension::ECHClientHelloType]
37
+ # @param cipher_suite [HpkeSymmetricCipherSuite]
38
+ # @param config_id [Integer]
39
+ # @param enc [String]
40
+ # @param payload [String]
41
+ def initialize(type:,
42
+ cipher_suite: nil,
43
+ config_id: nil,
44
+ enc: nil,
45
+ payload: nil)
46
+ @extension_type = ExtensionType::ENCRYPTED_CLIENT_HELLO
47
+ @type = type
48
+ @cipher_suite = cipher_suite
49
+ raise Error::ErrorAlerts, :internal_error \
50
+ if @type == ECHClientHelloType::OUTER && \
51
+ !@cipher_suite.is_a?(HpkeSymmetricCipherSuite)
52
+
53
+ @config_id = config_id
54
+ @enc = enc
55
+ @payload = payload
56
+ end
57
+
58
+ # @raise [TTTLS13::Error::ErrorAlerts]
59
+ #
60
+ # @return [String]
61
+ def serialize
62
+ case @type
63
+ when ECHClientHelloType::OUTER
64
+ binary = @type + @cipher_suite.encode + @config_id.to_uint8 \
65
+ + @enc.prefix_uint16_length + @payload.prefix_uint16_length
66
+ when ECHClientHelloType::INNER
67
+ binary = @type
68
+ else
69
+ raise Error::ErrorAlerts, :internal_error
70
+ end
71
+
72
+ @extension_type + binary.prefix_uint16_length
73
+ end
74
+
75
+ # @param binary [String]
76
+ #
77
+ # @raise [TTTLS13::Error::ErrorAlerts]
78
+ #
79
+ # @return [TTTLS13::Message::Extensions::ECHClientHello]
80
+ def self.deserialize(binary)
81
+ raise Error::ErrorAlerts, :internal_error \
82
+ if binary.nil? || binary.empty?
83
+
84
+ case binary[0]
85
+ when ECHClientHelloType::OUTER
86
+ return deserialize_outer_ech(binary[1..])
87
+ when ECHClientHelloType::INNER
88
+ return deserialize_inner_ech(binary[1..])
89
+ end
90
+
91
+ raise Error::ErrorAlerts, :internal_error
92
+ end
93
+
94
+ class << self
95
+ private
96
+
97
+ # @param binary [String]
98
+ #
99
+ # @raise [TTTLS13::Error::ErrorAlerts]
100
+ #
101
+ # @return [TTTLS13::Message::Extensions::ECHClientHello]
102
+ def deserialize_outer_ech(binary)
103
+ raise Error::ErrorAlerts, :internal_error \
104
+ if binary.nil? || binary.length < 5
105
+
106
+ kdf_id = \
107
+ HpkeSymmetricCipherSuite::HpkeKdfId.decode(binary.slice(0, 2))
108
+ aead_id = \
109
+ HpkeSymmetricCipherSuite::HpkeAeadId.decode(binary.slice(2, 2))
110
+ cs = HpkeSymmetricCipherSuite.new(kdf_id, aead_id)
111
+ cid = Convert.bin2i(binary.slice(4, 1))
112
+ enc_len = Convert.bin2i(binary.slice(5, 2))
113
+ i = 7
114
+ raise Error::ErrorAlerts, :internal_error \
115
+ if i + enc_len > binary.length
116
+
117
+ enc = binary.slice(i, enc_len)
118
+ i += enc_len
119
+ raise Error::ErrorAlerts, :internal_error \
120
+ if i + 2 > binary.length
121
+
122
+ payload_len = Convert.bin2i(binary.slice(i, 2))
123
+ raise Error::ErrorAlerts, :internal_error \
124
+ if i + payload_len > binary.length
125
+
126
+ payload = binary.slice(i, payload_len)
127
+ ECHClientHello.new(
128
+ type: ECHClientHelloType::OUTER,
129
+ cipher_suite: cs,
130
+ config_id: cid,
131
+ enc: enc,
132
+ payload: payload
133
+ )
134
+ end
135
+
136
+ # @param binary [String]
137
+ #
138
+ # @raise [TTTLS13::Error::ErrorAlerts]
139
+ #
140
+ # @return [TTTLS13::Message::Extensions::ECHClientHello]
141
+ def deserialize_inner_ech(binary)
142
+ raise Error::ErrorAlerts, :internal_error unless binary.empty?
143
+
144
+ ECHClientHello.new(type: ECHClientHelloType::INNER)
145
+ end
146
+ end
147
+
148
+ # @return [TTTLS13::Message::Extensions::ECHClientHello]
149
+ def self.new_inner
150
+ ECHClientHello.new(type: ECHClientHelloType::INNER)
151
+ end
152
+
153
+ # @param cipher_suite [HpkeSymmetricCipherSuite]
154
+ # @param config_id [Integer]
155
+ # @param enc [String]
156
+ # @param payload [String]
157
+ #
158
+ # @return [TTTLS13::Message::Extensions::ECHClientHello]
159
+ def self.new_outer(cipher_suite:, config_id:, enc:, payload:)
160
+ ECHClientHello.new(
161
+ type: ECHClientHelloType::OUTER,
162
+ cipher_suite: cipher_suite,
163
+ config_id: config_id,
164
+ enc: enc,
165
+ payload: payload
166
+ )
167
+ end
168
+ end
169
+
170
+ # NOTE:
171
+ # struct {
172
+ # ECHConfigList retry_configs;
173
+ # } ECHEncryptedExtensions;
174
+ class ECHEncryptedExtensions
175
+ attr_accessor :extension_type
176
+ attr_accessor :retry_configs
177
+
178
+ # @param retry_configs [Array of ECHConfig]
179
+ def initialize(retry_configs)
180
+ @extension_type = ExtensionType::ENCRYPTED_CLIENT_HELLO
181
+ @retry_configs = retry_configs
182
+ end
183
+
184
+ # @return [String]
185
+ def serialize
186
+ @extension_type + @retry_configs.map(&:encode)
187
+ .join
188
+ .prefix_uint16_length
189
+ .prefix_uint16_length
190
+ end
191
+
192
+ # @param binary [String]
193
+ #
194
+ # @raise [TTTLS13::Error::ErrorAlerts]
195
+ #
196
+ # @return [TTTLS13::Message::Extensions::ECHEncryptedExtensions]
197
+ def self.deserialize(binary)
198
+ raise Error::ErrorAlerts, :decode_error \
199
+ if binary.nil? ||
200
+ binary.length != binary.slice(0, 2).unpack1('n') + 2
201
+
202
+ ECHEncryptedExtensions.new(
203
+ ECHConfig.decode_vectors(binary.slice(2..))
204
+ )
205
+ end
206
+ end
207
+
208
+ # NOTE:
209
+ # struct {
210
+ # opaque confirmation[8];
211
+ # } ECHHelloRetryRequest;
212
+ class ECHHelloRetryRequest
213
+ attr_accessor :extension_type
214
+ attr_accessor :confirmation
215
+
216
+ # @param confirmation [String]
217
+ def initialize(confirmation)
218
+ @extension_type = ExtensionType::ENCRYPTED_CLIENT_HELLO
219
+ @confirmation = confirmation
220
+ end
221
+
222
+ # @return [String]
223
+ def serialize
224
+ @extension_type + @confirmation.prefix_uint16_length
225
+ end
226
+
227
+ # @param binary [String]
228
+ #
229
+ # @raise [TTTLS13::Error::ErrorAlerts]
230
+ #
231
+ # @return [TTTLS13::Message::Extensions::ECHHelloRetryRequest]
232
+ def self.deserialize(binary)
233
+ raise Error::ErrorAlerts, :decode_error \
234
+ if binary.nil? || binary.length != 8
235
+
236
+ ECHHelloRetryRequest.new(binary)
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -15,7 +15,7 @@ module TTTLS13
15
15
  #
16
16
  # 00 00 00 00
17
17
  #
18
- # https://tools.ietf.org/html/rfc6066#section-3
18
+ # https://datatracker.ietf.org/doc/html/rfc6066#section-3
19
19
  class ServerName
20
20
  attr_reader :extension_type
21
21
  attr_reader :server_name
@@ -7,6 +7,7 @@ Dir[File.dirname(__FILE__) + '/extension/*.rb'].sort.each { |f| require f }
7
7
  module TTTLS13
8
8
  using Refinements
9
9
  module Message
10
+ # rubocop: disable Metrics/ClassLength
10
11
  class Extensions < Hash
11
12
  # @param extensions [Array of TTTLS13::Message::Extension::$Object]
12
13
  #
@@ -119,6 +120,7 @@ module TTTLS13
119
120
  # @raise [TTTLS13::Error::ErrorAlerts]
120
121
  #
121
122
  # @return [TTTLS13::Message::Extension::$Object, nil]
123
+ # rubocop: disable Metrics/AbcSize
122
124
  # rubocop: disable Metrics/CyclomaticComplexity
123
125
  # rubocop: disable Metrics/MethodLength
124
126
  # rubocop: disable Metrics/PerceivedComplexity
@@ -130,14 +132,12 @@ module TTTLS13
130
132
  Extension::ServerName.deserialize(binary)
131
133
  when ExtensionType::STATUS_REQUEST
132
134
  if msg_type == HandshakeType::CLIENT_HELLO
133
- return Extension::OCSPStatusRequest.deserialize(binary)
135
+ Extension::OCSPStatusRequest.deserialize(binary)
136
+ elsif msg_type == HandshakeType::CERTIFICATE
137
+ Extension::OCSPResponse.deserialize(binary)
138
+ else
139
+ Extension::UnknownExtension.deserialize(binary, extension_type)
134
140
  end
135
-
136
- if msg_type == HandshakeType::CERTIFICATE
137
- return Extension::OCSPResponse.deserialize(binary)
138
- end
139
-
140
- Extension::UnknownExtension.deserialize(binary, extension_type)
141
141
  when ExtensionType::SUPPORTED_GROUPS
142
142
  Extension::SupportedGroups.deserialize(binary)
143
143
  when ExtensionType::SIGNATURE_ALGORITHMS
@@ -162,14 +162,27 @@ module TTTLS13
162
162
  Extension::SignatureAlgorithmsCert.deserialize(binary)
163
163
  when ExtensionType::KEY_SHARE
164
164
  Extension::KeyShare.deserialize(binary, msg_type)
165
+ when ExtensionType::ENCRYPTED_CLIENT_HELLO
166
+ case msg_type
167
+ when HandshakeType::CLIENT_HELLO
168
+ Extension::ECHClientHello.deserialize(binary)
169
+ when HandshakeType::ENCRYPTED_EXTENSIONS
170
+ Extension::ECHEncryptedExtensions.deserialize(binary)
171
+ when HandshakeType::HELLO_RETRY_REQUEST
172
+ Extension::ECHHelloRetryRequest.deserialize(binary)
173
+ else
174
+ Extension::UnknownExtension.deserialize(binary, extension_type)
175
+ end
165
176
  else
166
177
  Extension::UnknownExtension.deserialize(binary, extension_type)
167
178
  end
168
179
  end
180
+ # rubocop: enable Metrics/AbcSize
169
181
  # rubocop: enable Metrics/CyclomaticComplexity
170
182
  # rubocop: enable Metrics/MethodLength
171
183
  # rubocop: enable Metrics/PerceivedComplexity
172
184
  end
173
185
  end
186
+ # rubocop: enable Metrics/ClassLength
174
187
  end
175
188
  end
@@ -3,7 +3,7 @@
3
3
  module TTTLS13
4
4
  using Refinements
5
5
  module Message
6
- # https://tools.ietf.org/html/rfc8449#section-4
6
+ # https://datatracker.ietf.org/doc/html/rfc8449#section-4
7
7
  DEFAULT_RECORD_SIZE_LIMIT = 2**14 + 1
8
8
 
9
9
  # rubocop: disable Metrics/ClassLength
@@ -17,7 +17,8 @@ module TTTLS13
17
17
  ExtensionType::COOKIE,
18
18
  ExtensionType::PASSWORD_SALT,
19
19
  ExtensionType::SUPPORTED_VERSIONS,
20
- ExtensionType::KEY_SHARE
20
+ ExtensionType::KEY_SHARE,
21
+ ExtensionType::ENCRYPTED_CLIENT_HELLO
21
22
  ].freeze
22
23
  private_constant :APPEARABLE_HRR_EXTENSIONS
23
24
 
@@ -61,7 +62,6 @@ module TTTLS13
61
62
  @cipher_suite = cipher_suite
62
63
  @legacy_compression_method = legacy_compression_method
63
64
  @extensions = extensions
64
- @hrr = (random == HRR_RANDOM)
65
65
  end
66
66
  # rubocop: enable Metrics/ParameterLists
67
67
 
@@ -108,10 +108,8 @@ module TTTLS13
108
108
  exs_bin = binary.slice(i, exs_len)
109
109
  if random == HRR_RANDOM
110
110
  msg_type = HandshakeType::HELLO_RETRY_REQUEST
111
- @hrr = true
112
111
  else
113
112
  msg_type = HandshakeType::SERVER_HELLO
114
- @hrr = false
115
113
  end
116
114
  extensions = Extensions.deserialize(exs_bin, msg_type)
117
115
  i += exs_len
@@ -132,7 +130,7 @@ module TTTLS13
132
130
 
133
131
  # @return [Boolean]
134
132
  def hrr?
135
- @hrr
133
+ @random == HRR_RANDOM
136
134
  end
137
135
 
138
136
  # @return [Boolean]
@@ -27,7 +27,7 @@ module TTTLS13
27
27
  HELLO_VERIFY_REQUEST = "\x03" # RESERVED
28
28
  NEW_SESSION_TICKET = "\x04"
29
29
  END_OF_EARLY_DATA = "\x05"
30
- HELLO_RETRY_REQUEST = "\x06" # RESERVED
30
+ HELLO_RETRY_REQUEST = "\x06"
31
31
  ENCRYPTED_EXTENSIONS = "\x08"
32
32
  CERTIFICATE = "\x0b"
33
33
  SERVER_KEY_EXCHANGE = "\x0c" # RESERVED
@@ -72,6 +72,8 @@ module TTTLS13
72
72
  POST_HANDSHAKE_AUTH = "\x00\x31"
73
73
  SIGNATURE_ALGORITHMS_CERT = "\x00\x32"
74
74
  KEY_SHARE = "\x00\x33"
75
+ # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-11.1
76
+ ENCRYPTED_CLIENT_HELLO = "\xfe\x0d"
75
77
  end
76
78
 
77
79
  DEFINED_EXTENSIONS = ExtensionType.constants.map do |c|
@@ -64,7 +64,7 @@ module TTTLS13
64
64
  # secp384r1 | | NIST P-384
65
65
  # secp521r1 | | NIST P-521
66
66
  #
67
- # https://tools.ietf.org/html/rfc4492#appendix-A
67
+ # https://datatracker.ietf.org/doc/html/rfc4492#appendix-A
68
68
  #
69
69
  # @param groups [Array of TTTLS13::Message::Extension::NamedGroup]
70
70
  #
@@ -136,7 +136,7 @@ module TTTLS13
136
136
  # v
137
137
  # CONNECTED
138
138
  #
139
- # https://tools.ietf.org/html/rfc8446#appendix-A.2
139
+ # https://datatracker.ietf.org/doc/html/rfc8446#appendix-A.2
140
140
  #
141
141
  # rubocop: disable Metrics/AbcSize
142
142
  # rubocop: disable Metrics/BlockLength