tttls1.3 0.3.3 → 0.3.5

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -2
  3. data/.rubocop.yml +16 -11
  4. data/.ruby-version +1 -1
  5. data/Gemfile +5 -4
  6. data/README.md +4 -4
  7. data/Rakefile +3 -3
  8. data/example/helper.rb +14 -5
  9. data/example/https_client_using_0rtt.rb +1 -1
  10. data/example/https_client_using_ech.rb +1 -1
  11. data/example/https_client_using_hrr_and_ech.rb +1 -1
  12. data/example/https_client_using_hrr_and_ticket.rb +1 -1
  13. data/example/https_client_using_status_request.rb +1 -1
  14. data/example/https_client_using_ticket.rb +1 -1
  15. data/example/https_client_using_ticket_and_ech.rb +3 -3
  16. data/example/https_server.rb +1 -1
  17. data/interop/client_spec.rb +57 -31
  18. data/interop/server_spec.rb +74 -46
  19. data/interop/spec_helper.rb +2 -2
  20. data/lib/tttls1.3/cipher_suites.rb +21 -16
  21. data/lib/tttls1.3/client.rb +89 -78
  22. data/lib/tttls1.3/connection.rb +6 -15
  23. data/lib/tttls1.3/cryptograph/aead.rb +26 -21
  24. data/lib/tttls1.3/ech.rb +13 -17
  25. data/lib/tttls1.3/endpoint.rb +4 -25
  26. data/lib/tttls1.3/key_schedule.rb +2 -2
  27. data/lib/tttls1.3/logging.rb +1 -1
  28. data/lib/tttls1.3/message/alert.rb +3 -4
  29. data/lib/tttls1.3/message/application_data.rb +1 -1
  30. data/lib/tttls1.3/message/certificate.rb +4 -7
  31. data/lib/tttls1.3/message/certificate_verify.rb +3 -5
  32. data/lib/tttls1.3/message/client_hello.rb +17 -15
  33. data/lib/tttls1.3/message/compressed_certificate.rb +3 -9
  34. data/lib/tttls1.3/message/encrypted_extensions.rb +1 -2
  35. data/lib/tttls1.3/message/extension/alpn.rb +2 -7
  36. data/lib/tttls1.3/message/extension/compress_certificate.rb +1 -2
  37. data/lib/tttls1.3/message/extension/cookie.rb +1 -2
  38. data/lib/tttls1.3/message/extension/early_data_indication.rb +1 -2
  39. data/lib/tttls1.3/message/extension/ech.rb +9 -19
  40. data/lib/tttls1.3/message/extension/ech_outer_extensions.rb +1 -3
  41. data/lib/tttls1.3/message/extension/key_share.rb +20 -49
  42. data/lib/tttls1.3/message/extension/pre_shared_key.rb +8 -20
  43. data/lib/tttls1.3/message/extension/psk_key_exchange_modes.rb +1 -2
  44. data/lib/tttls1.3/message/extension/record_size_limit.rb +1 -2
  45. data/lib/tttls1.3/message/extension/server_name.rb +1 -3
  46. data/lib/tttls1.3/message/extension/signature_algorithms.rb +1 -2
  47. data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +1 -1
  48. data/lib/tttls1.3/message/extension/status_request.rb +4 -12
  49. data/lib/tttls1.3/message/extension/supported_groups.rb +1 -4
  50. data/lib/tttls1.3/message/extension/supported_versions.rb +2 -8
  51. data/lib/tttls1.3/message/extension/unknown_extension.rb +2 -4
  52. data/lib/tttls1.3/message/extensions.rb +1 -9
  53. data/lib/tttls1.3/message/finished.rb +1 -2
  54. data/lib/tttls1.3/message/new_session_ticket.rb +6 -12
  55. data/lib/tttls1.3/message/record.rb +10 -25
  56. data/lib/tttls1.3/message/server_hello.rb +10 -21
  57. data/lib/tttls1.3/named_group.rb +13 -9
  58. data/lib/tttls1.3/server.rb +39 -35
  59. data/lib/tttls1.3/shared_secret.rb +118 -0
  60. data/lib/tttls1.3/utils.rb +0 -15
  61. data/lib/tttls1.3/version.rb +1 -1
  62. data/lib/tttls1.3.rb +1 -1
  63. data/spec/certificate_verify_spec.rb +1 -1
  64. data/spec/client_hello_spec.rb +22 -3
  65. data/spec/client_spec.rb +13 -13
  66. data/spec/endpoint_spec.rb +11 -11
  67. data/spec/key_schedule_spec.rb +4 -4
  68. data/spec/new_session_ticket_spec.rb +4 -4
  69. data/spec/pre_shared_key_spec.rb +8 -8
  70. data/spec/record_spec.rb +1 -1
  71. data/spec/server_hello_spec.rb +5 -5
  72. data/spec/server_spec.rb +8 -8
  73. data/tttls1.3.gemspec +2 -2
  74. metadata +7 -10
  75. data/example/https_client_using_grease_psk.rb +0 -58
@@ -34,13 +34,8 @@ module TTTLS13
34
34
  "\xc2\xa2\x11\x16\x7a\xbb\x8c\x5e\x07\x9e\x09\xe2\xc8\xa8\x33\x9c"
35
35
 
36
36
  class ServerHello
37
- attr_reader :msg_type
38
- attr_reader :legacy_version
39
- attr_reader :random
40
- attr_reader :legacy_session_id_echo
41
- attr_reader :cipher_suite
42
- attr_reader :legacy_compression_method
43
- attr_reader :extensions
37
+ attr_reader :msg_type, :legacy_version, :random, :legacy_session_id_echo, :cipher_suite,
38
+ :legacy_compression_method, :extensions
44
39
 
45
40
  # @param legacy_version [String]
46
41
  # @param random [String]
@@ -49,10 +44,8 @@ module TTTLS13
49
44
  # @param legacy_compression_method [String]
50
45
  # @param extensions [TTTLS13::Message::Extensions]
51
46
  # rubocop: disable Metrics/ParameterLists
52
- def initialize(legacy_version: ProtocolVersion::TLS_1_2,
47
+ def initialize(legacy_session_id_echo:, cipher_suite:, legacy_version: ProtocolVersion::TLS_1_2,
53
48
  random: OpenSSL::Random.random_bytes(32),
54
- legacy_session_id_echo:,
55
- cipher_suite:,
56
49
  legacy_compression_method: "\x00",
57
50
  extensions: Extensions.new)
58
51
  @msg_type = HandshakeType::SERVER_HELLO
@@ -84,9 +77,7 @@ module TTTLS13
84
77
  #
85
78
  # @return [TTTLS13::Message::ServerHello]
86
79
  # rubocop: disable Metrics/AbcSize
87
- # rubocop: disable Metrics/CyclomaticComplexity
88
80
  # rubocop: disable Metrics/MethodLength
89
- # rubocop: disable Metrics/PerceivedComplexity
90
81
  def self.deserialize(binary)
91
82
  raise Error::ErrorAlerts, :internal_error if binary.nil?
92
83
  raise Error::ErrorAlerts, :decode_error if binary.length < 39
@@ -116,18 +107,16 @@ module TTTLS13
116
107
  raise Error::ErrorAlerts, :decode_error unless i == msg_len + 4 &&
117
108
  i == binary.length
118
109
 
119
- ServerHello.new(legacy_version: legacy_version,
120
- random: random,
121
- legacy_session_id_echo: legacy_session_id_echo,
122
- cipher_suite: cipher_suite,
123
- legacy_compression_method: legacy_compression_method,
124
- extensions: extensions)
110
+ ServerHello.new(legacy_version:,
111
+ random:,
112
+ legacy_session_id_echo:,
113
+ cipher_suite:,
114
+ legacy_compression_method:,
115
+ extensions:)
125
116
  end
117
+
126
118
  # rubocop: enable Metrics/AbcSize
127
- # rubocop: enable Metrics/CyclomaticComplexity
128
119
  # rubocop: enable Metrics/MethodLength
129
- # rubocop: enable Metrics/PerceivedComplexity
130
-
131
120
  # @return [Boolean]
132
121
  def hrr?
133
122
  @random == HRR_RANDOM
@@ -6,8 +6,8 @@ module TTTLS13
6
6
  SECP256R1 = "\x00\x17"
7
7
  SECP384R1 = "\x00\x18"
8
8
  SECP521R1 = "\x00\x19"
9
- # X25519 = "\x00\x1d" # UNSUPPORTED
10
- # X448 = "\x00\x1e" # UNSUPPORTED
9
+ X25519 = "\x00\x1d"
10
+ X448 = "\x00\x1e"
11
11
  # FFDHE2048 = "\x01\x00" # UNSUPPORTED
12
12
  # FFDHE3072 = "\x01\x01" # UNSUPPORTED
13
13
  # FFDHE4096 = "\x01\x02" # UNSUPPORTED
@@ -17,7 +17,6 @@ module TTTLS13
17
17
  # ecdhe_private_use "\xfe\x00" ~ "\xfe\xff"
18
18
 
19
19
  class << self
20
- # NOTE:
21
20
  # For secp256r1, secp384r1, and secp521r1
22
21
  #
23
22
  # struct {
@@ -26,6 +25,8 @@ module TTTLS13
26
25
  # opaque Y[coordinate_length];
27
26
  # } UncompressedPointRepresentation;
28
27
  #
28
+ # https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8.2
29
+ #
29
30
  # @param group [TTTLS13::Message::Extension::NamedGroup]
30
31
  #
31
32
  # @raise [TTTLS13::Error::ErrorAlerts]
@@ -39,11 +40,11 @@ module TTTLS13
39
40
  97
40
41
  when SECP521R1
41
42
  133
43
+ when X25519
44
+ 32
45
+ when X448
46
+ 56
42
47
  # not supported other NamedGroup
43
- # when X25519
44
- # 32
45
- # when X448
46
- # 56
47
48
  # when FFDHE2048
48
49
  # 256
49
50
  # when FFDHE4096
@@ -57,7 +58,6 @@ module TTTLS13
57
58
  end
58
59
  end
59
60
 
60
- # NOTE:
61
61
  # SECG | ANSI X9.62 | NIST
62
62
  # ------------+---------------+-------------
63
63
  # secp256r1 | prime256v1 | NIST P-256
@@ -66,7 +66,7 @@ module TTTLS13
66
66
  #
67
67
  # https://datatracker.ietf.org/doc/html/rfc4492#appendix-A
68
68
  #
69
- # @param groups [Array of TTTLS13::Message::Extension::NamedGroup]
69
+ # @param group [TTTLS13::Message::Extension::NamedGroup]
70
70
  #
71
71
  # @raise [TTTLS13::Error::ErrorAlerts]
72
72
  #
@@ -79,6 +79,10 @@ module TTTLS13
79
79
  'secp384r1'
80
80
  when SECP521R1
81
81
  'secp521r1'
82
+ when X25519
83
+ 'X25519'
84
+ when X448
85
+ 'X448'
82
86
  else
83
87
  # not supported other NamedGroup
84
88
  raise Error::ErrorAlerts, :internal_error
@@ -38,6 +38,7 @@ module TTTLS13
38
38
  private_constant :DEFAULT_SP_SIGNATURE_ALGORITHMS
39
39
 
40
40
  DEFAULT_SP_NAMED_GROUP_LIST = [
41
+ NamedGroup::X25519,
41
42
  NamedGroup::SECP256R1,
42
43
  NamedGroup::SECP384R1,
43
44
  NamedGroup::SECP521R1
@@ -73,6 +74,7 @@ module TTTLS13
73
74
 
74
75
  # @param socket [Socket]
75
76
  # @param settings [Hash]
77
+ # rubocop: disable Metrics/AbcSize
76
78
  def initialize(socket, **settings)
77
79
  @connection = Connection.new(socket, :server)
78
80
  @settings = DEFAULT_SERVER_SETTINGS.merge(settings)
@@ -95,8 +97,8 @@ module TTTLS13
95
97
  raise Error::ConfigError unless cert.verify(sign.public_key)
96
98
  end
97
99
  end
100
+ # rubocop: enable Metrics/AbcSize
98
101
 
99
- # NOTE:
100
102
  # START <-----+
101
103
  # Recv ClientHello | | Send HelloRetryRequest
102
104
  # v |
@@ -148,7 +150,7 @@ module TTTLS13
148
150
  def accept
149
151
  @transcript = Transcript.new
150
152
  key_schedule = nil # TTTLS13::KeySchedule
151
- priv_key = nil # OpenSSL::PKey::$Object
153
+ shared_secret = nil # TTTLS13::SharedSecret
152
154
  hs_wcipher = nil # TTTLS13::Cryptograph::$Object
153
155
  hs_rcipher = nil # TTTLS13::Cryptograph::$Object
154
156
  sslkeylogfile = nil # TTTLS13::SslKeyLogFile::Writer
@@ -187,7 +189,7 @@ module TTTLS13
187
189
  ch_alpn = ch.extensions[
188
190
  Message::ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
189
191
  ]
190
- if !@settings[:alpn].nil? && !@settings[:alpn].empty? && !ch_alpn.nil?
192
+ if use_alpn? && !ch_alpn.nil?
191
193
  @alpn = ch_alpn.protocol_name_list
192
194
  .find { |p| @settings[:alpn].include?(p) }
193
195
 
@@ -223,7 +225,7 @@ module TTTLS13
223
225
  logger.debug('ServerState::NEGOTIATED')
224
226
 
225
227
  ch, = @transcript[CH]
226
- extensions, priv_key = gen_sh_extensions(@named_group)
228
+ extensions, shared_secret = gen_sh_extensions(@named_group)
227
229
  sh = send_server_hello(
228
230
  extensions,
229
231
  @cipher_suite,
@@ -234,13 +236,12 @@ module TTTLS13
234
236
 
235
237
  # generate shared secret
236
238
  ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
237
- &.key_share_entry
238
- &.find { |kse| kse.group == @named_group }
239
- &.key_exchange
240
- shared_secret = Endpoint.gen_shared_secret(ke, priv_key, @named_group)
239
+ &.key_share_entry
240
+ &.find { |kse| kse.group == @named_group }
241
+ &.key_exchange
241
242
  key_schedule = KeySchedule.new(
242
243
  psk: @psk,
243
- shared_secret: shared_secret,
244
+ shared_secret: shared_secret.build(@named_group, ke),
244
245
  cipher_suite: @cipher_suite,
245
246
  transcript: @transcript
246
247
  )
@@ -286,8 +287,8 @@ module TTTLS13
286
287
  @transcript[CV] = [cv, cv.serialize]
287
288
  finished_key = key_schedule.server_finished_key
288
289
  signature = Endpoint.sign_finished(
289
- digest: digest,
290
- finished_key: finished_key,
290
+ digest:,
291
+ finished_key:,
291
292
  hash: @transcript.hash(digest, CV)
292
293
  )
293
294
  sf = Message::Finished.new(signature)
@@ -305,7 +306,7 @@ module TTTLS13
305
306
  digest = CipherSuite.digest(@cipher_suite)
306
307
  verified = Endpoint.verified_finished?(
307
308
  finished: cf,
308
- digest: digest,
309
+ digest:,
309
310
  finished_key: key_schedule.client_finished_key,
310
311
  hash: @transcript.hash(digest, EOED)
311
312
  )
@@ -417,6 +418,11 @@ module TTTLS13
417
418
  true
418
419
  end
419
420
 
421
+ # @return [Boolean]
422
+ def use_alpn?
423
+ !@settings[:alpn].nil? && !@settings[:alpn].empty?
424
+ end
425
+
420
426
  # @param receivable_ccs [Boolean]
421
427
  #
422
428
  # @raise [TTTLS13::Error::ErrorAlerts]
@@ -425,7 +431,7 @@ module TTTLS13
425
431
  # @return [String]
426
432
  def recv_client_hello(receivable_ccs)
427
433
  ch, orig_msg = @connection.recv_message(
428
- receivable_ccs: receivable_ccs,
434
+ receivable_ccs:,
429
435
  cipher: Cryptograph::Passer.new
430
436
  )
431
437
  @connection.terminate(:unexpected_message) \
@@ -442,8 +448,8 @@ module TTTLS13
442
448
  def send_server_hello(extensions, cipher_suite, session_id)
443
449
  sh = Message::ServerHello.new(
444
450
  legacy_session_id_echo: session_id,
445
- cipher_suite: cipher_suite,
446
- extensions: extensions
451
+ cipher_suite:,
452
+ extensions:
447
453
  )
448
454
  @connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
449
455
  Cryptograph::Passer.new)
@@ -464,9 +470,9 @@ module TTTLS13
464
470
 
465
471
  # key_share
466
472
  sp_groups = ch1.extensions[Message::ExtensionType::SUPPORTED_GROUPS]
467
- &.named_group_list || []
473
+ &.named_group_list || []
468
474
  ks_groups = ch1.extensions[Message::ExtensionType::KEY_SHARE]
469
- &.key_share_entry&.map(&:group) || []
475
+ &.key_share_entry&.map(&:group) || []
470
476
  ksg = sp_groups.find do |g|
471
477
  !ks_groups.include?(g) && @settings[:supported_groups].include?(g)
472
478
  end
@@ -477,7 +483,7 @@ module TTTLS13
477
483
  sh = Message::ServerHello.new(
478
484
  random: Message::HRR_RANDOM,
479
485
  legacy_session_id_echo: ch1.legacy_session_id,
480
- cipher_suite: cipher_suite,
486
+ cipher_suite:,
481
487
  extensions: exs
482
488
  )
483
489
  @connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
@@ -514,7 +520,6 @@ module TTTLS13
514
520
  # @param ocsp_response [OpenSSL::OCSP::Response]
515
521
  #
516
522
  # @return [TTTLS13::Message::Certificate, CompressedCertificate, nil]
517
- # rubocop: disable Metrics/CyclomaticComplexity
518
523
  def gen_certificate(crt, ch, chain = [], ocsp_response = nil)
519
524
  exs = Message::Extensions.new
520
525
  # status_request
@@ -541,7 +546,6 @@ module TTTLS13
541
546
 
542
547
  ct
543
548
  end
544
- # rubocop: enable Metrics/CyclomaticComplexity
545
549
 
546
550
  # @param key [OpenSSL::PKey::PKey]
547
551
  # @param signature_scheme [TTTLS13::SignatureScheme]
@@ -550,12 +554,12 @@ module TTTLS13
550
554
  # @return [TTTLS13::Message::CertificateVerify, nil]
551
555
  def gen_certificate_verify(key, signature_scheme, hash)
552
556
  signature = sign_certificate_verify(
553
- key: key,
554
- signature_scheme: signature_scheme,
555
- hash: hash
557
+ key:,
558
+ signature_scheme:,
559
+ hash:
556
560
  )
557
- Message::CertificateVerify.new(signature_scheme: signature_scheme,
558
- signature: signature)
561
+ Message::CertificateVerify.new(signature_scheme:,
562
+ signature:)
559
563
  end
560
564
 
561
565
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -566,7 +570,7 @@ module TTTLS13
566
570
  # @return [String]
567
571
  def recv_finished(cipher)
568
572
  cf, orig_msg \
569
- = @connection.recv_message(receivable_ccs: true, cipher: cipher)
573
+ = @connection.recv_message(receivable_ccs: true, cipher:)
570
574
  @connection.terminate(:unexpected_message) \
571
575
  unless cf.is_a?(Message::Finished)
572
576
 
@@ -576,7 +580,7 @@ module TTTLS13
576
580
  # @param named_group [TTTLS13::NamedGroup]
577
581
  #
578
582
  # @return [TTTLS13::Message::Extensions]
579
- # @return [OpenSSL::PKey::EC.$Object]
583
+ # @return [TTTLS13::SharedSecret]
580
584
  def gen_sh_extensions(named_group)
581
585
  exs = Message::Extensions.new
582
586
  # supported_versions: only TLS 1.3
@@ -585,11 +589,11 @@ module TTTLS13
585
589
  )
586
590
 
587
591
  # key_share
588
- key_share, priv_key \
592
+ key_share, shared_secret \
589
593
  = Message::Extension::KeyShare.gen_sh_key_share(named_group)
590
594
  exs << key_share
591
595
 
592
- [exs, priv_key]
596
+ [exs, shared_secret]
593
597
  end
594
598
 
595
599
  # @param ch [TTTLS13::Message::ClientHello]
@@ -626,10 +630,10 @@ module TTTLS13
626
630
  # @return [String]
627
631
  def sign_certificate_verify(key:, signature_scheme:, hash:)
628
632
  Endpoint.sign_certificate_verify(
629
- key: key,
630
- signature_scheme: signature_scheme,
633
+ key:,
634
+ signature_scheme:,
631
635
  context: 'TLS 1.3, server CertificateVerify',
632
- hash: hash
636
+ hash:
633
637
  )
634
638
  end
635
639
 
@@ -647,7 +651,7 @@ module TTTLS13
647
651
  # @return [TTTLS13::NamedGroup, nil]
648
652
  def select_named_group(ch)
649
653
  ks_groups = ch.extensions[Message::ExtensionType::KEY_SHARE]
650
- &.key_share_entry&.map(&:group) || []
654
+ &.key_share_entry&.map(&:group) || []
651
655
 
652
656
  ks_groups.find do |g|
653
657
  @settings[:supported_groups].include?(g)
@@ -660,7 +664,7 @@ module TTTLS13
660
664
  # @return [TTTLS13::SignatureScheme, nil]
661
665
  def select_signature_scheme(ch, crt)
662
666
  algorithms = ch.extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
663
- &.supported_signature_algorithms || []
667
+ &.supported_signature_algorithms || []
664
668
 
665
669
  Endpoint.select_signature_algorithms(algorithms, crt).find do |ss|
666
670
  @settings[:signature_algorithms].include?(ss)
@@ -673,7 +677,7 @@ module TTTLS13
673
677
  # @return [Boolean]
674
678
  def recognized_server_name?(ch, crt)
675
679
  server_name = ch.extensions[Message::ExtensionType::SERVER_NAME]
676
- &.server_name
680
+ &.server_name
677
681
  return true if server_name.nil?
678
682
 
679
683
  Endpoint.matching_san?(crt, server_name)
@@ -0,0 +1,118 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ class SharedSecret
6
+ def initialize
7
+ @priv_keys = {}
8
+ end
9
+
10
+ # @param group [TTTLS13::NamedGroup]
11
+ # @param priv_key [OpenSSL::PKey::EC.$Object | OpenSSL::PKey::PKey.$Object]
12
+ def store!(group, priv_key)
13
+ @priv_keys[group] = priv_key
14
+ end
15
+
16
+ # @param group [TTTLS13::NamedGroup]
17
+ # @param key_exchange [String]
18
+ #
19
+ # @return String
20
+ # rubocop: disable Metrics/MethodLength
21
+ def build(group, key_exchange)
22
+ case group
23
+ when NamedGroup::SECP256R1, NamedGroup::SECP384R1, NamedGroup::SECP521R1
24
+ curve = NamedGroup.curve_name(group)
25
+ pub_key = OpenSSL::PKey::EC::Point.new(
26
+ OpenSSL::PKey::EC::Group.new(curve),
27
+ OpenSSL::BN.new(key_exchange, 2)
28
+ )
29
+ @priv_keys[group].dh_compute_key(pub_key)
30
+ when NamedGroup::X25519
31
+ asn1_seq = OpenSSL::ASN1.Sequence(
32
+ [
33
+ OpenSSL::ASN1.Sequence(
34
+ [
35
+ # https://datatracker.ietf.org/doc/html/rfc8410#section-3
36
+ OpenSSL::ASN1.ObjectId('1.3.101.110')
37
+ ]
38
+ ),
39
+ OpenSSL::ASN1.BitString(key_exchange)
40
+ ]
41
+ )
42
+
43
+ @priv_keys[group].derive(OpenSSL::PKey.read(asn1_seq.to_der))
44
+ when NamedGroup::X448
45
+ asn1_seq = OpenSSL::ASN1.Sequence(
46
+ [
47
+ OpenSSL::ASN1.Sequence(
48
+ [
49
+ # https://datatracker.ietf.org/doc/html/rfc8410#section-3
50
+ OpenSSL::ASN1.ObjectId('1.3.101.111')
51
+ ]
52
+ ),
53
+ OpenSSL::ASN1.BitString(key_exchange)
54
+ ]
55
+ )
56
+
57
+ @priv_keys[group].derive(OpenSSL::PKey.read(asn1_seq.to_der))
58
+ else
59
+ # not supported other NamedGroup
60
+ raise Error::ErrorAlerts, :internal_error
61
+ end
62
+ end
63
+ # rubocop: enable Metrics/MethodLength
64
+
65
+ # @return [Array of TTTLS13::Message::Extensions::KeyShare]
66
+ def key_share_entries
67
+ @priv_keys.map do |group, priv_key|
68
+ case group
69
+ when NamedGroup::SECP256R1, NamedGroup::SECP384R1, NamedGroup::SECP521R1
70
+ Message::Extension::KeyShareEntry.new(
71
+ group:,
72
+ key_exchange: priv_key.public_key.to_octet_string(:uncompressed)
73
+ )
74
+ when NamedGroup::X25519, NamedGroup::X448
75
+ n_pk = NamedGroup.key_exchange_len(group)
76
+ Message::Extension::KeyShareEntry.new(
77
+ group:,
78
+ key_exchange: priv_key.public_to_der[-n_pk, n_pk]
79
+ )
80
+ else
81
+ # not supported other NamedGroup
82
+ raise Error::ErrorAlerts, :internal_error
83
+ end
84
+ end
85
+ end
86
+
87
+ # @param group [TTTLS13::Message::Extension::NamedGroup]
88
+ #
89
+ # @return [OpenSSL::PKey::EC.$Object | OpenSSL::PKey::PKey.$Object]]
90
+ def [](group)
91
+ @priv_keys[group]
92
+ end
93
+
94
+ # @param groups [Array of TTTLS13::NamedGroup]
95
+ #
96
+ # @return [TTTLS13::SharedSecret]
97
+ def self.gen_from_named_groups(groups)
98
+ shared_secret = SharedSecret.new
99
+
100
+ groups.each do |group|
101
+ case group
102
+ when NamedGroup::SECP256R1, NamedGroup::SECP384R1, NamedGroup::SECP521R1
103
+ curve = NamedGroup.curve_name(group)
104
+ ec = OpenSSL::PKey::EC.generate(curve)
105
+ shared_secret.store!(group, ec)
106
+ when NamedGroup::X25519, NamedGroup::X448
107
+ pkey = OpenSSL::PKey.generate_key(NamedGroup.curve_name(group))
108
+ shared_secret.store!(group, pkey)
109
+ else
110
+ # not supported other NamedGroup
111
+ raise Error::ErrorAlerts, :internal_error
112
+ end
113
+ end
114
+
115
+ shared_secret
116
+ end
117
+ end
118
+ end
@@ -69,21 +69,6 @@ module TTTLS13
69
69
  length.to_uint64 + self
70
70
  end
71
71
  end
72
-
73
- refine OpenSSL::X509::Certificate do
74
- unless method_defined?(:ocsp_uris)
75
- define_method(:ocsp_uris) do
76
- aia = extensions.find { |ex| ex.oid == 'authorityInfoAccess' }
77
- return nil if aia.nil?
78
-
79
- ostr = OpenSSL::ASN1.decode(aia.to_der).value.last
80
- ocsp = OpenSSL::ASN1.decode(ostr.value)
81
- .map(&:value)
82
- .select { |des| des.first.value == 'OCSP' }
83
- ocsp&.map { |o| o[1].value }
84
- end
85
- end
86
- end
87
72
  end
88
73
 
89
74
  module Convert
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.3.3'
4
+ VERSION = '0.3.5'
5
5
  end
data/lib/tttls1.3.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'openssl'
4
4
  require 'net/http'
5
- require 'pp'
6
5
  require 'logger'
7
6
 
8
7
  require 'ech_config'
@@ -18,6 +17,7 @@ require 'tttls1.3/named_group'
18
17
  require 'tttls1.3/cryptograph'
19
18
  require 'tttls1.3/transcript'
20
19
  require 'tttls1.3/key_schedule'
20
+ require 'tttls1.3/shared_secret'
21
21
  require 'tttls1.3/message'
22
22
  require 'tttls1.3/sequence_number'
23
23
  require 'tttls1.3/sslkeylogfile'
@@ -13,7 +13,7 @@ RSpec.describe CertificateVerify do
13
13
  let(:message) do
14
14
  CertificateVerify.new(
15
15
  signature_scheme: SignatureScheme::RSA_PSS_RSAE_SHA256,
16
- signature: signature
16
+ signature:
17
17
  )
18
18
  end
19
19
 
@@ -21,9 +21,9 @@ RSpec.describe ClientHello do
21
21
  end
22
22
 
23
23
  let(:message) do
24
- ClientHello.new(random: random,
25
- legacy_session_id: legacy_session_id,
26
- cipher_suites: cipher_suites)
24
+ ClientHello.new(random:,
25
+ legacy_session_id:,
26
+ cipher_suites:)
27
27
  end
28
28
 
29
29
  it 'should be generated' do
@@ -37,6 +37,7 @@ RSpec.describe ClientHello do
37
37
  expect(message.legacy_compression_methods).to eq ["\x00"]
38
38
  expect(message.extensions).to be_empty
39
39
  expect(message.negotiated_tls_1_3?).to be false
40
+ expect(message.ch_inner?).to be false
40
41
  end
41
42
 
42
43
  it 'should be serialized' do
@@ -83,4 +84,22 @@ RSpec.describe ClientHello do
83
84
  expect(message.serialize).to eq TESTBINARY_0_RTT_CLIENT_HELLO
84
85
  end
85
86
  end
87
+
88
+ context 'valid inner client_hello' do
89
+ let(:message) do
90
+ cipher_suites = CipherSuites.new([TLS_AES_256_GCM_SHA384,
91
+ TLS_CHACHA20_POLY1305_SHA256,
92
+ TLS_AES_128_GCM_SHA256])
93
+ ch = ClientHello.new(random: OpenSSL::Random.random_bytes(32),
94
+ legacy_session_id: Array.new(32, 0).map(&:chr).join,
95
+ cipher_suites:)
96
+ ch.extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO] \
97
+ = Message::Extension::ECHClientHello.new_inner
98
+ ch
99
+ end
100
+
101
+ it 'should generate ClientHelloInner' do
102
+ expect(message.ch_inner?).to be true
103
+ end
104
+ end
86
105
  end
data/spec/client_spec.rb CHANGED
@@ -118,8 +118,8 @@ RSpec.describe Client do
118
118
  let(:finished_key) do
119
119
  key_schedule = KeySchedule.new(
120
120
  shared_secret: TESTBINARY_SHARED_SECRET,
121
- cipher_suite: cipher_suite,
122
- transcript: transcript
121
+ cipher_suite:,
122
+ transcript:
123
123
  )
124
124
  key_schedule.client_finished_key
125
125
  end
@@ -130,19 +130,19 @@ RSpec.describe Client do
130
130
  digest = CipherSuite.digest(cipher_suite)
131
131
  hash = transcript.hash(digest, EOED)
132
132
  signature = Endpoint.sign_finished(
133
- digest: digest,
134
- finished_key: finished_key,
135
- hash: hash
133
+ digest:,
134
+ finished_key:,
135
+ hash:
136
136
  )
137
137
  hs_wcipher = Cryptograph::Aead.new(
138
- cipher_suite: cipher_suite,
138
+ cipher_suite:,
139
139
  write_key: TESTBINARY_CLIENT_FINISHED_WRITE_KEY,
140
140
  write_iv: TESTBINARY_CLIENT_FINISHED_WRITE_IV,
141
141
  sequence_number: SequenceNumber.new
142
142
  )
143
143
  client.send(:send_finished, signature, hs_wcipher)
144
144
  hs_rcipher = Cryptograph::Aead.new(
145
- cipher_suite: cipher_suite,
145
+ cipher_suite:,
146
146
  write_key: TESTBINARY_CLIENT_FINISHED_WRITE_KEY,
147
147
  write_iv: TESTBINARY_CLIENT_FINISHED_WRITE_IV,
148
148
  sequence_number: SequenceNumber.new
@@ -194,8 +194,8 @@ RSpec.describe Client do
194
194
  let(:key_schedule) do
195
195
  KeySchedule.new(
196
196
  shared_secret: TESTBINARY_SHARED_SECRET,
197
- cipher_suite: cipher_suite,
198
- transcript: transcript
197
+ cipher_suite:,
198
+ transcript:
199
199
  )
200
200
  end
201
201
 
@@ -218,9 +218,9 @@ RSpec.describe Client do
218
218
  hash = transcript.hash(digest, CV)
219
219
  expect(Endpoint.verified_finished?(
220
220
  finished: sf,
221
- digest: digest,
221
+ digest:,
222
222
  finished_key: key_schedule.server_finished_key,
223
- hash: hash
223
+ hash:
224
224
  )).to be true
225
225
  end
226
226
 
@@ -228,9 +228,9 @@ RSpec.describe Client do
228
228
  digest = CipherSuite.digest(cipher_suite)
229
229
  hash = transcript.hash(digest, EOED)
230
230
  expect(Endpoint.sign_finished(
231
- digest: digest,
231
+ digest:,
232
232
  finished_key: key_schedule.client_finished_key,
233
- hash: hash
233
+ hash:
234
234
  )).to eq cf.verify_data
235
235
  end
236
236
  end