tttls1.3 0.1.4 → 0.2.0

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/README.md +35 -13
  4. data/Rakefile +2 -4
  5. data/example/helper.rb +30 -7
  6. data/example/https_client.rb +3 -20
  7. data/example/https_client_using_0rtt.rb +10 -24
  8. data/example/https_client_using_hrr.rb +3 -20
  9. data/example/https_client_using_ticket.rb +3 -20
  10. data/example/https_server.rb +43 -0
  11. data/interop/client_spec.rb +111 -22
  12. data/interop/helper.rb +1 -0
  13. data/interop/server_spec.rb +182 -0
  14. data/lib/tttls1.3/client.rb +115 -98
  15. data/lib/tttls1.3/connection.rb +119 -32
  16. data/lib/tttls1.3/message/certificate.rb +18 -0
  17. data/lib/tttls1.3/message/client_hello.rb +38 -0
  18. data/lib/tttls1.3/message/encrypted_extensions.rb +20 -16
  19. data/lib/tttls1.3/message/extension/key_share.rb +24 -2
  20. data/lib/tttls1.3/message/extension/supported_groups.rb +0 -87
  21. data/lib/tttls1.3/message/extensions.rb +1 -27
  22. data/lib/tttls1.3/message/new_session_ticket.rb +14 -0
  23. data/lib/tttls1.3/message/record.rb +23 -20
  24. data/lib/tttls1.3/message/server_hello.rb +27 -0
  25. data/lib/tttls1.3/message.rb +35 -2
  26. data/lib/tttls1.3/named_group.rb +89 -0
  27. data/lib/tttls1.3/server.rb +439 -0
  28. data/lib/tttls1.3/transcript.rb +6 -0
  29. data/lib/tttls1.3/version.rb +1 -1
  30. data/lib/tttls1.3.rb +3 -0
  31. data/spec/certificate_spec.rb +28 -1
  32. data/spec/client_spec.rb +14 -10
  33. data/spec/connection_spec.rb +43 -13
  34. data/spec/encrypted_extensions_spec.rb +4 -4
  35. data/spec/fixtures/rsa_ca.crt +29 -0
  36. data/spec/fixtures/rsa_ca.key +51 -0
  37. data/spec/fixtures/rsa_rsa.crt +23 -0
  38. data/spec/fixtures/rsa_rsa.key +27 -0
  39. data/spec/fixtures/rsa_secp256r1.crt +19 -0
  40. data/spec/fixtures/rsa_secp256r1.key +5 -0
  41. data/spec/fixtures/rsa_secp384r1.crt +19 -0
  42. data/spec/fixtures/rsa_secp384r1.key +6 -0
  43. data/spec/fixtures/rsa_secp521r1.crt +20 -0
  44. data/spec/fixtures/rsa_secp521r1.key +7 -0
  45. data/spec/server_spec.rb +186 -0
  46. data/spec/spec_helper.rb +43 -0
  47. metadata +28 -2
@@ -30,10 +30,13 @@ module TTTLS13
30
30
  # @raise [TTTLS13::Error::ConfigError]
31
31
  #
32
32
  # @return [String]
33
+ # rubocop: disable Metrics/CyclomaticComplexity
34
+ # rubocop: disable Metrics/PerceivedComplexity
33
35
  def read
34
36
  # secure channel has not established yet
35
37
  raise Error::ConfigError \
36
- unless @endpoint == :client && @state == ClientState::CONNECTED
38
+ unless (@endpoint == :client && @state == ClientState::CONNECTED) ||
39
+ (@endpoint == :server && @state == ServerState::CONNECTED)
37
40
  return '' if @state == EOF
38
41
 
39
42
  message = nil
@@ -49,6 +52,8 @@ module TTTLS13
49
52
 
50
53
  message.fragment
51
54
  end
55
+ # rubocop: enable Metrics/CyclomaticComplexity
56
+ # rubocop: enable Metrics/PerceivedComplexity
52
57
 
53
58
  # @return [Boolean]
54
59
  def eof?
@@ -61,7 +66,8 @@ module TTTLS13
61
66
  def write(binary)
62
67
  # secure channel has not established yet
63
68
  raise Error::ConfigError \
64
- unless @endpoint == :client && @state == ClientState::CONNECTED
69
+ unless (@endpoint == :client && @state == ClientState::CONNECTED) ||
70
+ (@endpoint == :server && @state == ServerState::CONNECTED)
65
71
 
66
72
  ap = Message::ApplicationData.new(binary)
67
73
  send_application_data(ap, @write_cipher)
@@ -144,7 +150,7 @@ module TTTLS13
144
150
 
145
151
  # @param record [TTTLS13::Message::Record]
146
152
  def send_record(record)
147
- logger.debug('send ' + record.inspect)
153
+ logger.debug("send \n" + record.pretty_inspect)
148
154
  @socket.write(record.serialize(@send_record_size))
149
155
  end
150
156
 
@@ -164,7 +170,7 @@ module TTTLS13
164
170
  messages = record.messages
165
171
  break unless messages.empty?
166
172
  when Message::ContentType::CCS
167
- terminate(:unexpected_message) unless ccs_receivable?
173
+ terminate(:unexpected_message) unless receivable_ccs?
168
174
  next
169
175
  when Message::ContentType::ALERT
170
176
  handle_received_alert(record.messages.first)
@@ -205,23 +211,69 @@ module TTTLS13
205
211
  terminate(:unexpected_message)
206
212
  end
207
213
 
208
- logger.debug('receive ' + record.inspect)
214
+ logger.debug("receive \n" + record.pretty_inspect)
209
215
  record
210
216
  end
211
217
 
212
218
  # @param digest [String] name of digest algorithm
219
+ # @param transcript [TTTLS13::Transcript]
213
220
  #
214
221
  # @return [String]
215
- def do_sign_psk_binder(digest)
222
+ def do_sign_psk_binder(digest, transcript)
216
223
  # TODO: ext binder
217
224
  secret = @key_schedule.binder_key_res
218
225
  hash_len = OpenSSL::Digest.new(digest).digest_length
219
226
  # transcript-hash (CH1 + HRR +) truncated-CH
220
- hash = @transcript.truncate_hash(digest, CH, hash_len + 3)
227
+ hash = transcript.truncate_hash(digest, CH, hash_len + 3)
221
228
  OpenSSL::HMAC.digest(digest, secret, hash)
222
229
  end
223
230
 
224
- # @param certificate_pem [String]
231
+ # @param private_key [OpenSSL::PKey::PKey]
232
+ # @param signature_scheme [TTTLS13::SignatureScheme]
233
+ # @param context [String]
234
+ # @param handshake_context_end [Integer]
235
+ #
236
+ # @raise [TTTLS13::Error::ErrorAlerts]
237
+ #
238
+ # @return [String]
239
+ # rubocop: disable Metrics/CyclomaticComplexity
240
+ def do_sign_certificate_verify(private_key:, signature_scheme:, context:,
241
+ handshake_context_end:)
242
+ digest = CipherSuite.digest(@cipher_suite)
243
+ hash = @transcript.hash(digest, handshake_context_end)
244
+ content = "\x20" * 64 + context + "\x00" + hash
245
+
246
+ # RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether
247
+ # RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms".
248
+ case signature_scheme
249
+ when SignatureScheme::RSA_PKCS1_SHA256,
250
+ SignatureScheme::RSA_PSS_RSAE_SHA256,
251
+ SignatureScheme::RSA_PSS_PSS_SHA256
252
+ private_key.sign_pss('SHA256', content, salt_length: :digest,
253
+ mgf1_hash: 'SHA256')
254
+ when SignatureScheme::RSA_PKCS1_SHA384,
255
+ SignatureScheme::RSA_PSS_RSAE_SHA384,
256
+ SignatureScheme::RSA_PSS_PSS_SHA384
257
+ private_key.sign_pss('SHA384', content, salt_length: :digest,
258
+ mgf1_hash: 'SHA384')
259
+ when SignatureScheme::RSA_PKCS1_SHA512,
260
+ SignatureScheme::RSA_PSS_RSAE_SHA512,
261
+ SignatureScheme::RSA_PSS_PSS_SHA512
262
+ private_key.sign_pss('SHA512', content, salt_length: :digest,
263
+ mgf1_hash: 'SHA512')
264
+ when SignatureScheme::ECDSA_SECP256R1_SHA256
265
+ private_key.sign('SHA256', content)
266
+ when SignatureScheme::ECDSA_SECP384R1_SHA384
267
+ private_key.sign('SHA384', content)
268
+ when SignatureScheme::ECDSA_SECP521R1_SHA512
269
+ private_key.sign('SHA512', content)
270
+ else # TODO: ED25519, ED448
271
+ terminate(:internal_error)
272
+ end
273
+ end
274
+ # rubocop: enable Metrics/CyclomaticComplexity
275
+
276
+ # @param public_key [OpenSSL::PKey::PKey]
225
277
  # @param signature_scheme [TTTLS13::SignatureScheme]
226
278
  # @param signature [String]
227
279
  # @param context [String]
@@ -231,13 +283,12 @@ module TTTLS13
231
283
  #
232
284
  # @return [Boolean]
233
285
  # rubocop: disable Metrics/CyclomaticComplexity
234
- def do_verify_certificate_verify(certificate_pem:, signature_scheme:,
235
- signature:, context:,
236
- handshake_context_end:)
286
+ def do_verified_certificate_verify?(public_key:, signature_scheme:,
287
+ signature:, context:,
288
+ handshake_context_end:)
237
289
  digest = CipherSuite.digest(@cipher_suite)
238
290
  hash = @transcript.hash(digest, handshake_context_end)
239
291
  content = "\x20" * 64 + context + "\x00" + hash
240
- public_key = OpenSSL::X509::Certificate.new(certificate_pem).public_key
241
292
 
242
293
  # RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether
243
294
  # RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms".
@@ -285,8 +336,8 @@ module TTTLS13
285
336
  # @param signature [String]
286
337
  #
287
338
  # @return [Boolean]
288
- def do_verify_finished(digest:, finished_key:, handshake_context_end:,
289
- signature:)
339
+ def do_verified_finished?(digest:, finished_key:, handshake_context_end:,
340
+ signature:)
290
341
  do_sign_finished(
291
342
  digest: digest,
292
343
  finished_key: finished_key,
@@ -296,11 +347,11 @@ module TTTLS13
296
347
 
297
348
  # @param key_exchange [String]
298
349
  # @param priv_key [OpenSSL::PKey::$Object]
299
- # @param group [TTTLS13::Message::ExtensionType::NamedGroup]
350
+ # @param group [TTTLS13::NamedGroup]
300
351
  #
301
352
  # @return [String]
302
353
  def gen_shared_secret(key_exchange, priv_key, group)
303
- curve = Message::Extension::NamedGroup.curve_name(group)
354
+ curve = NamedGroup.curve_name(group)
304
355
  terminate(:internal_error) if curve.nil?
305
356
 
306
357
  pub_key = OpenSSL::PKey::EC::Point.new(
@@ -315,7 +366,7 @@ module TTTLS13
315
366
  #
316
367
  # Received ccs before the first ClientHello message or after the peer's
317
368
  # Finished message, peer MUST abort.
318
- def ccs_receivable?
369
+ def receivable_ccs?
319
370
  return false unless @transcript.include?(CH)
320
371
  return false if @endpoint == :client && @transcript.include?(SF)
321
372
  return false if @endpoint == :server && @transcript.include?(CF)
@@ -352,23 +403,13 @@ module TTTLS13
352
403
  # @param hostname [String]
353
404
  #
354
405
  # @return [Boolean]
355
- # rubocop: disable Metrics/AbcSize
356
- # rubocop: disable Metrics/CyclomaticComplexity
357
- def certified_certificate?(certificate_list, ca_file = nil, hostname = nil)
406
+ def trusted_certificate?(certificate_list, ca_file = nil, hostname = nil)
358
407
  cert_bin = certificate_list.first.cert_data
359
408
  cert = OpenSSL::X509::Certificate.new(cert_bin)
360
409
 
361
410
  # not support CN matching, only support SAN matching
362
- unless hostname.nil?
363
- san = cert.extensions.find { |ex| ex.oid == 'subjectAltName' }
364
- return false if san.nil?
365
-
366
- ostr = OpenSSL::ASN1.decode(san.to_der).value.last
367
- san_match = OpenSSL::ASN1.decode(ostr.value).map(&:value)
368
- .map { |s| s.gsub('.', '\.').gsub('*', '.*') }
369
- .any? { |s| hostname.match(/#{s}/) }
370
- return false unless san_match
371
- end
411
+ return false if !hostname.nil? && !matching_san?(cert, hostname)
412
+
372
413
  store = OpenSSL::X509::Store.new
373
414
  store.set_default_paths
374
415
  store.add_file(ca_file) unless ca_file.nil?
@@ -380,8 +421,54 @@ module TTTLS13
380
421
  now = Time.now
381
422
  ctx.verify && cert.not_before < now && now < cert.not_after
382
423
  end
383
- # rubocop: enable Metrics/AbcSize
384
- # rubocop: enable Metrics/CyclomaticComplexity
424
+
425
+ # @param cert [OpenSSL::X509::Certificate]
426
+ # @param name [String]
427
+ #
428
+ # @return [Boolean]
429
+ def matching_san?(cert, name)
430
+ san = cert.extensions.find { |ex| ex.oid == 'subjectAltName' }
431
+ return false if san.nil?
432
+
433
+ ostr = OpenSSL::ASN1.decode(san.to_der).value.last
434
+ matching = OpenSSL::ASN1.decode(ostr.value).map(&:value)
435
+ .map { |s| s.gsub('.', '\.').gsub('*', '.*') }
436
+ .any? { |s| name.match(/#{s}/) }
437
+
438
+ matching
439
+ end
440
+
441
+ # @param signature_algorithms [Array of SignatureAlgorithms]
442
+ # @param crt [OpenSSL::X509::Certificate]
443
+ #
444
+ # @return [Array of TTTLS13::Message::Extension::SignatureAlgorithms]
445
+ def do_select_signature_algorithms(signature_algorithms, crt)
446
+ spki = OpenSSL::Netscape::SPKI.new
447
+ spki.public_key = crt.public_key
448
+ oid_str = spki.to_text.split("\n")
449
+ .find { |l| l.include?('Public Key Algorithm:') }
450
+ signature_algorithms.select do |sa|
451
+ case sa
452
+ when SignatureScheme::ECDSA_SECP256R1_SHA256,
453
+ SignatureScheme::ECDSA_SECP384R1_SHA384,
454
+ SignatureScheme::ECDSA_SECP521R1_SHA512
455
+ oid_str.include?('id-ecPublicKey')
456
+ when SignatureScheme::RSA_PSS_PSS_SHA256,
457
+ SignatureScheme::RSA_PSS_PSS_SHA384,
458
+ SignatureScheme::RSA_PSS_PSS_SHA512
459
+ oid_str.include?('rsassaPss')
460
+ when SignatureScheme::RSA_PSS_RSAE_SHA256,
461
+ SignatureScheme::RSA_PSS_RSAE_SHA384,
462
+ SignatureScheme::RSA_PSS_RSAE_SHA512
463
+ oid_str.include?('rsaEncryption')
464
+ else
465
+ # RSASSA-PKCS1-v1_5 algorithms refer solely to signatures which appear
466
+ # in certificates and are not defined for use in signed TLS handshake
467
+ # messages
468
+ false
469
+ end
470
+ end
471
+ end
385
472
  end
386
473
  # rubocop: enable Metrics/ClassLength
387
474
  end
@@ -4,6 +4,13 @@
4
4
  module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
8
+ APPEARABLE_CT_EXTENSIONS = [
9
+ ExtensionType::STATUS_REQUEST,
10
+ ExtensionType::SIGNED_CERTIFICATE_TIMESTAMP
11
+ ].freeze
12
+ private_constant :APPEARABLE_CT_EXTENSIONS
13
+
7
14
  class Certificate
8
15
  attr_reader :msg_type
9
16
  attr_reader :certificate_request_context
@@ -58,6 +65,17 @@ module TTTLS13
58
65
  )
59
66
  end
60
67
 
68
+ # @return [Boolean]
69
+ def only_appearable_extensions?
70
+ cl_exs = @certificate_list.map do |e|
71
+ e.instance_variable_get(:@extensions).keys
72
+ end
73
+ exs = cl_exs.uniq.flatten - APPEARABLE_CT_EXTENSIONS
74
+ return true if exs.empty?
75
+
76
+ !(exs - DEFINED_EXTENSIONS).empty?
77
+ end
78
+
61
79
  class << self
62
80
  private
63
81
 
@@ -4,6 +4,36 @@
4
4
  module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
8
+ APPEARABLE_CH_EXTENSIONS = [
9
+ ExtensionType::SERVER_NAME,
10
+ ExtensionType::MAX_FRAGMENT_LENGTH,
11
+ ExtensionType::STATUS_REQUEST,
12
+ ExtensionType::SUPPORTED_GROUPS,
13
+ ExtensionType::SIGNATURE_ALGORITHMS,
14
+ ExtensionType::USE_SRTP,
15
+ ExtensionType::HEARTBEAT,
16
+ ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION,
17
+ ExtensionType::SIGNED_CERTIFICATE_TIMESTAMP,
18
+ ExtensionType::CLIENT_CERTIFICATE_TYPE,
19
+ ExtensionType::SERVER_CERTIFICATE_TYPE,
20
+ ExtensionType::PADDING,
21
+ ExtensionType::RECORD_SIZE_LIMIT,
22
+ ExtensionType::PWD_PROTECT,
23
+ ExtensionType::PWD_CLEAR,
24
+ ExtensionType::PASSWORD_SALT,
25
+ ExtensionType::PRE_SHARED_KEY,
26
+ ExtensionType::EARLY_DATA,
27
+ ExtensionType::SUPPORTED_VERSIONS,
28
+ ExtensionType::COOKIE,
29
+ ExtensionType::PSK_KEY_EXCHANGE_MODES,
30
+ ExtensionType::CERTIFICATE_AUTHORITIES,
31
+ ExtensionType::POST_HANDSHAKE_AUTH,
32
+ ExtensionType::SIGNATURE_ALGORITHMS_CERT,
33
+ ExtensionType::KEY_SHARE
34
+ ].freeze
35
+ private_constant :APPEARABLE_CH_EXTENSIONS
36
+
7
37
  class ClientHello
8
38
  attr_reader :msg_type
9
39
  attr_reader :legacy_version
@@ -95,6 +125,14 @@ module TTTLS13
95
125
  end
96
126
  # rubocop: enable Metrics/AbcSize
97
127
  # rubocop: enable Metrics/MethodLength
128
+
129
+ # @return [Boolean]
130
+ def only_appearable_extensions?
131
+ exs = @extensions.keys - APPEARABLE_CH_EXTENSIONS
132
+ return true if exs.empty?
133
+
134
+ !(exs - DEFINED_EXTENSIONS).empty?
135
+ end
98
136
  end
99
137
  end
100
138
  end
@@ -4,24 +4,25 @@
4
4
  module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
8
+ APPEARABLE_EE_EXTENSIONS = [
9
+ ExtensionType::SERVER_NAME,
10
+ ExtensionType::MAX_FRAGMENT_LENGTH,
11
+ ExtensionType::SUPPORTED_GROUPS,
12
+ ExtensionType::USE_SRTP,
13
+ ExtensionType::HEARTBEAT,
14
+ ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION,
15
+ ExtensionType::CLIENT_CERTIFICATE_TYPE,
16
+ ExtensionType::SERVER_CERTIFICATE_TYPE,
17
+ ExtensionType::RECORD_SIZE_LIMIT,
18
+ ExtensionType::EARLY_DATA
19
+ ].freeze
20
+ private_constant :APPEARABLE_EE_EXTENSIONS
21
+
7
22
  class EncryptedExtensions
8
23
  attr_reader :msg_type
9
24
  attr_reader :extensions
10
25
 
11
- # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
12
- ALLOWED_EXTENSIONS = [
13
- ExtensionType::SERVER_NAME,
14
- ExtensionType::MAX_FRAGMENT_LENGTH,
15
- ExtensionType::SUPPORTED_GROUPS,
16
- ExtensionType::USE_SRTP,
17
- ExtensionType::HEARTBEAT,
18
- ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION,
19
- ExtensionType::CLIENT_CERTIFICATE_TYPE,
20
- ExtensionType::SERVER_CERTIFICATE_TYPE,
21
- ExtensionType::RECORD_SIZE_LIMIT,
22
- ExtensionType::EARLY_DATA
23
- ].freeze
24
-
25
26
  # @param extensions [TTTLS13::Message::Extensions]
26
27
  def initialize(extensions = Extensions.new)
27
28
  @msg_type = HandshakeType::ENCRYPTED_EXTENSIONS
@@ -57,8 +58,11 @@ module TTTLS13
57
58
  end
58
59
 
59
60
  # @return [Boolean]
60
- def any_forbidden_extensions?
61
- !(@extensions.keys - ALLOWED_EXTENSIONS).empty?
61
+ def only_appearable_extensions?
62
+ exs = @extensions.keys - APPEARABLE_EE_EXTENSIONS
63
+ return true if exs.empty?
64
+
65
+ !(exs - DEFINED_EXTENSIONS).empty?
62
66
  end
63
67
  end
64
68
  end
@@ -83,7 +83,7 @@ module TTTLS13
83
83
  end
84
84
  # rubocop: enable Metrics/CyclomaticComplexity
85
85
 
86
- # @param groups [Array of TTTLS13::Message::Extension::NamedGroup]
86
+ # @param groups [Array of TTTLS13::NamedGroup]
87
87
  #
88
88
  # @return [TTTLS13::Message::Extensions::KeyShare]
89
89
  # @return [Hash of NamedGroup => OpenSSL::PKey::EC.$Object]
@@ -109,6 +109,28 @@ module TTTLS13
109
109
  [key_share, priv_keys]
110
110
  end
111
111
 
112
+ # @param groups [TTTLS13::NamedGroup]
113
+ #
114
+ # @return [TTTLS13::Message::Extensions::KeyShare]
115
+ # @return [OpenSSL::PKey::EC.$Object]
116
+ def self.gen_sh_key_share(group)
117
+ curve = NamedGroup.curve_name(group)
118
+ ec = OpenSSL::PKey::EC.new(curve)
119
+ ec.generate_key!
120
+
121
+ key_share = KeyShare.new(
122
+ msg_type: HandshakeType::SERVER_HELLO,
123
+ key_share_entry: [
124
+ KeyShareEntry.new(
125
+ group: group,
126
+ key_exchange: ec.public_key.to_octet_string(:uncompressed)
127
+ )
128
+ ]
129
+ )
130
+
131
+ [key_share, ec]
132
+ end
133
+
112
134
  class << self
113
135
  private
114
136
 
@@ -196,7 +218,7 @@ module TTTLS13
196
218
  attr_reader :group
197
219
  attr_reader :key_exchange
198
220
 
199
- # @param group [TTTLS13::Message::Extension::NamedGroup]
221
+ # @param group [TTTLS13::NamedGroup]
200
222
  # @param key_exchange [String]
201
223
  #
202
224
  # @raise [TTTLS13::Error::ErrorAlerts]
@@ -5,93 +5,6 @@ module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
7
  module Extension
8
- module NamedGroup
9
- SECP256R1 = "\x00\x17"
10
- SECP384R1 = "\x00\x18"
11
- SECP521R1 = "\x00\x19"
12
- # X25519 = "\x00\x1d" # UNSUPPORTED
13
- # X448 = "\x00\x1e" # UNSUPPORTED
14
- # FFDHE2048 = "\x01\x00" # UNSUPPORTED
15
- # FFDHE3072 = "\x01\x01" # UNSUPPORTED
16
- # FFDHE4096 = "\x01\x02" # UNSUPPORTED
17
- # FFDHE6144 = "\x01\x03" # UNSUPPORTED
18
- # FFDHE8192 = "\x01\x04" # UNSUPPORTED
19
- # ffdhe_private_use "\x01\xfc" ~ "\x01\xff"
20
- # ecdhe_private_use "\xfe\x00" ~ "\xfe\xff"
21
-
22
- class << self
23
- # NOTE:
24
- # For secp256r1, secp384r1, and secp521r1
25
- #
26
- # struct {
27
- # uint8 legacy_form = 4;
28
- # opaque X[coordinate_length];
29
- # opaque Y[coordinate_length];
30
- # } UncompressedPointRepresentation;
31
- #
32
- # @param group [TTTLS13::Message::Extension::NamedGroup]
33
- #
34
- # @raise [TTTLS13::Error::ErrorAlerts]
35
- #
36
- # @return [Integer]
37
- def key_exchange_len(group)
38
- case group
39
- when SECP256R1
40
- 65
41
- when SECP384R1
42
- 97
43
- when SECP521R1
44
- 133
45
- # NOTE:
46
- # not supported other NamedGroup
47
- # when X25519
48
- # 32
49
- # when X448
50
- # 56
51
- # when FFDHE2048
52
- # 256
53
- # when FFDHE4096
54
- # 512
55
- # when FFDHE6144
56
- # 768
57
- # when FFDHE8192
58
- # 1024
59
- else
60
- raise Error::ErrorAlerts, :internal_error
61
- end
62
- end
63
-
64
- # NOTE:
65
- # SECG | ANSI X9.62 | NIST
66
- # ------------+---------------+-------------
67
- # secp256r1 | prime256v1 | NIST P-256
68
- # secp384r1 | | NIST P-384
69
- # secp521r1 | | NIST P-521
70
- #
71
- # https://tools.ietf.org/html/rfc4492#appendix-A
72
- #
73
- # @param groups [Array of TTTLS13::Message::Extension::NamedGroup]
74
- #
75
- # @raise [TTTLS13::Error::ErrorAlerts]
76
- #
77
- # @return [String] EC_builtin_curves
78
- def curve_name(group)
79
- case group
80
- when NamedGroup::SECP256R1
81
- 'prime256v1'
82
- when NamedGroup::SECP384R1
83
- 'secp384r1'
84
- when NamedGroup::SECP521R1
85
- 'secp521r1'
86
- else
87
- # NOTE:
88
- # not supported other NamedGroup
89
- raise Error::ErrorAlerts, :internal_error
90
- end
91
- end
92
- end
93
- end
94
-
95
8
  class SupportedGroups
96
9
  attr_reader :extension_type
97
10
  attr_reader :named_group_list
@@ -6,32 +6,6 @@ Dir[File.dirname(__FILE__) + '/extension/*.rb'].each { |f| require f }
6
6
  module TTTLS13
7
7
  using Refinements
8
8
  module Message
9
- module ExtensionType
10
- SERVER_NAME = "\x00\x00"
11
- MAX_FRAGMENT_LENGTH = "\x00\x01"
12
- STATUS_REQUEST = "\x00\x05"
13
- SUPPORTED_GROUPS = "\x00\x0a"
14
- SIGNATURE_ALGORITHMS = "\x00\x0d"
15
- USE_SRTP = "\x00\x0e"
16
- HEARTBEAT = "\x00\x0f"
17
- APPLICATION_LAYER_PROTOCOL_NEGOTIATION = "\x00\x10"
18
- SIGNED_CERTIFICATE_TIMESTAMP = "\x00\x12"
19
- CLIENT_CERTIFICATE_TYPE = "\x00\x13"
20
- SERVER_CERTIFICATE_TYPE = "\x00\x14"
21
- PADDING = "\x00\x15"
22
- RECORD_SIZE_LIMIT = "\x00\x1c"
23
- PRE_SHARED_KEY = "\x00\x29"
24
- EARLY_DATA = "\x00\x2a"
25
- SUPPORTED_VERSIONS = "\x00\x2b"
26
- COOKIE = "\x00\x2c"
27
- PSK_KEY_EXCHANGE_MODES = "\x00\x2d"
28
- CERTIFICATE_AUTHORITIES = "\x00\x2f"
29
- OID_FILTERS = "\x00\x30"
30
- POST_HANDSHAKE_AUTH = "\x00\x31"
31
- SIGNATURE_ALGORITHMS_CERT = "\x00\x32"
32
- KEY_SHARE = "\x00\x33"
33
- end
34
-
35
9
  class Extensions < Hash
36
10
  # @param extensions [Array of TTTLS13::Message::Extension::$Object]
37
11
  #
@@ -145,7 +119,7 @@ module TTTLS13
145
119
  when ExtensionType::SIGNATURE_ALGORITHMS
146
120
  Extension::SignatureAlgorithms.deserialize(binary)
147
121
  when ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
148
- Extension::Alpn..deserialize(binary)
122
+ Extension::Alpn.deserialize(binary)
149
123
  when ExtensionType::RECORD_SIZE_LIMIT
150
124
  Extension::RecordSizeLimit.deserialize(binary)
151
125
  when ExtensionType::PRE_SHARED_KEY
@@ -4,6 +4,12 @@
4
4
  module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
8
+ APPEARABLE_NST_EXTENSIONS = [
9
+ ExtensionType::EARLY_DATA
10
+ ].freeze
11
+ private_constant :APPEARABLE_NST_EXTENSIONS
12
+
7
13
  class NewSessionTicket
8
14
  attr_reader :msg_type
9
15
  attr_reader :ticket_lifetime
@@ -84,6 +90,14 @@ module TTTLS13
84
90
  extensions: extensions)
85
91
  end
86
92
  # rubocop: enable Metrics/AbcSize
93
+
94
+ # @return [Boolean]
95
+ def only_appearable_extensions?
96
+ exs = @extensions.keys - APPEARABLE_NST_EXTENSIONS
97
+ return true if exs.empty?
98
+
99
+ !(exs - DEFINED_EXTENSIONS).empty?
100
+ end
87
101
  end
88
102
  end
89
103
  end
@@ -108,28 +108,31 @@ module TTTLS13
108
108
  #
109
109
  # @return [TTTLS13::Message::ContentType]
110
110
  def messages_type
111
- types = @messages.map(&:class).uniq
111
+ types = @messages.map do |m|
112
+ if [Message::ClientHello,
113
+ Message::ServerHello,
114
+ Message::EncryptedExtensions,
115
+ Message::Certificate,
116
+ Message::CertificateVerify,
117
+ Message::Finished,
118
+ Message::EndOfEarlyData,
119
+ Message::NewSessionTicket].include?(m.class)
120
+ ContentType::HANDSHAKE
121
+ elsif m.class == ChangeCipherSpec
122
+ ContentType::CCS
123
+ elsif m.class == Message::ApplicationData
124
+ ContentType::APPLICATION_DATA
125
+ elsif m.class == Message::Alert
126
+ ContentType::ALERT
127
+ else
128
+ raise Error::ErrorAlerts, :internal_error
129
+ end
130
+ end
131
+
132
+ types.uniq!
112
133
  raise Error::ErrorAlerts, :internal_error unless types.length == 1
113
134
 
114
- type = types.first
115
- if [Message::ClientHello,
116
- Message::ServerHello,
117
- Message::EncryptedExtensions,
118
- Message::Certificate,
119
- Message::CertificateVerify,
120
- Message::Finished,
121
- Message::EndOfEarlyData,
122
- Message::NewSessionTicket].include?(type)
123
- ContentType::HANDSHAKE
124
- elsif type == ChangeCipherSpec
125
- ContentType::CCS
126
- elsif type == Message::ApplicationData
127
- ContentType::APPLICATION_DATA
128
- elsif type == Message::Alert
129
- ContentType::ALERT
130
- else
131
- raise Error::ErrorAlerts, :internal_error
132
- end
135
+ types.first
133
136
  end
134
137
 
135
138
  class << self