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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +35 -13
- data/Rakefile +2 -4
- data/example/helper.rb +30 -7
- data/example/https_client.rb +3 -20
- data/example/https_client_using_0rtt.rb +10 -24
- data/example/https_client_using_hrr.rb +3 -20
- data/example/https_client_using_ticket.rb +3 -20
- data/example/https_server.rb +43 -0
- data/interop/client_spec.rb +111 -22
- data/interop/helper.rb +1 -0
- data/interop/server_spec.rb +182 -0
- data/lib/tttls1.3/client.rb +115 -98
- data/lib/tttls1.3/connection.rb +119 -32
- data/lib/tttls1.3/message/certificate.rb +18 -0
- data/lib/tttls1.3/message/client_hello.rb +38 -0
- data/lib/tttls1.3/message/encrypted_extensions.rb +20 -16
- data/lib/tttls1.3/message/extension/key_share.rb +24 -2
- data/lib/tttls1.3/message/extension/supported_groups.rb +0 -87
- data/lib/tttls1.3/message/extensions.rb +1 -27
- data/lib/tttls1.3/message/new_session_ticket.rb +14 -0
- data/lib/tttls1.3/message/record.rb +23 -20
- data/lib/tttls1.3/message/server_hello.rb +27 -0
- data/lib/tttls1.3/message.rb +35 -2
- data/lib/tttls1.3/named_group.rb +89 -0
- data/lib/tttls1.3/server.rb +439 -0
- data/lib/tttls1.3/transcript.rb +6 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +3 -0
- data/spec/certificate_spec.rb +28 -1
- data/spec/client_spec.rb +14 -10
- data/spec/connection_spec.rb +43 -13
- data/spec/encrypted_extensions_spec.rb +4 -4
- data/spec/fixtures/rsa_ca.crt +29 -0
- data/spec/fixtures/rsa_ca.key +51 -0
- data/spec/fixtures/rsa_rsa.crt +23 -0
- data/spec/fixtures/rsa_rsa.key +27 -0
- data/spec/fixtures/rsa_secp256r1.crt +19 -0
- data/spec/fixtures/rsa_secp256r1.key +5 -0
- data/spec/fixtures/rsa_secp384r1.crt +19 -0
- data/spec/fixtures/rsa_secp384r1.key +6 -0
- data/spec/fixtures/rsa_secp521r1.crt +20 -0
- data/spec/fixtures/rsa_secp521r1.key +7 -0
- data/spec/server_spec.rb +186 -0
- data/spec/spec_helper.rb +43 -0
- metadata +28 -2
data/lib/tttls1.3/connection.rb
CHANGED
@@ -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(
|
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
|
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(
|
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 =
|
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
|
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
|
235
|
-
|
236
|
-
|
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
|
289
|
-
|
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::
|
350
|
+
# @param group [TTTLS13::NamedGroup]
|
300
351
|
#
|
301
352
|
# @return [String]
|
302
353
|
def gen_shared_secret(key_exchange, priv_key, group)
|
303
|
-
curve =
|
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
|
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
|
-
|
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
|
-
|
363
|
-
|
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
|
-
|
384
|
-
#
|
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
|
61
|
-
|
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::
|
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::
|
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
|
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
|
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
|
-
|
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
|