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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +32 -0
  3. data/.rubocop.yml +2 -2
  4. data/Gemfile +3 -4
  5. data/README.md +4 -1
  6. data/example/helper.rb +3 -3
  7. data/example/https_client.rb +1 -1
  8. data/example/https_client_using_0rtt.rb +2 -2
  9. data/example/https_client_using_hrr.rb +1 -1
  10. data/example/https_client_using_hrr_and_ticket.rb +2 -2
  11. data/example/https_client_using_status_request.rb +2 -2
  12. data/example/https_client_using_ticket.rb +2 -2
  13. data/example/https_server.rb +2 -2
  14. data/interop/client_spec.rb +6 -6
  15. data/interop/server_spec.rb +6 -6
  16. data/lib/tttls1.3/client.rb +106 -65
  17. data/lib/tttls1.3/connection.rb +43 -30
  18. data/lib/tttls1.3/cryptograph/aead.rb +20 -7
  19. data/lib/tttls1.3/cryptograph.rb +1 -1
  20. data/lib/tttls1.3/message/alert.rb +2 -2
  21. data/lib/tttls1.3/message/client_hello.rb +1 -0
  22. data/lib/tttls1.3/message/compressed_certificate.rb +82 -0
  23. data/lib/tttls1.3/message/extension/alpn.rb +5 -2
  24. data/lib/tttls1.3/message/extension/compress_certificate.rb +58 -0
  25. data/lib/tttls1.3/message/extension/signature_algorithms.rb +15 -5
  26. data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +5 -4
  27. data/lib/tttls1.3/message/extension/supported_groups.rb +2 -2
  28. data/lib/tttls1.3/message/extensions.rb +31 -18
  29. data/lib/tttls1.3/message/record.rb +28 -16
  30. data/lib/tttls1.3/message.rb +23 -21
  31. data/lib/tttls1.3/server.rb +88 -37
  32. data/lib/tttls1.3/transcript.rb +3 -7
  33. data/lib/tttls1.3/version.rb +1 -1
  34. data/spec/client_spec.rb +28 -19
  35. data/spec/compress_certificate_spec.rb +54 -0
  36. data/spec/connection_spec.rb +22 -15
  37. data/spec/extensions_spec.rb +16 -0
  38. data/spec/fixtures/rsa_rsa.crt +15 -15
  39. data/spec/fixtures/rsa_rsa.key +25 -25
  40. data/spec/key_schedule_spec.rb +48 -25
  41. data/spec/record_spec.rb +2 -2
  42. data/spec/server_hello_spec.rb +1 -1
  43. data/spec/server_spec.rb +23 -11
  44. data/spec/signature_algorithms_cert_spec.rb +4 -0
  45. data/spec/signature_algorithms_spec.rb +4 -0
  46. data/spec/spec_helper.rb +4 -0
  47. data/spec/transcript_spec.rb +34 -20
  48. data/tttls1.3.gemspec +0 -1
  49. metadata +11 -7
  50. data/.github/workflows/main.yml +0 -25
@@ -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
- transcript[CH] = send_client_hello(extensions, binder_key)
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
- ch1 = transcript[CH1] = transcript.delete(CH)
216
- hrr = transcript[HRR] = transcript.delete(SH)
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
- transcript[CH] = send_new_client_hello(ch1, hrr, extensions,
239
- binder_key)
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(receivable_ccs: true, cipher: hs_rcipher)
303
- if message.msg_type == Message::HandshakeType::CERTIFICATE
304
- ct = transcript[CT] = message
305
- alert = check_invalid_certificate(ct, transcript[CH])
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
- elsif message.msg_type == Message::HandshakeType::CERTIFICATE_REQUEST
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
- alert = check_invalid_certificate(ct, transcript[CH])
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?(transcript[CT], cv, hash)
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
- verified = verified_finished?(
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
- transcript[CF] = send_finished(signature, hs_wcipher)
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,
@@ -403,23 +430,16 @@ module TTTLS13
403
430
  # @return [Boolean]
404
431
  #
405
432
  # @example
406
- # meth = Client.method(:softfail_check_certificate_status)
433
+ # m = Client.method(:softfail_check_certificate_status)
407
434
  # Client.new(
408
435
  # socket,
409
436
  # hostname,
410
437
  # check_certificate_status: true,
411
- # process_certificate_status: meth
438
+ # process_certificate_status: m
412
439
  # )
413
- # rubocop: disable Metrics/AbcSize
414
- # rubocop: disable Metrics/CyclomaticComplexity
415
- # rubocop: disable Metrics/PerceivedComplexity
416
440
  def self.softfail_check_certificate_status(res, cert, chain)
417
441
  ocsp_response = res
418
- store = OpenSSL::X509::Store.new
419
- store.set_default_paths
420
- context = OpenSSL::X509::StoreContext.new(store, cert, chain)
421
- context.verify
422
- cid = OpenSSL::OCSP::CertificateId.new(cert, context.chain[1])
442
+ cid = OpenSSL::OCSP::CertificateId.new(cert, chain.first)
423
443
 
424
444
  # When NOT received OCSPResponse in TLS handshake, this method will
425
445
  # send OCSPRequest. If ocsp_uri is NOT presented in Certificate, return
@@ -430,23 +450,25 @@ module TTTLS13
430
450
  return true if uri.nil?
431
451
 
432
452
  begin
433
- Timeout.timeout(2) { ocsp_response = send_ocsp_request(cid, uri) }
453
+ # send OCSP::Request
454
+ ocsp_request = gen_ocsp_request(cid)
455
+ Timeout.timeout(2) do
456
+ ocsp_response = send_ocsp_request(ocsp_request, uri)
457
+ end
458
+
459
+ # check nonce of OCSP::Response
460
+ check_nonce = ocsp_request.check_nonce(ocsp_response.basic)
461
+ return true unless [-1, 1].include?(check_nonce)
434
462
  rescue StandardError
435
463
  return true
436
464
  end
437
465
  end
438
- return false \
466
+ return true \
439
467
  if ocsp_response.status != OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL
440
468
 
441
469
  status = ocsp_response.basic.status.find { |s| s.first.cmp(cid) }
442
- return false if status[1] != OpenSSL::OCSP::V_CERTSTATUS_GOOD
443
- return false if !status[3].nil? && status[3] < Time.now
444
-
445
- ocsp_response.basic.verify(chain, store)
470
+ status[1] != OpenSSL::OCSP::V_CERTSTATUS_REVOKED
446
471
  end
447
- # rubocop: enable Metrics/AbcSize
448
- # rubocop: enable Metrics/CyclomaticComplexity
449
- # rubocop: enable Metrics/PerceivedComplexity
450
472
 
451
473
  private
452
474
 
@@ -479,6 +501,9 @@ module TTTLS13
479
501
  rsl = @settings[:record_size_limit]
480
502
  return false if !rsl.nil? && (rsl < 64 || rsl > 2**14 + 1)
481
503
 
504
+ return false if @settings[:check_certificate_status] &&
505
+ @settings[:process_certificate_status].nil?
506
+
482
507
  true
483
508
  end
484
509
  # rubocop: enable Metrics/AbcSize
@@ -530,7 +555,7 @@ module TTTLS13
530
555
  # rubocop: disable Metrics/MethodLength
531
556
  # rubocop: disable Metrics/PerceivedComplexity
532
557
  def gen_ch_extensions
533
- exs = []
558
+ exs = Message::Extensions.new
534
559
  # server_name
535
560
  exs << Message::Extension::ServerName.new(@hostname)
536
561
 
@@ -580,7 +605,15 @@ module TTTLS13
580
605
  exs << Message::Extension::OCSPStatusRequest.new \
581
606
  if @settings[:check_certificate_status]
582
607
 
583
- [Message::Extensions.new(exs), priv_keys]
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
+
616
+ [exs, priv_keys]
584
617
  end
585
618
  # rubocop: enable Metrics/AbcSize
586
619
  # rubocop: enable Metrics/CyclomaticComplexity
@@ -673,7 +706,7 @@ module TTTLS13
673
706
  # @return [TTTLS13::Message::Extensions]
674
707
  # @return [Hash of NamedGroup => OpenSSL::PKey::EC.$Object]
675
708
  def gen_newch_extensions(ch1, hrr)
676
- exs = []
709
+ exs = Message::Extensions.new
677
710
  # key_share
678
711
  if hrr.extensions.include?(Message::ExtensionType::KEY_SHARE)
679
712
  group = hrr.extensions[Message::ExtensionType::KEY_SHARE]
@@ -695,7 +728,7 @@ module TTTLS13
695
728
  if hrr.extensions.include?(Message::ExtensionType::COOKIE)
696
729
 
697
730
  # early_data
698
- new_exs = ch1.extensions.merge(Message::Extensions.new(exs))
731
+ new_exs = ch1.extensions.merge(exs)
699
732
  new_exs.delete(Message::ExtensionType::EARLY_DATA)
700
733
 
701
734
  [new_exs, priv_keys]
@@ -737,11 +770,15 @@ module TTTLS13
737
770
  # @raise [TTTLS13::Error::ErrorAlerts]
738
771
  #
739
772
  # @return [TTTLS13::Message::ServerHello]
773
+ # @return [String]
740
774
  def recv_server_hello
741
- sh = recv_message(receivable_ccs: true, cipher: Cryptograph::Passer.new)
775
+ sh, orig_msg = recv_message(
776
+ receivable_ccs: true,
777
+ cipher: Cryptograph::Passer.new
778
+ )
742
779
  terminate(:unexpected_message) unless sh.is_a?(Message::ServerHello)
743
780
 
744
- sh
781
+ [sh, orig_msg]
745
782
  end
746
783
 
747
784
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -749,12 +786,13 @@ module TTTLS13
749
786
  # @raise [TTTLS13::Error::ErrorAlerts]
750
787
  #
751
788
  # @return [TTTLS13::Message::EncryptedExtensions]
789
+ # @return [String]
752
790
  def recv_encrypted_extensions(cipher)
753
- ee = recv_message(receivable_ccs: true, cipher: cipher)
791
+ ee, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
754
792
  terminate(:unexpected_message) \
755
793
  unless ee.is_a?(Message::EncryptedExtensions)
756
794
 
757
- ee
795
+ [ee, orig_msg]
758
796
  end
759
797
 
760
798
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -762,11 +800,12 @@ module TTTLS13
762
800
  # @raise [TTTLS13::Error::ErrorAlerts]
763
801
  #
764
802
  # @return [TTTLS13::Message::Certificate]
803
+ # @return [String]
765
804
  def recv_certificate(cipher)
766
- ct = recv_message(receivable_ccs: true, cipher: cipher)
805
+ ct, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
767
806
  terminate(:unexpected_message) unless ct.is_a?(Message::Certificate)
768
807
 
769
- ct
808
+ [ct, orig_msg]
770
809
  end
771
810
 
772
811
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -774,11 +813,12 @@ module TTTLS13
774
813
  # @raise [TTTLS13::Error::ErrorAlerts]
775
814
  #
776
815
  # @return [TTTLS13::Message::CertificateVerify]
816
+ # @return [String]
777
817
  def recv_certificate_verify(cipher)
778
- cv = recv_message(receivable_ccs: true, cipher: cipher)
818
+ cv, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
779
819
  terminate(:unexpected_message) unless cv.is_a?(Message::CertificateVerify)
780
820
 
781
- cv
821
+ [cv, orig_msg]
782
822
  end
783
823
 
784
824
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -786,11 +826,12 @@ module TTTLS13
786
826
  # @raise [TTTLS13::Error::ErrorAlerts]
787
827
  #
788
828
  # @return [TTTLS13::Message::Finished]
829
+ # @return [String]
789
830
  def recv_finished(cipher)
790
- sf = recv_message(receivable_ccs: true, cipher: cipher)
831
+ sf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
791
832
  terminate(:unexpected_message) unless sf.is_a?(Message::Finished)
792
833
 
793
- sf
834
+ [sf, orig_msg]
794
835
  end
795
836
 
796
837
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -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(binary, cipher, buffer,
268
- @recv_record_size)
269
- @binary_buffer = record.surplus_binary
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.merge!(
296
- CH1 => ch1,
297
- HRR => hrr,
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
- matching = OpenSSL::ASN1.decode(ostr.value).map(&:value)
504
- .map { |s| s.gsub('.', '\.').gsub('*', '.*') }
505
- .any? { |s| name.match(/#{s}/) }
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]
@@ -514,22 +519,22 @@ module TTTLS13
514
519
  def do_select_signature_algorithms(signature_algorithms, crt)
515
520
  spki = OpenSSL::Netscape::SPKI.new
516
521
  spki.public_key = crt.public_key
517
- oid_str = spki.to_text.split("\n")
518
- .find { |l| l.include?('Public Key Algorithm:') }
522
+ pka = OpenSSL::ASN1.decode(spki.to_der)
523
+ .value.first.value.first.value.first.value.first.value
519
524
  signature_algorithms.select do |sa|
520
525
  case sa
521
526
  when SignatureScheme::ECDSA_SECP256R1_SHA256,
522
527
  SignatureScheme::ECDSA_SECP384R1_SHA384,
523
528
  SignatureScheme::ECDSA_SECP521R1_SHA512
524
- oid_str.include?('id-ecPublicKey')
529
+ pka == 'id-ecPublicKey'
525
530
  when SignatureScheme::RSA_PSS_PSS_SHA256,
526
531
  SignatureScheme::RSA_PSS_PSS_SHA384,
527
532
  SignatureScheme::RSA_PSS_PSS_SHA512
528
- oid_str.include?('rsassaPss')
533
+ pka == 'rsassaPss'
529
534
  when SignatureScheme::RSA_PSS_RSAE_SHA256,
530
535
  SignatureScheme::RSA_PSS_RSAE_SHA384,
531
536
  SignatureScheme::RSA_PSS_RSAE_SHA512
532
- oid_str.include?('rsaEncryption')
537
+ pka == 'rsaEncryption'
533
538
  else
534
539
  # RSASSA-PKCS1-v1_5 algorithms refer solely to signatures which appear
535
540
  # in certificates and are not defined for use in signed TLS handshake
@@ -541,19 +546,27 @@ module TTTLS13
541
546
 
542
547
  class << self
543
548
  # @param cid [OpenSSL::OCSP::CertificateId]
544
- # @param uri [String]
545
549
  #
546
- # @return [OpenSSL::OCSP::Response]
547
- def send_ocsp_request(cid, uri)
548
- # generate OCSPRequest
550
+ # @return [OpenSSL::OCSP::Request]
551
+ def gen_ocsp_request(cid)
549
552
  ocsp_request = OpenSSL::OCSP::Request.new
550
553
  ocsp_request.add_certid(cid)
551
554
  ocsp_request.add_nonce
555
+ ocsp_request
556
+ end
557
+
558
+ # @param ocsp_request [OpenSSL::OCSP::Request]
559
+ # @param uri_string [String]
560
+ #
561
+ # @raise [Net::OpenTimeout, OpenSSL::OCSP::OCSPError, URI::$Exception]
562
+ #
563
+ # @return [OpenSSL::OCSP::Response, n
564
+ def send_ocsp_request(ocsp_request, uri_string)
552
565
  # send HTTP POST
553
- uri = URI.parse(uri)
566
+ uri = URI.parse(uri_string)
554
567
  path = uri.path
555
568
  path = '/' if path.nil? || path.empty?
556
- http_response = Net::HTTP.start uri.host, uri.port do |http|
569
+ http_response = Net::HTTP.start(uri.host, uri.port) do |http|
557
570
  http.post(
558
571
  path,
559
572
  ocsp_request.to_der,
@@ -44,8 +44,7 @@ module TTTLS13
44
44
  #
45
45
  # @return [String]
46
46
  def encrypt(content, type)
47
- reset_cipher
48
- cipher = @cipher.encrypt
47
+ cipher = reset_cipher
49
48
  plaintext = content + type + "\x00" * @length_of_padding
50
49
  cipher.auth_data = additional_data(plaintext.length)
51
50
  encrypted_data = cipher.update(plaintext) + cipher.final
@@ -66,8 +65,7 @@ module TTTLS13
66
65
  # @return [String]
67
66
  # @return [TTTLS13::Message::ContentType]
68
67
  def decrypt(encrypted_record, auth_data)
69
- reset_cipher
70
- decipher = @cipher.decrypt
68
+ decipher = reset_decipher
71
69
  auth_tag = encrypted_record[-@auth_tag_len..-1]
72
70
  decipher.auth_tag = auth_tag
73
71
  decipher.auth_data = auth_data # record header of TLSCiphertext
@@ -105,11 +103,26 @@ module TTTLS13
105
103
  + ciphertext_len.to_uint16
106
104
  end
107
105
 
106
+ # @return [OpenSSL::Cipher]
108
107
  def reset_cipher
109
- @cipher.reset
110
- @cipher.key = @write_key
108
+ cipher = @cipher.encrypt
109
+ cipher.reset
110
+ cipher.key = @write_key
111
111
  iv_len = CipherSuite.iv_len(@cipher_suite)
112
- @cipher.iv = @sequence_number.xor(@write_iv, iv_len)
112
+ cipher.iv = @sequence_number.xor(@write_iv, iv_len)
113
+
114
+ cipher
115
+ end
116
+
117
+ # @return [OpenSSL::Cipher]
118
+ def reset_decipher
119
+ decipher = @cipher.decrypt
120
+ decipher.reset
121
+ decipher.key = @write_key
122
+ iv_len = CipherSuite.iv_len(@cipher_suite)
123
+ decipher.iv = @sequence_number.xor(@write_iv, iv_len)
124
+
125
+ decipher
113
126
  end
114
127
 
115
128
  # @param clear [String]
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir[File.dirname(__FILE__) + '/cryptograph/*.rb'].each { |f| require f }
3
+ Dir[File.dirname(__FILE__) + '/cryptograph/*.rb'].sort.each { |f| require f }
@@ -8,7 +8,7 @@ module TTTLS13
8
8
  FATAL = "\x02"
9
9
  end
10
10
 
11
- # rubocop: disable Layout/AlignHash
11
+ # rubocop: disable Layout/HashAlignment
12
12
  ALERT_DESCRIPTION = {
13
13
  close_notify: "\x00",
14
14
  unexpected_message: "\x0a",
@@ -38,7 +38,7 @@ module TTTLS13
38
38
  certificate_required: "\x74",
39
39
  no_application_protocol: "\x78"
40
40
  }.freeze
41
- # rubocop: enable Layout/AlignHash
41
+ # rubocop: enable Layout/HashAlignment
42
42
 
43
43
  class Alert
44
44
  attr_reader :level
@@ -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,