tttls1.3 0.3.1 → 0.3.2
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.
- 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
|