tttls1.3 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/example/helper.rb +21 -0
- data/example/https_client_using_0rtt.rb +1 -1
- data/example/https_server.rb +14 -1
- data/lib/tttls1.3/client.rb +205 -418
- data/lib/tttls1.3/connection.rb +21 -362
- data/lib/tttls1.3/ech.rb +410 -0
- data/lib/tttls1.3/endpoint.rb +276 -0
- data/lib/tttls1.3/message/certificate_verify.rb +1 -1
- data/lib/tttls1.3/message/extension/ech.rb +12 -10
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +2 -2
- data/lib/tttls1.3/message/extension/supported_versions.rb +3 -3
- data/lib/tttls1.3/message/extension/unknown_extension.rb +2 -2
- data/lib/tttls1.3/server.rb +125 -63
- data/lib/tttls1.3/utils.rb +37 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +2 -1
- data/spec/client_spec.rb +21 -60
- data/spec/ech_spec.rb +39 -0
- data/spec/{connection_spec.rb → endpoint_spec.rb} +41 -49
- data/spec/server_spec.rb +12 -12
- metadata +7 -6
- data/lib/tttls1.3/hpke.rb +0 -91
data/lib/tttls1.3/client.rb
CHANGED
@@ -58,8 +58,6 @@ module TTTLS13
|
|
58
58
|
alpn: nil,
|
59
59
|
process_new_session_ticket: nil,
|
60
60
|
ticket: nil,
|
61
|
-
# @deprecated Please use `resumption_secret` instead
|
62
|
-
resumption_master_secret: nil,
|
63
61
|
resumption_secret: nil,
|
64
62
|
psk_cipher_suite: nil,
|
65
63
|
ticket_nonce: nil,
|
@@ -80,36 +78,29 @@ module TTTLS13
|
|
80
78
|
STANDARD_CLIENT_ECH_HPKE_SYMMETRIC_CIPHER_SUITES = [
|
81
79
|
HpkeSymmetricCipherSuite.new(
|
82
80
|
HpkeSymmetricCipherSuite::HpkeKdfId.new(
|
83
|
-
|
81
|
+
Ech::KdfId::HKDF_SHA256
|
84
82
|
),
|
85
83
|
HpkeSymmetricCipherSuite::HpkeAeadId.new(
|
86
|
-
|
84
|
+
Ech::AeadId::AES_128_GCM
|
87
85
|
)
|
88
86
|
)
|
89
87
|
].freeze
|
90
88
|
# rubocop: disable Metrics/ClassLength
|
91
|
-
class Client
|
89
|
+
class Client
|
90
|
+
include Logging
|
91
|
+
|
92
92
|
HpkeSymmetricCipherSuit = \
|
93
93
|
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite
|
94
94
|
|
95
|
+
attr_reader :transcript
|
96
|
+
|
95
97
|
# @param socket [Socket]
|
96
98
|
# @param hostname [String]
|
97
99
|
# @param settings [Hash]
|
98
100
|
def initialize(socket, hostname, **settings)
|
99
|
-
|
100
|
-
|
101
|
-
@endpoint = :client
|
101
|
+
@connection = Connection.new(socket, :client)
|
102
102
|
@hostname = hostname
|
103
103
|
@settings = DEFAULT_CLIENT_SETTINGS.merge(settings)
|
104
|
-
# NOTE: backward compatibility
|
105
|
-
if @settings[:resumption_secret].nil? &&
|
106
|
-
!@settings[:resumption_master_secret].nil?
|
107
|
-
@settings[:resumption_secret] =
|
108
|
-
@settings.delete(:resumption_master_secret) \
|
109
|
-
end
|
110
|
-
raise Error::ConfigError if @settings[:resumption_secret] !=
|
111
|
-
@settings[:resumption_master_secret]
|
112
|
-
|
113
104
|
logger.level = @settings[:loglevel]
|
114
105
|
|
115
106
|
@early_data = ''
|
@@ -159,7 +150,7 @@ module TTTLS13
|
|
159
150
|
# rubocop: disable Metrics/MethodLength
|
160
151
|
# rubocop: disable Metrics/PerceivedComplexity
|
161
152
|
def connect
|
162
|
-
transcript = Transcript.new
|
153
|
+
@transcript = Transcript.new
|
163
154
|
key_schedule = nil # TTTLS13::KeySchedule
|
164
155
|
psk = nil
|
165
156
|
priv_keys = {} # Hash of NamedGroup => OpenSSL::PKey::$Object
|
@@ -173,7 +164,7 @@ module TTTLS13
|
|
173
164
|
psk: psk,
|
174
165
|
shared_secret: nil,
|
175
166
|
cipher_suite: @settings[:psk_cipher_suite],
|
176
|
-
transcript: transcript
|
167
|
+
transcript: @transcript
|
177
168
|
)
|
178
169
|
end
|
179
170
|
|
@@ -183,7 +174,7 @@ module TTTLS13
|
|
183
174
|
sslkeylogfile = nil # TTTLS13::SslKeyLogFile::Writer
|
184
175
|
ch1_outer = nil # TTTLS13::Message::ClientHello for rejected ECH
|
185
176
|
ch_outer = nil # TTTLS13::Message::ClientHello for rejected ECH
|
186
|
-
ech_state = nil # TTTLS13::
|
177
|
+
ech_state = nil # TTTLS13::EchState for ECH with HRR
|
187
178
|
unless @settings[:sslkeylogfile].nil?
|
188
179
|
begin
|
189
180
|
sslkeylogfile = SslKeyLogFile::Writer.new(@settings[:sslkeylogfile])
|
@@ -193,9 +184,9 @@ module TTTLS13
|
|
193
184
|
end
|
194
185
|
end
|
195
186
|
|
196
|
-
@state = ClientState::START
|
187
|
+
@connection.state = ClientState::START
|
197
188
|
loop do
|
198
|
-
case @state
|
189
|
+
case @connection.state
|
199
190
|
when ClientState::START
|
200
191
|
logger.debug('ClientState::START')
|
201
192
|
|
@@ -205,76 +196,77 @@ module TTTLS13
|
|
205
196
|
ch_outer = ch
|
206
197
|
# use ClientHelloInner messages for the transcript hash
|
207
198
|
ch = inner.nil? ? ch : inner
|
208
|
-
transcript[CH] = [ch, ch.serialize]
|
209
|
-
send_ccs if @settings[:compatibility_mode]
|
199
|
+
@transcript[CH] = [ch, ch.serialize]
|
200
|
+
@connection.send_ccs if @settings[:compatibility_mode]
|
210
201
|
if use_early_data?
|
211
|
-
e_wcipher = gen_cipher(
|
202
|
+
e_wcipher = Endpoint.gen_cipher(
|
212
203
|
@settings[:psk_cipher_suite],
|
213
204
|
key_schedule.early_data_write_key,
|
214
205
|
key_schedule.early_data_write_iv
|
215
206
|
)
|
216
207
|
sslkeylogfile&.write_client_early_traffic_secret(
|
217
|
-
transcript[CH].first.random,
|
208
|
+
@transcript[CH].first.random,
|
218
209
|
key_schedule.client_early_traffic_secret
|
219
210
|
)
|
220
211
|
send_early_data(e_wcipher)
|
221
212
|
end
|
222
213
|
|
223
|
-
@state = ClientState::WAIT_SH
|
214
|
+
@connection.state = ClientState::WAIT_SH
|
224
215
|
when ClientState::WAIT_SH
|
225
216
|
logger.debug('ClientState::WAIT_SH')
|
226
217
|
|
227
|
-
sh, = transcript[SH] = recv_server_hello
|
218
|
+
sh, = @transcript[SH] = recv_server_hello
|
228
219
|
|
229
220
|
# downgrade protection
|
230
221
|
if !sh.negotiated_tls_1_3? && sh.downgraded?
|
231
|
-
terminate(:illegal_parameter)
|
222
|
+
@connection.terminate(:illegal_parameter)
|
232
223
|
# support only TLS 1.3
|
233
224
|
elsif !sh.negotiated_tls_1_3?
|
234
|
-
terminate(:protocol_version)
|
225
|
+
@connection.terminate(:protocol_version)
|
235
226
|
end
|
236
227
|
|
237
228
|
# validate parameters
|
238
|
-
terminate(:illegal_parameter) \
|
229
|
+
@connection.terminate(:illegal_parameter) \
|
239
230
|
unless sh.appearable_extensions?
|
240
|
-
terminate(:illegal_parameter) \
|
231
|
+
@connection.terminate(:illegal_parameter) \
|
241
232
|
unless sh.legacy_compression_method == "\x00"
|
242
233
|
|
243
234
|
# validate sh using ch
|
244
|
-
ch, = transcript[CH]
|
245
|
-
terminate(:illegal_parameter) \
|
235
|
+
ch, = @transcript[CH]
|
236
|
+
@connection.terminate(:illegal_parameter) \
|
246
237
|
unless sh.legacy_version == ch.legacy_version
|
247
|
-
terminate(:illegal_parameter) \
|
238
|
+
@connection.terminate(:illegal_parameter) \
|
248
239
|
unless sh.legacy_session_id_echo == ch.legacy_session_id
|
249
|
-
terminate(:illegal_parameter) \
|
240
|
+
@connection.terminate(:illegal_parameter) \
|
250
241
|
unless ch.cipher_suites.include?(sh.cipher_suite)
|
251
|
-
terminate(:unsupported_extension) \
|
242
|
+
@connection.terminate(:unsupported_extension) \
|
252
243
|
unless (sh.extensions.keys - ch.extensions.keys).empty?
|
253
244
|
|
254
245
|
# validate sh using hrr
|
255
|
-
if transcript.include?(HRR)
|
256
|
-
hrr, = transcript[HRR]
|
257
|
-
terminate(:illegal_parameter) \
|
246
|
+
if @transcript.include?(HRR)
|
247
|
+
hrr, = @transcript[HRR]
|
248
|
+
@connection.terminate(:illegal_parameter) \
|
258
249
|
unless sh.cipher_suite == hrr.cipher_suite
|
259
250
|
|
260
251
|
sh_sv = sh.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
|
261
252
|
hrr_sv = hrr.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
|
262
|
-
terminate(:illegal_parameter) \
|
253
|
+
@connection.terminate(:illegal_parameter) \
|
263
254
|
unless sh_sv.versions == hrr_sv.versions
|
264
255
|
end
|
265
256
|
|
266
257
|
# handling HRR
|
267
258
|
if sh.hrr?
|
268
|
-
terminate(:unexpected_message)
|
259
|
+
@connection.terminate(:unexpected_message) \
|
260
|
+
if @transcript.include?(HRR)
|
269
261
|
|
270
|
-
ch1, = transcript[CH1] = transcript.delete(CH)
|
271
|
-
hrr, = transcript[HRR] = transcript.delete(SH)
|
262
|
+
ch1, = @transcript[CH1] = @transcript.delete(CH)
|
263
|
+
hrr, = @transcript[HRR] = @transcript.delete(SH)
|
272
264
|
ch1_outer = ch_outer
|
273
265
|
ch_outer = nil
|
274
266
|
|
275
267
|
# validate cookie
|
276
268
|
diff_sets = sh.extensions.keys - ch1.extensions.keys
|
277
|
-
terminate(:unsupported_extension) \
|
269
|
+
@connection.terminate(:unsupported_extension) \
|
278
270
|
unless (diff_sets - [Message::ExtensionType::COOKIE]).empty?
|
279
271
|
|
280
272
|
# validate key_share
|
@@ -285,7 +277,7 @@ module TTTLS13
|
|
285
277
|
.key_share_entry
|
286
278
|
group = hrr.extensions[Message::ExtensionType::KEY_SHARE]
|
287
279
|
.key_share_entry.first.group
|
288
|
-
terminate(:illegal_parameter) \
|
280
|
+
@connection.terminate(:illegal_parameter) \
|
289
281
|
unless ngl.include?(group) && !kse.map(&:group).include?(group)
|
290
282
|
|
291
283
|
# send new client_hello
|
@@ -302,9 +294,9 @@ module TTTLS13
|
|
302
294
|
# use ClientHelloInner messages for the transcript hash
|
303
295
|
ch_outer = ch
|
304
296
|
ch = inner.nil? ? ch : inner
|
305
|
-
transcript[CH] = [ch, ch.serialize]
|
297
|
+
@transcript[CH] = [ch, ch.serialize]
|
306
298
|
|
307
|
-
@state = ClientState::WAIT_SH
|
299
|
+
@connection.state = ClientState::WAIT_SH
|
308
300
|
next
|
309
301
|
end
|
310
302
|
|
@@ -318,69 +310,70 @@ module TTTLS13
|
|
318
310
|
.key_share_entry.map(&:group)
|
319
311
|
sh_ks = sh.extensions[Message::ExtensionType::KEY_SHARE]
|
320
312
|
.key_share_entry.first.group
|
321
|
-
terminate(:illegal_parameter) unless ch_ks.include?(sh_ks)
|
313
|
+
@connection.terminate(:illegal_parameter) unless ch_ks.include?(sh_ks)
|
322
314
|
|
323
315
|
kse = sh.extensions[Message::ExtensionType::KEY_SHARE]
|
324
316
|
.key_share_entry.first
|
325
317
|
ke = kse.key_exchange
|
326
318
|
@named_group = kse.group
|
327
319
|
priv_key = priv_keys[@named_group]
|
328
|
-
shared_secret = gen_shared_secret(ke, priv_key, @named_group)
|
320
|
+
shared_secret = Endpoint.gen_shared_secret(ke, priv_key, @named_group)
|
329
321
|
@cipher_suite = sh.cipher_suite
|
330
322
|
key_schedule = KeySchedule.new(
|
331
323
|
psk: psk,
|
332
324
|
shared_secret: shared_secret,
|
333
325
|
cipher_suite: @cipher_suite,
|
334
|
-
transcript: transcript
|
326
|
+
transcript: @transcript
|
335
327
|
)
|
336
328
|
|
337
329
|
# rejected ECH
|
338
330
|
# NOTE: It can compute (hrr_)accept_ech until client selects the
|
339
331
|
# cipher_suite.
|
340
332
|
if !sh.hrr? && use_ech?
|
341
|
-
if
|
333
|
+
if !@transcript.include?(HRR) && !key_schedule.accept_ech?
|
342
334
|
# 1sh SH
|
343
|
-
transcript[CH] = [ch_outer, ch_outer.serialize]
|
335
|
+
@transcript[CH] = [ch_outer, ch_outer.serialize]
|
344
336
|
@rejected_ech = true
|
345
|
-
elsif transcript.include?(HRR) &&
|
337
|
+
elsif @transcript.include?(HRR) &&
|
346
338
|
key_schedule.hrr_accept_ech? != key_schedule.accept_ech?
|
347
339
|
# 2nd SH
|
348
|
-
terminate(:illegal_parameter)
|
349
|
-
elsif transcript.include?(HRR) && !key_schedule.hrr_accept_ech?
|
340
|
+
@connection.terminate(:illegal_parameter)
|
341
|
+
elsif @transcript.include?(HRR) && !key_schedule.hrr_accept_ech?
|
350
342
|
# 2nd SH
|
351
|
-
transcript[CH1] = [ch1_outer, ch1_outer.serialize]
|
352
|
-
transcript[CH] = [ch_outer, ch_outer.serialize]
|
343
|
+
@transcript[CH1] = [ch1_outer, ch1_outer.serialize]
|
344
|
+
@transcript[CH] = [ch_outer, ch_outer.serialize]
|
353
345
|
@rejected_ech = true
|
354
346
|
end
|
355
347
|
end
|
356
348
|
|
357
|
-
@alert_wcipher = hs_wcipher = gen_cipher(
|
349
|
+
@connection.alert_wcipher = hs_wcipher = Endpoint.gen_cipher(
|
358
350
|
@cipher_suite,
|
359
351
|
key_schedule.client_handshake_write_key,
|
360
352
|
key_schedule.client_handshake_write_iv
|
361
353
|
)
|
362
354
|
sslkeylogfile&.write_client_handshake_traffic_secret(
|
363
|
-
transcript[CH].first.random,
|
355
|
+
@transcript[CH].first.random,
|
364
356
|
key_schedule.client_handshake_traffic_secret
|
365
357
|
)
|
366
|
-
hs_rcipher = gen_cipher(
|
358
|
+
hs_rcipher = Endpoint.gen_cipher(
|
367
359
|
@cipher_suite,
|
368
360
|
key_schedule.server_handshake_write_key,
|
369
361
|
key_schedule.server_handshake_write_iv
|
370
362
|
)
|
371
363
|
sslkeylogfile&.write_server_handshake_traffic_secret(
|
372
|
-
transcript[CH].first.random,
|
364
|
+
@transcript[CH].first.random,
|
373
365
|
key_schedule.server_handshake_traffic_secret
|
374
366
|
)
|
375
|
-
@state = ClientState::WAIT_EE
|
367
|
+
@connection.state = ClientState::WAIT_EE
|
376
368
|
when ClientState::WAIT_EE
|
377
369
|
logger.debug('ClientState::WAIT_EE')
|
378
370
|
|
379
|
-
ee, = transcript[EE] = recv_encrypted_extensions(hs_rcipher)
|
380
|
-
terminate(:illegal_parameter)
|
371
|
+
ee, = @transcript[EE] = recv_encrypted_extensions(hs_rcipher)
|
372
|
+
@connection.terminate(:illegal_parameter) \
|
373
|
+
unless ee.appearable_extensions?
|
381
374
|
|
382
|
-
ch, = transcript[CH]
|
383
|
-
terminate(:unsupported_extension) \
|
375
|
+
ch, = @transcript[CH]
|
376
|
+
@connection.terminate(:unsupported_extension) \
|
384
377
|
unless (ee.extensions.keys - ch.extensions.keys).empty?
|
385
378
|
|
386
379
|
rsl = ee.extensions[Message::ExtensionType::RECORD_SIZE_LIMIT]
|
@@ -393,118 +386,120 @@ module TTTLS13
|
|
393
386
|
@retry_configs = ee.extensions[
|
394
387
|
Message::ExtensionType::ENCRYPTED_CLIENT_HELLO
|
395
388
|
]&.retry_configs
|
396
|
-
terminate(:unsupported_extension) \
|
389
|
+
@connection.terminate(:unsupported_extension) \
|
397
390
|
if !rejected_ech? && !@retry_configs.nil?
|
398
391
|
|
399
|
-
@state = ClientState::WAIT_CERT_CR
|
400
|
-
@state = ClientState::WAIT_FINISHED unless psk.nil?
|
392
|
+
@connection.state = ClientState::WAIT_CERT_CR
|
393
|
+
@connection.state = ClientState::WAIT_FINISHED unless psk.nil?
|
401
394
|
when ClientState::WAIT_CERT_CR
|
402
395
|
logger.debug('ClientState::WAIT_CERT_CR')
|
403
396
|
|
404
|
-
message, orig_msg = recv_message(
|
397
|
+
message, orig_msg = @connection.recv_message(
|
405
398
|
receivable_ccs: true,
|
406
399
|
cipher: hs_rcipher
|
407
400
|
)
|
408
401
|
case message.msg_type
|
409
402
|
when Message::HandshakeType::CERTIFICATE,
|
410
403
|
Message::HandshakeType::COMPRESSED_CERTIFICATE
|
411
|
-
ct, = transcript[CT] = [message, orig_msg]
|
412
|
-
terminate(:bad_certificate) \
|
404
|
+
ct, = @transcript[CT] = [message, orig_msg]
|
405
|
+
@connection.terminate(:bad_certificate) \
|
413
406
|
if ct.is_a?(Message::CompressedCertificate) &&
|
414
407
|
!@settings[:compress_certificate_algorithms]
|
415
408
|
.include?(ct.algorithm)
|
416
409
|
|
417
410
|
ct = ct.certificate_message \
|
418
411
|
if ct.is_a?(Message::CompressedCertificate)
|
419
|
-
alert = check_invalid_certificate(ct, transcript[CH].first)
|
420
|
-
terminate(alert) unless alert.nil?
|
412
|
+
alert = check_invalid_certificate(ct, @transcript[CH].first)
|
413
|
+
@connection.terminate(alert) unless alert.nil?
|
421
414
|
|
422
|
-
@state = ClientState::WAIT_CV
|
415
|
+
@connection.state = ClientState::WAIT_CV
|
423
416
|
when Message::HandshakeType::CERTIFICATE_REQUEST
|
424
|
-
transcript[CR] = [message, orig_msg]
|
417
|
+
@transcript[CR] = [message, orig_msg]
|
425
418
|
# TODO: client authentication
|
426
|
-
@state = ClientState::WAIT_CERT
|
419
|
+
@connection.state = ClientState::WAIT_CERT
|
427
420
|
else
|
428
|
-
terminate(:unexpected_message)
|
421
|
+
@connection.terminate(:unexpected_message)
|
429
422
|
end
|
430
423
|
when ClientState::WAIT_CERT
|
431
424
|
logger.debug('ClientState::WAIT_CERT')
|
432
425
|
|
433
|
-
ct, = transcript[CT] = recv_certificate(hs_rcipher)
|
426
|
+
ct, = @transcript[CT] = recv_certificate(hs_rcipher)
|
434
427
|
if ct.is_a?(Message::CompressedCertificate) &&
|
435
428
|
!@settings[:compress_certificate_algorithms].include?(ct.algorithm)
|
436
|
-
terminate(:bad_certificate)
|
429
|
+
@connection.terminate(:bad_certificate)
|
437
430
|
elsif ct.is_a?(Message::CompressedCertificate)
|
438
431
|
ct = ct.certificate_message
|
439
432
|
end
|
440
433
|
|
441
|
-
alert = check_invalid_certificate(ct, transcript[CH].first)
|
442
|
-
terminate(alert) unless alert.nil?
|
434
|
+
alert = check_invalid_certificate(ct, @transcript[CH].first)
|
435
|
+
@connection.terminate(alert) unless alert.nil?
|
443
436
|
|
444
|
-
@state = ClientState::WAIT_CV
|
437
|
+
@connection.state = ClientState::WAIT_CV
|
445
438
|
when ClientState::WAIT_CV
|
446
439
|
logger.debug('ClientState::WAIT_CV')
|
447
440
|
|
448
|
-
cv, = transcript[CV] = recv_certificate_verify(hs_rcipher)
|
441
|
+
cv, = @transcript[CV] = recv_certificate_verify(hs_rcipher)
|
449
442
|
digest = CipherSuite.digest(@cipher_suite)
|
450
|
-
hash = transcript.hash(digest, CT)
|
451
|
-
ct, = transcript[CT]
|
443
|
+
hash = @transcript.hash(digest, CT)
|
444
|
+
ct, = @transcript[CT]
|
452
445
|
ct = ct.certificate_message \
|
453
446
|
if ct.is_a?(Message::CompressedCertificate)
|
454
|
-
terminate(:decrypt_error) \
|
447
|
+
@connection.terminate(:decrypt_error) \
|
455
448
|
unless verified_certificate_verify?(ct, cv, hash)
|
456
449
|
|
457
450
|
@signature_scheme = cv.signature_scheme
|
458
|
-
@state = ClientState::WAIT_FINISHED
|
451
|
+
@connection.state = ClientState::WAIT_FINISHED
|
459
452
|
when ClientState::WAIT_FINISHED
|
460
453
|
logger.debug('ClientState::WAIT_FINISHED')
|
461
454
|
|
462
|
-
sf, = transcript[SF] = recv_finished(hs_rcipher)
|
455
|
+
sf, = @transcript[SF] = recv_finished(hs_rcipher)
|
463
456
|
digest = CipherSuite.digest(@cipher_suite)
|
464
|
-
terminate(:decrypt_error)
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
457
|
+
@connection.terminate(:decrypt_error) \
|
458
|
+
unless Endpoint.verified_finished?(
|
459
|
+
finished: sf,
|
460
|
+
digest: digest,
|
461
|
+
finished_key: key_schedule.server_finished_key,
|
462
|
+
hash: @transcript.hash(digest, CV)
|
463
|
+
)
|
470
464
|
|
471
465
|
if use_early_data? && succeed_early_data?
|
472
466
|
eoed = send_eoed(e_wcipher)
|
473
|
-
transcript[EOED] = [eoed, eoed.serialize]
|
467
|
+
@transcript[EOED] = [eoed, eoed.serialize]
|
474
468
|
end
|
475
469
|
# TODO: Send Certificate [+ CertificateVerify]
|
476
|
-
signature = sign_finished(
|
470
|
+
signature = Endpoint.sign_finished(
|
477
471
|
digest: digest,
|
478
472
|
finished_key: key_schedule.client_finished_key,
|
479
|
-
hash: transcript.hash(digest, EOED)
|
473
|
+
hash: @transcript.hash(digest, EOED)
|
480
474
|
)
|
481
475
|
cf = send_finished(signature, hs_wcipher)
|
482
|
-
transcript[CF] = [cf, cf.serialize]
|
483
|
-
@
|
476
|
+
@transcript[CF] = [cf, cf.serialize]
|
477
|
+
@connection.ap_wcipher = Endpoint.gen_cipher(
|
484
478
|
@cipher_suite,
|
485
479
|
key_schedule.client_application_write_key,
|
486
480
|
key_schedule.client_application_write_iv
|
487
481
|
)
|
482
|
+
@connection.alert_wcipher = @connection.ap_wcipher
|
488
483
|
sslkeylogfile&.write_client_traffic_secret_0(
|
489
|
-
transcript[CH].first.random,
|
484
|
+
@transcript[CH].first.random,
|
490
485
|
key_schedule.client_application_traffic_secret
|
491
486
|
)
|
492
|
-
@ap_rcipher = gen_cipher(
|
487
|
+
@connection.ap_rcipher = Endpoint.gen_cipher(
|
493
488
|
@cipher_suite,
|
494
489
|
key_schedule.server_application_write_key,
|
495
490
|
key_schedule.server_application_write_iv
|
496
491
|
)
|
497
492
|
sslkeylogfile&.write_server_traffic_secret_0(
|
498
|
-
transcript[CH].first.random,
|
493
|
+
@transcript[CH].first.random,
|
499
494
|
key_schedule.server_application_traffic_secret
|
500
495
|
)
|
501
496
|
@exporter_secret = key_schedule.exporter_secret
|
502
497
|
@resumption_secret = key_schedule.resumption_secret
|
503
|
-
@state = ClientState::CONNECTED
|
498
|
+
@connection.state = ClientState::CONNECTED
|
504
499
|
when ClientState::CONNECTED
|
505
500
|
logger.debug('ClientState::CONNECTED')
|
506
501
|
|
507
|
-
send_alert(:ech_required) \
|
502
|
+
@connection.send_alert(:ech_required) \
|
508
503
|
if use_ech? && (!@retry_configs.nil? && !@retry_configs.empty?)
|
509
504
|
break
|
510
505
|
end
|
@@ -517,6 +512,14 @@ module TTTLS13
|
|
517
512
|
# rubocop: enable Metrics/MethodLength
|
518
513
|
# rubocop: enable Metrics/PerceivedComplexity
|
519
514
|
|
515
|
+
# @raise [TTTLS13::Error::ConfigError]
|
516
|
+
#
|
517
|
+
# @return [String]
|
518
|
+
def read
|
519
|
+
nst_process = method(:process_new_session_ticket)
|
520
|
+
@connection.read(nst_process)
|
521
|
+
end
|
522
|
+
|
520
523
|
# @param binary [String]
|
521
524
|
def write(binary)
|
522
525
|
# the client can regard ECH as securely disabled by the server, and it
|
@@ -528,14 +531,55 @@ module TTTLS13
|
|
528
531
|
return
|
529
532
|
end
|
530
533
|
|
531
|
-
|
534
|
+
@connection.write(binary)
|
535
|
+
end
|
536
|
+
|
537
|
+
# return [Boolean]
|
538
|
+
def eof?
|
539
|
+
@connection.eof?
|
540
|
+
end
|
541
|
+
|
542
|
+
def close
|
543
|
+
@connection.close
|
544
|
+
end
|
545
|
+
|
546
|
+
# @return [TTTLS13::CipherSuite, nil]
|
547
|
+
def negotiated_cipher_suite
|
548
|
+
@cipher_suite
|
549
|
+
end
|
550
|
+
|
551
|
+
# @return [TTTLS13::NamedGroup, nil]
|
552
|
+
def negotiated_named_group
|
553
|
+
@named_group
|
554
|
+
end
|
555
|
+
|
556
|
+
# @return [TTTLS13::SignatureScheme, nil]
|
557
|
+
def negotiated_signature_scheme
|
558
|
+
@signature_scheme
|
559
|
+
end
|
560
|
+
|
561
|
+
# @return [String]
|
562
|
+
def negotiated_alpn
|
563
|
+
@alpn
|
564
|
+
end
|
565
|
+
|
566
|
+
# @param label [String]
|
567
|
+
# @param context [String]
|
568
|
+
# @param key_length [Integer]
|
569
|
+
#
|
570
|
+
# @return [String, nil]
|
571
|
+
def exporter(label, context, key_length)
|
572
|
+
return nil if @exporter_secret.nil? || @cipher_suite.nil?
|
573
|
+
|
574
|
+
digest = CipherSuite.digest(@cipher_suite)
|
575
|
+
Endpoint.exporter(@exporter_secret, digest, label, context, key_length)
|
532
576
|
end
|
533
577
|
|
534
578
|
# @param binary [String]
|
535
579
|
#
|
536
580
|
# @raise [TTTLS13::Error::ConfigError]
|
537
581
|
def early_data(binary)
|
538
|
-
raise Error::ConfigError unless @state == INITIAL && use_psk?
|
582
|
+
raise Error::ConfigError unless @connection.state == INITIAL && use_psk?
|
539
583
|
|
540
584
|
@early_data = binary
|
541
585
|
end
|
@@ -677,7 +721,7 @@ module TTTLS13
|
|
677
721
|
messages: [ap],
|
678
722
|
cipher: cipher
|
679
723
|
)
|
680
|
-
send_record(ap_record)
|
724
|
+
@connection.send_record(ap_record)
|
681
725
|
end
|
682
726
|
|
683
727
|
# @param resumption_secret [String]
|
@@ -768,7 +812,7 @@ module TTTLS13
|
|
768
812
|
#
|
769
813
|
# @return [TTTLS13::Message::ClientHello] outer
|
770
814
|
# @return [TTTLS13::Message::ClientHello] inner
|
771
|
-
# @return [TTTLS13::
|
815
|
+
# @return [TTTLS13::EchState]
|
772
816
|
# rubocop: disable Metrics/MethodLength
|
773
817
|
def send_client_hello(extensions, binder_key = nil)
|
774
818
|
ch = Message::ClientHello.new(
|
@@ -783,7 +827,11 @@ module TTTLS13
|
|
783
827
|
inner_ech = Message::Extension::ECHClientHello.new_inner
|
784
828
|
inner.extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO] \
|
785
829
|
= inner_ech
|
786
|
-
ch, inner, ech_state = offer_ech(
|
830
|
+
ch, inner, ech_state = Ech.offer_ech(
|
831
|
+
inner,
|
832
|
+
@settings[:ech_config],
|
833
|
+
method(:select_ech_hpke_cipher_suite)
|
834
|
+
)
|
787
835
|
end
|
788
836
|
|
789
837
|
# psk_key_exchange_modes
|
@@ -814,8 +862,8 @@ module TTTLS13
|
|
814
862
|
end
|
815
863
|
end
|
816
864
|
|
817
|
-
send_handshakes(Message::ContentType::HANDSHAKE, [ch],
|
818
|
-
|
865
|
+
@connection.send_handshakes(Message::ContentType::HANDSHAKE, [ch],
|
866
|
+
Cryptograph::Passer.new)
|
819
867
|
|
820
868
|
[ch, inner, ech_state]
|
821
869
|
end
|
@@ -850,7 +898,7 @@ module TTTLS13
|
|
850
898
|
)
|
851
899
|
ch.extensions[Message::ExtensionType::PRE_SHARED_KEY] = psk
|
852
900
|
|
853
|
-
psk.offered_psks.binders[0] =
|
901
|
+
psk.offered_psks.binders[0] = Endpoint.sign_psk_binder(
|
854
902
|
ch1: ch1,
|
855
903
|
hrr: hrr,
|
856
904
|
ch: ch,
|
@@ -900,7 +948,7 @@ module TTTLS13
|
|
900
948
|
)
|
901
949
|
ch_outer.extensions[Message::ExtensionType::PRE_SHARED_KEY] = psk
|
902
950
|
|
903
|
-
psk.offered_psks.binders[0] =
|
951
|
+
psk.offered_psks.binders[0] = Endpoint.sign_psk_binder(
|
904
952
|
ch1: ch1,
|
905
953
|
hrr: hrr,
|
906
954
|
ch: ch_outer,
|
@@ -909,209 +957,6 @@ module TTTLS13
|
|
909
957
|
)
|
910
958
|
end
|
911
959
|
|
912
|
-
# @param inner [TTTLS13::Message::ClientHello]
|
913
|
-
# @param ech_config [ECHConfig]
|
914
|
-
#
|
915
|
-
# @return [TTTLS13::Message::ClientHello]
|
916
|
-
# @return [TTTLS13::Message::ClientHello]
|
917
|
-
# @return [TTTLS13::Client::EchState]
|
918
|
-
# rubocop: disable Metrics/AbcSize
|
919
|
-
# rubocop: disable Metrics/MethodLength
|
920
|
-
def offer_ech(inner, ech_config)
|
921
|
-
return [new_greased_ch(inner, new_grease_ech), nil, nil] \
|
922
|
-
if ech_config.nil? ||
|
923
|
-
!SUPPORTED_ECHCONFIG_VERSIONS.include?(ech_config.version)
|
924
|
-
|
925
|
-
# Encrypted ClientHello Configuration
|
926
|
-
public_name = ech_config.echconfig_contents.public_name
|
927
|
-
key_config = ech_config.echconfig_contents.key_config
|
928
|
-
public_key = key_config.public_key.opaque
|
929
|
-
kem_id = key_config&.kem_id&.uint16
|
930
|
-
config_id = key_config.config_id
|
931
|
-
cipher_suite = select_ech_hpke_cipher_suite(key_config)
|
932
|
-
overhead_len = Hpke.aead_id2overhead_len(cipher_suite&.aead_id&.uint16)
|
933
|
-
aead_cipher = Hpke.aead_id2aead_cipher(cipher_suite&.aead_id&.uint16)
|
934
|
-
kdf_hash = Hpke.kdf_id2kdf_hash(cipher_suite&.kdf_id&.uint16)
|
935
|
-
return [new_greased_ch(inner, new_grease_ech), nil, nil] \
|
936
|
-
if [kem_id, overhead_len, aead_cipher, kdf_hash].any?(&:nil?)
|
937
|
-
|
938
|
-
kem_curve_name, kem_hash = Hpke.kem_id2dhkem(kem_id)
|
939
|
-
dhkem = Hpke.kem_curve_name2dhkem(kem_curve_name)
|
940
|
-
pkr = dhkem&.new(kem_hash)&.deserialize_public_key(public_key)
|
941
|
-
return [new_greased_ch(inner, new_grease_ech), nil, nil] if pkr.nil?
|
942
|
-
|
943
|
-
hpke = HPKE.new(kem_curve_name, kem_hash, kdf_hash, aead_cipher)
|
944
|
-
base_s = hpke.setup_base_s(pkr, "tls ech\x00" + ech_config.encode)
|
945
|
-
enc = base_s[:enc]
|
946
|
-
ctx = base_s[:context_s]
|
947
|
-
mnl = ech_config.echconfig_contents.maximum_name_length
|
948
|
-
encoded = encode_ch_inner(inner, mnl)
|
949
|
-
|
950
|
-
# Encoding the ClientHelloInner
|
951
|
-
aad = new_ch_outer_aad(
|
952
|
-
inner,
|
953
|
-
cipher_suite,
|
954
|
-
config_id,
|
955
|
-
enc,
|
956
|
-
encoded.length + overhead_len,
|
957
|
-
public_name
|
958
|
-
)
|
959
|
-
# Authenticating the ClientHelloOuter
|
960
|
-
# which does not include the Handshake structure's four byte header.
|
961
|
-
outer = new_ch_outer(
|
962
|
-
aad,
|
963
|
-
cipher_suite,
|
964
|
-
config_id,
|
965
|
-
enc,
|
966
|
-
ctx.seal(aad.serialize[4..], encoded)
|
967
|
-
)
|
968
|
-
|
969
|
-
ech_state = EchState.new(mnl, config_id, cipher_suite, public_name, ctx)
|
970
|
-
[outer, inner, ech_state]
|
971
|
-
end
|
972
|
-
# rubocop: enable Metrics/AbcSize
|
973
|
-
# rubocop: enable Metrics/MethodLength
|
974
|
-
|
975
|
-
# @param inner [TTTLS13::Message::ClientHello]
|
976
|
-
# @param ech_state [TTTLS13::Client::EchState]
|
977
|
-
#
|
978
|
-
# @return [TTTLS13::Message::ClientHello]
|
979
|
-
# @return [TTTLS13::Message::ClientHello]
|
980
|
-
def offer_new_ech(inner, ech_state)
|
981
|
-
encoded = encode_ch_inner(inner, ech_state.maximum_name_length)
|
982
|
-
overhead_len \
|
983
|
-
= Hpke.aead_id2overhead_len(ech_state.cipher_suite.aead_id.uint16)
|
984
|
-
|
985
|
-
# It encrypts EncodedClientHelloInner as described in Section 6.1.1, using
|
986
|
-
# the second partial ClientHelloOuterAAD, to obtain a second
|
987
|
-
# ClientHelloOuter. It reuses the original HPKE encryption context
|
988
|
-
# computed in Section 6.1 and uses the empty string for enc.
|
989
|
-
#
|
990
|
-
# https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-6.1.5-4.4.1
|
991
|
-
aad = new_ch_outer_aad(
|
992
|
-
inner,
|
993
|
-
ech_state.cipher_suite,
|
994
|
-
ech_state.config_id,
|
995
|
-
'',
|
996
|
-
encoded.length + overhead_len,
|
997
|
-
ech_state.public_name
|
998
|
-
)
|
999
|
-
# Authenticating the ClientHelloOuter
|
1000
|
-
# which does not include the Handshake structure's four byte header.
|
1001
|
-
outer = new_ch_outer(
|
1002
|
-
aad,
|
1003
|
-
ech_state.cipher_suite,
|
1004
|
-
ech_state.config_id,
|
1005
|
-
'',
|
1006
|
-
ech_state.ctx.seal(aad.serialize[4..], encoded)
|
1007
|
-
)
|
1008
|
-
|
1009
|
-
[outer, inner]
|
1010
|
-
end
|
1011
|
-
|
1012
|
-
# @param inner [TTTLS13::Message::ClientHello]
|
1013
|
-
# @param maximum_name_length [Integer]
|
1014
|
-
#
|
1015
|
-
# @return [String] EncodedClientHelloInner
|
1016
|
-
def encode_ch_inner(inner, maximum_name_length)
|
1017
|
-
# TODO: ech_outer_extensions
|
1018
|
-
encoded = Message::ClientHello.new(
|
1019
|
-
legacy_version: inner.legacy_version,
|
1020
|
-
random: inner.random,
|
1021
|
-
legacy_session_id: '',
|
1022
|
-
cipher_suites: inner.cipher_suites,
|
1023
|
-
legacy_compression_methods: inner.legacy_compression_methods,
|
1024
|
-
extensions: inner.extensions
|
1025
|
-
)
|
1026
|
-
server_name_length = \
|
1027
|
-
inner.extensions[Message::ExtensionType::SERVER_NAME].server_name.length
|
1028
|
-
|
1029
|
-
# which does not include the Handshake structure's four byte header.
|
1030
|
-
padding_encoded_ch_inner(
|
1031
|
-
encoded.serialize[4..],
|
1032
|
-
server_name_length,
|
1033
|
-
maximum_name_length
|
1034
|
-
)
|
1035
|
-
end
|
1036
|
-
|
1037
|
-
# @param s [String]
|
1038
|
-
# @param server_name_length [Integer]
|
1039
|
-
# @param maximum_name_length [Integer]
|
1040
|
-
#
|
1041
|
-
# @return [String]
|
1042
|
-
def padding_encoded_ch_inner(s, server_name_length, maximum_name_length)
|
1043
|
-
padding_len =
|
1044
|
-
if server_name_length.positive?
|
1045
|
-
[maximum_name_length - server_name_length, 0].max
|
1046
|
-
else
|
1047
|
-
9 + maximum_name_length
|
1048
|
-
end
|
1049
|
-
|
1050
|
-
padding_len = 31 - ((s.length + padding_len - 1) % 32)
|
1051
|
-
s + padding_len.zeros
|
1052
|
-
end
|
1053
|
-
|
1054
|
-
# @param inner [TTTLS13::Message::ClientHello]
|
1055
|
-
# @param cipher_suite [HpkeSymmetricCipherSuite]
|
1056
|
-
# @param config_id [Integer]
|
1057
|
-
# @param enc [String]
|
1058
|
-
# @param payload_len [Integer]
|
1059
|
-
# @param server_name [String]
|
1060
|
-
#
|
1061
|
-
# @return [TTTLS13::Message::ClientHello]
|
1062
|
-
# rubocop: disable Metrics/ParameterLists
|
1063
|
-
def new_ch_outer_aad(inner,
|
1064
|
-
cipher_suite,
|
1065
|
-
config_id,
|
1066
|
-
enc,
|
1067
|
-
payload_len,
|
1068
|
-
server_name)
|
1069
|
-
aad_ech = Message::Extension::ECHClientHello.new_outer(
|
1070
|
-
cipher_suite: cipher_suite,
|
1071
|
-
config_id: config_id,
|
1072
|
-
enc: enc,
|
1073
|
-
payload: payload_len.zeros
|
1074
|
-
)
|
1075
|
-
Message::ClientHello.new(
|
1076
|
-
legacy_version: inner.legacy_version,
|
1077
|
-
legacy_session_id: inner.legacy_session_id,
|
1078
|
-
cipher_suites: inner.cipher_suites,
|
1079
|
-
legacy_compression_methods: inner.legacy_compression_methods,
|
1080
|
-
extensions: inner.extensions.merge(
|
1081
|
-
Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => aad_ech,
|
1082
|
-
Message::ExtensionType::SERVER_NAME => \
|
1083
|
-
Message::Extension::ServerName.new(server_name)
|
1084
|
-
)
|
1085
|
-
)
|
1086
|
-
end
|
1087
|
-
# rubocop: enable Metrics/ParameterLists
|
1088
|
-
|
1089
|
-
# @param aad [TTTLS13::Message::ClientHello]
|
1090
|
-
# @param cipher_suite [HpkeSymmetricCipherSuite]
|
1091
|
-
# @param config_id [Integer]
|
1092
|
-
# @param enc [String]
|
1093
|
-
# @param payload [String]
|
1094
|
-
#
|
1095
|
-
# @return [TTTLS13::Message::ClientHello]
|
1096
|
-
def new_ch_outer(aad, cipher_suite, config_id, enc, payload)
|
1097
|
-
outer_ech = Message::Extension::ECHClientHello.new_outer(
|
1098
|
-
cipher_suite: cipher_suite,
|
1099
|
-
config_id: config_id,
|
1100
|
-
enc: enc,
|
1101
|
-
payload: payload
|
1102
|
-
)
|
1103
|
-
Message::ClientHello.new(
|
1104
|
-
legacy_version: aad.legacy_version,
|
1105
|
-
random: aad.random,
|
1106
|
-
legacy_session_id: aad.legacy_session_id,
|
1107
|
-
cipher_suites: aad.cipher_suites,
|
1108
|
-
legacy_compression_methods: aad.legacy_compression_methods,
|
1109
|
-
extensions: aad.extensions.merge(
|
1110
|
-
Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => outer_ech
|
1111
|
-
)
|
1112
|
-
)
|
1113
|
-
end
|
1114
|
-
|
1115
960
|
# @param conf [HpkeKeyConfig]
|
1116
961
|
#
|
1117
962
|
# @return [HpkeSymmetricCipherSuite, nil]
|
@@ -1121,63 +966,6 @@ module TTTLS13
|
|
1121
966
|
end
|
1122
967
|
end
|
1123
968
|
|
1124
|
-
# @return [Message::Extension::ECHClientHello]
|
1125
|
-
def new_grease_ech
|
1126
|
-
# https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#name-compliance-requirements
|
1127
|
-
cipher_suite = HpkeSymmetricCipherSuite.new(
|
1128
|
-
HpkeSymmetricCipherSuite::HpkeKdfId.new(
|
1129
|
-
TTTLS13::Hpke::KdfId::HKDF_SHA256
|
1130
|
-
),
|
1131
|
-
HpkeSymmetricCipherSuite::HpkeAeadId.new(
|
1132
|
-
TTTLS13::Hpke::AeadId::AES_128_GCM
|
1133
|
-
)
|
1134
|
-
)
|
1135
|
-
# Set the enc field to a randomly-generated valid encapsulated public key
|
1136
|
-
# output by the HPKE KEM.
|
1137
|
-
#
|
1138
|
-
# https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-6.2-2.3.1
|
1139
|
-
public_key = OpenSSL::PKey.read(
|
1140
|
-
OpenSSL::PKey.generate_key('X25519').public_to_pem
|
1141
|
-
)
|
1142
|
-
hpke = HPKE.new(:x25519, :sha256, :sha256, :aes_128_gcm)
|
1143
|
-
enc = hpke.setup_base_s(public_key, '')[:enc]
|
1144
|
-
# Set the payload field to a randomly-generated string of L+C bytes, where
|
1145
|
-
# C is the ciphertext expansion of the selected AEAD scheme and L is the
|
1146
|
-
# size of the EncodedClientHelloInner the client would compute when
|
1147
|
-
# offering ECH, padded according to Section 6.1.3.
|
1148
|
-
#
|
1149
|
-
# https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-6.2-2.4.1
|
1150
|
-
payload_len = placeholder_encoded_ch_inner_len \
|
1151
|
-
+ Hpke.aead_id2overhead_len(Hpke::AeadId::AES_128_GCM)
|
1152
|
-
|
1153
|
-
Message::Extension::ECHClientHello.new_outer(
|
1154
|
-
cipher_suite: cipher_suite,
|
1155
|
-
config_id: Convert.bin2i(OpenSSL::Random.random_bytes(1)),
|
1156
|
-
enc: enc,
|
1157
|
-
payload: OpenSSL::Random.random_bytes(payload_len)
|
1158
|
-
)
|
1159
|
-
end
|
1160
|
-
|
1161
|
-
# @return [Integer]
|
1162
|
-
def placeholder_encoded_ch_inner_len
|
1163
|
-
448
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
# @param inner [TTTLS13::Message::ClientHello]
|
1167
|
-
# @param ech [Message::Extension::ECHClientHello]
|
1168
|
-
def new_greased_ch(inner, ech)
|
1169
|
-
Message::ClientHello.new(
|
1170
|
-
legacy_version: inner.legacy_version,
|
1171
|
-
random: inner.random,
|
1172
|
-
legacy_session_id: inner.legacy_session_id,
|
1173
|
-
cipher_suites: inner.cipher_suites,
|
1174
|
-
legacy_compression_methods: inner.legacy_compression_methods,
|
1175
|
-
extensions: inner.extensions.merge(
|
1176
|
-
Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => ech
|
1177
|
-
)
|
1178
|
-
)
|
1179
|
-
end
|
1180
|
-
|
1181
969
|
# @return [Integer]
|
1182
970
|
def calc_obfuscated_ticket_age
|
1183
971
|
# the "ticket_lifetime" field in the NewSessionTicket message is
|
@@ -1227,7 +1015,7 @@ module TTTLS13
|
|
1227
1015
|
# @param hrr [TTTLS13::Message::ServerHello]
|
1228
1016
|
# @param extensions [TTTLS13::Message::Extensions]
|
1229
1017
|
# @param binder_key [String, nil]
|
1230
|
-
# @param ech_state [TTTLS13::
|
1018
|
+
# @param ech_state [TTTLS13::EchState]
|
1231
1019
|
#
|
1232
1020
|
# @return [TTTLS13::Message::ClientHello] outer
|
1233
1021
|
# @return [TTTLS13::Message::ClientHello] inner
|
@@ -1258,7 +1046,7 @@ module TTTLS13
|
|
1258
1046
|
ch.extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO] \
|
1259
1047
|
= ch1.extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO]
|
1260
1048
|
elsif use_ech?
|
1261
|
-
ch, inner = offer_new_ech(ch, ech_state)
|
1049
|
+
ch, inner = Ech.offer_new_ech(ch, ech_state)
|
1262
1050
|
end
|
1263
1051
|
|
1264
1052
|
# pre_shared_key
|
@@ -1286,8 +1074,8 @@ module TTTLS13
|
|
1286
1074
|
end
|
1287
1075
|
end
|
1288
1076
|
|
1289
|
-
send_handshakes(Message::ContentType::HANDSHAKE, [ch],
|
1290
|
-
|
1077
|
+
@connection.send_handshakes(Message::ContentType::HANDSHAKE, [ch],
|
1078
|
+
Cryptograph::Passer.new)
|
1291
1079
|
|
1292
1080
|
[ch, inner]
|
1293
1081
|
end
|
@@ -1299,11 +1087,12 @@ module TTTLS13
|
|
1299
1087
|
# @return [TTTLS13::Message::ServerHello]
|
1300
1088
|
# @return [String]
|
1301
1089
|
def recv_server_hello
|
1302
|
-
sh, orig_msg = recv_message(
|
1090
|
+
sh, orig_msg = @connection.recv_message(
|
1303
1091
|
receivable_ccs: true,
|
1304
1092
|
cipher: Cryptograph::Passer.new
|
1305
1093
|
)
|
1306
|
-
terminate(:unexpected_message)
|
1094
|
+
@connection.terminate(:unexpected_message) \
|
1095
|
+
unless sh.is_a?(Message::ServerHello)
|
1307
1096
|
|
1308
1097
|
[sh, orig_msg]
|
1309
1098
|
end
|
@@ -1315,8 +1104,9 @@ module TTTLS13
|
|
1315
1104
|
# @return [TTTLS13::Message::EncryptedExtensions]
|
1316
1105
|
# @return [String]
|
1317
1106
|
def recv_encrypted_extensions(cipher)
|
1318
|
-
ee, orig_msg
|
1319
|
-
|
1107
|
+
ee, orig_msg \
|
1108
|
+
= @connection.recv_message(receivable_ccs: true, cipher: cipher)
|
1109
|
+
@connection.terminate(:unexpected_message) \
|
1320
1110
|
unless ee.is_a?(Message::EncryptedExtensions)
|
1321
1111
|
|
1322
1112
|
[ee, orig_msg]
|
@@ -1329,8 +1119,10 @@ module TTTLS13
|
|
1329
1119
|
# @return [TTTLS13::Message::Certificate]
|
1330
1120
|
# @return [String]
|
1331
1121
|
def recv_certificate(cipher)
|
1332
|
-
ct, orig_msg
|
1333
|
-
|
1122
|
+
ct, orig_msg \
|
1123
|
+
= @connection.recv_message(receivable_ccs: true, cipher: cipher)
|
1124
|
+
@connection.terminate(:unexpected_message) \
|
1125
|
+
unless ct.is_a?(Message::Certificate)
|
1334
1126
|
|
1335
1127
|
[ct, orig_msg]
|
1336
1128
|
end
|
@@ -1342,8 +1134,10 @@ module TTTLS13
|
|
1342
1134
|
# @return [TTTLS13::Message::CertificateVerify]
|
1343
1135
|
# @return [String]
|
1344
1136
|
def recv_certificate_verify(cipher)
|
1345
|
-
cv, orig_msg
|
1346
|
-
|
1137
|
+
cv, orig_msg \
|
1138
|
+
= @connection.recv_message(receivable_ccs: true, cipher: cipher)
|
1139
|
+
@connection.terminate(:unexpected_message) \
|
1140
|
+
unless cv.is_a?(Message::CertificateVerify)
|
1347
1141
|
|
1348
1142
|
[cv, orig_msg]
|
1349
1143
|
end
|
@@ -1355,8 +1149,10 @@ module TTTLS13
|
|
1355
1149
|
# @return [TTTLS13::Message::Finished]
|
1356
1150
|
# @return [String]
|
1357
1151
|
def recv_finished(cipher)
|
1358
|
-
sf, orig_msg
|
1359
|
-
|
1152
|
+
sf, orig_msg \
|
1153
|
+
= @connection.recv_message(receivable_ccs: true, cipher: cipher)
|
1154
|
+
@connection.terminate(:unexpected_message) \
|
1155
|
+
unless sf.is_a?(Message::Finished)
|
1360
1156
|
|
1361
1157
|
[sf, orig_msg]
|
1362
1158
|
end
|
@@ -1366,7 +1162,11 @@ module TTTLS13
|
|
1366
1162
|
# @return [TTTLS13::Message::Finished]
|
1367
1163
|
def send_finished(signature, cipher)
|
1368
1164
|
cf = Message::Finished.new(signature)
|
1369
|
-
send_handshakes(
|
1165
|
+
@connection.send_handshakes(
|
1166
|
+
Message::ContentType::APPLICATION_DATA,
|
1167
|
+
[cf],
|
1168
|
+
cipher
|
1169
|
+
)
|
1370
1170
|
|
1371
1171
|
cf
|
1372
1172
|
end
|
@@ -1376,7 +1176,11 @@ module TTTLS13
|
|
1376
1176
|
# @return [TTTLS13::Message::EndOfEarlyData]
|
1377
1177
|
def send_eoed(cipher)
|
1378
1178
|
eoed = Message::EndOfEarlyData.new
|
1379
|
-
send_handshakes(
|
1179
|
+
@connection.send_handshakes(
|
1180
|
+
Message::ContentType::APPLICATION_DATA,
|
1181
|
+
[eoed],
|
1182
|
+
cipher
|
1183
|
+
)
|
1380
1184
|
|
1381
1185
|
eoed
|
1382
1186
|
end
|
@@ -1392,7 +1196,7 @@ module TTTLS13
|
|
1392
1196
|
unless ct.certificate_list.map(&:extensions)
|
1393
1197
|
.all? { |e| (e.keys - ch.extensions.keys).empty? }
|
1394
1198
|
|
1395
|
-
return :certificate_unknown unless trusted_certificate?(
|
1199
|
+
return :certificate_unknown unless Endpoint.trusted_certificate?(
|
1396
1200
|
ct.certificate_list,
|
1397
1201
|
@settings[:ca_file],
|
1398
1202
|
@hostname
|
@@ -1421,7 +1225,7 @@ module TTTLS13
|
|
1421
1225
|
signature_scheme = cv.signature_scheme
|
1422
1226
|
signature = cv.signature
|
1423
1227
|
|
1424
|
-
|
1228
|
+
Endpoint.verified_certificate_verify?(
|
1425
1229
|
public_key: public_key,
|
1426
1230
|
signature_scheme: signature_scheme,
|
1427
1231
|
signature: signature,
|
@@ -1443,36 +1247,19 @@ module TTTLS13
|
|
1443
1247
|
#
|
1444
1248
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
1445
1249
|
def process_new_session_ticket(nst)
|
1446
|
-
super(nst)
|
1447
|
-
|
1448
1250
|
rms = @resumption_secret
|
1449
1251
|
cs = @cipher_suite
|
1450
1252
|
@settings[:process_new_session_ticket]&.call(nst, rms, cs)
|
1451
1253
|
end
|
1452
1254
|
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
# @param config_id [Integer]
|
1462
|
-
# @param cipher_suite [HpkeSymmetricCipherSuite]
|
1463
|
-
# @param public_name [String]
|
1464
|
-
# @param ctx [[HPKE::ContextS]
|
1465
|
-
def initialize(maximum_name_length,
|
1466
|
-
config_id,
|
1467
|
-
cipher_suite,
|
1468
|
-
public_name,
|
1469
|
-
ctx)
|
1470
|
-
@maximum_name_length = maximum_name_length
|
1471
|
-
@config_id = config_id
|
1472
|
-
@cipher_suite = cipher_suite
|
1473
|
-
@public_name = public_name
|
1474
|
-
@ctx = ctx
|
1475
|
-
end
|
1255
|
+
# @param cid [OpenSSL::OCSP::CertificateId]
|
1256
|
+
#
|
1257
|
+
# @return [OpenSSL::OCSP::Request]
|
1258
|
+
def gen_ocsp_request(cid)
|
1259
|
+
ocsp_request = OpenSSL::OCSP::Request.new
|
1260
|
+
ocsp_request.add_certid(cid)
|
1261
|
+
ocsp_request.add_nonce
|
1262
|
+
ocsp_request
|
1476
1263
|
end
|
1477
1264
|
end
|
1478
1265
|
# rubocop: enable Metrics/ClassLength
|