tttls1.3 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/example/helper.rb +13 -4
- data/lib/tttls1.3/client.rb +3 -5
- data/lib/tttls1.3/cryptograph/aead.rb +0 -5
- data/lib/tttls1.3/ech.rb +2 -2
- data/lib/tttls1.3/key_schedule.rb +1 -1
- data/lib/tttls1.3/message/application_data.rb +1 -1
- data/lib/tttls1.3/message/client_hello.rb +8 -0
- data/lib/tttls1.3/message/extension/alpn.rb +1 -1
- data/lib/tttls1.3/message/extension/ech.rb +0 -3
- data/lib/tttls1.3/message/extension/ech_outer_extensions.rb +0 -1
- data/lib/tttls1.3/message/extension/key_share.rb +3 -6
- data/lib/tttls1.3/message/extension/pre_shared_key.rb +0 -3
- data/lib/tttls1.3/message/extension/server_name.rb +0 -1
- data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +1 -1
- data/lib/tttls1.3/message/extension/unknown_extension.rb +0 -1
- data/lib/tttls1.3/message/extensions.rb +0 -2
- data/lib/tttls1.3/message/record.rb +0 -2
- data/lib/tttls1.3/named_group.rb +1 -3
- data/lib/tttls1.3/server.rb +0 -1
- data/lib/tttls1.3/version.rb +1 -1
- data/spec/client_hello_spec.rb +19 -0
- 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: '0913f70f0bdbfd6740f41ce7902f55660ea1bd99533a8f765f9d98a1bd56a58c'
|
4
|
+
data.tar.gz: 611a063ae74498d19636ebf3ee3741b76164856341bb38ec9966a999579bdfb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88f39003d30f4642c67a61169923fe248bc572b4a1c638eb36803dc4278aa91a499919784cd060fa35c522bcb935745d1b4542abb1963514aba1f86f1ea789fd
|
7
|
+
data.tar.gz: cd2ae8cd383cd9737a732d53c8ca27cbacdcd3c4a5b6bee62f5f43faba4fd8eb8067b0621df18d8b77db679823c3aa26947508fe5827939bf6741e6f417a1d80
|
data/Gemfile
CHANGED
data/example/helper.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH << __dir__ + '/../lib'
|
4
4
|
|
5
|
+
require 'base64'
|
6
|
+
require 'resolv'
|
5
7
|
require 'socket'
|
6
8
|
require 'time'
|
7
9
|
require 'uri'
|
@@ -9,7 +11,6 @@ require 'webrick'
|
|
9
11
|
|
10
12
|
require 'ech_config'
|
11
13
|
require 'http/parser'
|
12
|
-
require 'svcb_rr_patch'
|
13
14
|
|
14
15
|
require 'tttls1.3'
|
15
16
|
|
@@ -86,7 +87,8 @@ def transcript_htmlize(transcript)
|
|
86
87
|
end
|
87
88
|
|
88
89
|
def parse_echconfigs_pem(pem)
|
89
|
-
|
90
|
+
# https://datatracker.ietf.org/doc/html/draft-farrell-tls-pemesni-08#section-3-4
|
91
|
+
s = pem.gsub(/-----(BEGIN|END) (ECH CONFIGS|ECHCONFIG)-----/, '')
|
90
92
|
.gsub("\n", '')
|
91
93
|
b = Base64.decode64(s)
|
92
94
|
raise 'failed to parse ECHConfigs' \
|
@@ -100,8 +102,15 @@ def resolve_echconfig(hostname)
|
|
100
102
|
hostname,
|
101
103
|
Resolv::DNS::Resource::IN::HTTPS
|
102
104
|
)
|
105
|
+
|
106
|
+
# https://datatracker.ietf.org/doc/html/draft-ietf-tls-svcb-ech-01#section-6
|
107
|
+
ech = 5
|
103
108
|
raise "failed to resolve echconfig via #{hostname} HTTPS RR" \
|
104
|
-
if rr.first.nil? ||
|
109
|
+
if rr.first.nil? || rr.first.params[ech].nil?
|
110
|
+
|
111
|
+
octet = rr.first.params[ech].value
|
112
|
+
raise 'failed to parse ECHConfigs' \
|
113
|
+
unless octet.length == octet.slice(0, 2).unpack1('n') + 2
|
105
114
|
|
106
|
-
|
115
|
+
ECHConfig.decode_vectors(octet.slice(2..)).first
|
107
116
|
end
|
data/lib/tttls1.3/client.rb
CHANGED
@@ -89,8 +89,8 @@ module TTTLS13
|
|
89
89
|
class Client
|
90
90
|
include Logging
|
91
91
|
|
92
|
-
HpkeSymmetricCipherSuit
|
93
|
-
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite
|
92
|
+
HpkeSymmetricCipherSuit \
|
93
|
+
= ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite
|
94
94
|
|
95
95
|
attr_reader :transcript
|
96
96
|
|
@@ -110,7 +110,6 @@ module TTTLS13
|
|
110
110
|
raise Error::ConfigError unless valid_settings?
|
111
111
|
end
|
112
112
|
|
113
|
-
# NOTE:
|
114
113
|
# START <----+
|
115
114
|
# Send ClientHello | | Recv HelloRetryRequest
|
116
115
|
# [K_send = early data] | |
|
@@ -327,7 +326,7 @@ module TTTLS13
|
|
327
326
|
)
|
328
327
|
|
329
328
|
# rejected ECH
|
330
|
-
#
|
329
|
+
# It can compute (hrr_)accept_ech until client selects the
|
331
330
|
# cipher_suite.
|
332
331
|
if !sh.hrr? && use_ech?
|
333
332
|
if !@transcript.include?(HRR) && !key_schedule.accept_ech?
|
@@ -1008,7 +1007,6 @@ module TTTLS13
|
|
1008
1007
|
[new_exs, priv_keys]
|
1009
1008
|
end
|
1010
1009
|
|
1011
|
-
# NOTE:
|
1012
1010
|
# https://datatracker.ietf.org/doc/html/rfc8446#section-4.1.2
|
1013
1011
|
#
|
1014
1012
|
# @param ch1 [TTTLS13::Message::ClientHello]
|
@@ -23,8 +23,6 @@ module TTTLS13
|
|
23
23
|
when CipherSuite::TLS_CHACHA20_POLY1305_SHA256
|
24
24
|
@cipher = OpenSSL::Cipher.new('chacha20-poly1305')
|
25
25
|
else
|
26
|
-
# Note:
|
27
|
-
# not supported
|
28
26
|
# CipherSuite::TLS_AES_128_CCM_SHA256
|
29
27
|
# CipherSuite::TLS_AES_128_CCM_8_SHA256
|
30
28
|
raise Error::ErrorAlerts, :internal_error
|
@@ -36,7 +34,6 @@ module TTTLS13
|
|
36
34
|
@auth_tag_len = CipherSuite.auth_tag_len(@cipher_suite)
|
37
35
|
end
|
38
36
|
|
39
|
-
# NOTE:
|
40
37
|
# AEAD-Encrypt(write_key, nonce, additional_data, plaintext)
|
41
38
|
#
|
42
39
|
# @param content [String]
|
@@ -53,7 +50,6 @@ module TTTLS13
|
|
53
50
|
encrypted_data + cipher.auth_tag
|
54
51
|
end
|
55
52
|
|
56
|
-
# NOTE:
|
57
53
|
# AEAD-Decrypt(peer_write_key, nonce,
|
58
54
|
# additional_data, AEADEncrypted)
|
59
55
|
#
|
@@ -78,7 +74,6 @@ module TTTLS13
|
|
78
74
|
[clear[0...-postfix_len], clear[-postfix_len]]
|
79
75
|
end
|
80
76
|
|
81
|
-
# NOTE:
|
82
77
|
# struct {
|
83
78
|
# opaque content[TLSPlaintext.length];
|
84
79
|
# ContentType type;
|
data/lib/tttls1.3/ech.rb
CHANGED
@@ -19,7 +19,7 @@ module TTTLS13
|
|
19
19
|
# @param hpke_cipher_suite_selector [Method]
|
20
20
|
#
|
21
21
|
# @return [TTTLS13::Message::ClientHello]
|
22
|
-
# @return [TTTLS13::Message::ClientHello]
|
22
|
+
# @return [TTTLS13::Message::ClientHello] ClientHelloInner
|
23
23
|
# @return [TTTLS13::EchState]
|
24
24
|
# rubocop: disable Metrics/AbcSize
|
25
25
|
def self.offer_ech(inner, ech_config, hpke_cipher_suite_selector)
|
@@ -110,7 +110,7 @@ module TTTLS13
|
|
110
110
|
# @param ech_state [TTTLS13::EchState]
|
111
111
|
#
|
112
112
|
# @return [TTTLS13::Message::ClientHello]
|
113
|
-
# @return [TTTLS13::Message::ClientHello]
|
113
|
+
# @return [TTTLS13::Message::ClientHello] ClientHelloInner
|
114
114
|
def self.offer_new_ech(inner, ech_state)
|
115
115
|
# for ech_outer_extensions
|
116
116
|
replaced = \
|
@@ -250,7 +250,7 @@ module TTTLS13
|
|
250
250
|
#
|
251
251
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
252
252
|
#
|
253
|
-
# @
|
253
|
+
# @return [String]
|
254
254
|
def self.hkdf_expand(secret, info, length, digest)
|
255
255
|
hash_len = OpenSSL::Digest.new(digest).digest_length
|
256
256
|
raise Error::ErrorAlerts, :internal_error if length > 255 * hash_len
|
@@ -160,6 +160,14 @@ module TTTLS13
|
|
160
160
|
sg_groups.filter { |g| ks_groups.include?(g) } == ks_groups &&
|
161
161
|
ks_groups.uniq == ks_groups
|
162
162
|
end
|
163
|
+
|
164
|
+
# @return [Boolean]
|
165
|
+
def ch_inner?
|
166
|
+
ech = @extensions[Message::ExtensionType::ENCRYPTED_CLIENT_HELLO]
|
167
|
+
return false if ech.nil?
|
168
|
+
|
169
|
+
ech.type == Message::Extension::ECHClientHelloType::INNER
|
170
|
+
end
|
163
171
|
end
|
164
172
|
end
|
165
173
|
end
|
@@ -12,7 +12,6 @@ module TTTLS13
|
|
12
12
|
INNER = "\x01"
|
13
13
|
end
|
14
14
|
|
15
|
-
# NOTE:
|
16
15
|
# struct {
|
17
16
|
# ECHClientHelloType type;
|
18
17
|
# select (ECHClientHello.type) {
|
@@ -165,7 +164,6 @@ module TTTLS13
|
|
165
164
|
end
|
166
165
|
end
|
167
166
|
|
168
|
-
# NOTE:
|
169
167
|
# struct {
|
170
168
|
# ECHConfigList retry_configs;
|
171
169
|
# } ECHEncryptedExtensions;
|
@@ -202,7 +200,6 @@ module TTTLS13
|
|
202
200
|
end
|
203
201
|
end
|
204
202
|
|
205
|
-
# NOTE:
|
206
203
|
# struct {
|
207
204
|
# opaque confirmation[8];
|
208
205
|
# } ECHHelloRetryRequest;
|
@@ -11,7 +11,7 @@ module TTTLS13
|
|
11
11
|
attr_reader :msg_type
|
12
12
|
attr_reader :key_share_entry
|
13
13
|
|
14
|
-
# @param msg_type [TTTLS13::Message::
|
14
|
+
# @param msg_type [TTTLS13::Message::HandshakeType]
|
15
15
|
# @param key_share_entry [Array of KeyShareEntry]
|
16
16
|
#
|
17
17
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
@@ -108,7 +108,7 @@ module TTTLS13
|
|
108
108
|
[key_share, priv_keys]
|
109
109
|
end
|
110
110
|
|
111
|
-
# @param
|
111
|
+
# @param group [TTTLS13::NamedGroup]
|
112
112
|
#
|
113
113
|
# @return [TTTLS13::Message::Extensions::KeyShare]
|
114
114
|
# @return [OpenSSL::PKey::EC.$Object]
|
@@ -129,7 +129,7 @@ module TTTLS13
|
|
129
129
|
[key_share, ec]
|
130
130
|
end
|
131
131
|
|
132
|
-
# @param
|
132
|
+
# @param group [TTTLS13::NamedGroup]
|
133
133
|
#
|
134
134
|
# @return [TTTLS13::Message::Extensions::KeyShare]
|
135
135
|
def self.gen_hrr_key_share(group)
|
@@ -143,7 +143,6 @@ module TTTLS13
|
|
143
143
|
class << self
|
144
144
|
private
|
145
145
|
|
146
|
-
# NOTE:
|
147
146
|
# struct {
|
148
147
|
# KeyShareEntry client_shares<0..2^16-1>;
|
149
148
|
# } KeyShareClientHello;
|
@@ -178,7 +177,6 @@ module TTTLS13
|
|
178
177
|
key_share_entry
|
179
178
|
end
|
180
179
|
|
181
|
-
# NOTE:
|
182
180
|
# struct {
|
183
181
|
# KeyShareEntry server_share;
|
184
182
|
# } KeyShareServerHello;
|
@@ -201,7 +199,6 @@ module TTTLS13
|
|
201
199
|
[KeyShareEntry.new(group: group, key_exchange: key_exchange)]
|
202
200
|
end
|
203
201
|
|
204
|
-
# NOTE:
|
205
202
|
# struct {
|
206
203
|
# NamedGroup selected_group;
|
207
204
|
# } KeyShareHelloRetryRequest;
|
@@ -5,7 +5,6 @@ module TTTLS13
|
|
5
5
|
using Refinements
|
6
6
|
module Message
|
7
7
|
module Extension
|
8
|
-
# NOTE:
|
9
8
|
# struct {
|
10
9
|
# select (Handshake.msg_type) {
|
11
10
|
# case client_hello: OfferedPsks;
|
@@ -83,7 +82,6 @@ module TTTLS13
|
|
83
82
|
end
|
84
83
|
end
|
85
84
|
|
86
|
-
# NOTE:
|
87
85
|
# opaque PskBinderEntry<32..255>;
|
88
86
|
#
|
89
87
|
# struct {
|
@@ -172,7 +170,6 @@ module TTTLS13
|
|
172
170
|
# rubocop: enable Metrics/PerceivedComplexity
|
173
171
|
end
|
174
172
|
|
175
|
-
# NOTE:
|
176
173
|
# struct {
|
177
174
|
# opaque identity<1..2^16-1>;
|
178
175
|
# uint32 obfuscated_ticket_age;
|
@@ -5,7 +5,7 @@ module TTTLS13
|
|
5
5
|
module Message
|
6
6
|
module Extension
|
7
7
|
class SignatureAlgorithmsCert < SignatureAlgorithms
|
8
|
-
# @param
|
8
|
+
# @param supported_signature_algorithms [Array] Array of SignatureScheme
|
9
9
|
def initialize(supported_signature_algorithms)
|
10
10
|
super(supported_signature_algorithms)
|
11
11
|
@extension_type = ExtensionType::SIGNATURE_ALGORITHMS_CERT
|
@@ -21,7 +21,6 @@ module TTTLS13
|
|
21
21
|
|
22
22
|
alias super_fetch fetch
|
23
23
|
|
24
|
-
# NOTE:
|
25
24
|
# "pre_shared_key" MUST be the last extension in the ClientHello
|
26
25
|
#
|
27
26
|
# @return [String]
|
@@ -136,7 +135,6 @@ module TTTLS13
|
|
136
135
|
class << self
|
137
136
|
private
|
138
137
|
|
139
|
-
# NOTE:
|
140
138
|
# deserialize_extension ignores unparsable extension.
|
141
139
|
# Received unparsable binary, returns nil, doesn't raise
|
142
140
|
# ErrorAlerts :decode_error.
|
@@ -27,7 +27,6 @@ module TTTLS13
|
|
27
27
|
@cipher = cipher
|
28
28
|
end
|
29
29
|
|
30
|
-
# NOTE:
|
31
30
|
# serialize joins messages.
|
32
31
|
# If serialize is received Server Parameters(EE, CT, CV),
|
33
32
|
# it returns one binary.
|
@@ -50,7 +49,6 @@ module TTTLS13
|
|
50
49
|
end.join
|
51
50
|
end
|
52
51
|
|
53
|
-
# NOTE:
|
54
52
|
# If previous Record has surplus_binary,
|
55
53
|
# surplus_binary should is given to Record.deserialize as buffered.
|
56
54
|
#
|
data/lib/tttls1.3/named_group.rb
CHANGED
@@ -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 {
|
@@ -57,7 +56,6 @@ module TTTLS13
|
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
# NOTE:
|
61
59
|
# SECG | ANSI X9.62 | NIST
|
62
60
|
# ------------+---------------+-------------
|
63
61
|
# secp256r1 | prime256v1 | NIST P-256
|
@@ -66,7 +64,7 @@ module TTTLS13
|
|
66
64
|
#
|
67
65
|
# https://datatracker.ietf.org/doc/html/rfc4492#appendix-A
|
68
66
|
#
|
69
|
-
# @param
|
67
|
+
# @param group [TTTLS13::Message::Extension::NamedGroup]
|
70
68
|
#
|
71
69
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
72
70
|
#
|
data/lib/tttls1.3/server.rb
CHANGED
data/lib/tttls1.3/version.rb
CHANGED
data/spec/client_hello_spec.rb
CHANGED
@@ -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: 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
|
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.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekuwayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|