tttls1.3 0.2.19 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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