tttls1.3 0.2.15 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba824030b1a295566777d4d12c35e259d379bc9a830b0cb95792356cc547a436
4
- data.tar.gz: c3f2e8fd07567133cce7e8f24fcaf02499b8cceff6088ca403ca2e9be9e5ab5f
3
+ metadata.gz: 1a07aded25aecad8bd61ff9fd49a70df15c8abf356d4747891486dd81386b68d
4
+ data.tar.gz: 4637b3288dab22caae951cc43c283057fd3ed215fc5fa86e318becc3369ac7b2
5
5
  SHA512:
6
- metadata.gz: 00e939bf927db1923274985cdad6526d16b6d99216f62ff3978b3bae9cdcedf675482b96f49a224f9f982f1d8c6f7ca0b49f282086422e73e93b4b74d13f0722
7
- data.tar.gz: 1e523ad0d29d6f29dbd94388f9f895abf69324ceb4336406b13e21793395abdf795a0f043ee89899e888b851d85f2190064e93b70efec092964e34c94b15ac76
6
+ metadata.gz: 621a8f82c99e21e964cfb6defe14e2f8864f1c42cc94c9af725de2ff73929226d99a694c893ada3fc44c5224be70ec87bfcb291eceab271b33e4759c6c900cd8
7
+ data.tar.gz: 9088db06f998013577eb647d064e97035047a2cef7799010bc91f18384787bdf158357fd33c296b92ec1bc07a2ad1b307c98d0217735dfef5c6acf565f3c9433
@@ -3,7 +3,7 @@ name: CI
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - master
6
+ - main
7
7
  pull_request:
8
8
  branches:
9
9
  - '*'
@@ -13,12 +13,14 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby-version: ['2.6.x', '2.7.x']
16
+ ruby-version: ['2.7.x', '3.0.x', '3.1.x']
17
17
  steps:
18
+ - uses: actions/checkout@v3
18
19
  - uses: docker://thekuwayama/openssl:latest
19
20
  - name: Set up Ruby
20
- uses: actions/setup-ruby@v1
21
- - uses: actions/checkout@v1
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
22
24
  - name: Install dependencies
23
25
  run: |
24
26
  gem --version
data/.gitignore CHANGED
@@ -14,3 +14,4 @@ Gemfile.lock
14
14
  /coverage/
15
15
  /spec/reports/
16
16
  /tmp/
17
+ .DS_Store
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 2.7
3
3
 
4
4
  Style/ConditionalAssignment:
5
5
  Enabled: false
@@ -28,3 +28,7 @@ Metrics/BlockLength:
28
28
  Layout/LineLength:
29
29
  Exclude:
30
30
  - 'tttls1.3.gemspec'
31
+
32
+ # https://github.com/rubocop/rubocop/issues/10258
33
+ Layout/BlockAlignment:
34
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.2
data/Gemfile CHANGED
@@ -6,10 +6,12 @@ gem 'logger'
6
6
  gem 'openssl'
7
7
  gem 'rake'
8
8
 
9
- group :test do
9
+ group :development do
10
10
  gem 'byebug'
11
+ gem 'http_parser.rb'
11
12
  gem 'rspec', '3.9.0'
12
13
  gem 'rubocop', '0.78.0'
14
+ gem 'webrick'
13
15
  end
14
16
 
15
17
  gemspec
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/tttls1.3.svg)](https://badge.fury.io/rb/tttls1.3)
4
4
  [![Actions Status](https://github.com/thekuwayama/tttls1.3/workflows/CI/badge.svg)](https://github.com/thekuwayama/tttls1.3/actions?workflow=CI)
5
- [![Maintainability](https://api.codeclimate.com/v1/badges/47f3c267d9cfd2c8e388/maintainability)](https://codeclimate.com/github/thekuwayama/tttls1.3/maintainability)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/b5ae1b3a43828142d2fa/maintainability)](https://codeclimate.com/github/thekuwayama/tttls1.3/maintainability)
6
6
 
7
7
  tttls1.3 is Ruby implementation of [TLS 1.3](https://tools.ietf.org/html/rfc8446) protocol.
8
8
 
@@ -74,7 +74,7 @@ server.write(YOUR_MESSAGE)
74
74
  server.close
75
75
  ```
76
76
 
77
- [Here](https://github.com/thekuwayama/tttls1.3/tree/master/example) are some examples of HTTPS.
77
+ [Here](https://github.com/thekuwayama/tttls1.3/tree/main/example) are some examples of HTTPS.
78
78
 
79
79
 
80
80
  ## Settings
@@ -102,7 +102,9 @@ 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. |
107
+ | `:sslkeylogfile` | String | nil | If needed to log SSLKEYLOGFILE, set the file path. |
106
108
  | `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
107
109
 
108
110
 
@@ -120,7 +122,9 @@ tttls1.3 server is configurable using keyword arguments.
120
122
  | `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of supported named groups. |
121
123
  | `:alpn` | Array of String | nil | List of supported application protocols. If not needed to check this extension, set nil. |
122
124
  | `:process_ocsp_response` | Proc | nil | Proc that gets OpenSSL::OCSP::Response. If not needed to staple OCSP::Response, set nil. |
125
+ | `:compress_certificate_algorithms` | Array of TTTLS13::Message::Extension::CertificateCompressionAlgorithm constant | `ZLIB` | The compression algorithms are supported for compressing the Certificate message. |
123
126
  | `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
127
+ | `:sslkeylogfile` | String | nil | If needed to log SSLKEYLOGFILE, set the file path. |
124
128
  | `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
125
129
 
126
130
 
@@ -10,7 +10,8 @@ req = simple_http_request(hostname)
10
10
  socket = TCPSocket.new(hostname, port)
11
11
  settings = {
12
12
  ca_file: File.exist?(ca_file) ? ca_file : nil,
13
- alpn: ['http/1.1']
13
+ alpn: ['http/1.1'],
14
+ sslkeylogfile: '/tmp/sslkeylogfile.log'
14
15
  }
15
16
  client = TTTLS13::Client.new(socket, hostname, **settings)
16
17
  client.connect
@@ -12,7 +12,8 @@ settings = {
12
12
  crt_file: __dir__ + '/../tmp/server.crt',
13
13
  chain_files: [__dir__ + '/../tmp/intermediate.crt'],
14
14
  key_file: __dir__ + '/../tmp/server.key',
15
- alpn: ['http/1.1']
15
+ alpn: ['http/1.1'],
16
+ sslkeylogfile: '/tmp/sslkeylogfile.log'
16
17
  }
17
18
 
18
19
  q = Queue.new
@@ -49,7 +50,7 @@ Etc.nprocessors.times do
49
50
  rescue Timeout::Error
50
51
  logger.warn 'Timeout'
51
52
  ensure
52
- s.close
53
+ s&.close
53
54
  end
54
55
  end
55
56
  end
@@ -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,7 +66,9 @@ 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,
71
+ sslkeylogfile: nil,
65
72
  loglevel: Logger::WARN
66
73
  }.freeze
67
74
  private_constant :DEFAULT_CLIENT_SETTINGS
@@ -145,6 +152,15 @@ module TTTLS13
145
152
  hs_wcipher = nil # TTTLS13::Cryptograph::$Object
146
153
  hs_rcipher = nil # TTTLS13::Cryptograph::$Object
147
154
  e_wcipher = nil # TTTLS13::Cryptograph::$Object
155
+ sslkeylogfile = nil # TTTLS13::SslKeyLogFile::Writer
156
+ unless @settings[:sslkeylogfile].nil?
157
+ begin
158
+ sslkeylogfile = SslKeyLogFile::Writer.new(@settings[:sslkeylogfile])
159
+ rescue SystemCallError => e
160
+ msg = "\"#{@settings[:sslkeylogfile]}\" file can NOT open: #{e}"
161
+ logger.warn(msg)
162
+ end
163
+ end
148
164
 
149
165
  @state = ClientState::START
150
166
  loop do
@@ -154,8 +170,8 @@ module TTTLS13
154
170
 
155
171
  extensions, priv_keys = gen_ch_extensions
156
172
  binder_key = (use_psk? ? key_schedule.binder_key_res : nil)
157
- transcript[CH] = send_client_hello(extensions, binder_key)
158
-
173
+ ch = send_client_hello(extensions, binder_key)
174
+ transcript[CH] = [ch, ch.serialize]
159
175
  send_ccs if @settings[:compatibility_mode]
160
176
  if use_early_data?
161
177
  e_wcipher = gen_cipher(
@@ -163,6 +179,10 @@ module TTTLS13
163
179
  key_schedule.early_data_write_key,
164
180
  key_schedule.early_data_write_iv
165
181
  )
182
+ sslkeylogfile&.write_client_early_traffic_secret(
183
+ transcript[CH].first.random,
184
+ key_schedule.client_early_traffic_secret
185
+ )
166
186
  send_early_data(e_wcipher)
167
187
  end
168
188
 
@@ -170,7 +190,7 @@ module TTTLS13
170
190
  when ClientState::WAIT_SH
171
191
  logger.debug('ClientState::WAIT_SH')
172
192
 
173
- sh = transcript[SH] = recv_server_hello
193
+ sh, = transcript[SH] = recv_server_hello
174
194
 
175
195
  # downgrade protection
176
196
  if !sh.negotiated_tls_1_3? && sh.downgraded?
@@ -187,7 +207,7 @@ module TTTLS13
187
207
  unless sh.legacy_compression_method == "\x00"
188
208
 
189
209
  # validate sh using ch
190
- ch = transcript[CH]
210
+ ch, = transcript[CH]
191
211
  terminate(:illegal_parameter) \
192
212
  unless sh.legacy_version == ch.legacy_version
193
213
  terminate(:illegal_parameter) \
@@ -199,7 +219,7 @@ module TTTLS13
199
219
 
200
220
  # validate sh using hrr
201
221
  if transcript.include?(HRR)
202
- hrr = transcript[HRR]
222
+ hrr, = transcript[HRR]
203
223
  terminate(:illegal_parameter) \
204
224
  unless sh.cipher_suite == hrr.cipher_suite
205
225
 
@@ -212,8 +232,9 @@ module TTTLS13
212
232
  # handling HRR
213
233
  if sh.hrr?
214
234
  terminate(:unexpected_message) if transcript.include?(HRR)
215
- ch1 = transcript[CH1] = transcript.delete(CH)
216
- hrr = transcript[HRR] = transcript.delete(SH)
235
+
236
+ ch1, = transcript[CH1] = transcript.delete(CH)
237
+ hrr, = transcript[HRR] = transcript.delete(SH)
217
238
 
218
239
  # validate cookie
219
240
  diff_sets = sh.extensions.keys - ch1.extensions.keys
@@ -235,8 +256,9 @@ module TTTLS13
235
256
  extensions, pk = gen_newch_extensions(ch1, hrr)
236
257
  priv_keys = pk.merge(priv_keys)
237
258
  binder_key = (use_psk? ? key_schedule.binder_key_res : nil)
238
- transcript[CH] = send_new_client_hello(ch1, hrr, extensions,
239
- binder_key)
259
+ ch = send_new_client_hello(ch1, hrr, extensions, binder_key)
260
+ transcript[CH] = [ch, ch.serialize]
261
+
240
262
  @state = ClientState::WAIT_SH
241
263
  next
242
264
  end
@@ -268,46 +290,63 @@ module TTTLS13
268
290
  key_schedule.client_handshake_write_key,
269
291
  key_schedule.client_handshake_write_iv
270
292
  )
293
+ sslkeylogfile&.write_client_handshake_traffic_secret(
294
+ transcript[CH].first.random,
295
+ key_schedule.client_handshake_traffic_secret
296
+ )
271
297
  hs_rcipher = gen_cipher(
272
298
  @cipher_suite,
273
299
  key_schedule.server_handshake_write_key,
274
300
  key_schedule.server_handshake_write_iv
275
301
  )
302
+ sslkeylogfile&.write_server_handshake_traffic_secret(
303
+ transcript[CH].first.random,
304
+ key_schedule.server_handshake_traffic_secret
305
+ )
276
306
  @state = ClientState::WAIT_EE
277
307
  when ClientState::WAIT_EE
278
308
  logger.debug('ClientState::WAIT_EE')
279
309
 
280
- ee = transcript[EE] = recv_encrypted_extensions(hs_rcipher)
310
+ ee, = transcript[EE] = recv_encrypted_extensions(hs_rcipher)
281
311
  terminate(:illegal_parameter) unless ee.appearable_extensions?
282
312
 
283
- ch = transcript[CH]
313
+ ch, = transcript[CH]
284
314
  terminate(:unsupported_extension) \
285
315
  unless (ee.extensions.keys - ch.extensions.keys).empty?
286
316
 
287
317
  rsl = ee.extensions[Message::ExtensionType::RECORD_SIZE_LIMIT]
288
318
  @recv_record_size = rsl.record_size_limit unless rsl.nil?
289
-
290
319
  @succeed_early_data = true \
291
320
  if ee.extensions.include?(Message::ExtensionType::EARLY_DATA)
292
-
293
321
  @alpn = ee.extensions[
294
322
  Message::ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
295
323
  ]&.protocol_name_list&.first
296
-
297
324
  @state = ClientState::WAIT_CERT_CR
298
325
  @state = ClientState::WAIT_FINISHED unless psk.nil?
299
326
  when ClientState::WAIT_CERT_CR
300
327
  logger.debug('ClientState::WAIT_CERT_CR')
301
328
 
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])
329
+ message, orig_msg = recv_message(
330
+ receivable_ccs: true,
331
+ cipher: hs_rcipher
332
+ )
333
+ case message.msg_type
334
+ when Message::HandshakeType::CERTIFICATE,
335
+ Message::HandshakeType::COMPRESSED_CERTIFICATE
336
+ ct, = transcript[CT] = [message, orig_msg]
337
+ terminate(:bad_certificate) \
338
+ if ct.is_a?(Message::CompressedCertificate) &&
339
+ !@settings[:compress_certificate_algorithms]
340
+ .include?(ct.algorithm)
341
+
342
+ ct = ct.certificate_message \
343
+ if ct.is_a?(Message::CompressedCertificate)
344
+ alert = check_invalid_certificate(ct, transcript[CH].first)
306
345
  terminate(alert) unless alert.nil?
307
346
 
308
347
  @state = ClientState::WAIT_CV
309
- elsif message.msg_type == Message::HandshakeType::CERTIFICATE_REQUEST
310
- transcript[CR] = message
348
+ when Message::HandshakeType::CERTIFICATE_REQUEST
349
+ transcript[CR] = [message, orig_msg]
311
350
  # TODO: client authentication
312
351
  @state = ClientState::WAIT_CERT
313
352
  else
@@ -316,56 +355,74 @@ module TTTLS13
316
355
  when ClientState::WAIT_CERT
317
356
  logger.debug('ClientState::WAIT_CERT')
318
357
 
319
- ct = transcript[CT] = recv_certificate(hs_rcipher)
320
- alert = check_invalid_certificate(ct, transcript[CH])
358
+ ct, = transcript[CT] = recv_certificate(hs_rcipher)
359
+ if ct.is_a?(Message::CompressedCertificate) &&
360
+ !@settings[:compress_certificate_algorithms].include?(ct.algorithm)
361
+ terminate(:bad_certificate)
362
+ elsif ct.is_a?(Message::CompressedCertificate)
363
+ ct = ct.certificate_message
364
+ end
365
+
366
+ alert = check_invalid_certificate(ct, transcript[CH].first)
321
367
  terminate(alert) unless alert.nil?
322
368
 
323
369
  @state = ClientState::WAIT_CV
324
370
  when ClientState::WAIT_CV
325
371
  logger.debug('ClientState::WAIT_CV')
326
372
 
327
- cv = transcript[CV] = recv_certificate_verify(hs_rcipher)
373
+ cv, = transcript[CV] = recv_certificate_verify(hs_rcipher)
328
374
  digest = CipherSuite.digest(@cipher_suite)
329
375
  hash = transcript.hash(digest, CT)
376
+ ct, = transcript[CT]
377
+ ct = ct.certificate_message \
378
+ if ct.is_a?(Message::CompressedCertificate)
330
379
  terminate(:decrypt_error) \
331
- unless verified_certificate_verify?(transcript[CT], cv, hash)
380
+ unless verified_certificate_verify?(ct, cv, hash)
332
381
 
333
382
  @signature_scheme = cv.signature_scheme
334
-
335
383
  @state = ClientState::WAIT_FINISHED
336
384
  when ClientState::WAIT_FINISHED
337
385
  logger.debug('ClientState::WAIT_FINISHED')
338
386
 
339
- sf = transcript[SF] = recv_finished(hs_rcipher)
387
+ sf, = transcript[SF] = recv_finished(hs_rcipher)
340
388
  digest = CipherSuite.digest(@cipher_suite)
341
- verified = verified_finished?(
389
+ terminate(:decrypt_error) unless verified_finished?(
342
390
  finished: sf,
343
391
  digest: digest,
344
392
  finished_key: key_schedule.server_finished_key,
345
393
  hash: transcript.hash(digest, CV)
346
394
  )
347
- terminate(:decrypt_error) unless verified
348
-
349
- transcript[EOED] = send_eoed(e_wcipher) \
350
- if use_early_data? && succeed_early_data?
351
395
 
396
+ if use_early_data? && succeed_early_data?
397
+ eoed = send_eoed(e_wcipher)
398
+ transcript[EOED] = [eoed, eoed.serialize]
399
+ end
352
400
  # TODO: Send Certificate [+ CertificateVerify]
353
401
  signature = sign_finished(
354
402
  digest: digest,
355
403
  finished_key: key_schedule.client_finished_key,
356
404
  hash: transcript.hash(digest, EOED)
357
405
  )
358
- transcript[CF] = send_finished(signature, hs_wcipher)
406
+ cf = send_finished(signature, hs_wcipher)
407
+ transcript[CF] = [cf, cf.serialize]
359
408
  @alert_wcipher = @ap_wcipher = gen_cipher(
360
409
  @cipher_suite,
361
410
  key_schedule.client_application_write_key,
362
411
  key_schedule.client_application_write_iv
363
412
  )
413
+ sslkeylogfile&.write_client_traffic_secret_0(
414
+ transcript[CH].first.random,
415
+ key_schedule.client_application_traffic_secret
416
+ )
364
417
  @ap_rcipher = gen_cipher(
365
418
  @cipher_suite,
366
419
  key_schedule.server_application_write_key,
367
420
  key_schedule.server_application_write_iv
368
421
  )
422
+ sslkeylogfile&.write_server_traffic_secret_0(
423
+ transcript[CH].first.random,
424
+ key_schedule.server_application_traffic_secret
425
+ )
369
426
  @exporter_master_secret = key_schedule.exporter_master_secret
370
427
  @resumption_master_secret = key_schedule.resumption_master_secret
371
428
  @state = ClientState::CONNECTED
@@ -375,6 +432,7 @@ module TTTLS13
375
432
  break
376
433
  end
377
434
  end
435
+ sslkeylogfile&.close
378
436
  end
379
437
  # rubocop: enable Metrics/AbcSize
380
438
  # rubocop: enable Metrics/BlockLength
@@ -578,6 +636,14 @@ module TTTLS13
578
636
  exs << Message::Extension::OCSPStatusRequest.new \
579
637
  if @settings[:check_certificate_status]
580
638
 
639
+ # compress_certificate
640
+ if !@settings[:compress_certificate_algorithms].nil? &&
641
+ !@settings[:compress_certificate_algorithms].empty?
642
+ exs << Message::Extension::CompressCertificate.new(
643
+ @settings[:compress_certificate_algorithms]
644
+ )
645
+ end
646
+
581
647
  [exs, priv_keys]
582
648
  end
583
649
  # rubocop: enable Metrics/AbcSize
@@ -735,11 +801,15 @@ module TTTLS13
735
801
  # @raise [TTTLS13::Error::ErrorAlerts]
736
802
  #
737
803
  # @return [TTTLS13::Message::ServerHello]
804
+ # @return [String]
738
805
  def recv_server_hello
739
- sh = recv_message(receivable_ccs: true, cipher: Cryptograph::Passer.new)
806
+ sh, orig_msg = recv_message(
807
+ receivable_ccs: true,
808
+ cipher: Cryptograph::Passer.new
809
+ )
740
810
  terminate(:unexpected_message) unless sh.is_a?(Message::ServerHello)
741
811
 
742
- sh
812
+ [sh, orig_msg]
743
813
  end
744
814
 
745
815
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -747,12 +817,13 @@ module TTTLS13
747
817
  # @raise [TTTLS13::Error::ErrorAlerts]
748
818
  #
749
819
  # @return [TTTLS13::Message::EncryptedExtensions]
820
+ # @return [String]
750
821
  def recv_encrypted_extensions(cipher)
751
- ee = recv_message(receivable_ccs: true, cipher: cipher)
822
+ ee, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
752
823
  terminate(:unexpected_message) \
753
824
  unless ee.is_a?(Message::EncryptedExtensions)
754
825
 
755
- ee
826
+ [ee, orig_msg]
756
827
  end
757
828
 
758
829
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -760,11 +831,12 @@ module TTTLS13
760
831
  # @raise [TTTLS13::Error::ErrorAlerts]
761
832
  #
762
833
  # @return [TTTLS13::Message::Certificate]
834
+ # @return [String]
763
835
  def recv_certificate(cipher)
764
- ct = recv_message(receivable_ccs: true, cipher: cipher)
836
+ ct, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
765
837
  terminate(:unexpected_message) unless ct.is_a?(Message::Certificate)
766
838
 
767
- ct
839
+ [ct, orig_msg]
768
840
  end
769
841
 
770
842
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -772,11 +844,12 @@ module TTTLS13
772
844
  # @raise [TTTLS13::Error::ErrorAlerts]
773
845
  #
774
846
  # @return [TTTLS13::Message::CertificateVerify]
847
+ # @return [String]
775
848
  def recv_certificate_verify(cipher)
776
- cv = recv_message(receivable_ccs: true, cipher: cipher)
849
+ cv, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
777
850
  terminate(:unexpected_message) unless cv.is_a?(Message::CertificateVerify)
778
851
 
779
- cv
852
+ [cv, orig_msg]
780
853
  end
781
854
 
782
855
  # @param cipher [TTTLS13::Cryptograph::Aead]
@@ -784,11 +857,12 @@ module TTTLS13
784
857
  # @raise [TTTLS13::Error::ErrorAlerts]
785
858
  #
786
859
  # @return [TTTLS13::Message::Finished]
860
+ # @return [String]
787
861
  def recv_finished(cipher)
788
- sf = recv_message(receivable_ccs: true, cipher: cipher)
862
+ sf, orig_msg = recv_message(receivable_ccs: true, cipher: cipher)
789
863
  terminate(:unexpected_message) unless sf.is_a?(Message::Finished)
790
864
 
791
- sf
865
+ [sf, orig_msg]
792
866
  end
793
867
 
794
868
  # @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]
@@ -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,