tttls1.3 0.2.17 → 0.2.19
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 +12 -7
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -1
- data/README.md +5 -3
- data/example/https_client.rb +2 -1
- data/example/https_client_using_0rtt.rb +1 -1
- data/example/https_client_using_hrr_and_ticket.rb +1 -1
- data/example/https_client_using_ticket.rb +1 -1
- data/example/https_server.rb +3 -2
- data/interop/client_spec.rb +3 -2
- data/interop/server_spec.rb +1 -3
- data/interop/{helper.rb → spec_helper.rb} +12 -5
- data/lib/tttls1.3/client.rb +50 -8
- data/lib/tttls1.3/connection.rb +6 -8
- data/lib/tttls1.3/key_schedule.rb +40 -5
- data/lib/tttls1.3/message/extension/key_share.rb +2 -4
- data/lib/tttls1.3/server.rb +29 -2
- data/lib/tttls1.3/sslkeylogfile.rb +87 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +1 -0
- data/spec/connection_spec.rb +22 -7
- data/spec/extensions_spec.rb +1 -2
- data/spec/key_schedule_spec.rb +2 -2
- data/spec/server_spec.rb +22 -7
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60aaa0dddc8e01d6ee1c89a81de02e7cd9e05e0169e11381ebb68aa919644f11
|
4
|
+
data.tar.gz: 974b5c89009c2a63a6d99a608b32463cb0b6dc4bb0ed9e915cd03cca45ce2ea9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9ab939f9010481de463c2fbf81dc230cdd653dac47286e1fd61f8820da796a09b0675837dc119ebd8f1ddd137383ccc87aec18edd4945312cb0923ebbe77e52
|
7
|
+
data.tar.gz: 74d0635bba0274cfaf9ed980d2f0cef3351ab1f820a17720424dececaeb86c6ea36d6f9c3d7b69c8e81b52c4790b1796ba59d02a95a30d4afe90bad35767d442
|
data/.github/workflows/ci.yml
CHANGED
@@ -15,18 +15,23 @@ jobs:
|
|
15
15
|
matrix:
|
16
16
|
ruby-version: ['2.7.x', '3.0.x', '3.1.x']
|
17
17
|
steps:
|
18
|
+
- uses: actions/checkout@v3
|
18
19
|
- uses: docker://thekuwayama/openssl:latest
|
19
20
|
- name: Set up Ruby
|
20
|
-
uses:
|
21
|
-
|
21
|
+
uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
22
24
|
- name: Install dependencies
|
23
25
|
run: |
|
24
26
|
gem --version
|
25
27
|
gem install bundler
|
26
28
|
bundle --version
|
27
29
|
bundle install
|
28
|
-
- name: Run
|
29
|
-
run:
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
- name: Run rubocop
|
31
|
+
run: bundle exec rake rubocop
|
32
|
+
- name: Run rspec
|
33
|
+
run: bundle exec rake spec
|
34
|
+
- name: Run interop client
|
35
|
+
run: bundle exec rake interop:client
|
36
|
+
- name: Run interop server
|
37
|
+
run: bundle exec rake interop:server
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.1.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/tttls1.3)
|
4
4
|
[](https://github.com/thekuwayama/tttls1.3/actions?workflow=CI)
|
5
|
-
[](https://codeclimate.com/github/thekuwayama/tttls1.3/maintainability)
|
6
6
|
|
7
7
|
tttls1.3 is Ruby implementation of [TLS 1.3](https://tools.ietf.org/html/rfc8446) protocol.
|
8
8
|
|
@@ -92,9 +92,9 @@ tttls1.3 client is configurable using keyword arguments.
|
|
92
92
|
| `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of named groups offered in ClientHello extensions. |
|
93
93
|
| `:key_share_groups` | Array of TTTLS13::NamedGroup constant | nil | List of named groups offered in KeyShareClientHello. In default, KeyShareClientHello has only a KeyShareEntry of most preferred named group in `:supported_groups`. You can set this to send KeyShareClientHello that has multiple KeyShareEntry. |
|
94
94
|
| `:alpn` | Array of String | nil | List of application protocols offered in ClientHello extensions. If not needed to be present, set nil. |
|
95
|
-
| `:process_new_session_ticket` | Proc | nil | Proc that processes received NewSessionTicket. Its 3 arguments are TTTLS13::Message::NewSessionTicket, resumption
|
95
|
+
| `:process_new_session_ticket` | Proc | nil | Proc that processes received NewSessionTicket. Its 3 arguments are TTTLS13::Message::NewSessionTicket, resumption main secret and cipher suite. If not needed to process NewSessionTicket, set nil. |
|
96
96
|
| `:ticket` | String | nil | The ticket for PSK. |
|
97
|
-
| `:
|
97
|
+
| `:resumption_secret` | String | nil | The resumption main secret. |
|
98
98
|
| `:psk_cipher_suite` | TTTLS13::CipherSuite constant | nil | The cipher suite for PSK. |
|
99
99
|
| `:ticket_nonce` | String | nil | The ticket\_nonce for PSK. |
|
100
100
|
| `:ticket_age_add` | String | nil | The ticket\_age\_add for PSK. |
|
@@ -104,6 +104,7 @@ tttls1.3 client is configurable using keyword arguments.
|
|
104
104
|
| `:process_certificate_status` | Proc | `TTTLS13::Client.method(:softfail_check_certificate_status)` | Proc(or Method) that checks received OCSPResponse. Its 3 arguments are OpenSSL::OCSP::Response, end-entity certificate(OpenSSL::X509::Certificate) and certificates chain(Array of Certificate) used for verification and it returns Boolean. |
|
105
105
|
| `:compress_certificate_algorithms` | Array of TTTLS13::Message::Extension::CertificateCompressionAlgorithm constant | `ZLIB` | The compression algorithms are supported for compressing the Certificate message. |
|
106
106
|
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
107
|
+
| `:sslkeylogfile` | String | nil | If needed to log SSLKEYLOGFILE, set the file path. |
|
107
108
|
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
108
109
|
|
109
110
|
|
@@ -123,6 +124,7 @@ tttls1.3 server is configurable using keyword arguments.
|
|
123
124
|
| `:process_ocsp_response` | Proc | nil | Proc that gets OpenSSL::OCSP::Response. If not needed to staple OCSP::Response, set nil. |
|
124
125
|
| `:compress_certificate_algorithms` | Array of TTTLS13::Message::Extension::CertificateCompressionAlgorithm constant | `ZLIB` | The compression algorithms are supported for compressing the Certificate message. |
|
125
126
|
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
127
|
+
| `:sslkeylogfile` | String | nil | If needed to log SSLKEYLOGFILE, set the file path. |
|
126
128
|
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
127
129
|
|
128
130
|
|
data/example/https_client.rb
CHANGED
@@ -10,7 +10,8 @@ req = simple_http_request(hostname)
|
|
10
10
|
socket = TCPSocket.new(hostname, port)
|
11
11
|
settings = {
|
12
12
|
ca_file: File.exist?(ca_file) ? ca_file : nil,
|
13
|
-
alpn: ['http/1.1']
|
13
|
+
alpn: ['http/1.1'],
|
14
|
+
sslkeylogfile: '/tmp/sslkeylogfile.log'
|
14
15
|
}
|
15
16
|
client = TTTLS13::Client.new(socket, hostname, **settings)
|
16
17
|
client.connect
|
@@ -15,7 +15,7 @@ process_new_session_ticket = lambda do |nst, rms, cs|
|
|
15
15
|
return if Time.now.to_i - nst.timestamp > nst.ticket_lifetime
|
16
16
|
|
17
17
|
settings_2nd[:ticket] = nst.ticket
|
18
|
-
settings_2nd[:
|
18
|
+
settings_2nd[:resumption_main_secret] = rms
|
19
19
|
settings_2nd[:psk_cipher_suite] = cs
|
20
20
|
settings_2nd[:ticket_nonce] = nst.ticket_nonce
|
21
21
|
settings_2nd[:ticket_age_add] = nst.ticket_age_add
|
@@ -16,7 +16,7 @@ process_new_session_ticket = lambda do |nst, rms, cs|
|
|
16
16
|
|
17
17
|
settings_2nd[:key_share_groups] = [] # empty KeyShareClientHello.client_shares
|
18
18
|
settings_2nd[:ticket] = nst.ticket
|
19
|
-
settings_2nd[:
|
19
|
+
settings_2nd[:resumption_main_secret] = rms
|
20
20
|
settings_2nd[:psk_cipher_suite] = cs
|
21
21
|
settings_2nd[:ticket_nonce] = nst.ticket_nonce
|
22
22
|
settings_2nd[:ticket_age_add] = nst.ticket_age_add
|
@@ -15,7 +15,7 @@ process_new_session_ticket = lambda do |nst, rms, cs|
|
|
15
15
|
return if Time.now.to_i - nst.timestamp > nst.ticket_lifetime
|
16
16
|
|
17
17
|
settings_2nd[:ticket] = nst.ticket
|
18
|
-
settings_2nd[:
|
18
|
+
settings_2nd[:resumption_main_secret] = rms
|
19
19
|
settings_2nd[:psk_cipher_suite] = cs
|
20
20
|
settings_2nd[:ticket_nonce] = nst.ticket_nonce
|
21
21
|
settings_2nd[:ticket_age_add] = nst.ticket_age_add
|
data/example/https_server.rb
CHANGED
@@ -12,7 +12,8 @@ settings = {
|
|
12
12
|
crt_file: __dir__ + '/../tmp/server.crt',
|
13
13
|
chain_files: [__dir__ + '/../tmp/intermediate.crt'],
|
14
14
|
key_file: __dir__ + '/../tmp/server.key',
|
15
|
-
alpn: ['http/1.1']
|
15
|
+
alpn: ['http/1.1'],
|
16
|
+
sslkeylogfile: '/tmp/sslkeylogfile.log'
|
16
17
|
}
|
17
18
|
|
18
19
|
q = Queue.new
|
@@ -49,7 +50,7 @@ Etc.nprocessors.times do
|
|
49
50
|
rescue Timeout::Error
|
50
51
|
logger.warn 'Timeout'
|
51
52
|
ensure
|
52
|
-
s
|
53
|
+
s&.close
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
data/interop/client_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative '
|
4
|
+
require_relative 'spec_helper'
|
5
5
|
|
6
6
|
FIXTURES_DIR = __dir__ + '/../spec/fixtures'
|
7
|
-
PORT =
|
7
|
+
PORT = 14433
|
8
8
|
|
9
9
|
RSpec.describe Client do
|
10
10
|
# normal [Boolean] Is this nominal scenarios?
|
@@ -173,6 +173,7 @@ RSpec.describe Client do
|
|
173
173
|
+ '-tls1_3 ' \
|
174
174
|
+ '-www ' \
|
175
175
|
+ '-quiet ' \
|
176
|
+
+ "-accept #{PORT} " \
|
176
177
|
+ opt
|
177
178
|
pid = spawn('docker run ' \
|
178
179
|
+ "--volume #{FIXTURES_DIR}:/tmp " \
|
data/interop/server_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative '
|
4
|
+
require_relative 'spec_helper'
|
5
5
|
|
6
6
|
FIXTURES_DIR = __dir__ + '/../spec/fixtures'
|
7
7
|
PORT = 4433
|
@@ -187,8 +187,6 @@ RSpec.describe Server do
|
|
187
187
|
|
188
188
|
let(:client) do
|
189
189
|
ip = Socket.ip_address_list.find(&:ipv4_private?).ip_address
|
190
|
-
wait_to_listen(ip, PORT)
|
191
|
-
|
192
190
|
cmd = 'echo -n ping | openssl s_client ' \
|
193
191
|
+ "-connect local:#{PORT} " \
|
194
192
|
+ '-tls1_3 ' \
|
@@ -13,13 +13,20 @@ include TTTLS13::Error
|
|
13
13
|
# rubocop: enable Style/MixinUsage
|
14
14
|
|
15
15
|
def wait_to_listen(host, port)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
10.times do
|
17
|
+
soc = TCPSocket.open(host, port)
|
18
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
19
|
+
ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
|
20
|
+
ssl = OpenSSL::SSL::SSLSocket.new(soc, ctx)
|
21
|
+
ssl.sync_close = true
|
22
|
+
ssl.connect
|
23
|
+
rescue => e # rubocop: disable Style/RescueStandardError
|
24
|
+
p e
|
25
|
+
soc&.close
|
26
|
+
sleep(0.5)
|
20
27
|
next
|
21
28
|
else
|
22
|
-
|
29
|
+
ssl.close
|
23
30
|
break
|
24
31
|
end
|
25
32
|
end
|
data/lib/tttls1.3/client.rb
CHANGED
@@ -58,7 +58,9 @@ module TTTLS13
|
|
58
58
|
alpn: nil,
|
59
59
|
process_new_session_ticket: nil,
|
60
60
|
ticket: nil,
|
61
|
+
# @deprecated Please use `resumption_secret` instead
|
61
62
|
resumption_master_secret: nil,
|
63
|
+
resumption_secret: nil,
|
62
64
|
psk_cipher_suite: nil,
|
63
65
|
ticket_nonce: nil,
|
64
66
|
ticket_age_add: nil,
|
@@ -68,6 +70,7 @@ module TTTLS13
|
|
68
70
|
process_certificate_status: nil,
|
69
71
|
compress_certificate_algorithms: DEFALUT_CH_COMPRESS_CERTIFICATE_ALGORITHMS,
|
70
72
|
compatibility_mode: true,
|
73
|
+
sslkeylogfile: nil,
|
71
74
|
loglevel: Logger::WARN
|
72
75
|
}.freeze
|
73
76
|
private_constant :DEFAULT_CLIENT_SETTINGS
|
@@ -83,6 +86,15 @@ module TTTLS13
|
|
83
86
|
@endpoint = :client
|
84
87
|
@hostname = hostname
|
85
88
|
@settings = DEFAULT_CLIENT_SETTINGS.merge(settings)
|
89
|
+
# NOTE: backward compatibility
|
90
|
+
if @settings[:resumption_secret].nil? &&
|
91
|
+
!@settings[:resumption_master_secret].nil?
|
92
|
+
@settings[:resumption_secret] =
|
93
|
+
@settings.delete(:resumption_master_secret) \
|
94
|
+
end
|
95
|
+
raise Error::ConfigError if @settings[:resumption_secret] !=
|
96
|
+
@settings[:resumption_master_secret]
|
97
|
+
|
86
98
|
logger.level = @settings[:loglevel]
|
87
99
|
|
88
100
|
@early_data = ''
|
@@ -136,7 +148,7 @@ module TTTLS13
|
|
136
148
|
priv_keys = {} # Hash of NamedGroup => OpenSSL::PKey::$Object
|
137
149
|
if use_psk?
|
138
150
|
psk = gen_psk_from_nst(
|
139
|
-
@settings[:
|
151
|
+
@settings[:resumption_secret],
|
140
152
|
@settings[:ticket_nonce],
|
141
153
|
CipherSuite.digest(@settings[:psk_cipher_suite])
|
142
154
|
)
|
@@ -151,6 +163,15 @@ module TTTLS13
|
|
151
163
|
hs_wcipher = nil # TTTLS13::Cryptograph::$Object
|
152
164
|
hs_rcipher = nil # TTTLS13::Cryptograph::$Object
|
153
165
|
e_wcipher = nil # TTTLS13::Cryptograph::$Object
|
166
|
+
sslkeylogfile = nil # TTTLS13::SslKeyLogFile::Writer
|
167
|
+
unless @settings[:sslkeylogfile].nil?
|
168
|
+
begin
|
169
|
+
sslkeylogfile = SslKeyLogFile::Writer.new(@settings[:sslkeylogfile])
|
170
|
+
rescue SystemCallError => e
|
171
|
+
msg = "\"#{@settings[:sslkeylogfile]}\" file can NOT open: #{e}"
|
172
|
+
logger.warn(msg)
|
173
|
+
end
|
174
|
+
end
|
154
175
|
|
155
176
|
@state = ClientState::START
|
156
177
|
loop do
|
@@ -169,6 +190,10 @@ module TTTLS13
|
|
169
190
|
key_schedule.early_data_write_key,
|
170
191
|
key_schedule.early_data_write_iv
|
171
192
|
)
|
193
|
+
sslkeylogfile&.write_client_early_traffic_secret(
|
194
|
+
transcript[CH].first.random,
|
195
|
+
key_schedule.client_early_traffic_secret
|
196
|
+
)
|
172
197
|
send_early_data(e_wcipher)
|
173
198
|
end
|
174
199
|
|
@@ -276,11 +301,19 @@ module TTTLS13
|
|
276
301
|
key_schedule.client_handshake_write_key,
|
277
302
|
key_schedule.client_handshake_write_iv
|
278
303
|
)
|
304
|
+
sslkeylogfile&.write_client_handshake_traffic_secret(
|
305
|
+
transcript[CH].first.random,
|
306
|
+
key_schedule.client_handshake_traffic_secret
|
307
|
+
)
|
279
308
|
hs_rcipher = gen_cipher(
|
280
309
|
@cipher_suite,
|
281
310
|
key_schedule.server_handshake_write_key,
|
282
311
|
key_schedule.server_handshake_write_iv
|
283
312
|
)
|
313
|
+
sslkeylogfile&.write_server_handshake_traffic_secret(
|
314
|
+
transcript[CH].first.random,
|
315
|
+
key_schedule.server_handshake_traffic_secret
|
316
|
+
)
|
284
317
|
@state = ClientState::WAIT_EE
|
285
318
|
when ClientState::WAIT_EE
|
286
319
|
logger.debug('ClientState::WAIT_EE')
|
@@ -388,13 +421,21 @@ module TTTLS13
|
|
388
421
|
key_schedule.client_application_write_key,
|
389
422
|
key_schedule.client_application_write_iv
|
390
423
|
)
|
424
|
+
sslkeylogfile&.write_client_traffic_secret_0(
|
425
|
+
transcript[CH].first.random,
|
426
|
+
key_schedule.client_application_traffic_secret
|
427
|
+
)
|
391
428
|
@ap_rcipher = gen_cipher(
|
392
429
|
@cipher_suite,
|
393
430
|
key_schedule.server_application_write_key,
|
394
431
|
key_schedule.server_application_write_iv
|
395
432
|
)
|
396
|
-
|
397
|
-
|
433
|
+
sslkeylogfile&.write_server_traffic_secret_0(
|
434
|
+
transcript[CH].first.random,
|
435
|
+
key_schedule.server_application_traffic_secret
|
436
|
+
)
|
437
|
+
@exporter_secret = key_schedule.exporter_secret
|
438
|
+
@resumption_secret = key_schedule.resumption_secret
|
398
439
|
@state = ClientState::CONNECTED
|
399
440
|
when ClientState::CONNECTED
|
400
441
|
logger.debug('ClientState::CONNECTED')
|
@@ -402,6 +443,7 @@ module TTTLS13
|
|
402
443
|
break
|
403
444
|
end
|
404
445
|
end
|
446
|
+
sslkeylogfile&.close
|
405
447
|
end
|
406
448
|
# rubocop: enable Metrics/AbcSize
|
407
449
|
# rubocop: enable Metrics/BlockLength
|
@@ -513,7 +555,7 @@ module TTTLS13
|
|
513
555
|
# @return [Boolean]
|
514
556
|
def use_psk?
|
515
557
|
!@settings[:ticket].nil? &&
|
516
|
-
!@settings[:
|
558
|
+
!@settings[:resumption_secret].nil? &&
|
517
559
|
!@settings[:psk_cipher_suite].nil? &&
|
518
560
|
!@settings[:ticket_nonce].nil? &&
|
519
561
|
!@settings[:ticket_age_add].nil? &&
|
@@ -537,14 +579,14 @@ module TTTLS13
|
|
537
579
|
send_record(ap_record)
|
538
580
|
end
|
539
581
|
|
540
|
-
# @param
|
582
|
+
# @param resumption_secret [String]
|
541
583
|
# @param ticket_nonce [String]
|
542
584
|
# @param digest [String] name of digest algorithm
|
543
585
|
#
|
544
586
|
# @return [String]
|
545
|
-
def gen_psk_from_nst(
|
587
|
+
def gen_psk_from_nst(resumption_secret, ticket_nonce, digest)
|
546
588
|
hash_len = OpenSSL::Digest.new(digest).digest_length
|
547
|
-
KeySchedule.hkdf_expand_label(
|
589
|
+
KeySchedule.hkdf_expand_label(resumption_secret, 'resumption',
|
548
590
|
ticket_nonce, hash_len, digest)
|
549
591
|
end
|
550
592
|
|
@@ -918,7 +960,7 @@ module TTTLS13
|
|
918
960
|
def process_new_session_ticket(nst)
|
919
961
|
super(nst)
|
920
962
|
|
921
|
-
rms = @
|
963
|
+
rms = @resumption_secret
|
922
964
|
cs = @cipher_suite
|
923
965
|
@settings[:process_new_session_ticket]&.call(nst, rms, cs)
|
924
966
|
end
|
data/lib/tttls1.3/connection.rb
CHANGED
@@ -25,7 +25,7 @@ module TTTLS13
|
|
25
25
|
@send_record_size = Message::DEFAULT_RECORD_SIZE_LIMIT
|
26
26
|
@recv_record_size = Message::DEFAULT_RECORD_SIZE_LIMIT
|
27
27
|
@alpn = nil # String
|
28
|
-
@
|
28
|
+
@exporter_secret = nil # String
|
29
29
|
end
|
30
30
|
|
31
31
|
# @raise [TTTLS13::Error::ConfigError]
|
@@ -109,15 +109,15 @@ module TTTLS13
|
|
109
109
|
#
|
110
110
|
# @return [String, nil]
|
111
111
|
def exporter(label, context, key_length)
|
112
|
-
return nil if @
|
112
|
+
return nil if @exporter_secret.nil? || @cipher_suite.nil?
|
113
113
|
|
114
114
|
digest = CipherSuite.digest(@cipher_suite)
|
115
|
-
do_exporter(@
|
115
|
+
do_exporter(@exporter_secret, digest, label, context, key_length)
|
116
116
|
end
|
117
117
|
|
118
118
|
private
|
119
119
|
|
120
|
-
# @param secret [String] (early_)
|
120
|
+
# @param secret [String] (early_)exporter_secret
|
121
121
|
# @param digest [String] name of digest algorithm
|
122
122
|
# @param label [String]
|
123
123
|
# @param context [String]
|
@@ -517,10 +517,8 @@ module TTTLS13
|
|
517
517
|
#
|
518
518
|
# @return [Array of TTTLS13::Message::Extension::SignatureAlgorithms]
|
519
519
|
def do_select_signature_algorithms(signature_algorithms, crt)
|
520
|
-
|
521
|
-
|
522
|
-
pka = OpenSSL::ASN1.decode(spki.to_der)
|
523
|
-
.value.first.value.first.value.first.value.first.value
|
520
|
+
pka = OpenSSL::ASN1.decode(crt.public_key.to_der)
|
521
|
+
.value.first.value.first.value
|
524
522
|
signature_algorithms.select do |sa|
|
525
523
|
case sa
|
526
524
|
when SignatureScheme::ECDSA_SECP256R1_SHA256,
|
@@ -61,8 +61,15 @@ module TTTLS13
|
|
61
61
|
self.class.hkdf_expand_label(secret, 'iv', '', @iv_len, @digest)
|
62
62
|
end
|
63
63
|
|
64
|
+
# @deprecated Please use `early_exporter_secret` instead
|
65
|
+
#
|
64
66
|
# @return [String]
|
65
67
|
def early_exporter_master_secret
|
68
|
+
early_exporter_secret
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [String]
|
72
|
+
def early_exporter_secret
|
66
73
|
hash = OpenSSL::Digest.digest(@digest, '')
|
67
74
|
derive_secret(early_secret, 'e exp master', hash)
|
68
75
|
end
|
@@ -126,22 +133,36 @@ module TTTLS13
|
|
126
133
|
self.class.hkdf_expand_label(secret, 'iv', '', @iv_len, @digest)
|
127
134
|
end
|
128
135
|
|
136
|
+
# @deprecated Please use `main_salt` instead
|
137
|
+
#
|
129
138
|
# @return [String]
|
130
139
|
def master_salt
|
140
|
+
main_salt
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [String]
|
144
|
+
def main_salt
|
131
145
|
hash = OpenSSL::Digest.digest(@digest, '')
|
132
146
|
derive_secret(handshake_secret, 'derived', hash)
|
133
147
|
end
|
134
148
|
|
149
|
+
# @deprecated Please use `main_secret` instead
|
150
|
+
#
|
135
151
|
# @return [String]
|
136
152
|
def master_secret
|
153
|
+
main_secret
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [String]
|
157
|
+
def main_secret
|
137
158
|
ikm = "\x00" * @hash_len
|
138
|
-
hkdf_extract(ikm,
|
159
|
+
hkdf_extract(ikm, main_salt)
|
139
160
|
end
|
140
161
|
|
141
162
|
# @return [String]
|
142
163
|
def client_application_traffic_secret
|
143
164
|
hash = @transcript.hash(@digest, SF)
|
144
|
-
derive_secret(
|
165
|
+
derive_secret(main_secret, 'c ap traffic', hash)
|
145
166
|
end
|
146
167
|
|
147
168
|
# @return [String]
|
@@ -159,7 +180,7 @@ module TTTLS13
|
|
159
180
|
# @return [String]
|
160
181
|
def server_application_traffic_secret
|
161
182
|
hash = @transcript.hash(@digest, SF)
|
162
|
-
derive_secret(
|
183
|
+
derive_secret(main_secret, 's ap traffic', hash)
|
163
184
|
end
|
164
185
|
|
165
186
|
# @return [String]
|
@@ -174,16 +195,30 @@ module TTTLS13
|
|
174
195
|
self.class.hkdf_expand_label(secret, 'iv', '', @iv_len, @digest)
|
175
196
|
end
|
176
197
|
|
198
|
+
# @deprecated Please use `exporter_secret` instead
|
199
|
+
#
|
177
200
|
# @return [String]
|
178
201
|
def exporter_master_secret
|
202
|
+
exporter_secret
|
203
|
+
end
|
204
|
+
|
205
|
+
# @return [String]
|
206
|
+
def exporter_secret
|
179
207
|
hash = @transcript.hash(@digest, SF)
|
180
|
-
derive_secret(
|
208
|
+
derive_secret(main_secret, 'exp master', hash)
|
181
209
|
end
|
182
210
|
|
211
|
+
# @deprecated Please use `resumption_secret` instead
|
212
|
+
#
|
183
213
|
# @return [String]
|
184
214
|
def resumption_master_secret
|
215
|
+
resumption_secret
|
216
|
+
end
|
217
|
+
|
218
|
+
# @return [String]
|
219
|
+
def resumption_secret
|
185
220
|
hash = @transcript.hash(@digest, CF)
|
186
|
-
derive_secret(
|
221
|
+
derive_secret(main_secret, 'res master', hash)
|
187
222
|
end
|
188
223
|
|
189
224
|
# @param ikm [String]
|
@@ -91,8 +91,7 @@ module TTTLS13
|
|
91
91
|
priv_keys = {}
|
92
92
|
kse = groups.map do |group|
|
93
93
|
curve = NamedGroup.curve_name(group)
|
94
|
-
ec = OpenSSL::PKey::EC.
|
95
|
-
ec.generate_key!
|
94
|
+
ec = OpenSSL::PKey::EC.generate(curve)
|
96
95
|
# store private key to do the key-exchange
|
97
96
|
priv_keys.store(group, ec)
|
98
97
|
KeyShareEntry.new(
|
@@ -115,8 +114,7 @@ module TTTLS13
|
|
115
114
|
# @return [OpenSSL::PKey::EC.$Object]
|
116
115
|
def self.gen_sh_key_share(group)
|
117
116
|
curve = NamedGroup.curve_name(group)
|
118
|
-
ec = OpenSSL::PKey::EC.
|
119
|
-
ec.generate_key!
|
117
|
+
ec = OpenSSL::PKey::EC.generate(curve)
|
120
118
|
|
121
119
|
key_share = KeyShare.new(
|
122
120
|
msg_type: HandshakeType::SERVER_HELLO,
|
data/lib/tttls1.3/server.rb
CHANGED
@@ -60,6 +60,7 @@ module TTTLS13
|
|
60
60
|
process_ocsp_response: nil,
|
61
61
|
compress_certificate_algorithms: DEFAULT_SP_COMPRESS_CERTIFICATE_ALGORITHMS,
|
62
62
|
compatibility_mode: true,
|
63
|
+
sslkeylogfile: nil,
|
63
64
|
loglevel: Logger::WARN
|
64
65
|
}.freeze
|
65
66
|
private_constant :DEFAULT_SERVER_SETTINGS
|
@@ -148,6 +149,15 @@ module TTTLS13
|
|
148
149
|
priv_key = nil # OpenSSL::PKey::$Object
|
149
150
|
hs_wcipher = nil # TTTLS13::Cryptograph::$Object
|
150
151
|
hs_rcipher = nil # TTTLS13::Cryptograph::$Object
|
152
|
+
sslkeylogfile = nil # TTTLS13::SslKeyLogFile::Writer
|
153
|
+
unless @settings[:sslkeylogfile].nil?
|
154
|
+
begin
|
155
|
+
sslkeylogfile = SslKeyLogFile::Writer.new(@settings[:sslkeylogfile])
|
156
|
+
rescue SystemCallError => e
|
157
|
+
msg = "\"#{@settings[:sslkeylogfile]}\" file can NOT open: #{e}"
|
158
|
+
logger.warn(msg)
|
159
|
+
end
|
160
|
+
end
|
151
161
|
|
152
162
|
@state = ServerState::START
|
153
163
|
loop do
|
@@ -220,7 +230,7 @@ module TTTLS13
|
|
220
230
|
# generate shared secret
|
221
231
|
ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
|
222
232
|
&.key_share_entry
|
223
|
-
&.find { |
|
233
|
+
&.find { |kse| kse.group == @named_group }
|
224
234
|
&.key_exchange
|
225
235
|
shared_secret = gen_shared_secret(ke, priv_key, @named_group)
|
226
236
|
key_schedule = KeySchedule.new(
|
@@ -234,11 +244,19 @@ module TTTLS13
|
|
234
244
|
key_schedule.server_handshake_write_key,
|
235
245
|
key_schedule.server_handshake_write_iv
|
236
246
|
)
|
247
|
+
sslkeylogfile&.write_server_handshake_traffic_secret(
|
248
|
+
transcript[CH].first.random,
|
249
|
+
key_schedule.server_handshake_traffic_secret
|
250
|
+
)
|
237
251
|
hs_rcipher = gen_cipher(
|
238
252
|
@cipher_suite,
|
239
253
|
key_schedule.client_handshake_write_key,
|
240
254
|
key_schedule.client_handshake_write_iv
|
241
255
|
)
|
256
|
+
sslkeylogfile&.write_client_handshake_traffic_secret(
|
257
|
+
transcript[CH].first.random,
|
258
|
+
key_schedule.client_handshake_traffic_secret
|
259
|
+
)
|
242
260
|
@state = ServerState::WAIT_FLIGHT2
|
243
261
|
when ServerState::WAIT_EOED
|
244
262
|
logger.debug('ServerState::WAIT_EOED')
|
@@ -292,12 +310,20 @@ module TTTLS13
|
|
292
310
|
key_schedule.server_application_write_key,
|
293
311
|
key_schedule.server_application_write_iv
|
294
312
|
)
|
313
|
+
sslkeylogfile&.write_server_traffic_secret_0(
|
314
|
+
transcript[CH].first.random,
|
315
|
+
key_schedule.server_application_traffic_secret
|
316
|
+
)
|
295
317
|
@ap_rcipher = gen_cipher(
|
296
318
|
@cipher_suite,
|
297
319
|
key_schedule.client_application_write_key,
|
298
320
|
key_schedule.client_application_write_iv
|
299
321
|
)
|
300
|
-
|
322
|
+
sslkeylogfile&.write_client_traffic_secret_0(
|
323
|
+
transcript[CH].first.random,
|
324
|
+
key_schedule.client_application_traffic_secret
|
325
|
+
)
|
326
|
+
@exporter_secret = key_schedule.exporter_secret
|
301
327
|
@state = ServerState::CONNECTED
|
302
328
|
when ServerState::CONNECTED
|
303
329
|
logger.debug('ServerState::CONNECTED')
|
@@ -305,6 +331,7 @@ module TTTLS13
|
|
305
331
|
break
|
306
332
|
end
|
307
333
|
end
|
334
|
+
sslkeylogfile&.close
|
308
335
|
end
|
309
336
|
# rubocop: enable Metrics/AbcSize
|
310
337
|
# rubocop: enable Metrics/BlockLength
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
module SslKeyLogFile
|
6
|
+
module Label
|
7
|
+
CLIENT_EARLY_TRAFFIC_SECRET = 'CLIENT_EARLY_TRAFFIC_SECRET'
|
8
|
+
CLIENT_HANDSHAKE_TRAFFIC_SECRET = 'CLIENT_HANDSHAKE_TRAFFIC_SECRET'
|
9
|
+
SERVER_HANDSHAKE_TRAFFIC_SECRET = 'SERVER_HANDSHAKE_TRAFFIC_SECRET'
|
10
|
+
CLIENT_TRAFFIC_SECRET_0 = 'CLIENT_TRAFFIC_SECRET_0'
|
11
|
+
SERVER_TRAFFIC_SECRET_0 = 'SERVER_TRAFFIC_SECRET_0'
|
12
|
+
end
|
13
|
+
|
14
|
+
class Writer
|
15
|
+
# @param path [String]
|
16
|
+
#
|
17
|
+
# @raise [SystemCallError]
|
18
|
+
def initialize(path)
|
19
|
+
@file = File.new(path, 'a+')
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param client_random [String]
|
23
|
+
# @param secret [String]
|
24
|
+
def write_client_early_traffic_secret(client_random, secret)
|
25
|
+
write_key_log(
|
26
|
+
Label::CLIENT_EARLY_TRAFFIC_SECRET,
|
27
|
+
client_random,
|
28
|
+
secret
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param client_random [String]
|
33
|
+
# @param secret [String]
|
34
|
+
def write_client_handshake_traffic_secret(client_random, secret)
|
35
|
+
write_key_log(
|
36
|
+
Label::CLIENT_HANDSHAKE_TRAFFIC_SECRET,
|
37
|
+
client_random,
|
38
|
+
secret
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param client_random [String]
|
43
|
+
# @param secret [String]
|
44
|
+
def write_server_handshake_traffic_secret(client_random, secret)
|
45
|
+
write_key_log(
|
46
|
+
Label::SERVER_HANDSHAKE_TRAFFIC_SECRET,
|
47
|
+
client_random,
|
48
|
+
secret
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param client_random [String]
|
53
|
+
# @param secret [String]
|
54
|
+
def write_client_traffic_secret_0(client_random, secret)
|
55
|
+
write_key_log(
|
56
|
+
Label::CLIENT_TRAFFIC_SECRET_0,
|
57
|
+
client_random,
|
58
|
+
secret
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param client_random [String]
|
63
|
+
# @param secret [String]
|
64
|
+
def write_server_traffic_secret_0(client_random, secret)
|
65
|
+
write_key_log(
|
66
|
+
Label::SERVER_TRAFFIC_SECRET_0,
|
67
|
+
client_random,
|
68
|
+
secret
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def close
|
73
|
+
@file&.close
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# @param label [TTTLS13::SslKeyLogFile::Label]
|
79
|
+
# @param client_random [String]
|
80
|
+
# @param secret [String]
|
81
|
+
def write_key_log(label, client_random, secret)
|
82
|
+
s = "#{label} #{client_random.unpack1('H*')} #{secret.unpack1('H*')}\n"
|
83
|
+
@file&.print(s)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/tttls1.3/version.rb
CHANGED
data/lib/tttls1.3.rb
CHANGED
data/spec/connection_spec.rb
CHANGED
@@ -6,13 +6,28 @@ require_relative 'spec_helper'
|
|
6
6
|
RSpec.describe Connection do
|
7
7
|
context 'connection, Simple 1-RTT Handshake,' do
|
8
8
|
let(:key) do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
n = OpenSSL::BN.new(TESTBINARY_PKEY_MODULUS, 2)
|
10
|
+
e = OpenSSL::BN.new(TESTBINARY_PKEY_PUBLIC_EXPONENT, 2)
|
11
|
+
d = OpenSSL::BN.new(TESTBINARY_PKEY_PRIVATE_EXPONENT, 2)
|
12
|
+
p = OpenSSL::BN.new(TESTBINARY_PKEY_PRIME1, 2)
|
13
|
+
q = OpenSSL::BN.new(TESTBINARY_PKEY_PRIME2, 2)
|
14
|
+
dmp1 = d % (p - 1.to_bn)
|
15
|
+
dmq1 = d % (q - 1.to_bn)
|
16
|
+
iqmp = q**-1.to_bn % p
|
17
|
+
asn1 = OpenSSL::ASN1::Sequence(
|
18
|
+
[
|
19
|
+
OpenSSL::ASN1::Integer(0),
|
20
|
+
OpenSSL::ASN1::Integer(n),
|
21
|
+
OpenSSL::ASN1::Integer(e),
|
22
|
+
OpenSSL::ASN1::Integer(d),
|
23
|
+
OpenSSL::ASN1::Integer(p),
|
24
|
+
OpenSSL::ASN1::Integer(q),
|
25
|
+
OpenSSL::ASN1::Integer(dmp1),
|
26
|
+
OpenSSL::ASN1::Integer(dmq1),
|
27
|
+
OpenSSL::ASN1::Integer(iqmp)
|
28
|
+
]
|
29
|
+
)
|
30
|
+
OpenSSL::PKey::RSA.new(asn1)
|
16
31
|
end
|
17
32
|
|
18
33
|
let(:ct) do
|
data/spec/extensions_spec.rb
CHANGED
data/spec/key_schedule_spec.rb
CHANGED
@@ -37,9 +37,9 @@ RSpec.describe KeySchedule do
|
|
37
37
|
.to eq TESTBINARY_C_AP_TRAFFIC
|
38
38
|
expect(key_schedule.server_application_traffic_secret)
|
39
39
|
.to eq TESTBINARY_S_AP_TRAFFIC
|
40
|
-
expect(key_schedule.
|
40
|
+
expect(key_schedule.exporter_secret)
|
41
41
|
.to eq TESTBINARY_EXP_MASTER
|
42
|
-
expect(key_schedule.
|
42
|
+
expect(key_schedule.resumption_secret)
|
43
43
|
.to eq TESTBINARY_RES_MASTER
|
44
44
|
end
|
45
45
|
|
data/spec/server_spec.rb
CHANGED
@@ -109,13 +109,28 @@ RSpec.describe Server do
|
|
109
109
|
|
110
110
|
context 'server' do
|
111
111
|
let(:key) do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
112
|
+
n = OpenSSL::BN.new(TESTBINARY_PKEY_MODULUS, 2)
|
113
|
+
e = OpenSSL::BN.new(TESTBINARY_PKEY_PUBLIC_EXPONENT, 2)
|
114
|
+
d = OpenSSL::BN.new(TESTBINARY_PKEY_PRIVATE_EXPONENT, 2)
|
115
|
+
p = OpenSSL::BN.new(TESTBINARY_PKEY_PRIME1, 2)
|
116
|
+
q = OpenSSL::BN.new(TESTBINARY_PKEY_PRIME2, 2)
|
117
|
+
dmp1 = d % (p - 1.to_bn)
|
118
|
+
dmq1 = d % (q - 1.to_bn)
|
119
|
+
iqmp = q**-1.to_bn % p
|
120
|
+
asn1 = OpenSSL::ASN1::Sequence(
|
121
|
+
[
|
122
|
+
OpenSSL::ASN1::Integer(0),
|
123
|
+
OpenSSL::ASN1::Integer(n),
|
124
|
+
OpenSSL::ASN1::Integer(e),
|
125
|
+
OpenSSL::ASN1::Integer(d),
|
126
|
+
OpenSSL::ASN1::Integer(p),
|
127
|
+
OpenSSL::ASN1::Integer(q),
|
128
|
+
OpenSSL::ASN1::Integer(dmp1),
|
129
|
+
OpenSSL::ASN1::Integer(dmq1),
|
130
|
+
OpenSSL::ASN1::Integer(iqmp)
|
131
|
+
]
|
132
|
+
)
|
133
|
+
OpenSSL::PKey::RSA.new(asn1)
|
119
134
|
end
|
120
135
|
|
121
136
|
let(:ct) do
|
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.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekuwayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- ".gitignore"
|
64
64
|
- ".rspec"
|
65
65
|
- ".rubocop.yml"
|
66
|
+
- ".ruby-version"
|
66
67
|
- Gemfile
|
67
68
|
- LICENSE.txt
|
68
69
|
- README.md
|
@@ -77,8 +78,8 @@ files:
|
|
77
78
|
- example/https_client_using_ticket.rb
|
78
79
|
- example/https_server.rb
|
79
80
|
- interop/client_spec.rb
|
80
|
-
- interop/helper.rb
|
81
81
|
- interop/server_spec.rb
|
82
|
+
- interop/spec_helper.rb
|
82
83
|
- lib/tttls1.3.rb
|
83
84
|
- lib/tttls1.3/cipher_suites.rb
|
84
85
|
- lib/tttls1.3/client.rb
|
@@ -123,6 +124,7 @@ files:
|
|
123
124
|
- lib/tttls1.3/sequence_number.rb
|
124
125
|
- lib/tttls1.3/server.rb
|
125
126
|
- lib/tttls1.3/signature_scheme.rb
|
127
|
+
- lib/tttls1.3/sslkeylogfile.rb
|
126
128
|
- lib/tttls1.3/transcript.rb
|
127
129
|
- lib/tttls1.3/utils.rb
|
128
130
|
- lib/tttls1.3/version.rb
|
@@ -198,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
200
|
- !ruby/object:Gem::Version
|
199
201
|
version: '0'
|
200
202
|
requirements: []
|
201
|
-
rubygems_version: 3.
|
203
|
+
rubygems_version: 3.3.7
|
202
204
|
signing_key:
|
203
205
|
specification_version: 4
|
204
206
|
summary: TLS 1.3 implementation in Ruby (Tiny Trial TLS1.3 aka tttls1.3)
|