tttls1.3 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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