tttls1.3 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39cf5b4e5fd508981bdefedc27502ac14b984699983d44160d9a836b2ab2aa2b
4
- data.tar.gz: 0250c8ad97ef5bef6a52d7b6e22c990b842ce66a8ab6e2d3abc0c6ef90a4eb13
3
+ metadata.gz: 98d9d2196c5b71c0bef8d7abb8838afb1c6d6bc42cdf5b09f24402591cb259ce
4
+ data.tar.gz: 7fa9dbb492a6a1b8b1b4040b212c8678aaa1fa384da421faa550bb64891908c1
5
5
  SHA512:
6
- metadata.gz: e8ef15683ceabb9396eb51e5831f3dc48ed9c4df11871f10458160804891107fe3bff2d0c1810ad294134c8bec4d63534b2aee7cc6c8bff5f7ae07462bf753ef
7
- data.tar.gz: 7baf720c22742962380449ad01372264634e878113858643cdc8a0db55e0f0cf07e0bd45cd80ad461cab9a337c89c7e0ad9c0e0057e02cbcda77a0765f10bdb9
6
+ metadata.gz: ee9f193f6d30c8248cebe79a34c949dbbd39529eb5df949dfd02e6fb164c474334d6767b3d2c9ce99794fb04368744ccb24063e92ca078bdf45e64f05004ec70
7
+ data.tar.gz: 974e0c1bfd02a73fa38ce1e46fb22032e68d43c8823692b1f0b79e6c3f417e4cf94206e9d865ef3aea7ece3c8d4268e235248c88f664264cf2e83a2df8963ecc
@@ -420,6 +420,7 @@ module TTTLS13
420
420
  # supported_groups
421
421
  groups = @settings[:supported_groups]
422
422
  exs << Message::Extension::SupportedGroups.new(groups)
423
+
423
424
  # key_share
424
425
  ksg = @settings[:key_share_groups] || groups
425
426
  key_share, priv_keys \
@@ -668,7 +669,7 @@ module TTTLS13
668
669
  sh = @transcript[SH]
669
670
  sh_lv = sh.legacy_version
670
671
  sh_sv = sh.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
671
- &.versions || []
672
+ &.versions || []
672
673
 
673
674
  sh_lv == Message::ProtocolVersion::TLS_1_2 &&
674
675
  sh_sv.first == Message::ProtocolVersion::TLS_1_3
@@ -744,7 +745,7 @@ module TTTLS13
744
745
  def valid_sh_key_share?
745
746
  offered = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
746
747
  .key_share_entry.map(&:group)
747
- selected = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
748
+ selected = @transcript[SH].extensions[Message::ExtensionType::KEY_SHARE]
748
749
  .key_share_entry.first.group
749
750
  offered.include?(selected)
750
751
  end
@@ -754,14 +755,11 @@ module TTTLS13
754
755
  # TODO: pre_shared_key
755
756
  ch1_exs = @transcript[CH1].extensions
756
757
  ngl = ch1_exs[Message::ExtensionType::SUPPORTED_GROUPS].named_group_list
758
+ kse = ch1_exs[Message::ExtensionType::KEY_SHARE].key_share_entry
757
759
  group = @transcript[HRR].extensions[Message::ExtensionType::KEY_SHARE]
758
760
  .key_share_entry.first.group
759
- return false unless ngl.include?(group)
760
761
 
761
- kse = ch1_exs[Message::ExtensionType::KEY_SHARE].key_share_entry
762
- return false if !kse.empty? && kse.map(&:group).include?(group)
763
-
764
- true
762
+ ngl.include?(group) && !kse.map(&:group).include?(group)
765
763
  end
766
764
 
767
765
  # @param nst [TTTLS13::Message::NewSessionTicket]
@@ -363,15 +363,16 @@ module TTTLS13
363
363
  end
364
364
 
365
365
  # @return [Boolean]
366
- #
367
- # Received ccs before the first ClientHello message or after the peer's
368
- # Finished message, peer MUST abort.
369
366
  def receivable_ccs?
370
- return false unless @transcript.include?(CH)
371
- return false if @endpoint == :client && @transcript.include?(SF)
372
- return false if @endpoint == :server && @transcript.include?(CF)
373
-
374
- true
367
+ # Received ccs before the first ClientHello message or after the peer's
368
+ # Finished message, peer MUST abort.
369
+ #
370
+ # Server may receive an unprotected record of type change_cipher_spec
371
+ # between the first and second ClientHello
372
+ finished = (@endpoint == :client ? SF : CF)
373
+
374
+ (@transcript.include?(CH) || @transcript.include?(CH1)) &&
375
+ !@transcript.include?(finished)
375
376
  end
376
377
 
377
378
  # @param symbol [Symbol] key of ALERT_DESCRIPTION
@@ -131,6 +131,17 @@ module TTTLS13
131
131
  [key_share, ec]
132
132
  end
133
133
 
134
+ # @param groups [TTTLS13::NamedGroup]
135
+ #
136
+ # @return [TTTLS13::Message::Extensions::KeyShare]
137
+ def self.gen_hrr_key_share(group)
138
+ kse = KeyShareEntry.new(group: group)
139
+ KeyShare.new(
140
+ msg_type: HandshakeType::HELLO_RETRY_REQUEST,
141
+ key_share_entry: [kse]
142
+ )
143
+ end
144
+
134
145
  class << self
135
146
  private
136
147
 
@@ -21,13 +21,12 @@ module TTTLS13
21
21
  ].freeze
22
22
  private_constant :APPEARABLE_HRR_EXTENSIONS
23
23
 
24
- class ServerHello
25
- # special value of the SHA-256 of "HelloRetryRequest"
26
- HRR_RANDOM \
27
- = "\xcf\x21\xad\x74\xe5\x9a\x61\x11\xbe\x1d\x8c\x02\x1e\x65\xb8\x91" \
28
- "\xc2\xa2\x11\x16\x7a\xbb\x8c\x5e\x07\x9e\x09\xe2\xc8\xa8\x33\x9c"
29
- private_constant :HRR_RANDOM
24
+ # special value of the SHA-256 of "HelloRetryRequest"
25
+ HRR_RANDOM \
26
+ = "\xcf\x21\xad\x74\xe5\x9a\x61\x11\xbe\x1d\x8c\x02\x1e\x65\xb8\x91" \
27
+ "\xc2\xa2\x11\x16\x7a\xbb\x8c\x5e\x07\x9e\x09\xe2\xc8\xa8\x33\x9c"
30
28
 
29
+ class ServerHello
31
30
  attr_reader :msg_type
32
31
  attr_reader :legacy_version
33
32
  attr_reader :random
@@ -140,14 +140,22 @@ module TTTLS13
140
140
  terminate(:protocol_version) unless negotiated_tls_1_3?
141
141
 
142
142
  # validate/select parameters
143
+ terminamte(:illegal_parameter) unless valid_ch_compression_methods?
144
+ terminate(:illegal_parameter) unless valid_ch_key_share?
145
+ terminate(:unrecognized_name) unless recognized_server_name?
143
146
  @cipher_suite = select_cipher_suite
144
147
  @named_group = select_named_group
145
148
  @signature_scheme = select_signature_scheme
146
149
  terminate(:handshake_failure) \
147
- if @cipher_suite.nil? || @named_group.nil? || @signature_scheme.nil?
148
- terminamte(:illegal_parameter) unless valid_ch_compression_methods?
149
- terminate(:unrecognized_name) unless recognized_server_name?
150
-
150
+ if @cipher_suite.nil? || @signature_scheme.nil?
151
+
152
+ # send HRR
153
+ if @named_group.nil?
154
+ @transcript[CH1] = @transcript.delete(CH)
155
+ @transcript[HRR] = send_hello_retry_request
156
+ @state = ServerState::START
157
+ next
158
+ end
151
159
  @state = ServerState::NEGOTIATED
152
160
  when ServerState::NEGOTIATED
153
161
  logger.debug('ServerState::NEGOTIATED')
@@ -157,12 +165,10 @@ module TTTLS13
157
165
  send_ccs # compatibility mode
158
166
 
159
167
  # generate shared secret
160
- terminate(:illegal_parameter) unless valid_ch_key_share?
161
168
  ke = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
162
- &.key_share_entry
163
- &.find { |e| e.group == @named_group }
164
- &.key_exchange
165
- # TODO: Send HelloRetryRequest
169
+ &.key_share_entry
170
+ &.find { |e| e.group == @named_group }
171
+ &.key_exchange
166
172
  shared_secret = gen_shared_secret(ke, @priv_key, @named_group)
167
173
  @key_schedule = KeySchedule.new(psk: @psk,
168
174
  shared_secret: shared_secret,
@@ -260,6 +266,38 @@ module TTTLS13
260
266
  sh
261
267
  end
262
268
 
269
+ # @return [TTTLS13::Message::ServerHello]
270
+ def send_hello_retry_request
271
+ exs = []
272
+ # supported_versions
273
+ exs << Message::Extension::SupportedVersions.new(
274
+ msg_type: Message::HandshakeType::SERVER_HELLO
275
+ )
276
+
277
+ # key_share
278
+ ch1 = @transcript[CH1]
279
+ sp_groups = ch1.extensions[Message::ExtensionType::SUPPORTED_GROUPS]
280
+ &.named_group_list || []
281
+ ks_groups = ch1.extensions[Message::ExtensionType::KEY_SHARE]
282
+ &.key_share_entry&.map(&:group) || []
283
+ ksg = sp_groups.find do |g|
284
+ !ks_groups.include?(g) && @settings[:supported_groups].include?(g)
285
+ end
286
+
287
+ # TODO: cookie
288
+ exs << Message::Extension::KeyShare.gen_hrr_key_share(ksg)
289
+
290
+ sh = Message::ServerHello.new(
291
+ random: Message::HRR_RANDOM,
292
+ legacy_session_id_echo: ch1.legacy_session_id,
293
+ cipher_suite: @cipher_suite,
294
+ extensions: Message::Extensions.new(exs)
295
+ )
296
+ send_handshakes(Message::ContentType::HANDSHAKE, [sh], @write_cipher)
297
+
298
+ sh
299
+ end
300
+
263
301
  # @param messages [Array of TTTLS13::Message::$Object]
264
302
  #
265
303
  # @return [Array of TTTLS13::Message::$Object]
@@ -374,7 +412,7 @@ module TTTLS13
374
412
  ch = @transcript[CH]
375
413
  ch_lv = ch.legacy_version
376
414
  ch_sv = ch.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
377
- &.versions || []
415
+ &.versions || []
378
416
 
379
417
  ch_lv == Message::ProtocolVersion::TLS_1_2 &&
380
418
  ch_sv.include?(Message::ProtocolVersion::TLS_1_3)
@@ -389,12 +427,11 @@ module TTTLS13
389
427
 
390
428
  # @return [TTTLS13::NamedGroup, nil]
391
429
  def select_named_group
392
- groups \
393
- = @transcript[CH].extensions[Message::ExtensionType::SUPPORTED_GROUPS]
394
- &.named_group_list || []
430
+ ks_groups = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
431
+ &.key_share_entry&.map(&:group) || []
395
432
 
396
- groups.find do |sg|
397
- @settings[:supported_groups].include?(sg)
433
+ ks_groups.find do |g|
434
+ @settings[:supported_groups].include?(g)
398
435
  end
399
436
  end
400
437
 
@@ -402,7 +439,7 @@ module TTTLS13
402
439
  def select_signature_scheme
403
440
  algorithms \
404
441
  = @transcript[CH].extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
405
- &.supported_signature_algorithms || []
442
+ &.supported_signature_algorithms || []
406
443
 
407
444
  do_select_signature_algorithms(algorithms, @crt).find do |ss|
408
445
  @settings[:signature_algorithms].include?(ss)
@@ -418,7 +455,7 @@ module TTTLS13
418
455
  def recognized_server_name?
419
456
  server_name \
420
457
  = @transcript[CH].extensions[Message::ExtensionType::SERVER_NAME]
421
- &.server_name
458
+ &.server_name
422
459
 
423
460
  return true if server_name.nil?
424
461
 
@@ -432,7 +469,13 @@ module TTTLS13
432
469
  sg = @transcript[CH].extensions[Message::ExtensionType::SUPPORTED_GROUPS]
433
470
  sp_groups = sg&.named_group_list || []
434
471
 
435
- ks_groups.uniq == ks_groups && (ks_groups - sp_groups).empty?
472
+ # Each KeyShareEntry value MUST correspond to a group offered in the
473
+ # "supported_groups" extension and MUST appear in the same order.
474
+ #
475
+ # Clients MUST NOT offer multiple KeyShareEntry values for the same group.
476
+ (ks_groups - sp_groups).empty? &&
477
+ sp_groups.filter { |g| ks_groups.include?(g) } == ks_groups &&
478
+ ks_groups.uniq == ks_groups
436
479
  end
437
480
  end
438
481
  # rubocop: enable Metrics/ClassLength
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
@@ -98,4 +98,43 @@ RSpec.describe ServerHello do
98
98
  expect(message.serialize).to eq TESTBINARY_0_RTT_SERVER_HELLO
99
99
  end
100
100
  end
101
+
102
+ context 'default hello_retry_request' do
103
+ let(:legacy_session_id_echo) do
104
+ Array.new(32, 0).map(&:chr).join
105
+ end
106
+
107
+ let(:cipher_suite) do
108
+ CipherSuite::TLS_AES_256_GCM_SHA384
109
+ end
110
+
111
+ let(:message) do
112
+ ServerHello.new(random: Message::HRR_RANDOM,
113
+ legacy_session_id_echo: legacy_session_id_echo,
114
+ cipher_suite: cipher_suite)
115
+ end
116
+
117
+ it 'should be generated' do
118
+ expect(message.msg_type).to eq HandshakeType::SERVER_HELLO
119
+ expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
120
+ expect(message.random).to eq Message::HRR_RANDOM
121
+ expect(message.legacy_session_id_echo).to eq legacy_session_id_echo
122
+ expect(message.cipher_suite).to eq CipherSuite::TLS_AES_256_GCM_SHA384
123
+ expect(message.legacy_compression_method).to eq "\x00"
124
+ expect(message.extensions).to be_empty
125
+ expect(message.hrr?).to eq true
126
+ end
127
+
128
+ it 'should be serialized' do
129
+ expect(message.serialize).to eq HandshakeType::SERVER_HELLO \
130
+ + 72.to_uint24 \
131
+ + ProtocolVersion::TLS_1_2 \
132
+ + Message::HRR_RANDOM \
133
+ + legacy_session_id_echo.length.to_uint8 \
134
+ + legacy_session_id_echo \
135
+ + cipher_suite \
136
+ + "\x00" \
137
+ + Extensions.new.serialize
138
+ end
139
+ end
101
140
  end
data/spec/server_spec.rb CHANGED
@@ -40,8 +40,8 @@ RSpec.describe Server do
40
40
  server.instance_variable_set(:@transcript, transcript)
41
41
  cipher_suite = server.send(:select_cipher_suite)
42
42
  server.instance_variable_set(:@cipher_suite, cipher_suite)
43
- named_group = server.send(:select_named_group)
44
- server.instance_variable_set(:@named_group, named_group)
43
+ # X25519 is unsupported so @named_group uses SECP256R1.
44
+ server.instance_variable_set(:@named_group, NamedGroup::SECP256R1)
45
45
  signature_scheme = server.send(:select_signature_scheme)
46
46
  server.instance_variable_set(:@signature_scheme, signature_scheme)
47
47
  exs, _priv_key = server.send(:gen_sh_extensions)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tttls1.3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - thekuwayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-22 00:00:00.000000000 Z
11
+ date: 2019-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler