tttls1.3 0.2.15 → 0.2.16
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 +1 -1
- data/README.md +2 -0
- data/lib/tttls1.3/client.rb +85 -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/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 +61 -26
- 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/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
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7006bce3031f6232ae949b44eb31111562d581e359769952f48a537848d50418
|
4
|
+
data.tar.gz: d332e823eb8c677ff534e46a87e96c039aad2d5538c0f823ac7eb365f372ca88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca37fd2570b905759da152932eb2e6f29c3e37f59135353b9e3cfbce0c683f7493fdd360f9a56c50f2ab252f0460728c09585d018d04b8668de4000b1567d249
|
7
|
+
data.tar.gz: 6e37405f3034de1fe648f0882bbc9d9b65baeac8d1ef142fc776010b8480cd987a87060edf6ae85fd20327afc5327aacb23318e460f510259c99056aa76fb389
|
data/.github/workflows/ci.yml
CHANGED
data/README.md
CHANGED
@@ -102,6 +102,7 @@ tttls1.3 client is configurable using keyword arguments.
|
|
102
102
|
| `:record_size_limit` | Integer | nil | The record\_size\_limit offerd in ClientHello extensions. If not needed to be present, set nil. |
|
103
103
|
| `:check_certificate_status` | Boolean | false | If needed to check certificate status, set true. |
|
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
|
+
| `:compress_certificate_algorithms` | Array of TTTLS13::Message::Extension::CertificateCompressionAlgorithm constant | `ZLIB` | The compression algorithms are supported for compressing the Certificate message. |
|
105
106
|
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
106
107
|
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
107
108
|
|
@@ -120,6 +121,7 @@ tttls1.3 server is configurable using keyword arguments.
|
|
120
121
|
| `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of supported named groups. |
|
121
122
|
| `:alpn` | Array of String | nil | List of supported application protocols. If not needed to check this extension, set nil. |
|
122
123
|
| `:process_ocsp_response` | Proc | nil | Proc that gets OpenSSL::OCSP::Response. If not needed to staple OCSP::Response, set nil. |
|
124
|
+
| `:compress_certificate_algorithms` | Array of TTTLS13::Message::Extension::CertificateCompressionAlgorithm constant | `ZLIB` | The compression algorithms are supported for compressing the Certificate message. |
|
123
125
|
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
124
126
|
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
125
127
|
|
data/lib/tttls1.3/client.rb
CHANGED
@@ -43,6 +43,11 @@ module TTTLS13
|
|
43
43
|
].freeze
|
44
44
|
private_constant :DEFAULT_CH_NAMED_GROUP_LIST
|
45
45
|
|
46
|
+
DEFALUT_CH_COMPRESS_CERTIFICATE_ALGORITHMS = [
|
47
|
+
Message::Extension::CertificateCompressionAlgorithm::ZLIB
|
48
|
+
].freeze
|
49
|
+
private_constant :DEFALUT_CH_COMPRESS_CERTIFICATE_ALGORITHMS
|
50
|
+
|
46
51
|
DEFAULT_CLIENT_SETTINGS = {
|
47
52
|
ca_file: nil,
|
48
53
|
cipher_suites: DEFAULT_CH_CIPHER_SUITES,
|
@@ -61,6 +66,7 @@ module TTTLS13
|
|
61
66
|
record_size_limit: nil,
|
62
67
|
check_certificate_status: false,
|
63
68
|
process_certificate_status: nil,
|
69
|
+
compress_certificate_algorithms: DEFALUT_CH_COMPRESS_CERTIFICATE_ALGORITHMS,
|
64
70
|
compatibility_mode: true,
|
65
71
|
loglevel: Logger::WARN
|
66
72
|
}.freeze
|
@@ -154,8 +160,8 @@ module TTTLS13
|
|
154
160
|
|
155
161
|
extensions, priv_keys = gen_ch_extensions
|
156
162
|
binder_key = (use_psk? ? key_schedule.binder_key_res : nil)
|
157
|
-
|
158
|
-
|
163
|
+
ch = send_client_hello(extensions, binder_key)
|
164
|
+
transcript[CH] = [ch, ch.serialize]
|
159
165
|
send_ccs if @settings[:compatibility_mode]
|
160
166
|
if use_early_data?
|
161
167
|
e_wcipher = gen_cipher(
|
@@ -170,7 +176,7 @@ module TTTLS13
|
|
170
176
|
when ClientState::WAIT_SH
|
171
177
|
logger.debug('ClientState::WAIT_SH')
|
172
178
|
|
173
|
-
sh = transcript[SH] = recv_server_hello
|
179
|
+
sh, = transcript[SH] = recv_server_hello
|
174
180
|
|
175
181
|
# downgrade protection
|
176
182
|
if !sh.negotiated_tls_1_3? && sh.downgraded?
|
@@ -187,7 +193,7 @@ module TTTLS13
|
|
187
193
|
unless sh.legacy_compression_method == "\x00"
|
188
194
|
|
189
195
|
# validate sh using ch
|
190
|
-
ch = transcript[CH]
|
196
|
+
ch, = transcript[CH]
|
191
197
|
terminate(:illegal_parameter) \
|
192
198
|
unless sh.legacy_version == ch.legacy_version
|
193
199
|
terminate(:illegal_parameter) \
|
@@ -199,7 +205,7 @@ module TTTLS13
|
|
199
205
|
|
200
206
|
# validate sh using hrr
|
201
207
|
if transcript.include?(HRR)
|
202
|
-
hrr = transcript[HRR]
|
208
|
+
hrr, = transcript[HRR]
|
203
209
|
terminate(:illegal_parameter) \
|
204
210
|
unless sh.cipher_suite == hrr.cipher_suite
|
205
211
|
|
@@ -212,8 +218,9 @@ module TTTLS13
|
|
212
218
|
# handling HRR
|
213
219
|
if sh.hrr?
|
214
220
|
terminate(:unexpected_message) if transcript.include?(HRR)
|
215
|
-
|
216
|
-
|
221
|
+
|
222
|
+
ch1, = transcript[CH1] = transcript.delete(CH)
|
223
|
+
hrr, = transcript[HRR] = transcript.delete(SH)
|
217
224
|
|
218
225
|
# validate cookie
|
219
226
|
diff_sets = sh.extensions.keys - ch1.extensions.keys
|
@@ -235,8 +242,9 @@ module TTTLS13
|
|
235
242
|
extensions, pk = gen_newch_extensions(ch1, hrr)
|
236
243
|
priv_keys = pk.merge(priv_keys)
|
237
244
|
binder_key = (use_psk? ? key_schedule.binder_key_res : nil)
|
238
|
-
|
239
|
-
|
245
|
+
ch = send_new_client_hello(ch1, hrr, extensions, binder_key)
|
246
|
+
transcript[CH] = [ch, ch.serialize]
|
247
|
+
|
240
248
|
@state = ClientState::WAIT_SH
|
241
249
|
next
|
242
250
|
end
|
@@ -277,37 +285,46 @@ module TTTLS13
|
|
277
285
|
when ClientState::WAIT_EE
|
278
286
|
logger.debug('ClientState::WAIT_EE')
|
279
287
|
|
280
|
-
ee = transcript[EE] = recv_encrypted_extensions(hs_rcipher)
|
288
|
+
ee, = transcript[EE] = recv_encrypted_extensions(hs_rcipher)
|
281
289
|
terminate(:illegal_parameter) unless ee.appearable_extensions?
|
282
290
|
|
283
|
-
ch = transcript[CH]
|
291
|
+
ch, = transcript[CH]
|
284
292
|
terminate(:unsupported_extension) \
|
285
293
|
unless (ee.extensions.keys - ch.extensions.keys).empty?
|
286
294
|
|
287
295
|
rsl = ee.extensions[Message::ExtensionType::RECORD_SIZE_LIMIT]
|
288
296
|
@recv_record_size = rsl.record_size_limit unless rsl.nil?
|
289
|
-
|
290
297
|
@succeed_early_data = true \
|
291
298
|
if ee.extensions.include?(Message::ExtensionType::EARLY_DATA)
|
292
|
-
|
293
299
|
@alpn = ee.extensions[
|
294
300
|
Message::ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
|
295
301
|
]&.protocol_name_list&.first
|
296
|
-
|
297
302
|
@state = ClientState::WAIT_CERT_CR
|
298
303
|
@state = ClientState::WAIT_FINISHED unless psk.nil?
|
299
304
|
when ClientState::WAIT_CERT_CR
|
300
305
|
logger.debug('ClientState::WAIT_CERT_CR')
|
301
306
|
|
302
|
-
message = recv_message(
|
303
|
-
|
304
|
-
|
305
|
-
|
307
|
+
message, orig_msg = recv_message(
|
308
|
+
receivable_ccs: true,
|
309
|
+
cipher: hs_rcipher
|
310
|
+
)
|
311
|
+
case message.msg_type
|
312
|
+
when Message::HandshakeType::CERTIFICATE,
|
313
|
+
Message::HandshakeType::COMPRESSED_CERTIFICATE
|
314
|
+
ct, = transcript[CT] = [message, orig_msg]
|
315
|
+
terminate(:bad_certificate) \
|
316
|
+
if ct.is_a?(Message::CompressedCertificate) &&
|
317
|
+
!@settings[:compress_certificate_algorithms]
|
318
|
+
.include?(ct.algorithm)
|
319
|
+
|
320
|
+
ct = ct.certificate_message \
|
321
|
+
if ct.is_a?(Message::CompressedCertificate)
|
322
|
+
alert = check_invalid_certificate(ct, transcript[CH].first)
|
306
323
|
terminate(alert) unless alert.nil?
|
307
324
|
|
308
325
|
@state = ClientState::WAIT_CV
|
309
|
-
|
310
|
-
transcript[CR] = message
|
326
|
+
when Message::HandshakeType::CERTIFICATE_REQUEST
|
327
|
+
transcript[CR] = [message, orig_msg]
|
311
328
|
# TODO: client authentication
|
312
329
|
@state = ClientState::WAIT_CERT
|
313
330
|
else
|
@@ -316,46 +333,56 @@ module TTTLS13
|
|
316
333
|
when ClientState::WAIT_CERT
|
317
334
|
logger.debug('ClientState::WAIT_CERT')
|
318
335
|
|
319
|
-
ct = transcript[CT] = recv_certificate(hs_rcipher)
|
320
|
-
|
336
|
+
ct, = transcript[CT] = recv_certificate(hs_rcipher)
|
337
|
+
if ct.is_a?(Message::CompressedCertificate) &&
|
338
|
+
!@settings[:compress_certificate_algorithms].include?(ct.algorithm)
|
339
|
+
terminate(:bad_certificate)
|
340
|
+
elsif ct.is_a?(Message::CompressedCertificate)
|
341
|
+
ct = ct.certificate_message
|
342
|
+
end
|
343
|
+
|
344
|
+
alert = check_invalid_certificate(ct, transcript[CH].first)
|
321
345
|
terminate(alert) unless alert.nil?
|
322
346
|
|
323
347
|
@state = ClientState::WAIT_CV
|
324
348
|
when ClientState::WAIT_CV
|
325
349
|
logger.debug('ClientState::WAIT_CV')
|
326
350
|
|
327
|
-
cv = transcript[CV] = recv_certificate_verify(hs_rcipher)
|
351
|
+
cv, = transcript[CV] = recv_certificate_verify(hs_rcipher)
|
328
352
|
digest = CipherSuite.digest(@cipher_suite)
|
329
353
|
hash = transcript.hash(digest, CT)
|
354
|
+
ct, = transcript[CT]
|
355
|
+
ct = ct.certificate_message \
|
356
|
+
if ct.is_a?(Message::CompressedCertificate)
|
330
357
|
terminate(:decrypt_error) \
|
331
|
-
unless verified_certificate_verify?(
|
358
|
+
unless verified_certificate_verify?(ct, cv, hash)
|
332
359
|
|
333
360
|
@signature_scheme = cv.signature_scheme
|
334
|
-
|
335
361
|
@state = ClientState::WAIT_FINISHED
|
336
362
|
when ClientState::WAIT_FINISHED
|
337
363
|
logger.debug('ClientState::WAIT_FINISHED')
|
338
364
|
|
339
|
-
sf = transcript[SF] = recv_finished(hs_rcipher)
|
365
|
+
sf, = transcript[SF] = recv_finished(hs_rcipher)
|
340
366
|
digest = CipherSuite.digest(@cipher_suite)
|
341
|
-
|
367
|
+
terminate(:decrypt_error) unless verified_finished?(
|
342
368
|
finished: sf,
|
343
369
|
digest: digest,
|
344
370
|
finished_key: key_schedule.server_finished_key,
|
345
371
|
hash: transcript.hash(digest, CV)
|
346
372
|
)
|
347
|
-
terminate(:decrypt_error) unless verified
|
348
|
-
|
349
|
-
transcript[EOED] = send_eoed(e_wcipher) \
|
350
|
-
if use_early_data? && succeed_early_data?
|
351
373
|
|
374
|
+
if use_early_data? && succeed_early_data?
|
375
|
+
eoed = send_eoed(e_wcipher)
|
376
|
+
transcript[EOED] = [eoed, eoed.serialize]
|
377
|
+
end
|
352
378
|
# TODO: Send Certificate [+ CertificateVerify]
|
353
379
|
signature = sign_finished(
|
354
380
|
digest: digest,
|
355
381
|
finished_key: key_schedule.client_finished_key,
|
356
382
|
hash: transcript.hash(digest, EOED)
|
357
383
|
)
|
358
|
-
|
384
|
+
cf = send_finished(signature, hs_wcipher)
|
385
|
+
transcript[CF] = [cf, cf.serialize]
|
359
386
|
@alert_wcipher = @ap_wcipher = gen_cipher(
|
360
387
|
@cipher_suite,
|
361
388
|
key_schedule.client_application_write_key,
|
@@ -578,6 +605,14 @@ module TTTLS13
|
|
578
605
|
exs << Message::Extension::OCSPStatusRequest.new \
|
579
606
|
if @settings[:check_certificate_status]
|
580
607
|
|
608
|
+
# compress_certificate
|
609
|
+
if !@settings[:compress_certificate_algorithms].nil? &&
|
610
|
+
!@settings[:compress_certificate_algorithms].empty?
|
611
|
+
exs << Message::Extension::CompressCertificate.new(
|
612
|
+
@settings[:compress_certificate_algorithms]
|
613
|
+
)
|
614
|
+
end
|
615
|
+
|
581
616
|
[exs, priv_keys]
|
582
617
|
end
|
583
618
|
# rubocop: enable Metrics/AbcSize
|
@@ -735,11 +770,15 @@ module TTTLS13
|
|
735
770
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
736
771
|
#
|
737
772
|
# @return [TTTLS13::Message::ServerHello]
|
773
|
+
# @return [String]
|
738
774
|
def recv_server_hello
|
739
|
-
sh = recv_message(
|
775
|
+
sh, orig_msg = recv_message(
|
776
|
+
receivable_ccs: true,
|
777
|
+
cipher: Cryptograph::Passer.new
|
778
|
+
)
|
740
779
|
terminate(:unexpected_message) unless sh.is_a?(Message::ServerHello)
|
741
780
|
|
742
|
-
sh
|
781
|
+
[sh, orig_msg]
|
743
782
|
end
|
744
783
|
|
745
784
|
# @param cipher [TTTLS13::Cryptograph::Aead]
|
@@ -747,12 +786,13 @@ module TTTLS13
|
|
747
786
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
748
787
|
#
|
749
788
|
# @return [TTTLS13::Message::EncryptedExtensions]
|
789
|
+
# @return [String]
|
750
790
|
def recv_encrypted_extensions(cipher)
|
751
|
-
ee = recv_message(receivable_ccs: true, cipher: cipher)
|
791
|
+
ee, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
752
792
|
terminate(:unexpected_message) \
|
753
793
|
unless ee.is_a?(Message::EncryptedExtensions)
|
754
794
|
|
755
|
-
ee
|
795
|
+
[ee, orig_msg]
|
756
796
|
end
|
757
797
|
|
758
798
|
# @param cipher [TTTLS13::Cryptograph::Aead]
|
@@ -760,11 +800,12 @@ module TTTLS13
|
|
760
800
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
761
801
|
#
|
762
802
|
# @return [TTTLS13::Message::Certificate]
|
803
|
+
# @return [String]
|
763
804
|
def recv_certificate(cipher)
|
764
|
-
ct = recv_message(receivable_ccs: true, cipher: cipher)
|
805
|
+
ct, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
765
806
|
terminate(:unexpected_message) unless ct.is_a?(Message::Certificate)
|
766
807
|
|
767
|
-
ct
|
808
|
+
[ct, orig_msg]
|
768
809
|
end
|
769
810
|
|
770
811
|
# @param cipher [TTTLS13::Cryptograph::Aead]
|
@@ -772,11 +813,12 @@ module TTTLS13
|
|
772
813
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
773
814
|
#
|
774
815
|
# @return [TTTLS13::Message::CertificateVerify]
|
816
|
+
# @return [String]
|
775
817
|
def recv_certificate_verify(cipher)
|
776
|
-
cv = recv_message(receivable_ccs: true, cipher: cipher)
|
818
|
+
cv, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
777
819
|
terminate(:unexpected_message) unless cv.is_a?(Message::CertificateVerify)
|
778
820
|
|
779
|
-
cv
|
821
|
+
[cv, orig_msg]
|
780
822
|
end
|
781
823
|
|
782
824
|
# @param cipher [TTTLS13::Cryptograph::Aead]
|
@@ -784,11 +826,12 @@ module TTTLS13
|
|
784
826
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
785
827
|
#
|
786
828
|
# @return [TTTLS13::Message::Finished]
|
829
|
+
# @return [String]
|
787
830
|
def recv_finished(cipher)
|
788
|
-
sf = recv_message(receivable_ccs: true, cipher: cipher)
|
831
|
+
sf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
|
789
832
|
terminate(:unexpected_message) unless sf.is_a?(Message::Finished)
|
790
833
|
|
791
|
-
sf
|
834
|
+
[sf, orig_msg]
|
792
835
|
end
|
793
836
|
|
794
837
|
# @param cipher [TTTLS13::Cryptograph::Aead]
|
data/lib/tttls1.3/connection.rb
CHANGED
@@ -16,7 +16,7 @@ module TTTLS13
|
|
16
16
|
@ap_wcipher = Cryptograph::Passer.new
|
17
17
|
@ap_rcipher = Cryptograph::Passer.new
|
18
18
|
@alert_wcipher = Cryptograph::Passer.new
|
19
|
-
@message_queue = [] # Array of TTTLS13::Message::$Object
|
19
|
+
@message_queue = [] # Array of [TTTLS13::Message::$Object, String]
|
20
20
|
@binary_buffer = '' # deposit Record.surplus_binary
|
21
21
|
@cipher_suite = nil # TTTLS13::CipherSuite
|
22
22
|
@named_group = nil # TTTLS13::NamedGroup
|
@@ -42,7 +42,7 @@ module TTTLS13
|
|
42
42
|
|
43
43
|
message = nil
|
44
44
|
loop do
|
45
|
-
message = recv_message(receivable_ccs: false, cipher: @ap_rcipher)
|
45
|
+
message, = recv_message(receivable_ccs: false, cipher: @ap_rcipher)
|
46
46
|
# At any time after the server has received the client Finished
|
47
47
|
# message, it MAY send a NewSessionTicket message.
|
48
48
|
break unless message.is_a?(Message::NewSessionTicket)
|
@@ -220,13 +220,15 @@ module TTTLS13
|
|
220
220
|
# @raise [TTTLS13::Error::ErrorAlerts
|
221
221
|
#
|
222
222
|
# @return [TTTLS13::Message::$Object]
|
223
|
+
# @return [String]
|
223
224
|
# rubocop: disable Metrics/CyclomaticComplexity
|
224
225
|
def recv_message(receivable_ccs:, cipher:)
|
225
226
|
return @message_queue.shift unless @message_queue.empty?
|
226
227
|
|
227
228
|
messages = nil
|
229
|
+
orig_msgs = []
|
228
230
|
loop do
|
229
|
-
record = recv_record(cipher)
|
231
|
+
record, orig_msgs = recv_record(cipher)
|
230
232
|
case record.type
|
231
233
|
when Message::ContentType::HANDSHAKE,
|
232
234
|
Message::ContentType::APPLICATION_DATA
|
@@ -243,20 +245,22 @@ module TTTLS13
|
|
243
245
|
end
|
244
246
|
end
|
245
247
|
|
246
|
-
@message_queue += messages[1..]
|
248
|
+
@message_queue += messages[1..].zip(orig_msgs[1..])
|
247
249
|
message = messages.first
|
250
|
+
orig_msg = orig_msgs.first
|
248
251
|
if message.is_a?(Message::Alert)
|
249
252
|
handle_received_alert(message)
|
250
253
|
return nil
|
251
254
|
end
|
252
255
|
|
253
|
-
message
|
256
|
+
[message, orig_msg]
|
254
257
|
end
|
255
258
|
# rubocop: enable Metrics/CyclomaticComplexity
|
256
259
|
|
257
260
|
# @param cipher [TTTLS13::Cryptograph::Aead, Passer]
|
258
261
|
#
|
259
262
|
# @return [TTTLS13::Message::Record]
|
263
|
+
# @return [Array of String]
|
260
264
|
def recv_record(cipher)
|
261
265
|
binary = @socket.read(5)
|
262
266
|
record_len = Convert.bin2i(binary.slice(3, 2))
|
@@ -264,9 +268,13 @@ module TTTLS13
|
|
264
268
|
|
265
269
|
begin
|
266
270
|
buffer = @binary_buffer
|
267
|
-
record = Message::Record.deserialize(
|
268
|
-
|
269
|
-
|
271
|
+
record, orig_msgs, surplus_binary = Message::Record.deserialize(
|
272
|
+
binary,
|
273
|
+
cipher,
|
274
|
+
buffer,
|
275
|
+
@recv_record_size
|
276
|
+
)
|
277
|
+
@binary_buffer = surplus_binary
|
270
278
|
rescue Error::ErrorAlerts => e
|
271
279
|
terminate(e.message.to_sym)
|
272
280
|
end
|
@@ -278,7 +286,7 @@ module TTTLS13
|
|
278
286
|
end
|
279
287
|
|
280
288
|
logger.debug("receive \n" + record.pretty_inspect)
|
281
|
-
record
|
289
|
+
[record, orig_msgs]
|
282
290
|
end
|
283
291
|
|
284
292
|
# @param ch1 [TTTLS13::Message::ClientHello]
|
@@ -292,11 +300,9 @@ module TTTLS13
|
|
292
300
|
# TODO: ext binder
|
293
301
|
hash_len = OpenSSL::Digest.new(digest).digest_length
|
294
302
|
tt = Transcript.new
|
295
|
-
tt.
|
296
|
-
|
297
|
-
|
298
|
-
CH => ch
|
299
|
-
)
|
303
|
+
tt[CH1] = [ch1, ch1.serialize] unless ch1.nil?
|
304
|
+
tt[HRR] = [hrr, hrr.serialize] unless hrr.nil?
|
305
|
+
tt[CH] = [ch, ch.serialize]
|
300
306
|
# transcript-hash (CH1 + HRR +) truncated-CH
|
301
307
|
hash = tt.truncate_hash(digest, CH, hash_len + 3)
|
302
308
|
OpenSSL::HMAC.digest(digest, binder_key, hash)
|
@@ -500,11 +506,10 @@ module TTTLS13
|
|
500
506
|
return false if san.nil?
|
501
507
|
|
502
508
|
ostr = OpenSSL::ASN1.decode(san.to_der).value.last
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
matching
|
509
|
+
OpenSSL::ASN1.decode(ostr.value)
|
510
|
+
.map(&:value)
|
511
|
+
.map { |s| s.gsub('.', '\.').gsub('*', '.*') }
|
512
|
+
.any? { |s| name.match(/#{s}/) }
|
508
513
|
end
|
509
514
|
|
510
515
|
# @param signature_algorithms [Array of SignatureAlgorithms]
|
@@ -18,6 +18,7 @@ module TTTLS13
|
|
18
18
|
ExtensionType::CLIENT_CERTIFICATE_TYPE,
|
19
19
|
ExtensionType::SERVER_CERTIFICATE_TYPE,
|
20
20
|
ExtensionType::PADDING,
|
21
|
+
ExtensionType::COMPRESS_CERTIFICATE,
|
21
22
|
ExtensionType::RECORD_SIZE_LIMIT,
|
22
23
|
ExtensionType::PWD_PROTECT,
|
23
24
|
ExtensionType::PWD_CLEAR,
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
class CompressedCertificate
|
8
|
+
attr_reader :msg_type
|
9
|
+
attr_reader :certificate_message
|
10
|
+
attr_reader :algorithm
|
11
|
+
|
12
|
+
# @param certificate_message [TTTLS13::Message::Certificate]
|
13
|
+
# @param algorithm [CertificateCompressionAlgorithm]
|
14
|
+
def initialize(certificate_message:, algorithm:)
|
15
|
+
@msg_type = HandshakeType::COMPRESSED_CERTIFICATE
|
16
|
+
@certificate_message = certificate_message
|
17
|
+
@algorithm = algorithm
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String]
|
21
|
+
def serialize
|
22
|
+
binary = ''
|
23
|
+
binary += @algorithm
|
24
|
+
ct_bin = @certificate_message.serialize[4..]
|
25
|
+
binary += ct_bin.length.to_uint24
|
26
|
+
case @algorithm
|
27
|
+
when Extension::CertificateCompressionAlgorithm::ZLIB
|
28
|
+
binary += Zlib::Deflate.deflate(ct_bin).prefix_uint24_length
|
29
|
+
else # TODO: orig_msgs, ZSTD
|
30
|
+
raise Error::ErrorAlerts, :internal_error
|
31
|
+
end
|
32
|
+
|
33
|
+
@msg_type + binary.prefix_uint24_length
|
34
|
+
end
|
35
|
+
|
36
|
+
alias fragment serialize
|
37
|
+
|
38
|
+
# @param binary [String]
|
39
|
+
#
|
40
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
41
|
+
#
|
42
|
+
# @return [TTTLS13::Message::CompressedCertificate]
|
43
|
+
# rubocop: disable Metrics/AbcSize
|
44
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
45
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
46
|
+
def self.deserialize(binary)
|
47
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
48
|
+
raise Error::ErrorAlerts, :decode_error if binary.length < 5
|
49
|
+
raise Error::ErrorAlerts, :internal_error \
|
50
|
+
unless binary[0] == HandshakeType::COMPRESSED_CERTIFICATE
|
51
|
+
|
52
|
+
msg_len = Convert.bin2i(binary.slice(1, 3))
|
53
|
+
algorithm = binary.slice(4, 2)
|
54
|
+
uncompressed_length = Convert.bin2i(binary.slice(6, 3))
|
55
|
+
ccm_len = Convert.bin2i(binary.slice(9, 3))
|
56
|
+
ct_bin = ''
|
57
|
+
case algorithm
|
58
|
+
when Extension::CertificateCompressionAlgorithm::ZLIB
|
59
|
+
ct_bin = Zlib::Inflate.inflate(binary.slice(12, ccm_len))
|
60
|
+
else # TODO: BROTLI, ZSTD
|
61
|
+
raise Error::ErrorAlerts, :bad_certificate
|
62
|
+
end
|
63
|
+
|
64
|
+
raise Error::ErrorAlerts, :bad_certificate \
|
65
|
+
unless ct_bin.length == uncompressed_length
|
66
|
+
raise Error::ErrorAlerts, :decode_error \
|
67
|
+
unless ccm_len + 12 == binary.length && msg_len + 4 == binary.length
|
68
|
+
|
69
|
+
certificate_message = Certificate.deserialize(
|
70
|
+
HandshakeType::CERTIFICATE + ct_bin.prefix_uint24_length
|
71
|
+
)
|
72
|
+
CompressedCertificate.new(
|
73
|
+
certificate_message: certificate_message,
|
74
|
+
algorithm: algorithm
|
75
|
+
)
|
76
|
+
end
|
77
|
+
# rubocop: enable Metrics/AbcSize
|
78
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
79
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -27,9 +27,12 @@ module TTTLS13
|
|
27
27
|
|
28
28
|
# @return [String]
|
29
29
|
def serialize
|
30
|
-
binary = @protocol_name_list
|
30
|
+
binary = @protocol_name_list
|
31
|
+
.map(&:prefix_uint8_length)
|
32
|
+
.join
|
33
|
+
.prefix_uint16_length
|
31
34
|
|
32
|
-
@extension_type + binary.prefix_uint16_length
|
35
|
+
@extension_type + binary.prefix_uint16_length
|
33
36
|
end
|
34
37
|
|
35
38
|
# @param binary [String]
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
module Extension
|
8
|
+
module CertificateCompressionAlgorithm
|
9
|
+
ZLIB = "\x00\x01"
|
10
|
+
# BROTLI = "\x00\x02" # UNSUPPORTED
|
11
|
+
# ZSTD = "\x00\x03" # UNSUPPORTED
|
12
|
+
end
|
13
|
+
|
14
|
+
# https://tools.ietf.org/html/rfc8879
|
15
|
+
class CompressCertificate
|
16
|
+
attr_reader :extension_type
|
17
|
+
attr_reader :algorithms
|
18
|
+
|
19
|
+
# @param algorithms [Array of CertificateCompressionAlgorithm]
|
20
|
+
#
|
21
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# CompressCertificate([CertificateCompressionAlgorithm::ZLIB])
|
25
|
+
def initialize(algorithms)
|
26
|
+
@extension_type = ExtensionType::COMPRESS_CERTIFICATE
|
27
|
+
@algorithms = algorithms || []
|
28
|
+
raise Error::ErrorAlerts, :internal_error \
|
29
|
+
if @algorithms.join.length < 2 ||
|
30
|
+
@algorithms.join.length > 2**8 - 2
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [String]
|
34
|
+
def serialize
|
35
|
+
binary = @algorithms.join.prefix_uint8_length
|
36
|
+
|
37
|
+
@extension_type + binary.prefix_uint16_length
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param binary [String]
|
41
|
+
#
|
42
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
43
|
+
#
|
44
|
+
# @return [TTTLS13::Message::Extension::CompressCertificate, nil]
|
45
|
+
def self.deserialize(binary)
|
46
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
47
|
+
|
48
|
+
return nil if binary.length < 3
|
49
|
+
|
50
|
+
al_len = Convert.bin2i(binary.slice(0, 1))
|
51
|
+
return nil if binary.length != al_len + 1
|
52
|
+
|
53
|
+
CompressCertificate.new(binary.slice(1, al_len + 1).scan(/.{2}/m))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -35,9 +35,9 @@ module TTTLS13
|
|
35
35
|
|
36
36
|
# @return [String]
|
37
37
|
def serialize
|
38
|
-
binary = @supported_signature_algorithms.join
|
38
|
+
binary = @supported_signature_algorithms.join.prefix_uint16_length
|
39
39
|
|
40
|
-
@extension_type + binary.prefix_uint16_length
|
40
|
+
@extension_type + binary.prefix_uint16_length
|
41
41
|
end
|
42
42
|
|
43
43
|
# @param binary [String]
|
@@ -21,9 +21,9 @@ module TTTLS13
|
|
21
21
|
|
22
22
|
# @return [String]
|
23
23
|
def serialize
|
24
|
-
binary = @named_group_list.join
|
24
|
+
binary = @named_group_list.join.prefix_uint16_length
|
25
25
|
|
26
|
-
@extension_type + binary.prefix_uint16_length
|
26
|
+
@extension_type + binary.prefix_uint16_length
|
27
27
|
end
|
28
28
|
|
29
29
|
# @param binary [String]
|
@@ -121,6 +121,7 @@ module TTTLS13
|
|
121
121
|
# @return [TTTLS13::Message::Extension::$Object, nil]
|
122
122
|
# rubocop: disable Metrics/CyclomaticComplexity
|
123
123
|
# rubocop: disable Metrics/MethodLength
|
124
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
124
125
|
def deserialize_extension(binary, extension_type, msg_type)
|
125
126
|
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
126
127
|
|
@@ -143,6 +144,8 @@ module TTTLS13
|
|
143
144
|
Extension::SignatureAlgorithms.deserialize(binary)
|
144
145
|
when ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
|
145
146
|
Extension::Alpn.deserialize(binary)
|
147
|
+
when ExtensionType::COMPRESS_CERTIFICATE
|
148
|
+
Extension::CompressCertificate.deserialize(binary)
|
146
149
|
when ExtensionType::RECORD_SIZE_LIMIT
|
147
150
|
Extension::RecordSizeLimit.deserialize(binary)
|
148
151
|
when ExtensionType::PRE_SHARED_KEY
|
@@ -165,6 +168,7 @@ module TTTLS13
|
|
165
168
|
end
|
166
169
|
# rubocop: enable Metrics/CyclomaticComplexity
|
167
170
|
# rubocop: enable Metrics/MethodLength
|
171
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
168
172
|
end
|
169
173
|
end
|
170
174
|
end
|