tttls1.3 0.2.15 → 0.2.18
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 +6 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -0
- data/Gemfile +3 -1
- data/README.md +6 -2
- data/example/https_client.rb +2 -1
- data/example/https_server.rb +3 -2
- data/lib/tttls1.3/client.rb +116 -42
- data/lib/tttls1.3/connection.rb +24 -19
- data/lib/tttls1.3/message/client_hello.rb +1 -0
- data/lib/tttls1.3/message/compressed_certificate.rb +82 -0
- data/lib/tttls1.3/message/end_of_early_data.rb +8 -1
- data/lib/tttls1.3/message/extension/alpn.rb +5 -2
- data/lib/tttls1.3/message/extension/compress_certificate.rb +58 -0
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +2 -2
- data/lib/tttls1.3/message/extension/supported_groups.rb +2 -2
- data/lib/tttls1.3/message/extensions.rb +4 -0
- data/lib/tttls1.3/message/record.rb +28 -16
- data/lib/tttls1.3/message.rb +22 -20
- data/lib/tttls1.3/server.rb +89 -27
- data/lib/tttls1.3/sslkeylogfile.rb +87 -0
- data/lib/tttls1.3/transcript.rb +3 -7
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +1 -0
- data/spec/client_spec.rb +28 -19
- data/spec/compress_certificate_spec.rb +54 -0
- data/spec/connection_spec.rb +22 -15
- data/spec/end_of_early_data_spec.rb +28 -0
- data/spec/key_schedule_spec.rb +48 -25
- data/spec/record_spec.rb +2 -2
- data/spec/server_spec.rb +23 -11
- data/spec/spec_helper.rb +4 -0
- data/spec/transcript_spec.rb +34 -20
- data/tttls1.3.gemspec +1 -1
- metadata +12 -4
data/lib/tttls1.3/server.rb
CHANGED
@@ -44,6 +44,11 @@ module TTTLS13
|
|
44
44
|
].freeze
|
45
45
|
private_constant :DEFAULT_SP_NAMED_GROUP_LIST
|
46
46
|
|
47
|
+
DEFAULT_SP_COMPRESS_CERTIFICATE_ALGORITHMS = [
|
48
|
+
Message::Extension::CertificateCompressionAlgorithm::ZLIB
|
49
|
+
].freeze
|
50
|
+
private_constant :DEFAULT_SP_COMPRESS_CERTIFICATE_ALGORITHMS
|
51
|
+
|
47
52
|
DEFAULT_SERVER_SETTINGS = {
|
48
53
|
crt_file: nil,
|
49
54
|
chain_files: nil,
|
@@ -53,7 +58,9 @@ module TTTLS13
|
|
53
58
|
supported_groups: DEFAULT_SP_NAMED_GROUP_LIST,
|
54
59
|
alpn: nil,
|
55
60
|
process_ocsp_response: nil,
|
61
|
+
compress_certificate_algorithms: DEFAULT_SP_COMPRESS_CERTIFICATE_ALGORITHMS,
|
56
62
|
compatibility_mode: true,
|
63
|
+
sslkeylogfile: nil,
|
57
64
|
loglevel: Logger::WARN
|
58
65
|
}.freeze
|
59
66
|
private_constant :DEFAULT_SERVER_SETTINGS
|
@@ -140,9 +147,17 @@ module TTTLS13
|
|
140
147
|
transcript = Transcript.new
|
141
148
|
key_schedule = nil # TTTLS13::KeySchedule
|
142
149
|
priv_key = nil # OpenSSL::PKey::$Object
|
143
|
-
|
144
150
|
hs_wcipher = nil # TTTLS13::Cryptograph::$Object
|
145
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
|
146
161
|
|
147
162
|
@state = ServerState::START
|
148
163
|
loop do
|
@@ -151,7 +166,7 @@ module TTTLS13
|
|
151
166
|
logger.debug('ServerState::START')
|
152
167
|
|
153
168
|
receivable_ccs = transcript.include?(CH1)
|
154
|
-
ch = transcript[CH] = recv_client_hello(receivable_ccs)
|
169
|
+
ch, = transcript[CH] = recv_client_hello(receivable_ccs)
|
155
170
|
|
156
171
|
# support only TLS 1.3
|
157
172
|
terminate(:protocol_version) unless ch.negotiated_tls_1_3?
|
@@ -183,7 +198,7 @@ module TTTLS13
|
|
183
198
|
logger.debug('ServerState::RECVD_CH')
|
184
199
|
|
185
200
|
# select parameters
|
186
|
-
ch = transcript[CH]
|
201
|
+
ch, = transcript[CH]
|
187
202
|
@cipher_suite = select_cipher_suite(ch)
|
188
203
|
@named_group = select_named_group(ch)
|
189
204
|
@signature_scheme = select_signature_scheme(ch, @crt)
|
@@ -192,8 +207,9 @@ module TTTLS13
|
|
192
207
|
|
193
208
|
# send HRR
|
194
209
|
if @named_group.nil?
|
195
|
-
ch1 = transcript[CH1] = transcript.delete(CH)
|
196
|
-
|
210
|
+
ch1, = transcript[CH1] = transcript.delete(CH)
|
211
|
+
hrr = send_hello_retry_request(ch1, @cipher_suite)
|
212
|
+
transcript[HRR] = [hrr, hrr.serialize]
|
197
213
|
@state = ServerState::START
|
198
214
|
next
|
199
215
|
end
|
@@ -201,16 +217,20 @@ module TTTLS13
|
|
201
217
|
when ServerState::NEGOTIATED
|
202
218
|
logger.debug('ServerState::NEGOTIATED')
|
203
219
|
|
204
|
-
ch = transcript[CH]
|
220
|
+
ch, = transcript[CH]
|
205
221
|
extensions, priv_key = gen_sh_extensions(@named_group)
|
206
|
-
|
207
|
-
|
222
|
+
sh = send_server_hello(
|
223
|
+
extensions,
|
224
|
+
@cipher_suite,
|
225
|
+
ch.legacy_session_id
|
226
|
+
)
|
227
|
+
transcript[SH] = [sh, sh.serialize]
|
208
228
|
send_ccs if @settings[:compatibility_mode]
|
209
229
|
|
210
230
|
# generate shared secret
|
211
231
|
ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
|
212
232
|
&.key_share_entry
|
213
|
-
&.find { |
|
233
|
+
&.find { |kse| kse.group == @named_group }
|
214
234
|
&.key_exchange
|
215
235
|
shared_secret = gen_shared_secret(ke, priv_key, @named_group)
|
216
236
|
key_schedule = KeySchedule.new(
|
@@ -224,40 +244,49 @@ module TTTLS13
|
|
224
244
|
key_schedule.server_handshake_write_key,
|
225
245
|
key_schedule.server_handshake_write_iv
|
226
246
|
)
|
247
|
+
sslkeylogfile&.write_server_handshake_traffic_secret(
|
248
|
+
transcript[CH].first.random,
|
249
|
+
key_schedule.server_handshake_traffic_secret
|
250
|
+
)
|
227
251
|
hs_rcipher = gen_cipher(
|
228
252
|
@cipher_suite,
|
229
253
|
key_schedule.client_handshake_write_key,
|
230
254
|
key_schedule.client_handshake_write_iv
|
231
255
|
)
|
256
|
+
sslkeylogfile&.write_client_handshake_traffic_secret(
|
257
|
+
transcript[CH].first.random,
|
258
|
+
key_schedule.client_handshake_traffic_secret
|
259
|
+
)
|
232
260
|
@state = ServerState::WAIT_FLIGHT2
|
233
261
|
when ServerState::WAIT_EOED
|
234
262
|
logger.debug('ServerState::WAIT_EOED')
|
235
263
|
when ServerState::WAIT_FLIGHT2
|
236
264
|
logger.debug('ServerState::WAIT_FLIGHT2')
|
237
265
|
|
238
|
-
ch = transcript[CH]
|
266
|
+
ch, = transcript[CH]
|
239
267
|
rsl = @send_record_size \
|
240
268
|
if ch.extensions.include?(Message::ExtensionType::RECORD_SIZE_LIMIT)
|
241
|
-
ee =
|
269
|
+
ee = gen_encrypted_extensions(ch, @alpn, rsl)
|
270
|
+
transcript[EE] = [ee, ee.serialize]
|
242
271
|
# TODO: [Send CertificateRequest]
|
243
272
|
|
244
273
|
# status_request
|
245
274
|
ocsp_response = fetch_ocsp_response \
|
246
275
|
if ch.extensions.include?(Message::ExtensionType::STATUS_REQUEST)
|
247
|
-
ct =
|
276
|
+
ct = gen_certificate(@crt, ch, @chain, ocsp_response)
|
277
|
+
transcript[CT] = [ct, ct.serialize]
|
248
278
|
digest = CipherSuite.digest(@cipher_suite)
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
transcript.hash(digest, CT)
|
253
|
-
)
|
279
|
+
hash = transcript.hash(digest, CT)
|
280
|
+
cv = gen_certificate_verify(@key, @signature_scheme, hash)
|
281
|
+
transcript[CV] = [cv, cv.serialize]
|
254
282
|
finished_key = key_schedule.server_finished_key
|
255
283
|
signature = sign_finished(
|
256
284
|
digest: digest,
|
257
285
|
finished_key: finished_key,
|
258
286
|
hash: transcript.hash(digest, CV)
|
259
287
|
)
|
260
|
-
sf =
|
288
|
+
sf = Message::Finished.new(signature)
|
289
|
+
transcript[SF] = [sf, sf.serialize]
|
261
290
|
send_server_parameters([ee, ct, cv, sf], hs_wcipher)
|
262
291
|
@state = ServerState::WAIT_FINISHED
|
263
292
|
when ServerState::WAIT_CERT
|
@@ -267,7 +296,7 @@ module TTTLS13
|
|
267
296
|
when ServerState::WAIT_FINISHED
|
268
297
|
logger.debug('ServerState::WAIT_FINISHED')
|
269
298
|
|
270
|
-
cf = transcript[CF] = recv_finished(hs_rcipher)
|
299
|
+
cf, = transcript[CF] = recv_finished(hs_rcipher)
|
271
300
|
digest = CipherSuite.digest(@cipher_suite)
|
272
301
|
verified = verified_finished?(
|
273
302
|
finished: cf,
|
@@ -281,11 +310,19 @@ module TTTLS13
|
|
281
310
|
key_schedule.server_application_write_key,
|
282
311
|
key_schedule.server_application_write_iv
|
283
312
|
)
|
313
|
+
sslkeylogfile&.write_server_traffic_secret_0(
|
314
|
+
transcript[CH].first.random,
|
315
|
+
key_schedule.server_application_traffic_secret
|
316
|
+
)
|
284
317
|
@ap_rcipher = gen_cipher(
|
285
318
|
@cipher_suite,
|
286
319
|
key_schedule.client_application_write_key,
|
287
320
|
key_schedule.client_application_write_iv
|
288
321
|
)
|
322
|
+
sslkeylogfile&.write_client_traffic_secret_0(
|
323
|
+
transcript[CH].first.random,
|
324
|
+
key_schedule.client_application_traffic_secret
|
325
|
+
)
|
289
326
|
@exporter_master_secret = key_schedule.exporter_master_secret
|
290
327
|
@state = ServerState::CONNECTED
|
291
328
|
when ServerState::CONNECTED
|
@@ -294,6 +331,7 @@ module TTTLS13
|
|
294
331
|
break
|
295
332
|
end
|
296
333
|
end
|
334
|
+
sslkeylogfile&.close
|
297
335
|
end
|
298
336
|
# rubocop: enable Metrics/AbcSize
|
299
337
|
# rubocop: enable Metrics/BlockLength
|
@@ -325,12 +363,15 @@ module TTTLS13
|
|
325
363
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
326
364
|
#
|
327
365
|
# @return [TTTLS13::Message::ClientHello]
|
366
|
+
# @return [String]
|
328
367
|
def recv_client_hello(receivable_ccs)
|
329
|
-
ch = recv_message(
|
330
|
-
|
368
|
+
ch, orig_msg = recv_message(
|
369
|
+
receivable_ccs: receivable_ccs,
|
370
|
+
cipher: Cryptograph::Passer.new
|
371
|
+
)
|
331
372
|
terminate(:unexpected_message) unless ch.is_a?(Message::ClientHello)
|
332
373
|
|
333
|
-
ch
|
374
|
+
[ch, orig_msg]
|
334
375
|
end
|
335
376
|
|
336
377
|
# @param extensions [TTTLS13::Message::Extensions]
|
@@ -408,19 +449,39 @@ module TTTLS13
|
|
408
449
|
end
|
409
450
|
|
410
451
|
# @param crt [OpenSSL::X509::Certificate]
|
452
|
+
# @param ch [TTTLS13::Message::ClientHell]
|
411
453
|
# @param chain [Array of OpenSSL::X509::Certificate]
|
412
454
|
# @param ocsp_response [OpenSSL::OCSP::Response]
|
413
455
|
#
|
414
|
-
# @return [TTTLS13::Message::Certificate, nil]
|
415
|
-
|
456
|
+
# @return [TTTLS13::Message::Certificate, CompressedCertificate, nil]
|
457
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
458
|
+
def gen_certificate(crt, ch, chain = [], ocsp_response = nil)
|
416
459
|
exs = Message::Extensions.new
|
417
460
|
# status_request
|
418
461
|
exs << Message::Extension::OCSPResponse.new(ocsp_response) \
|
419
462
|
unless ocsp_response.nil?
|
420
463
|
ces = [Message::CertificateEntry.new(crt, exs)] \
|
421
464
|
+ (chain || []).map { |c| Message::CertificateEntry.new(c) }
|
422
|
-
Message::Certificate.new(certificate_list: ces)
|
465
|
+
ct = Message::Certificate.new(certificate_list: ces)
|
466
|
+
|
467
|
+
# compress_certificate
|
468
|
+
cc = ch.extensions[Message::ExtensionType::COMPRESS_CERTIFICATE]
|
469
|
+
if !cc.nil? && !cc.algorithms.empty?
|
470
|
+
cca = (@settings[:compress_certificate_algorithms] || []).find do |a|
|
471
|
+
cc.algorithms.include?(a)
|
472
|
+
end
|
473
|
+
|
474
|
+
unless cca.nil?
|
475
|
+
ct = Message::CompressedCertificate.new(
|
476
|
+
certificate_message: ct,
|
477
|
+
algorithm: cca
|
478
|
+
)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
ct
|
423
483
|
end
|
484
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
424
485
|
|
425
486
|
# @param key [OpenSSL::PKey::PKey]
|
426
487
|
# @param signature_scheme [TTTLS13::SignatureScheme]
|
@@ -442,11 +503,12 @@ module TTTLS13
|
|
442
503
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
443
504
|
#
|
444
505
|
# @return [TTTLS13::Message::Finished]
|
506
|
+
# @return [String]
|
445
507
|
def recv_finished(cipher)
|
446
|
-
cf = recv_message(receivable_ccs: true, cipher: cipher)
|
508
|
+
cf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
447
509
|
terminate(:unexpected_message) unless cf.is_a?(Message::Finished)
|
448
510
|
|
449
|
-
cf
|
511
|
+
[cf, orig_msg]
|
450
512
|
end
|
451
513
|
|
452
514
|
# @param named_group [TTTLS13::NamedGroup]
|
@@ -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/transcript.rb
CHANGED
@@ -19,10 +19,6 @@ module TTTLS13
|
|
19
19
|
CF = 12
|
20
20
|
|
21
21
|
class Transcript < Hash
|
22
|
-
def initialize
|
23
|
-
super
|
24
|
-
end
|
25
|
-
|
26
22
|
alias super_include? include?
|
27
23
|
|
28
24
|
# @param digest [String] name of digest algorithm
|
@@ -62,12 +58,12 @@ module TTTLS13
|
|
62
58
|
exc_prefix = Message::HandshakeType::MESSAGE_HASH \
|
63
59
|
+ "\x00\x00" \
|
64
60
|
+ OpenSSL::Digest.new(digest).digest_length.to_uint8 \
|
65
|
-
+ OpenSSL::Digest.digest(digest, self[CH1].
|
66
|
-
+ self[HRR].
|
61
|
+
+ OpenSSL::Digest.digest(digest, self[CH1].last) \
|
62
|
+
+ self[HRR].last
|
67
63
|
end
|
68
64
|
|
69
65
|
messages = (CH..end_index).to_a.map do |m|
|
70
|
-
include?(m) ? self[m].
|
66
|
+
include?(m) ? self[m].last : ''
|
71
67
|
end
|
72
68
|
exc_prefix + messages.join
|
73
69
|
end
|
data/lib/tttls1.3/version.rb
CHANGED
data/lib/tttls1.3.rb
CHANGED
data/spec/client_spec.rb
CHANGED
@@ -11,7 +11,7 @@ RSpec.describe Client do
|
|
11
11
|
client = Client.new(mock_socket, 'localhost')
|
12
12
|
extensions, _priv_keys = client.send(:gen_ch_extensions)
|
13
13
|
client.send(:send_client_hello, extensions)
|
14
|
-
Record.deserialize(mock_socket.read, Cryptograph::Passer.new)
|
14
|
+
Record.deserialize(mock_socket.read, Cryptograph::Passer.new).first
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should send default ClientHello' do
|
@@ -37,7 +37,7 @@ RSpec.describe Client do
|
|
37
37
|
+ msg_len.to_uint16 \
|
38
38
|
+ TESTBINARY_SERVER_HELLO)
|
39
39
|
client = Client.new(mock_socket, 'localhost')
|
40
|
-
client.send(:recv_server_hello)
|
40
|
+
client.send(:recv_server_hello).first
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should receive ServerHello' do
|
@@ -65,20 +65,20 @@ RSpec.describe Client do
|
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'should receive EncryptedExtensions' do
|
68
|
-
message = client.send(:recv_encrypted_extensions, cipher)
|
68
|
+
message, = client.send(:recv_encrypted_extensions, cipher)
|
69
69
|
expect(message.msg_type).to eq HandshakeType::ENCRYPTED_EXTENSIONS
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'should receive Certificate' do
|
73
73
|
client.send(:recv_encrypted_extensions, cipher) # to skip
|
74
|
-
message = client.send(:recv_certificate, cipher)
|
74
|
+
message, = client.send(:recv_certificate, cipher)
|
75
75
|
expect(message.msg_type).to eq HandshakeType::CERTIFICATE
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'should receive CertificateVerify' do
|
79
79
|
client.send(:recv_encrypted_extensions, cipher) # to skip
|
80
80
|
client.send(:recv_certificate, cipher) # to skip
|
81
|
-
message = client.send(:recv_certificate_verify, cipher)
|
81
|
+
message, = client.send(:recv_certificate_verify, cipher)
|
82
82
|
expect(message.msg_type).to eq HandshakeType::CERTIFICATE_VERIFY
|
83
83
|
end
|
84
84
|
|
@@ -86,7 +86,7 @@ RSpec.describe Client do
|
|
86
86
|
client.send(:recv_encrypted_extensions, cipher) # to skip
|
87
87
|
client.send(:recv_certificate, cipher) # to skip
|
88
88
|
client.send(:recv_certificate_verify, cipher) # to skip
|
89
|
-
message = client.send(:recv_finished, cipher)
|
89
|
+
message, = client.send(:recv_finished, cipher)
|
90
90
|
expect(message.msg_type).to eq HandshakeType::FINISHED
|
91
91
|
end
|
92
92
|
end
|
@@ -97,14 +97,20 @@ RSpec.describe Client do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
let(:transcript) do
|
100
|
+
ch = ClientHello.deserialize(TESTBINARY_CLIENT_HELLO)
|
101
|
+
sh = ServerHello.deserialize(TESTBINARY_SERVER_HELLO)
|
102
|
+
ee = EncryptedExtensions.deserialize(TESTBINARY_ENCRYPTED_EXTENSIONS)
|
103
|
+
ct = Certificate.deserialize(TESTBINARY_CERTIFICATE)
|
104
|
+
cv = CertificateVerify.deserialize(TESTBINARY_CERTIFICATE_VERIFY)
|
105
|
+
sf = Finished.deserialize(TESTBINARY_SERVER_FINISHED)
|
100
106
|
transcript = Transcript.new
|
101
107
|
transcript.merge!(
|
102
|
-
CH =>
|
103
|
-
SH =>
|
104
|
-
EE =>
|
105
|
-
CT =>
|
106
|
-
CV =>
|
107
|
-
SF =>
|
108
|
+
CH => [ch, TESTBINARY_CLIENT_HELLO],
|
109
|
+
SH => [sh, TESTBINARY_SERVER_HELLO],
|
110
|
+
EE => [ee, TESTBINARY_ENCRYPTED_EXTENSIONS],
|
111
|
+
CT => [ct, TESTBINARY_CERTIFICATE],
|
112
|
+
CV => [cv, TESTBINARY_CERTIFICATE_VERIFY],
|
113
|
+
SF => [sf, TESTBINARY_SERVER_FINISHED]
|
108
114
|
)
|
109
115
|
transcript
|
110
116
|
end
|
@@ -140,7 +146,7 @@ RSpec.describe Client do
|
|
140
146
|
write_iv: TESTBINARY_CLIENT_FINISHED_WRITE_IV,
|
141
147
|
sequence_number: SequenceNumber.new
|
142
148
|
)
|
143
|
-
Record.deserialize(mock_socket.read, hs_rcipher)
|
149
|
+
Record.deserialize(mock_socket.read, hs_rcipher).first
|
144
150
|
end
|
145
151
|
|
146
152
|
it 'should send Finished' do
|
@@ -170,14 +176,17 @@ RSpec.describe Client do
|
|
170
176
|
end
|
171
177
|
|
172
178
|
let(:transcript) do
|
179
|
+
ch = ClientHello.deserialize(TESTBINARY_CLIENT_HELLO)
|
180
|
+
sh = ServerHello.deserialize(TESTBINARY_SERVER_HELLO)
|
181
|
+
ee = EncryptedExtensions.deserialize(TESTBINARY_ENCRYPTED_EXTENSIONS)
|
173
182
|
transcript = Transcript.new
|
174
183
|
transcript.merge!(
|
175
|
-
CH =>
|
176
|
-
SH =>
|
177
|
-
EE =>
|
178
|
-
CT => ct,
|
179
|
-
CV => cv,
|
180
|
-
SF => sf
|
184
|
+
CH => [ch, TESTBINARY_CLIENT_HELLO],
|
185
|
+
SH => [sh, TESTBINARY_SERVER_HELLO],
|
186
|
+
EE => [ee, TESTBINARY_ENCRYPTED_EXTENSIONS],
|
187
|
+
CT => [ct, TESTBINARY_CERTIFICATE],
|
188
|
+
CV => [cv, TESTBINARY_CERTIFICATE_VERIFY],
|
189
|
+
SF => [sf, TESTBINARY_SERVER_FINISHED]
|
181
190
|
)
|
182
191
|
end
|
183
192
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe Alpn do
|
8
|
+
context 'valid compress_certificate' do
|
9
|
+
let(:algorithms) do
|
10
|
+
[CertificateCompressionAlgorithm::ZLIB]
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:extension) do
|
14
|
+
CompressCertificate.new(algorithms)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should be generated' do
|
18
|
+
expect(extension.extension_type)
|
19
|
+
.to eq ExtensionType::COMPRESS_CERTIFICATE
|
20
|
+
expect(extension.algorithms).to eq algorithms
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should be serialized' do
|
24
|
+
expect(extension.serialize)
|
25
|
+
.to eq ExtensionType::COMPRESS_CERTIFICATE \
|
26
|
+
+ 3.to_uint16 \
|
27
|
+
+ 2.to_uint8 \
|
28
|
+
+ "\x00\x01"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'invalid compress_certificate, empty,' do
|
33
|
+
let(:extension) do
|
34
|
+
CompressCertificate.new([])
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not be generated' do
|
38
|
+
expect { extension }.to raise_error(ErrorAlerts)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'valid compress_certificate binary' do
|
43
|
+
let(:extension) do
|
44
|
+
CompressCertificate.deserialize(TESTBINARY_COMPRESS_CERTIFICATE)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should generate valid object' do
|
48
|
+
expect(extension.extension_type)
|
49
|
+
.to eq ExtensionType::COMPRESS_CERTIFICATE
|
50
|
+
expect(extension.algorithms)
|
51
|
+
.to eq [CertificateCompressionAlgorithm::ZLIB]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/connection_spec.rb
CHANGED
@@ -32,15 +32,18 @@ RSpec.describe Connection do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
let(:transcript) do
|
35
|
+
ch = ClientHello.deserialize(TESTBINARY_CLIENT_HELLO)
|
36
|
+
sh = ServerHello.deserialize(TESTBINARY_SERVER_HELLO)
|
37
|
+
ee = EncryptedExtensions.deserialize(TESTBINARY_ENCRYPTED_EXTENSIONS)
|
35
38
|
transcript = Transcript.new
|
36
39
|
transcript.merge!(
|
37
|
-
CH =>
|
38
|
-
SH =>
|
39
|
-
EE =>
|
40
|
-
CT => ct,
|
41
|
-
CV => cv,
|
42
|
-
CF => cf,
|
43
|
-
SF => sf
|
40
|
+
CH => [ch, TESTBINARY_CLIENT_HELLO],
|
41
|
+
SH => [sh, TESTBINARY_SERVER_HELLO],
|
42
|
+
EE => [ee, TESTBINARY_ENCRYPTED_EXTENSIONS],
|
43
|
+
CT => [ct, TESTBINARY_CERTIFICATE],
|
44
|
+
CV => [cv, TESTBINARY_CERTIFICATE_VERIFY],
|
45
|
+
CF => [cf, TESTBINARY_CLIENT_FINISHED],
|
46
|
+
SF => [sf, TESTBINARY_SERVER_FINISHED]
|
44
47
|
)
|
45
48
|
end
|
46
49
|
|
@@ -115,16 +118,20 @@ RSpec.describe Connection do
|
|
115
118
|
end
|
116
119
|
|
117
120
|
let(:transcript) do
|
121
|
+
ch1 = ClientHello.deserialize(TESTBINARY_HRR_CLIENT_HELLO1)
|
122
|
+
hrr = ServerHello.deserialize(TESTBINARY_HRR_HELLO_RETRY_REQUEST)
|
123
|
+
ch = ClientHello.deserialize(TESTBINARY_HRR_CLIENT_HELLO)
|
124
|
+
sh = ServerHello.deserialize(TESTBINARY_HRR_SERVER_HELLO)
|
125
|
+
ee = EncryptedExtensions.deserialize(TESTBINARY_HRR_ENCRYPTED_EXTENSIONS)
|
118
126
|
transcript = Transcript.new
|
119
127
|
transcript.merge!(
|
120
|
-
CH1 =>
|
121
|
-
HRR =>
|
122
|
-
CH =>
|
123
|
-
SH =>
|
124
|
-
EE =>
|
125
|
-
|
126
|
-
|
127
|
-
CV => cv
|
128
|
+
CH1 => [ch1, TESTBINARY_HRR_CLIENT_HELLO1],
|
129
|
+
HRR => [hrr, TESTBINARY_HRR_HELLO_RETRY_REQUEST],
|
130
|
+
CH => [ch, TESTBINARY_HRR_CLIENT_HELLO],
|
131
|
+
SH => [sh, TESTBINARY_HRR_SERVER_HELLO],
|
132
|
+
EE => [ee, TESTBINARY_HRR_ENCRYPTED_EXTENSIONS],
|
133
|
+
CT => [ct, TESTBINARY_HRR_CERTIFICATE],
|
134
|
+
CV => [cv, TESTBINARY_HRR_CERTIFICATE_VERIFY]
|
128
135
|
)
|
129
136
|
end
|
130
137
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe EndOfEarlyData do
|
8
|
+
context 'end_of_early_data' do
|
9
|
+
let(:message) do
|
10
|
+
EndOfEarlyData.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be serialized' do
|
14
|
+
expect(message.serialize).to eq HandshakeType::END_OF_EARLY_DATA \
|
15
|
+
+ ''.prefix_uint24_length
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'valid end_of_early_data binary' do
|
20
|
+
let(:message) do
|
21
|
+
EndOfEarlyData.deserialize(TESTBINARY_0_RTT_END_OF_EARLY_DATA)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should generate valid serializable object' do
|
25
|
+
expect(message.serialize).to eq TESTBINARY_0_RTT_END_OF_EARLY_DATA
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|