tttls1.3 0.2.14 → 0.2.17

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: 3861f9a9864268fda75836b387c4a1f83e4edea0e885595155f2a352f69695ea
4
- data.tar.gz: 617f9b12aa8ac8e39367b1b5f9fcba57d1bd3dc669fe645c7c6888a7140795bd
3
+ metadata.gz: c2b9bfcfb3b52aaf74864e31adc9f132ab9ce94f4610bcaaefd8c7a5048666e5
4
+ data.tar.gz: 77ccec36eaeec3d0d569a8428209b14749d0d2d80ce33348ed1cdb6f5cbd6ec8
5
5
  SHA512:
6
- metadata.gz: 1f97901b82520b9c0a1fbc864e7e101749d9dacba3554e721eaf223fb1d4026384bf0756c8e9ac4578bcab37eb9c7b8e9c50b0387f3dfd7e8cf2d8456e709b14
7
- data.tar.gz: a0d104b2e5dba0e7e7f8297a51b858f0912007f59350e1842e026639c1cc27d107c2737292f01cc2bf1fbc6c3374cb3426696f00ee2462c72d014c841ea3ce7d
6
+ metadata.gz: 29ffa56dd58069ec5096bc0a19d81d79ee71a34f57d2381f91a1039d33b9ec0ca5cd965904a586d2f342957c3a05e92167e2c249fc2aad0ea4bfe2cebf9dc30f
7
+ data.tar.gz: a1cd0087f0d9ab6a2c7adf5245f9acca5756da7cd3084d1e2b79a601c6606b00680291be5fe7fcf442bdb9d90cdb22dc26a241bcf26ac754ff0476e889c3f092
@@ -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,7 +13,7 @@ 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
18
  - uses: docker://thekuwayama/openssl:latest
19
19
  - name: Set up Ruby
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/Gemfile CHANGED
@@ -7,9 +7,8 @@ gem 'openssl'
7
7
  gem 'rake'
8
8
 
9
9
  group :test do
10
- gem 'pry'
11
- gem 'pry-byebug'
12
- gem 'rspec', '3.8.0'
10
+ gem 'byebug'
11
+ gem 'rspec', '3.9.0'
13
12
  gem 'rubocop', '0.78.0'
14
13
  end
15
14
 
data/README.md CHANGED
@@ -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,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
 
@@ -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,
@@ -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(receivable_ccs: true, cipher: Cryptograph::Passer.new)
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]
@@ -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,
@@ -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
@@ -2,11 +2,18 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module TTTLS13
5
+ using Refinements
5
6
  module Message
6
7
  class EndOfEarlyData
8
+ attr_reader :msg_type
9
+
10
+ def initialize
11
+ @msg_type = HandshakeType::END_OF_EARLY_DATA
12
+ end
13
+
7
14
  # @return [String]
8
15
  def serialize
9
- ''
16
+ @msg_type + ''.prefix_uint24_length
10
17
  end
11
18
 
12
19
  # @param binary [String]
@@ -27,9 +27,12 @@ module TTTLS13
27
27
 
28
28
  # @return [String]
29
29
  def serialize
30
- binary = @protocol_name_list.map(&:prefix_uint8_length).join
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.prefix_uint16_length
35
+ @extension_type + binary.prefix_uint16_length
33
36
  end
34
37
 
35
38
  # @param binary [String]