tttls1.3 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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