tttls1.3 0.2.12 → 0.2.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +32 -0
- data/.rubocop.yml +2 -2
- data/Gemfile +3 -4
- data/README.md +4 -1
- data/example/helper.rb +3 -3
- data/example/https_client.rb +1 -1
- data/example/https_client_using_0rtt.rb +2 -2
- data/example/https_client_using_hrr.rb +1 -1
- data/example/https_client_using_hrr_and_ticket.rb +2 -2
- data/example/https_client_using_status_request.rb +2 -2
- data/example/https_client_using_ticket.rb +2 -2
- data/example/https_server.rb +2 -2
- data/interop/client_spec.rb +6 -6
- data/interop/server_spec.rb +6 -6
- data/lib/tttls1.3/client.rb +106 -65
- data/lib/tttls1.3/connection.rb +43 -30
- data/lib/tttls1.3/cryptograph/aead.rb +20 -7
- data/lib/tttls1.3/cryptograph.rb +1 -1
- data/lib/tttls1.3/message/alert.rb +2 -2
- 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/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 +15 -5
- data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +5 -4
- data/lib/tttls1.3/message/extension/supported_groups.rb +2 -2
- data/lib/tttls1.3/message/extensions.rb +31 -18
- data/lib/tttls1.3/message/record.rb +28 -16
- data/lib/tttls1.3/message.rb +23 -21
- data/lib/tttls1.3/server.rb +88 -37
- data/lib/tttls1.3/transcript.rb +3 -7
- data/lib/tttls1.3/version.rb +1 -1
- data/spec/client_spec.rb +28 -19
- data/spec/compress_certificate_spec.rb +54 -0
- data/spec/connection_spec.rb +22 -15
- data/spec/extensions_spec.rb +16 -0
- data/spec/fixtures/rsa_rsa.crt +15 -15
- data/spec/fixtures/rsa_rsa.key +25 -25
- data/spec/key_schedule_spec.rb +48 -25
- data/spec/record_spec.rb +2 -2
- data/spec/server_hello_spec.rb +1 -1
- data/spec/server_spec.rb +23 -11
- data/spec/signature_algorithms_cert_spec.rb +4 -0
- data/spec/signature_algorithms_spec.rb +4 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/transcript_spec.rb +34 -20
- data/tttls1.3.gemspec +0 -1
- metadata +11 -7
- data/.github/workflows/main.yml +0 -25
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,
|
@@ -52,6 +57,8 @@ module TTTLS13
|
|
52
57
|
signature_algorithms: DEFAULT_SP_SIGNATURE_ALGORITHMS,
|
53
58
|
supported_groups: DEFAULT_SP_NAMED_GROUP_LIST,
|
54
59
|
alpn: nil,
|
60
|
+
process_ocsp_response: nil,
|
61
|
+
compress_certificate_algorithms: DEFAULT_SP_COMPRESS_CERTIFICATE_ALGORITHMS,
|
55
62
|
compatibility_mode: true,
|
56
63
|
loglevel: Logger::WARN
|
57
64
|
}.freeze
|
@@ -139,7 +146,6 @@ module TTTLS13
|
|
139
146
|
transcript = Transcript.new
|
140
147
|
key_schedule = nil # TTTLS13::KeySchedule
|
141
148
|
priv_key = nil # OpenSSL::PKey::$Object
|
142
|
-
|
143
149
|
hs_wcipher = nil # TTTLS13::Cryptograph::$Object
|
144
150
|
hs_rcipher = nil # TTTLS13::Cryptograph::$Object
|
145
151
|
|
@@ -150,7 +156,7 @@ module TTTLS13
|
|
150
156
|
logger.debug('ServerState::START')
|
151
157
|
|
152
158
|
receivable_ccs = transcript.include?(CH1)
|
153
|
-
ch = transcript[CH] = recv_client_hello(receivable_ccs)
|
159
|
+
ch, = transcript[CH] = recv_client_hello(receivable_ccs)
|
154
160
|
|
155
161
|
# support only TLS 1.3
|
156
162
|
terminate(:protocol_version) unless ch.negotiated_tls_1_3?
|
@@ -182,7 +188,7 @@ module TTTLS13
|
|
182
188
|
logger.debug('ServerState::RECVD_CH')
|
183
189
|
|
184
190
|
# select parameters
|
185
|
-
ch = transcript[CH]
|
191
|
+
ch, = transcript[CH]
|
186
192
|
@cipher_suite = select_cipher_suite(ch)
|
187
193
|
@named_group = select_named_group(ch)
|
188
194
|
@signature_scheme = select_signature_scheme(ch, @crt)
|
@@ -191,8 +197,9 @@ module TTTLS13
|
|
191
197
|
|
192
198
|
# send HRR
|
193
199
|
if @named_group.nil?
|
194
|
-
ch1 = transcript[CH1] = transcript.delete(CH)
|
195
|
-
|
200
|
+
ch1, = transcript[CH1] = transcript.delete(CH)
|
201
|
+
hrr = send_hello_retry_request(ch1, @cipher_suite)
|
202
|
+
transcript[HRR] = [hrr, hrr.serialize]
|
196
203
|
@state = ServerState::START
|
197
204
|
next
|
198
205
|
end
|
@@ -200,10 +207,14 @@ module TTTLS13
|
|
200
207
|
when ServerState::NEGOTIATED
|
201
208
|
logger.debug('ServerState::NEGOTIATED')
|
202
209
|
|
203
|
-
ch = transcript[CH]
|
210
|
+
ch, = transcript[CH]
|
204
211
|
extensions, priv_key = gen_sh_extensions(@named_group)
|
205
|
-
|
206
|
-
|
212
|
+
sh = send_server_hello(
|
213
|
+
extensions,
|
214
|
+
@cipher_suite,
|
215
|
+
ch.legacy_session_id
|
216
|
+
)
|
217
|
+
transcript[SH] = [sh, sh.serialize]
|
207
218
|
send_ccs if @settings[:compatibility_mode]
|
208
219
|
|
209
220
|
# generate shared secret
|
@@ -234,25 +245,30 @@ module TTTLS13
|
|
234
245
|
when ServerState::WAIT_FLIGHT2
|
235
246
|
logger.debug('ServerState::WAIT_FLIGHT2')
|
236
247
|
|
237
|
-
ch = transcript[CH]
|
248
|
+
ch, = transcript[CH]
|
238
249
|
rsl = @send_record_size \
|
239
|
-
|
240
|
-
ee =
|
250
|
+
if ch.extensions.include?(Message::ExtensionType::RECORD_SIZE_LIMIT)
|
251
|
+
ee = gen_encrypted_extensions(ch, @alpn, rsl)
|
252
|
+
transcript[EE] = [ee, ee.serialize]
|
241
253
|
# TODO: [Send CertificateRequest]
|
242
|
-
|
254
|
+
|
255
|
+
# status_request
|
256
|
+
ocsp_response = fetch_ocsp_response \
|
257
|
+
if ch.extensions.include?(Message::ExtensionType::STATUS_REQUEST)
|
258
|
+
ct = gen_certificate(@crt, ch, @chain, ocsp_response)
|
259
|
+
transcript[CT] = [ct, ct.serialize]
|
243
260
|
digest = CipherSuite.digest(@cipher_suite)
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
transcript.hash(digest, CT)
|
248
|
-
)
|
261
|
+
hash = transcript.hash(digest, CT)
|
262
|
+
cv = gen_certificate_verify(@key, @signature_scheme, hash)
|
263
|
+
transcript[CV] = [cv, cv.serialize]
|
249
264
|
finished_key = key_schedule.server_finished_key
|
250
265
|
signature = sign_finished(
|
251
266
|
digest: digest,
|
252
267
|
finished_key: finished_key,
|
253
268
|
hash: transcript.hash(digest, CV)
|
254
269
|
)
|
255
|
-
sf =
|
270
|
+
sf = Message::Finished.new(signature)
|
271
|
+
transcript[SF] = [sf, sf.serialize]
|
256
272
|
send_server_parameters([ee, ct, cv, sf], hs_wcipher)
|
257
273
|
@state = ServerState::WAIT_FINISHED
|
258
274
|
when ServerState::WAIT_CERT
|
@@ -262,7 +278,7 @@ module TTTLS13
|
|
262
278
|
when ServerState::WAIT_FINISHED
|
263
279
|
logger.debug('ServerState::WAIT_FINISHED')
|
264
280
|
|
265
|
-
cf = transcript[CF] = recv_finished(hs_rcipher)
|
281
|
+
cf, = transcript[CF] = recv_finished(hs_rcipher)
|
266
282
|
digest = CipherSuite.digest(@cipher_suite)
|
267
283
|
verified = verified_finished?(
|
268
284
|
finished: cf,
|
@@ -320,12 +336,15 @@ module TTTLS13
|
|
320
336
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
321
337
|
#
|
322
338
|
# @return [TTTLS13::Message::ClientHello]
|
339
|
+
# @return [String]
|
323
340
|
def recv_client_hello(receivable_ccs)
|
324
|
-
ch = recv_message(
|
325
|
-
|
341
|
+
ch, orig_msg = recv_message(
|
342
|
+
receivable_ccs: receivable_ccs,
|
343
|
+
cipher: Cryptograph::Passer.new
|
344
|
+
)
|
326
345
|
terminate(:unexpected_message) unless ch.is_a?(Message::ClientHello)
|
327
346
|
|
328
|
-
ch
|
347
|
+
[ch, orig_msg]
|
329
348
|
end
|
330
349
|
|
331
350
|
# @param extensions [TTTLS13::Message::Extensions]
|
@@ -350,7 +369,7 @@ module TTTLS13
|
|
350
369
|
#
|
351
370
|
# @return [TTTLS13::Message::ServerHello]
|
352
371
|
def send_hello_retry_request(ch1, cipher_suite)
|
353
|
-
exs =
|
372
|
+
exs = Message::Extensions.new
|
354
373
|
# supported_versions
|
355
374
|
exs << Message::Extension::SupportedVersions.new(
|
356
375
|
msg_type: Message::HandshakeType::SERVER_HELLO
|
@@ -372,7 +391,7 @@ module TTTLS13
|
|
372
391
|
random: Message::HRR_RANDOM,
|
373
392
|
legacy_session_id_echo: ch1.legacy_session_id,
|
374
393
|
cipher_suite: cipher_suite,
|
375
|
-
extensions:
|
394
|
+
extensions: exs
|
376
395
|
)
|
377
396
|
send_handshakes(Message::ContentType::HANDSHAKE, [sh],
|
378
397
|
Cryptograph::Passer.new)
|
@@ -403,14 +422,39 @@ module TTTLS13
|
|
403
422
|
end
|
404
423
|
|
405
424
|
# @param crt [OpenSSL::X509::Certificate]
|
425
|
+
# @param ch [TTTLS13::Message::ClientHell]
|
406
426
|
# @param chain [Array of OpenSSL::X509::Certificate]
|
427
|
+
# @param ocsp_response [OpenSSL::OCSP::Response]
|
407
428
|
#
|
408
|
-
# @return [TTTLS13::Message::Certificate, nil]
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
429
|
+
# @return [TTTLS13::Message::Certificate, CompressedCertificate, nil]
|
430
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
431
|
+
def gen_certificate(crt, ch, chain = [], ocsp_response = nil)
|
432
|
+
exs = Message::Extensions.new
|
433
|
+
# status_request
|
434
|
+
exs << Message::Extension::OCSPResponse.new(ocsp_response) \
|
435
|
+
unless ocsp_response.nil?
|
436
|
+
ces = [Message::CertificateEntry.new(crt, exs)] \
|
437
|
+
+ (chain || []).map { |c| Message::CertificateEntry.new(c) }
|
438
|
+
ct = Message::Certificate.new(certificate_list: ces)
|
439
|
+
|
440
|
+
# compress_certificate
|
441
|
+
cc = ch.extensions[Message::ExtensionType::COMPRESS_CERTIFICATE]
|
442
|
+
if !cc.nil? && !cc.algorithms.empty?
|
443
|
+
cca = (@settings[:compress_certificate_algorithms] || []).find do |a|
|
444
|
+
cc.algorithms.include?(a)
|
445
|
+
end
|
446
|
+
|
447
|
+
unless cca.nil?
|
448
|
+
ct = Message::CompressedCertificate.new(
|
449
|
+
certificate_message: ct,
|
450
|
+
algorithm: cca
|
451
|
+
)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
ct
|
413
456
|
end
|
457
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
414
458
|
|
415
459
|
# @param key [OpenSSL::PKey::PKey]
|
416
460
|
# @param signature_scheme [TTTLS13::SignatureScheme]
|
@@ -432,11 +476,12 @@ module TTTLS13
|
|
432
476
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
433
477
|
#
|
434
478
|
# @return [TTTLS13::Message::Finished]
|
479
|
+
# @return [String]
|
435
480
|
def recv_finished(cipher)
|
436
|
-
cf = recv_message(receivable_ccs: true, cipher: cipher)
|
481
|
+
cf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
437
482
|
terminate(:unexpected_message) unless cf.is_a?(Message::Finished)
|
438
483
|
|
439
|
-
cf
|
484
|
+
[cf, orig_msg]
|
440
485
|
end
|
441
486
|
|
442
487
|
# @param named_group [TTTLS13::NamedGroup]
|
@@ -444,7 +489,7 @@ module TTTLS13
|
|
444
489
|
# @return [TTTLS13::Message::Extensions]
|
445
490
|
# @return [OpenSSL::PKey::EC.$Object]
|
446
491
|
def gen_sh_extensions(named_group)
|
447
|
-
exs =
|
492
|
+
exs = Message::Extensions.new
|
448
493
|
# supported_versions: only TLS 1.3
|
449
494
|
exs << Message::Extension::SupportedVersions.new(
|
450
495
|
msg_type: Message::HandshakeType::SERVER_HELLO
|
@@ -455,7 +500,7 @@ module TTTLS13
|
|
455
500
|
= Message::Extension::KeyShare.gen_sh_key_share(named_group)
|
456
501
|
exs << key_share
|
457
502
|
|
458
|
-
[
|
503
|
+
[exs, priv_key]
|
459
504
|
end
|
460
505
|
|
461
506
|
# @param ch [TTTLS13::Message::ClientHello]
|
@@ -464,15 +509,16 @@ module TTTLS13
|
|
464
509
|
#
|
465
510
|
# @return [TTTLS13::Message::Extensions]
|
466
511
|
def gen_ee_extensions(ch, alpn, record_size_limit)
|
467
|
-
exs =
|
512
|
+
exs = Message::Extensions.new
|
468
513
|
|
469
514
|
# server_name
|
470
515
|
exs << Message::Extension::ServerName.new('') \
|
471
516
|
if ch.extensions.include?(Message::ExtensionType::SERVER_NAME)
|
472
517
|
|
473
518
|
# supported_groups
|
474
|
-
exs
|
475
|
-
|
519
|
+
exs << Message::Extension::SupportedGroups.new(
|
520
|
+
@settings[:supported_groups]
|
521
|
+
)
|
476
522
|
|
477
523
|
# alpn
|
478
524
|
exs << Message::Extension::Alpn.new([alpn]) unless alpn.nil?
|
@@ -481,7 +527,7 @@ module TTTLS13
|
|
481
527
|
exs << Message::Extension::RecordSizeLimit.new(record_size_limit) \
|
482
528
|
unless record_size_limit.nil?
|
483
529
|
|
484
|
-
|
530
|
+
exs
|
485
531
|
end
|
486
532
|
|
487
533
|
# @param key [OpenSSL::PKey::PKey]
|
@@ -543,6 +589,11 @@ module TTTLS13
|
|
543
589
|
|
544
590
|
matching_san?(crt, server_name)
|
545
591
|
end
|
592
|
+
|
593
|
+
# @return [OpenSSL::OCSP::Response, nil]
|
594
|
+
def fetch_ocsp_response
|
595
|
+
@settings[:process_ocsp_response]&.call
|
596
|
+
end
|
546
597
|
end
|
547
598
|
# rubocop: enable Metrics/ClassLength
|
548
599
|
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/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
|
|
data/spec/extensions_spec.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require_relative 'spec_helper'
|
5
|
+
using Refinements
|
5
6
|
|
6
7
|
RSpec.describe Extensions do
|
7
8
|
context 'empty extensions' do
|
@@ -167,4 +168,19 @@ RSpec.describe Extensions do
|
|
167
168
|
expect(extensions).to include ExtensionType::RECORD_SIZE_LIMIT
|
168
169
|
end
|
169
170
|
end
|
171
|
+
|
172
|
+
context 'duplicated extension_type' do
|
173
|
+
let(:server_name) do
|
174
|
+
ServerName.new('example.com')
|
175
|
+
end
|
176
|
+
|
177
|
+
let(:testbinary) do
|
178
|
+
server_name.serialize * 2
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should raise error, if extension_type get duplicated' do
|
182
|
+
expect { Extensions.deserialize(testbinary, HandshakeType::CLIENT_HELLO) }
|
183
|
+
.to raise_error(ErrorAlerts)
|
184
|
+
end
|
185
|
+
end
|
170
186
|
end
|
data/spec/fixtures/rsa_rsa.crt
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
2
|
+
MIIC2TCCAcGgAwIBAgIJALo0YKZBVqYnMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
|
3
|
+
BAMMB3Rlc3QtY2EwHhcNMjAwNzE1MTU0NTE4WhcNMzAwNzEzMTU0NTE4WjAUMRIw
|
4
4
|
EAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
5
|
+
AQC65xzvPQrsXXRVsQ4rcrmvOF0gdWV38JKlhHUrS50//T0S55FUSBkuVXUDCZDx
|
6
|
+
dOf0y/5HaMb3hm68+ld5B/oNtoPlJWW6Sgc8OLERQy9qGpwR0mXND4SnZ9or7RDV
|
7
|
+
8tAEg/Hzq5rm6Xy2WClSR+nHg2tVh2Szde39j7o8ivJpHPzfEyZh37y9oIiY2/FP
|
8
|
+
QpbAe8n3Ses04D3jhZRoysdcuneWuG3h5DJ9X4IhZUBM54nEO5IQElyYnF6xY/Lt
|
9
|
+
Gykf8+ydiuAZpZF5FGGfoiKB7XdIwhSlK1XRFeBbHRqyAFjpSNtqy6RPdJINLseb
|
10
|
+
wG6DNSxcLm91C6ZJaaqu7Qp1AgMBAAGjMDAuMAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
11
|
+
AgWgMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEALqaQ
|
12
|
+
J5H9jB2VmIEDxhXAQTeqW1Hmp0oHhL1XcAvNS+JILjFfAdjMe/3Kei3hQJv8j8sE
|
13
|
+
uck3o7iA4kcE0ydUzO7TM7efjqcksyZrmWSB0xj+NHjcybwhD4Selr1vBSCU0IHN
|
14
|
+
Ap+zYbBX7eQawm2lIzniBvS6MmP+dgZjhy73FVQ4oSz+wTcg1iPkhulYL4iV/HSG
|
15
|
+
fND5gUvlRbLHGTETpCdq7iJNOpNl/OYboJLPvVpx8H7Jc+L2bQl05fj/koO35xaL
|
16
|
+
JuZGj5aVOKw45WvqERpe1RI3077dWE6bAr9DzrW13IqmFMbPD817pcB6+ILZnMAF
|
17
|
+
RhobWRU6PA4TdDP8bg==
|
18
18
|
-----END CERTIFICATE-----
|
data/spec/fixtures/rsa_rsa.key
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
-----BEGIN RSA PRIVATE KEY-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
/
|
25
|
-
|
26
|
-
|
2
|
+
MIIEowIBAAKCAQEAuucc7z0K7F10VbEOK3K5rzhdIHVld/CSpYR1K0udP/09EueR
|
3
|
+
VEgZLlV1AwmQ8XTn9Mv+R2jG94ZuvPpXeQf6DbaD5SVlukoHPDixEUMvahqcEdJl
|
4
|
+
zQ+Ep2faK+0Q1fLQBIPx86ua5ul8tlgpUkfpx4NrVYdks3Xt/Y+6PIryaRz83xMm
|
5
|
+
Yd+8vaCImNvxT0KWwHvJ90nrNOA944WUaMrHXLp3lrht4eQyfV+CIWVATOeJxDuS
|
6
|
+
EBJcmJxesWPy7RspH/PsnYrgGaWReRRhn6Iige13SMIUpStV0RXgWx0asgBY6Ujb
|
7
|
+
asukT3SSDS7Hm8BugzUsXC5vdQumSWmqru0KdQIDAQABAoIBABPIjNaB9psIVV0Q
|
8
|
+
rbhJn3/9jlX2NzRX4Z3lhGV9znpMet96ZXavXwL5hrY4mAAG6NqPkS3L2Guw7h3Q
|
9
|
+
vduQzZYQAKwLplXuqg9kzNFP9D/d6zEzvRTUlK0HoB9QK50J45zmvoCVZIMWqd2/
|
10
|
+
PTh5ZjR5I65c83rPe86AHS11Y61edr+vvGtI07kvj7EzR3jie0Lzzpj7TbmjTt5U
|
11
|
+
v9rskcxjulQOmp8t/3ouptUhi16PRXPof0yzRGo6rrCUoQ7Cuy1dbFZ96dIBxrt4
|
12
|
+
h9suE6MtpXdsGfI5FZPOKHqUcw8hZfUgeOYm4OTV3vBYie0xJ77i9YgqR+UwymjA
|
13
|
+
NK4AOY0CgYEA553JtUvl8py76HjL3DxfbU38Dq22AF9sdUAs9Xwy9B8Y6R9SyrPI
|
14
|
+
nab+3EE0gz5NnFLFCILK4A7ewe3OB3bE7/P4mc7JlUWM2LAcBz7K50seIKD3r+cj
|
15
|
+
VzLHarOBi/VZ0pe1lDj/cuQ6cXTLHbKtk2XGCRnCBMJlog4ruFMYJ+sCgYEAzpRD
|
16
|
+
3YtuQcT0rtvK05BcdWD3nGgsrAauLvKz80LIu4zX9nfz/H6lNRpZYJ2jrLR1ikbX
|
17
|
+
XVWIsNlWizAuWEbGokUEYDTuhkh3591nrdPyB6/0Lm2Snl+q7mKIUFrZ08MXe7U8
|
18
|
+
Z/qPq2VLVSzCyoGX0l4GuNymgDH6NVR/i5yQXx8CgYBNJ1OUz+aWbb1ukCagg3/q
|
19
|
+
QksPfLAe6aqQWENhtvCmP2Gl7mg+26qdUY6eQh5DBdMGms/FqQP5pRpxEU1LUTYD
|
20
|
+
FIsgeTDPR67GU8vSYglnCK/NgLFhaCZumpyxH4Cs5Zr5Os4ixOXbGMmbF6O9jdKi
|
21
|
+
Qgm46FqoCTWfyQapTQzD5wKBgGQV4WuNCjZDPmkZhANMhf84o77bmgkek3WbkSPi
|
22
|
+
z25OprN7GnLSySgZRARTW+Fo7Sm5eM53impkYlG9XjbW05X66kvSWV4l7jIgSwMl
|
23
|
+
FLY0wZFc9RRWNXKZuoF0AuVeOBpvjHy0ILdhtEXoEdgbQXtios8d2G1zyU3dSo5R
|
24
|
+
pIDxAoGBAIlXeI9tB0X9ywXKylI3CyHi8ex/k6o4WTj/5fH4bYp4faHBRm78Ho81
|
25
|
+
Ih9rewMw7fMC3YUN3rcyvHRQqbJ2Wcxpyf0k45GMxTRasoVXCXgV/sMNCHh/ddZM
|
26
|
+
Gf5ZTeq10gJPofBlPObg5VrlCLRnIFaNI4izpq2A+/FqTrEvSGlf
|
27
27
|
-----END RSA PRIVATE KEY-----
|