tttls1.3 0.3.0 → 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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/.rubocop.yml +3 -0
  4. data/.ruby-version +1 -1
  5. data/Gemfile +1 -0
  6. data/README.md +2 -2
  7. data/example/README.md +1 -1
  8. data/example/helper.rb +22 -0
  9. data/example/https_client.rb +4 -4
  10. data/example/https_client_using_0rtt.rb +6 -5
  11. data/example/https_client_using_ech.rb +5 -6
  12. data/example/https_client_using_grease_ech.rb +3 -5
  13. data/example/https_client_using_grease_psk.rb +8 -16
  14. data/example/https_client_using_hrr.rb +5 -4
  15. data/example/https_client_using_hrr_and_ech.rb +6 -6
  16. data/example/https_client_using_hrr_and_ticket.rb +5 -4
  17. data/example/https_client_using_status_request.rb +4 -5
  18. data/example/https_client_using_ticket.rb +5 -4
  19. data/example/https_server.rb +14 -1
  20. data/lib/tttls1.3/client.rb +205 -418
  21. data/lib/tttls1.3/connection.rb +21 -362
  22. data/lib/tttls1.3/ech.rb +410 -0
  23. data/lib/tttls1.3/endpoint.rb +276 -0
  24. data/lib/tttls1.3/message/certificate_verify.rb +1 -1
  25. data/lib/tttls1.3/message/extension/ech.rb +12 -10
  26. data/lib/tttls1.3/message/extension/signature_algorithms.rb +2 -2
  27. data/lib/tttls1.3/message/extension/supported_versions.rb +3 -3
  28. data/lib/tttls1.3/message/extension/unknown_extension.rb +2 -2
  29. data/lib/tttls1.3/server.rb +125 -63
  30. data/lib/tttls1.3/utils.rb +37 -0
  31. data/lib/tttls1.3/version.rb +1 -1
  32. data/lib/tttls1.3.rb +2 -1
  33. data/spec/client_spec.rb +21 -60
  34. data/spec/ech_spec.rb +39 -0
  35. data/spec/{connection_spec.rb → endpoint_spec.rb} +41 -49
  36. data/spec/server_spec.rb +12 -12
  37. data/tttls1.3.gemspec +1 -1
  38. metadata +8 -7
  39. data/lib/tttls1.3/hpke.rb +0 -91
@@ -99,9 +99,10 @@ module TTTLS13
99
99
  # @raise [TTTLS13::Error::ErrorAlerts]
100
100
  #
101
101
  # @return [TTTLS13::Message::Extensions::ECHClientHello]
102
+ # rubocop: disable Metrics/AbcSize
102
103
  def deserialize_outer_ech(binary)
103
- raise Error::ErrorAlerts, :internal_error \
104
- if binary.nil? || binary.length < 5
104
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
105
+ raise Error::ErrorAlerts, :decode_error if binary.length < 5
105
106
 
106
107
  kdf_id = \
107
108
  HpkeSymmetricCipherSuite::HpkeKdfId.decode(binary.slice(0, 2))
@@ -111,16 +112,16 @@ module TTTLS13
111
112
  cid = Convert.bin2i(binary.slice(4, 1))
112
113
  enc_len = Convert.bin2i(binary.slice(5, 2))
113
114
  i = 7
114
- raise Error::ErrorAlerts, :internal_error \
115
+ raise Error::ErrorAlerts, :decode_error \
115
116
  if i + enc_len > binary.length
116
117
 
117
118
  enc = binary.slice(i, enc_len)
118
119
  i += enc_len
119
- raise Error::ErrorAlerts, :internal_error \
120
+ raise Error::ErrorAlerts, :decode_error \
120
121
  if i + 2 > binary.length
121
122
 
122
123
  payload_len = Convert.bin2i(binary.slice(i, 2))
123
- raise Error::ErrorAlerts, :internal_error \
124
+ raise Error::ErrorAlerts, :decode_error \
124
125
  if i + payload_len > binary.length
125
126
 
126
127
  payload = binary.slice(i, payload_len)
@@ -132,6 +133,7 @@ module TTTLS13
132
133
  payload: payload
133
134
  )
134
135
  end
136
+ # rubocop: enable Metrics/AbcSize
135
137
 
136
138
  # @param binary [String]
137
139
  #
@@ -139,7 +141,7 @@ module TTTLS13
139
141
  #
140
142
  # @return [TTTLS13::Message::Extensions::ECHClientHello]
141
143
  def deserialize_inner_ech(binary)
142
- raise Error::ErrorAlerts, :internal_error unless binary.empty?
144
+ raise Error::ErrorAlerts, :illegal_parameter unless binary.empty?
143
145
 
144
146
  ECHClientHello.new(type: ECHClientHelloType::INNER)
145
147
  end
@@ -195,9 +197,9 @@ module TTTLS13
195
197
  #
196
198
  # @return [TTTLS13::Message::Extensions::ECHEncryptedExtensions]
197
199
  def self.deserialize(binary)
200
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
198
201
  raise Error::ErrorAlerts, :decode_error \
199
- if binary.nil? ||
200
- binary.length != binary.slice(0, 2).unpack1('n') + 2
202
+ if binary.length != binary.slice(0, 2).unpack1('n') + 2
201
203
 
202
204
  ECHEncryptedExtensions.new(
203
205
  ECHConfig.decode_vectors(binary.slice(2..))
@@ -230,8 +232,8 @@ module TTTLS13
230
232
  #
231
233
  # @return [TTTLS13::Message::Extensions::ECHHelloRetryRequest]
232
234
  def self.deserialize(binary)
233
- raise Error::ErrorAlerts, :decode_error \
234
- if binary.nil? || binary.length != 8
235
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
236
+ raise Error::ErrorAlerts, :decode_error if binary.length != 8
235
237
 
236
238
  ECHHelloRetryRequest.new(binary)
237
239
  end
@@ -21,8 +21,8 @@ module TTTLS13
21
21
  SignatureScheme::RSA_PKCS1_SHA512
22
22
  ].freeze
23
23
 
24
- attr_accessor :extension_type # for signature_algorithms_cert getter
25
- attr_reader :supported_signature_algorithms
24
+ attr_reader :extension_type # for signature_algorithms_cert getter
25
+ attr_reader :supported_signature_algorithms
26
26
 
27
27
  # @param supported_signature_algorithms [Array of SignatureScheme]
28
28
  def initialize(supported_signature_algorithms)
@@ -6,9 +6,9 @@ module TTTLS13
6
6
  module Message
7
7
  module Extension
8
8
  class SupportedVersions
9
- attr_reader :extension_type
10
- attr_accessor :msg_type
11
- attr_accessor :versions
9
+ attr_reader :extension_type
10
+ attr_reader :msg_type
11
+ attr_reader :versions
12
12
 
13
13
  # @param msg_type [TTTLS13::Message::ContentType]
14
14
  # @param versions [Array of ProtocolVersion]
@@ -9,8 +9,8 @@ module TTTLS13
9
9
  # Client/Server MUST ignore unrecognized extensions,
10
10
  # but transcript MUST include unrecognized extensions.
11
11
  class UnknownExtension
12
- attr_accessor :extension_type
13
- attr_accessor :extension_data
12
+ attr_reader :extension_type
13
+ attr_reader :extension_data
14
14
 
15
15
  # @param extension_type [String]
16
16
  # @param extension_data [String]
@@ -66,13 +66,15 @@ module TTTLS13
66
66
  private_constant :DEFAULT_SERVER_SETTINGS
67
67
 
68
68
  # rubocop: disable Metrics/ClassLength
69
- class Server < Connection
69
+ class Server
70
+ include Logging
71
+
72
+ attr_reader :transcript
73
+
70
74
  # @param socket [Socket]
71
75
  # @param settings [Hash]
72
76
  def initialize(socket, **settings)
73
- super(socket)
74
-
75
- @endpoint = :server
77
+ @connection = Connection.new(socket, :server)
76
78
  @settings = DEFAULT_SERVER_SETTINGS.merge(settings)
77
79
  logger.level = @settings[:loglevel]
78
80
 
@@ -144,7 +146,7 @@ module TTTLS13
144
146
  # rubocop: disable Metrics/MethodLength
145
147
  # rubocop: disable Metrics/PerceivedComplexity
146
148
  def accept
147
- transcript = Transcript.new
149
+ @transcript = Transcript.new
148
150
  key_schedule = nil # TTTLS13::KeySchedule
149
151
  priv_key = nil # OpenSSL::PKey::$Object
150
152
  hs_wcipher = nil # TTTLS13::Cryptograph::$Object
@@ -159,24 +161,27 @@ module TTTLS13
159
161
  end
160
162
  end
161
163
 
162
- @state = ServerState::START
164
+ @connection.state = ServerState::START
163
165
  loop do
164
- case @state
166
+ case @connection.state
165
167
  when ServerState::START
166
168
  logger.debug('ServerState::START')
167
169
 
168
- receivable_ccs = transcript.include?(CH1)
169
- ch, = transcript[CH] = recv_client_hello(receivable_ccs)
170
+ receivable_ccs = @transcript.include?(CH1)
171
+ ch, = @transcript[CH] = recv_client_hello(receivable_ccs)
170
172
 
171
173
  # support only TLS 1.3
172
- terminate(:protocol_version) unless ch.negotiated_tls_1_3?
174
+ @connection.terminate(:protocol_version) unless ch.negotiated_tls_1_3?
173
175
 
174
176
  # validate parameters
175
- terminate(:illegal_parameter) unless ch.appearable_extensions?
176
- terminamte(:illegal_parameter) \
177
+ @connection.terminate(:illegal_parameter) \
178
+ unless ch.appearable_extensions?
179
+ @connection.terminate(:illegal_parameter) \
177
180
  unless ch.legacy_compression_methods == ["\x00"]
178
- terminate(:illegal_parameter) unless ch.valid_key_share?
179
- terminate(:unrecognized_name) unless recognized_server_name?(ch, @crt)
181
+ @connection.terminate(:illegal_parameter) \
182
+ unless ch.valid_key_share?
183
+ @connection.terminate(:unrecognized_name) \
184
+ unless recognized_server_name?(ch, @crt)
180
185
 
181
186
  # alpn
182
187
  ch_alpn = ch.extensions[
@@ -186,109 +191,109 @@ module TTTLS13
186
191
  @alpn = ch_alpn.protocol_name_list
187
192
  .find { |p| @settings[:alpn].include?(p) }
188
193
 
189
- terminate(:no_application_protocol) if @alpn.nil?
194
+ @connection.terminate(:no_application_protocol) if @alpn.nil?
190
195
  end
191
196
 
192
197
  # record_size_limit
193
198
  ch_rsl = ch.extensions[Message::ExtensionType::RECORD_SIZE_LIMIT]
194
199
  @send_record_size = ch_rsl.record_size_limit unless ch_rsl.nil?
195
200
 
196
- @state = ServerState::RECVD_CH
201
+ @connection.state = ServerState::RECVD_CH
197
202
  when ServerState::RECVD_CH
198
203
  logger.debug('ServerState::RECVD_CH')
199
204
 
200
205
  # select parameters
201
- ch, = transcript[CH]
206
+ ch, = @transcript[CH]
202
207
  @cipher_suite = select_cipher_suite(ch)
203
208
  @named_group = select_named_group(ch)
204
209
  @signature_scheme = select_signature_scheme(ch, @crt)
205
- terminate(:handshake_failure) \
210
+ @connection.terminate(:handshake_failure) \
206
211
  if @cipher_suite.nil? || @signature_scheme.nil?
207
212
 
208
213
  # send HRR
209
214
  if @named_group.nil?
210
- ch1, = transcript[CH1] = transcript.delete(CH)
215
+ ch1, = @transcript[CH1] = @transcript.delete(CH)
211
216
  hrr = send_hello_retry_request(ch1, @cipher_suite)
212
- transcript[HRR] = [hrr, hrr.serialize]
213
- @state = ServerState::START
217
+ @transcript[HRR] = [hrr, hrr.serialize]
218
+ @connection.state = ServerState::START
214
219
  next
215
220
  end
216
- @state = ServerState::NEGOTIATED
221
+ @connection.state = ServerState::NEGOTIATED
217
222
  when ServerState::NEGOTIATED
218
223
  logger.debug('ServerState::NEGOTIATED')
219
224
 
220
- ch, = transcript[CH]
225
+ ch, = @transcript[CH]
221
226
  extensions, priv_key = gen_sh_extensions(@named_group)
222
227
  sh = send_server_hello(
223
228
  extensions,
224
229
  @cipher_suite,
225
230
  ch.legacy_session_id
226
231
  )
227
- transcript[SH] = [sh, sh.serialize]
228
- send_ccs if @settings[:compatibility_mode]
232
+ @transcript[SH] = [sh, sh.serialize]
233
+ @connection.send_ccs if @settings[:compatibility_mode]
229
234
 
230
235
  # generate shared secret
231
236
  ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
232
237
  &.key_share_entry
233
238
  &.find { |kse| kse.group == @named_group }
234
239
  &.key_exchange
235
- shared_secret = gen_shared_secret(ke, priv_key, @named_group)
240
+ shared_secret = Endpoint.gen_shared_secret(ke, priv_key, @named_group)
236
241
  key_schedule = KeySchedule.new(
237
242
  psk: @psk,
238
243
  shared_secret: shared_secret,
239
244
  cipher_suite: @cipher_suite,
240
- transcript: transcript
245
+ transcript: @transcript
241
246
  )
242
- @alert_wcipher = hs_wcipher = gen_cipher(
247
+ @connection.alert_wcipher = hs_wcipher = Endpoint.gen_cipher(
243
248
  @cipher_suite,
244
249
  key_schedule.server_handshake_write_key,
245
250
  key_schedule.server_handshake_write_iv
246
251
  )
247
252
  sslkeylogfile&.write_server_handshake_traffic_secret(
248
- transcript[CH].first.random,
253
+ @transcript[CH].first.random,
249
254
  key_schedule.server_handshake_traffic_secret
250
255
  )
251
- hs_rcipher = gen_cipher(
256
+ hs_rcipher = Endpoint.gen_cipher(
252
257
  @cipher_suite,
253
258
  key_schedule.client_handshake_write_key,
254
259
  key_schedule.client_handshake_write_iv
255
260
  )
256
261
  sslkeylogfile&.write_client_handshake_traffic_secret(
257
- transcript[CH].first.random,
262
+ @transcript[CH].first.random,
258
263
  key_schedule.client_handshake_traffic_secret
259
264
  )
260
- @state = ServerState::WAIT_FLIGHT2
265
+ @connection.state = ServerState::WAIT_FLIGHT2
261
266
  when ServerState::WAIT_EOED
262
267
  logger.debug('ServerState::WAIT_EOED')
263
268
  when ServerState::WAIT_FLIGHT2
264
269
  logger.debug('ServerState::WAIT_FLIGHT2')
265
270
 
266
- ch, = transcript[CH]
271
+ ch, = @transcript[CH]
267
272
  rsl = @send_record_size \
268
273
  if ch.extensions.include?(Message::ExtensionType::RECORD_SIZE_LIMIT)
269
274
  ee = gen_encrypted_extensions(ch, @alpn, rsl)
270
- transcript[EE] = [ee, ee.serialize]
275
+ @transcript[EE] = [ee, ee.serialize]
271
276
  # TODO: [Send CertificateRequest]
272
277
 
273
278
  # status_request
274
279
  ocsp_response = fetch_ocsp_response \
275
280
  if ch.extensions.include?(Message::ExtensionType::STATUS_REQUEST)
276
281
  ct = gen_certificate(@crt, ch, @chain, ocsp_response)
277
- transcript[CT] = [ct, ct.serialize]
282
+ @transcript[CT] = [ct, ct.serialize]
278
283
  digest = CipherSuite.digest(@cipher_suite)
279
- hash = transcript.hash(digest, CT)
284
+ hash = @transcript.hash(digest, CT)
280
285
  cv = gen_certificate_verify(@key, @signature_scheme, hash)
281
- transcript[CV] = [cv, cv.serialize]
286
+ @transcript[CV] = [cv, cv.serialize]
282
287
  finished_key = key_schedule.server_finished_key
283
- signature = sign_finished(
288
+ signature = Endpoint.sign_finished(
284
289
  digest: digest,
285
290
  finished_key: finished_key,
286
- hash: transcript.hash(digest, CV)
291
+ hash: @transcript.hash(digest, CV)
287
292
  )
288
293
  sf = Message::Finished.new(signature)
289
- transcript[SF] = [sf, sf.serialize]
294
+ @transcript[SF] = [sf, sf.serialize]
290
295
  send_server_parameters([ee, ct, cv, sf], hs_wcipher)
291
- @state = ServerState::WAIT_FINISHED
296
+ @connection.state = ServerState::WAIT_FINISHED
292
297
  when ServerState::WAIT_CERT
293
298
  logger.debug('ServerState::WAIT_CERT')
294
299
  when ServerState::WAIT_CV
@@ -296,35 +301,36 @@ module TTTLS13
296
301
  when ServerState::WAIT_FINISHED
297
302
  logger.debug('ServerState::WAIT_FINISHED')
298
303
 
299
- cf, = transcript[CF] = recv_finished(hs_rcipher)
304
+ cf, = @transcript[CF] = recv_finished(hs_rcipher)
300
305
  digest = CipherSuite.digest(@cipher_suite)
301
- verified = verified_finished?(
306
+ verified = Endpoint.verified_finished?(
302
307
  finished: cf,
303
308
  digest: digest,
304
309
  finished_key: key_schedule.client_finished_key,
305
- hash: transcript.hash(digest, EOED)
310
+ hash: @transcript.hash(digest, EOED)
306
311
  )
307
- terminate(:decrypt_error) unless verified
308
- @alert_wcipher = @ap_wcipher = gen_cipher(
312
+ @connection.terminate(:decrypt_error) unless verified
313
+ @connection.ap_wcipher = Endpoint.gen_cipher(
309
314
  @cipher_suite,
310
315
  key_schedule.server_application_write_key,
311
316
  key_schedule.server_application_write_iv
312
317
  )
318
+ @connection.alert_wcipher = @connection.ap_wcipher
313
319
  sslkeylogfile&.write_server_traffic_secret_0(
314
- transcript[CH].first.random,
320
+ @transcript[CH].first.random,
315
321
  key_schedule.server_application_traffic_secret
316
322
  )
317
- @ap_rcipher = gen_cipher(
323
+ @connection.ap_rcipher = Endpoint.gen_cipher(
318
324
  @cipher_suite,
319
325
  key_schedule.client_application_write_key,
320
326
  key_schedule.client_application_write_iv
321
327
  )
322
328
  sslkeylogfile&.write_client_traffic_secret_0(
323
- transcript[CH].first.random,
329
+ @transcript[CH].first.random,
324
330
  key_schedule.client_application_traffic_secret
325
331
  )
326
332
  @exporter_secret = key_schedule.exporter_secret
327
- @state = ServerState::CONNECTED
333
+ @connection.state = ServerState::CONNECTED
328
334
  when ServerState::CONNECTED
329
335
  logger.debug('ServerState::CONNECTED')
330
336
 
@@ -339,6 +345,59 @@ module TTTLS13
339
345
  # rubocop: enable Metrics/MethodLength
340
346
  # rubocop: enable Metrics/PerceivedComplexity
341
347
 
348
+ # @raise [TTTLS13::Error::ConfigError]
349
+ #
350
+ # @return [String]
351
+ def read
352
+ @connection.read(nil)
353
+ end
354
+
355
+ # @param binary [String]
356
+ def write(binary)
357
+ @connection.write(binary)
358
+ end
359
+
360
+ # @return [Boolean]
361
+ def eof?
362
+ @connection.eof?
363
+ end
364
+
365
+ def close
366
+ @connection.close
367
+ end
368
+
369
+ # @return [TTTLS13::CipherSuite, nil]
370
+ def negotiated_cipher_suite
371
+ @cipher_suite
372
+ end
373
+
374
+ # @return [TTTLS13::NamedGroup, nil]
375
+ def negotiated_named_group
376
+ @named_group
377
+ end
378
+
379
+ # @return [TTTLS13::SignatureScheme, nil]
380
+ def negotiated_signature_scheme
381
+ @signature_scheme
382
+ end
383
+
384
+ # @return [String]
385
+ def negotiated_alpn
386
+ @alpn
387
+ end
388
+
389
+ # @param label [String]
390
+ # @param context [String]
391
+ # @param key_length [Integer]
392
+ #
393
+ # @return [String, nil]
394
+ def exporter(label, context, key_length)
395
+ return nil if @exporter_secret.nil? || @cipher_suite.nil?
396
+
397
+ digest = CipherSuite.digest(@cipher_suite)
398
+ Endpoint.exporter(@exporter_secret, digest, label, context, key_length)
399
+ end
400
+
342
401
  private
343
402
 
344
403
  # @return [Boolean]
@@ -365,11 +424,12 @@ module TTTLS13
365
424
  # @return [TTTLS13::Message::ClientHello]
366
425
  # @return [String]
367
426
  def recv_client_hello(receivable_ccs)
368
- ch, orig_msg = recv_message(
427
+ ch, orig_msg = @connection.recv_message(
369
428
  receivable_ccs: receivable_ccs,
370
429
  cipher: Cryptograph::Passer.new
371
430
  )
372
- terminate(:unexpected_message) unless ch.is_a?(Message::ClientHello)
431
+ @connection.terminate(:unexpected_message) \
432
+ unless ch.is_a?(Message::ClientHello)
373
433
 
374
434
  [ch, orig_msg]
375
435
  end
@@ -385,8 +445,8 @@ module TTTLS13
385
445
  cipher_suite: cipher_suite,
386
446
  extensions: extensions
387
447
  )
388
- send_handshakes(Message::ContentType::HANDSHAKE, [sh],
389
- Cryptograph::Passer.new)
448
+ @connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
449
+ Cryptograph::Passer.new)
390
450
 
391
451
  sh
392
452
  end
@@ -420,8 +480,8 @@ module TTTLS13
420
480
  cipher_suite: cipher_suite,
421
481
  extensions: exs
422
482
  )
423
- send_handshakes(Message::ContentType::HANDSHAKE, [sh],
424
- Cryptograph::Passer.new)
483
+ @connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
484
+ Cryptograph::Passer.new)
425
485
 
426
486
  sh
427
487
  end
@@ -431,8 +491,8 @@ module TTTLS13
431
491
  #
432
492
  # @return [Array of TTTLS13::Message::$Object]
433
493
  def send_server_parameters(messages, cipher)
434
- send_handshakes(Message::ContentType::APPLICATION_DATA,
435
- messages.reject(&:nil?), cipher)
494
+ @connection.send_handshakes(Message::ContentType::APPLICATION_DATA,
495
+ messages.reject(&:nil?), cipher)
436
496
 
437
497
  messages
438
498
  end
@@ -505,8 +565,10 @@ module TTTLS13
505
565
  # @return [TTTLS13::Message::Finished]
506
566
  # @return [String]
507
567
  def recv_finished(cipher)
508
- cf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
509
- terminate(:unexpected_message) unless cf.is_a?(Message::Finished)
568
+ cf, orig_msg \
569
+ = @connection.recv_message(receivable_ccs: true, cipher: cipher)
570
+ @connection.terminate(:unexpected_message) \
571
+ unless cf.is_a?(Message::Finished)
510
572
 
511
573
  [cf, orig_msg]
512
574
  end
@@ -563,7 +625,7 @@ module TTTLS13
563
625
  #
564
626
  # @return [String]
565
627
  def sign_certificate_verify(key:, signature_scheme:, hash:)
566
- do_sign_certificate_verify(
628
+ Endpoint.sign_certificate_verify(
567
629
  key: key,
568
630
  signature_scheme: signature_scheme,
569
631
  context: 'TLS 1.3, server CertificateVerify',
@@ -600,7 +662,7 @@ module TTTLS13
600
662
  algorithms = ch.extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
601
663
  &.supported_signature_algorithms || []
602
664
 
603
- do_select_signature_algorithms(algorithms, crt).find do |ss|
665
+ Endpoint.select_signature_algorithms(algorithms, crt).find do |ss|
604
666
  @settings[:signature_algorithms].include?(ss)
605
667
  end
606
668
  end
@@ -614,7 +676,7 @@ module TTTLS13
614
676
  &.server_name
615
677
  return true if server_name.nil?
616
678
 
617
- matching_san?(crt, server_name)
679
+ Endpoint.matching_san?(crt, server_name)
618
680
  end
619
681
 
620
682
  # @return [OpenSSL::OCSP::Response, nil]
@@ -91,6 +91,43 @@ module TTTLS13
91
91
  def bin2i(binary)
92
92
  OpenSSL::BN.new(binary, 2).to_i
93
93
  end
94
+
95
+ # rubocop: disable Metrics/AbcSize
96
+ # rubocop: disable Metrics/CyclomaticComplexity
97
+ # rubocop: disable Metrics/PerceivedComplexity
98
+ def obj2html(obj)
99
+ if obj.is_a?(OpenSSL::X509::Certificate)
100
+ obj.to_pem.gsub("\n", '<br>')
101
+ elsif obj.is_a?(Numeric) ||
102
+ obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
103
+ obj.pretty_print_inspect
104
+ elsif obj.is_a?(String) && obj.empty?
105
+ ''
106
+ elsif obj.is_a? String
107
+ '0x' + obj.unpack1('H*')
108
+ elsif obj.is_a? NilClass
109
+ ''
110
+ elsif obj.is_a? Array
111
+ '<ul>' + obj.map { |i| '<li>' + obj2html(i) + '</li>' }.join + '</ul>'
112
+ elsif obj.is_a? Hash
113
+ obj.map do |k, v|
114
+ '<details><summary>' + obj2html(k) + '</summary>' \
115
+ + obj2html(v) \
116
+ + '</details>'
117
+ end.join
118
+ elsif obj.is_a?(Object) && !obj.instance_variables.empty?
119
+ obj.instance_variables.map do |i|
120
+ '<details><summary>' + i[1..] + '</summary>' \
121
+ + obj2html(obj.instance_variable_get(i)) \
122
+ + '</details>'
123
+ end.join
124
+ else
125
+ obj.class.name
126
+ end
127
+ end
128
+ # rubocop: enable Metrics/AbcSize
129
+ # rubocop: enable Metrics/CyclomaticComplexity
130
+ # rubocop: enable Metrics/PerceivedComplexity
94
131
  end
95
132
  end
96
133
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.3.0'
4
+ VERSION = '0.3.2'
5
5
  end
data/lib/tttls1.3.rb CHANGED
@@ -21,7 +21,8 @@ require 'tttls1.3/key_schedule'
21
21
  require 'tttls1.3/message'
22
22
  require 'tttls1.3/sequence_number'
23
23
  require 'tttls1.3/sslkeylogfile'
24
- require 'tttls1.3/hpke'
24
+ require 'tttls1.3/ech'
25
25
  require 'tttls1.3/connection'
26
+ require 'tttls1.3/endpoint'
26
27
  require 'tttls1.3/client'
27
28
  require 'tttls1.3/server'
data/spec/client_spec.rb CHANGED
@@ -129,10 +129,11 @@ RSpec.describe Client do
129
129
  client = Client.new(mock_socket, 'localhost')
130
130
  digest = CipherSuite.digest(cipher_suite)
131
131
  hash = transcript.hash(digest, EOED)
132
- signature = client.send(:sign_finished,
133
- digest: digest,
134
- finished_key: finished_key,
135
- hash: hash)
132
+ signature = Endpoint.sign_finished(
133
+ digest: digest,
134
+ finished_key: finished_key,
135
+ hash: hash
136
+ )
136
137
  hs_wcipher = Cryptograph::Aead.new(
137
138
  cipher_suite: cipher_suite,
138
139
  write_key: TESTBINARY_CLIENT_FINISHED_WRITE_KEY,
@@ -215,20 +216,22 @@ RSpec.describe Client do
215
216
  it 'should verify server Finished' do
216
217
  digest = CipherSuite.digest(cipher_suite)
217
218
  hash = transcript.hash(digest, CV)
218
- expect(client.send(:verified_finished?,
219
- finished: sf,
220
- digest: digest,
221
- finished_key: key_schedule.server_finished_key,
222
- hash: hash)).to be true
219
+ expect(Endpoint.verified_finished?(
220
+ finished: sf,
221
+ digest: digest,
222
+ finished_key: key_schedule.server_finished_key,
223
+ hash: hash
224
+ )).to be true
223
225
  end
224
226
 
225
227
  it 'should sign client Finished' do
226
228
  digest = CipherSuite.digest(cipher_suite)
227
229
  hash = transcript.hash(digest, EOED)
228
- expect(client.send(:sign_finished,
229
- digest: digest,
230
- finished_key: key_schedule.client_finished_key,
231
- hash: hash)).to eq cf.verify_data
230
+ expect(Endpoint.sign_finished(
231
+ digest: digest,
232
+ finished_key: key_schedule.client_finished_key,
233
+ hash: hash
234
+ )).to eq cf.verify_data
232
235
  end
233
236
  end
234
237
 
@@ -240,18 +243,16 @@ RSpec.describe Client do
240
243
  Certificate.new(certificate_list: [CertificateEntry.new(server_crt)])
241
244
  end
242
245
 
243
- let(:client) do
244
- Client.new(nil, 'localhost')
245
- end
246
-
247
246
  it 'should not certify certificate' do
248
- expect(client.send(:trusted_certificate?, certificate.certificate_list))
247
+ expect(Endpoint.trusted_certificate?(certificate.certificate_list))
249
248
  .to be false
250
249
  end
251
250
 
252
251
  it 'should certify certificate, received path to private ca.crt' do
253
- expect(client.send(:trusted_certificate?, certificate.certificate_list,
254
- __dir__ + '/fixtures/rsa_ca.crt')).to be true
252
+ expect(Endpoint.trusted_certificate?(
253
+ certificate.certificate_list,
254
+ __dir__ + '/fixtures/rsa_ca.crt'
255
+ )).to be true
255
256
  end
256
257
  end
257
258
 
@@ -270,44 +271,4 @@ RSpec.describe Client do
270
271
  'SHA256')).to eq TESTBINARY_0_RTT_PSK
271
272
  end
272
273
  end
273
-
274
- context 'EncodedClientHelloInner length' do
275
- let(:server_name) do
276
- 'localhost'
277
- end
278
-
279
- let(:client) do
280
- Client.new(nil, server_name)
281
- end
282
-
283
- let(:maximum_name_length) do
284
- 0
285
- end
286
-
287
- let(:encoded) do
288
- extensions, = client.send(:gen_ch_extensions)
289
- inner_ech = Message::Extension::ECHClientHello.new_inner
290
- Message::ClientHello.new(
291
- legacy_session_id: '',
292
- cipher_suites: CipherSuites.new(DEFAULT_CH_CIPHER_SUITES),
293
- extensions: extensions.merge(
294
- Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => inner_ech
295
- )
296
- )
297
- end
298
-
299
- let(:padding_encoded_ch_inner) do
300
- client.send(
301
- :padding_encoded_ch_inner,
302
- encoded.serialize[4..],
303
- server_name.length,
304
- maximum_name_length
305
- )
306
- end
307
-
308
- it 'should be equal placeholder_encoded_ch_inner_len' do
309
- expect(client.send(:placeholder_encoded_ch_inner_len))
310
- .to eq padding_encoded_ch_inner.length
311
- end
312
- end
313
274
  end