tttls1.3 0.2.12 → 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.
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,