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 +4 -4
- data/lib/tttls1.3/client.rb +5 -7
- data/lib/tttls1.3/connection.rb +9 -8
- data/lib/tttls1.3/message/extension/key_share.rb +11 -0
- data/lib/tttls1.3/message/server_hello.rb +5 -6
- data/lib/tttls1.3/server.rb +61 -18
- data/lib/tttls1.3/version.rb +1 -1
- data/spec/server_hello_spec.rb +39 -0
- data/spec/server_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98d9d2196c5b71c0bef8d7abb8838afb1c6d6bc42cdf5b09f24402591cb259ce
|
4
|
+
data.tar.gz: 7fa9dbb492a6a1b8b1b4040b212c8678aaa1fa384da421faa550bb64891908c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee9f193f6d30c8248cebe79a34c949dbbd39529eb5df949dfd02e6fb164c474334d6767b3d2c9ce99794fb04368744ccb24063e92ca078bdf45e64f05004ec70
|
7
|
+
data.tar.gz: 974e0c1bfd02a73fa38ce1e46fb22032e68d43c8823692b1f0b79e6c3f417e4cf94206e9d865ef3aea7ece3c8d4268e235248c88f664264cf2e83a2df8963ecc
|
data/lib/tttls1.3/client.rb
CHANGED
@@ -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
|
-
|
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[
|
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
|
-
|
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]
|
data/lib/tttls1.3/connection.rb
CHANGED
@@ -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
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
data/lib/tttls1.3/server.rb
CHANGED
@@ -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? || @
|
148
|
-
|
149
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
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
|
-
|
393
|
-
|
394
|
-
&.named_group_list || []
|
430
|
+
ks_groups = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
|
431
|
+
&.key_share_entry&.map(&:group) || []
|
395
432
|
|
396
|
-
|
397
|
-
@settings[:supported_groups].include?(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/tttls1.3/version.rb
CHANGED
data/spec/server_hello_spec.rb
CHANGED
@@ -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
|
44
|
-
server.instance_variable_set(:@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.
|
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-
|
11
|
+
date: 2019-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|