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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +4 -2
- data/.rubocop.yml +16 -11
- data/.ruby-version +1 -1
- data/Gemfile +5 -4
- data/README.md +4 -4
- data/Rakefile +3 -3
- data/example/helper.rb +14 -5
- data/example/https_client_using_0rtt.rb +1 -1
- data/example/https_client_using_ech.rb +1 -1
- data/example/https_client_using_hrr_and_ech.rb +1 -1
- data/example/https_client_using_hrr_and_ticket.rb +1 -1
- data/example/https_client_using_status_request.rb +1 -1
- data/example/https_client_using_ticket.rb +1 -1
- data/example/https_client_using_ticket_and_ech.rb +3 -3
- data/example/https_server.rb +1 -1
- data/interop/client_spec.rb +57 -31
- data/interop/server_spec.rb +74 -46
- data/interop/spec_helper.rb +2 -2
- data/lib/tttls1.3/cipher_suites.rb +21 -16
- data/lib/tttls1.3/client.rb +89 -78
- data/lib/tttls1.3/connection.rb +6 -15
- data/lib/tttls1.3/cryptograph/aead.rb +26 -21
- data/lib/tttls1.3/ech.rb +13 -17
- data/lib/tttls1.3/endpoint.rb +4 -25
- data/lib/tttls1.3/key_schedule.rb +2 -2
- data/lib/tttls1.3/logging.rb +1 -1
- data/lib/tttls1.3/message/alert.rb +3 -4
- data/lib/tttls1.3/message/application_data.rb +1 -1
- data/lib/tttls1.3/message/certificate.rb +4 -7
- data/lib/tttls1.3/message/certificate_verify.rb +3 -5
- data/lib/tttls1.3/message/client_hello.rb +17 -15
- data/lib/tttls1.3/message/compressed_certificate.rb +3 -9
- data/lib/tttls1.3/message/encrypted_extensions.rb +1 -2
- data/lib/tttls1.3/message/extension/alpn.rb +2 -7
- data/lib/tttls1.3/message/extension/compress_certificate.rb +1 -2
- data/lib/tttls1.3/message/extension/cookie.rb +1 -2
- data/lib/tttls1.3/message/extension/early_data_indication.rb +1 -2
- data/lib/tttls1.3/message/extension/ech.rb +9 -19
- data/lib/tttls1.3/message/extension/ech_outer_extensions.rb +1 -3
- data/lib/tttls1.3/message/extension/key_share.rb +20 -49
- data/lib/tttls1.3/message/extension/pre_shared_key.rb +8 -20
- data/lib/tttls1.3/message/extension/psk_key_exchange_modes.rb +1 -2
- data/lib/tttls1.3/message/extension/record_size_limit.rb +1 -2
- data/lib/tttls1.3/message/extension/server_name.rb +1 -3
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +1 -2
- data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +1 -1
- data/lib/tttls1.3/message/extension/status_request.rb +4 -12
- data/lib/tttls1.3/message/extension/supported_groups.rb +1 -4
- data/lib/tttls1.3/message/extension/supported_versions.rb +2 -8
- data/lib/tttls1.3/message/extension/unknown_extension.rb +2 -4
- data/lib/tttls1.3/message/extensions.rb +1 -9
- data/lib/tttls1.3/message/finished.rb +1 -2
- data/lib/tttls1.3/message/new_session_ticket.rb +6 -12
- data/lib/tttls1.3/message/record.rb +10 -25
- data/lib/tttls1.3/message/server_hello.rb +10 -21
- data/lib/tttls1.3/named_group.rb +13 -9
- data/lib/tttls1.3/server.rb +39 -35
- data/lib/tttls1.3/shared_secret.rb +118 -0
- data/lib/tttls1.3/utils.rb +0 -15
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +1 -1
- data/spec/certificate_verify_spec.rb +1 -1
- data/spec/client_hello_spec.rb +22 -3
- data/spec/client_spec.rb +13 -13
- data/spec/endpoint_spec.rb +11 -11
- data/spec/key_schedule_spec.rb +4 -4
- data/spec/new_session_ticket_spec.rb +4 -4
- data/spec/pre_shared_key_spec.rb +8 -8
- data/spec/record_spec.rb +1 -1
- data/spec/server_hello_spec.rb +5 -5
- data/spec/server_spec.rb +8 -8
- data/tttls1.3.gemspec +2 -2
- metadata +7 -10
- 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
|
-
|
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
|
120
|
-
random
|
121
|
-
legacy_session_id_echo
|
122
|
-
cipher_suite
|
123
|
-
legacy_compression_method
|
124
|
-
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
|
data/lib/tttls1.3/named_group.rb
CHANGED
@@ -6,8 +6,8 @@ module TTTLS13
|
|
6
6
|
SECP256R1 = "\x00\x17"
|
7
7
|
SECP384R1 = "\x00\x18"
|
8
8
|
SECP521R1 = "\x00\x19"
|
9
|
-
|
10
|
-
|
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
|
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
|
data/lib/tttls1.3/server.rb
CHANGED
@@ -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
|
-
|
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
|
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,
|
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
|
-
|
238
|
-
|
239
|
-
|
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
|
290
|
-
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
|
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
|
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
|
446
|
-
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
|
-
|
473
|
+
&.named_group_list || []
|
468
474
|
ks_groups = ch1.extensions[Message::ExtensionType::KEY_SHARE]
|
469
|
-
|
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
|
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
|
554
|
-
signature_scheme
|
555
|
-
hash:
|
557
|
+
key:,
|
558
|
+
signature_scheme:,
|
559
|
+
hash:
|
556
560
|
)
|
557
|
-
Message::CertificateVerify.new(signature_scheme
|
558
|
-
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:
|
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 [
|
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,
|
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,
|
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
|
630
|
-
signature_scheme
|
633
|
+
key:,
|
634
|
+
signature_scheme:,
|
631
635
|
context: 'TLS 1.3, server CertificateVerify',
|
632
|
-
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/tttls1.3/utils.rb
CHANGED
@@ -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
|
data/lib/tttls1.3/version.rb
CHANGED
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'
|
data/spec/client_hello_spec.rb
CHANGED
@@ -21,9 +21,9 @@ RSpec.describe ClientHello do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
let(:message) do
|
24
|
-
ClientHello.new(random
|
25
|
-
legacy_session_id
|
26
|
-
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
|
122
|
-
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
|
134
|
-
finished_key
|
135
|
-
hash:
|
133
|
+
digest:,
|
134
|
+
finished_key:,
|
135
|
+
hash:
|
136
136
|
)
|
137
137
|
hs_wcipher = Cryptograph::Aead.new(
|
138
|
-
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
|
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
|
198
|
-
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
|
221
|
+
digest:,
|
222
222
|
finished_key: key_schedule.server_finished_key,
|
223
|
-
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
|
231
|
+
digest:,
|
232
232
|
finished_key: key_schedule.client_finished_key,
|
233
|
-
hash:
|
233
|
+
hash:
|
234
234
|
)).to eq cf.verify_data
|
235
235
|
end
|
236
236
|
end
|