tttls1.3 0.1.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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.travis.yml +8 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +133 -0
- data/example/helper.rb +17 -0
- data/example/https_client.rb +32 -0
- data/example/https_client_using_0rtt.rb +64 -0
- data/example/https_client_using_hrr.rb +35 -0
- data/example/https_client_using_ticket.rb +56 -0
- data/lib/tttls1.3/cipher_suites.rb +102 -0
- data/lib/tttls1.3/client.rb +745 -0
- data/lib/tttls1.3/connection.rb +380 -0
- data/lib/tttls1.3/cryptograph/aead.rb +118 -0
- data/lib/tttls1.3/cryptograph/passer.rb +22 -0
- data/lib/tttls1.3/cryptograph.rb +3 -0
- data/lib/tttls1.3/error.rb +22 -0
- data/lib/tttls1.3/key_schedule.rb +242 -0
- data/lib/tttls1.3/message/alert.rb +86 -0
- data/lib/tttls1.3/message/application_data.rb +27 -0
- data/lib/tttls1.3/message/certificate.rb +121 -0
- data/lib/tttls1.3/message/certificate_verify.rb +59 -0
- data/lib/tttls1.3/message/change_cipher_spec.rb +26 -0
- data/lib/tttls1.3/message/client_hello.rb +100 -0
- data/lib/tttls1.3/message/encrypted_extensions.rb +65 -0
- data/lib/tttls1.3/message/end_of_early_data.rb +29 -0
- data/lib/tttls1.3/message/extension/alpn.rb +70 -0
- data/lib/tttls1.3/message/extension/cookie.rb +47 -0
- data/lib/tttls1.3/message/extension/early_data_indication.rb +58 -0
- data/lib/tttls1.3/message/extension/key_share.rb +236 -0
- data/lib/tttls1.3/message/extension/pre_shared_key.rb +205 -0
- data/lib/tttls1.3/message/extension/psk_key_exchange_modes.rb +54 -0
- data/lib/tttls1.3/message/extension/record_size_limit.rb +46 -0
- data/lib/tttls1.3/message/extension/server_name.rb +91 -0
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +69 -0
- data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +25 -0
- data/lib/tttls1.3/message/extension/status_request.rb +106 -0
- data/lib/tttls1.3/message/extension/supported_groups.rb +145 -0
- data/lib/tttls1.3/message/extension/supported_versions.rb +98 -0
- data/lib/tttls1.3/message/extension/unknown_extension.rb +38 -0
- data/lib/tttls1.3/message/extensions.rb +173 -0
- data/lib/tttls1.3/message/finished.rb +44 -0
- data/lib/tttls1.3/message/new_session_ticket.rb +89 -0
- data/lib/tttls1.3/message/record.rb +232 -0
- data/lib/tttls1.3/message/server_hello.rb +116 -0
- data/lib/tttls1.3/message.rb +48 -0
- data/lib/tttls1.3/sequence_number.rb +31 -0
- data/lib/tttls1.3/signature_scheme.rb +31 -0
- data/lib/tttls1.3/transcript.rb +69 -0
- data/lib/tttls1.3/utils.rb +91 -0
- data/lib/tttls1.3/version.rb +5 -0
- data/lib/tttls1.3.rb +16 -0
- data/spec/aead_spec.rb +95 -0
- data/spec/alert_spec.rb +54 -0
- data/spec/alpn_spec.rb +55 -0
- data/spec/application_data_spec.rb +26 -0
- data/spec/certificate_spec.rb +55 -0
- data/spec/certificate_verify_spec.rb +51 -0
- data/spec/change_cipher_spec_spec.rb +26 -0
- data/spec/cipher_suites_spec.rb +39 -0
- data/spec/client_hello_spec.rb +83 -0
- data/spec/client_spec.rb +319 -0
- data/spec/connection_spec.rb +114 -0
- data/spec/cookie_spec.rb +98 -0
- data/spec/early_data_indication_spec.rb +64 -0
- data/spec/encrypted_extensions_spec.rb +94 -0
- data/spec/error_spec.rb +18 -0
- data/spec/extensions_spec.rb +170 -0
- data/spec/finished_spec.rb +55 -0
- data/spec/key_schedule_spec.rb +198 -0
- data/spec/key_share_spec.rb +199 -0
- data/spec/new_session_ticket_spec.rb +80 -0
- data/spec/pre_shared_key_spec.rb +167 -0
- data/spec/psk_key_exchange_modes_spec.rb +45 -0
- data/spec/record_size_limit_spec.rb +61 -0
- data/spec/record_spec.rb +105 -0
- data/spec/server_hello_spec.rb +101 -0
- data/spec/server_name_spec.rb +110 -0
- data/spec/signature_algorithms_cert_spec.rb +73 -0
- data/spec/signature_algorithms_spec.rb +100 -0
- data/spec/spec_helper.rb +872 -0
- data/spec/status_request_spec.rb +73 -0
- data/spec/supported_groups_spec.rb +79 -0
- data/spec/supported_versions_spec.rb +136 -0
- data/spec/transcript_spec.rb +69 -0
- data/spec/unknown_extension_spec.rb +90 -0
- data/spec/utils_spec.rb +215 -0
- data/tttls1.3.gemspec +25 -0
- metadata +197 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
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
|
+
class SupportedGroups
|
96
|
+
attr_reader :extension_type
|
97
|
+
attr_reader :named_group_list
|
98
|
+
|
99
|
+
# @param named_group_list [Array of NamedGroup]
|
100
|
+
#
|
101
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
102
|
+
def initialize(named_group_list)
|
103
|
+
@extension_type = ExtensionType::SUPPORTED_GROUPS
|
104
|
+
@named_group_list = named_group_list || []
|
105
|
+
raise Error::ErrorAlerts, :internal_error \
|
106
|
+
if @named_group_list.empty? || @named_group_list.length >= 2**15 - 1
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [String]
|
110
|
+
def serialize
|
111
|
+
binary = @named_group_list.join
|
112
|
+
|
113
|
+
@extension_type + binary.prefix_uint16_length.prefix_uint16_length
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param binary [String]
|
117
|
+
#
|
118
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
119
|
+
#
|
120
|
+
# @return [TTTLS13::Message::Extension::SupportedGroups, nil]
|
121
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
122
|
+
def self.deserialize(binary)
|
123
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
124
|
+
|
125
|
+
return nil if binary.length < 2
|
126
|
+
|
127
|
+
nglist_len = Convert.bin2i(binary.slice(0, 2))
|
128
|
+
i = 2
|
129
|
+
named_group_list = []
|
130
|
+
while i < nglist_len + 2
|
131
|
+
return nil if i + 2 > binary.length
|
132
|
+
|
133
|
+
named_group_list << binary.slice(i, 2)
|
134
|
+
i += 2
|
135
|
+
end
|
136
|
+
return nil unless i == binary.length &&
|
137
|
+
nglist_len + 2 == binary.length
|
138
|
+
|
139
|
+
SupportedGroups.new(named_group_list)
|
140
|
+
end
|
141
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
module Extension
|
8
|
+
class SupportedVersions
|
9
|
+
attr_reader :extension_type
|
10
|
+
attr_accessor :msg_type
|
11
|
+
attr_accessor :versions
|
12
|
+
|
13
|
+
# @param msg_type [TTTLS13::Message::ContentType]
|
14
|
+
# @param versions [Array of ProtocolVersion]
|
15
|
+
#
|
16
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
17
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
18
|
+
def initialize(msg_type:, versions: DEFAULT_VERSIONS)
|
19
|
+
@extension_type = ExtensionType::SUPPORTED_VERSIONS
|
20
|
+
@msg_type = msg_type
|
21
|
+
@versions = versions || []
|
22
|
+
case @msg_type
|
23
|
+
when HandshakeType::CLIENT_HELLO
|
24
|
+
raise Error::ErrorAlerts, :internal_error \
|
25
|
+
if @versions.empty? || @versions.length > 127
|
26
|
+
when HandshakeType::SERVER_HELLO, HandshakeType::HELLO_RETRY_REQUEST
|
27
|
+
raise Error::ErrorAlerts, :internal_error \
|
28
|
+
unless @versions.length == 1
|
29
|
+
else
|
30
|
+
raise Error::ErrorAlerts, :internal_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
def serialize
|
37
|
+
binary = ''
|
38
|
+
binary += (@versions.length * 2).to_uint8 \
|
39
|
+
if @msg_type == HandshakeType::CLIENT_HELLO
|
40
|
+
binary += @versions.join
|
41
|
+
|
42
|
+
@extension_type + binary.prefix_uint16_length
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param binary [String]
|
46
|
+
# @param msg_type [TTTLS13::Message::HandshakeType]
|
47
|
+
#
|
48
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
49
|
+
#
|
50
|
+
# @return [TTTLS13::Message::Extensions::SupportedVersions, nil]
|
51
|
+
def self.deserialize(binary, msg_type)
|
52
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
53
|
+
|
54
|
+
versions = []
|
55
|
+
case msg_type
|
56
|
+
when HandshakeType::CLIENT_HELLO
|
57
|
+
versions = deserialize_versions(binary)
|
58
|
+
return nil if versions.nil? # unparsable versions
|
59
|
+
|
60
|
+
when HandshakeType::SERVER_HELLO, HandshakeType::HELLO_RETRY_REQUEST
|
61
|
+
return nil if binary.length != 2
|
62
|
+
|
63
|
+
versions << binary.slice(0, 2)
|
64
|
+
else
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
SupportedVersions.new(msg_type: msg_type, versions: versions)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param binary [String]
|
71
|
+
#
|
72
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
73
|
+
#
|
74
|
+
# @return [Array of String, nil]
|
75
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
76
|
+
def self.deserialize_versions(binary)
|
77
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
78
|
+
|
79
|
+
return nil if binary.empty?
|
80
|
+
|
81
|
+
versions_len = Convert.bin2i(binary[0])
|
82
|
+
i = 1
|
83
|
+
versions = []
|
84
|
+
while i < versions_len + 1
|
85
|
+
return nil if i + 2 > binary.length
|
86
|
+
|
87
|
+
versions << binary.slice(i, 2)
|
88
|
+
i += 2
|
89
|
+
end
|
90
|
+
return nil if i != binary.length || i != versions_len + 1
|
91
|
+
|
92
|
+
versions
|
93
|
+
end
|
94
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
module Extension
|
8
|
+
# NOTE:
|
9
|
+
# Client/Server MUST ignore unrecognized extensions,
|
10
|
+
# but transcript MUST include unrecognized extensions.
|
11
|
+
class UnknownExtension
|
12
|
+
attr_accessor :extension_type
|
13
|
+
attr_accessor :extension_data
|
14
|
+
|
15
|
+
# @param extension_type [String]
|
16
|
+
# @param extension_data [String]
|
17
|
+
def initialize(extension_type:, extension_data: '')
|
18
|
+
@extension_type = extension_type
|
19
|
+
@extension_data = extension_data || ''
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String]
|
23
|
+
def serialize
|
24
|
+
@extension_type + @extension_data.prefix_uint16_length
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param binary [String]
|
28
|
+
# @param extension_type [String]
|
29
|
+
#
|
30
|
+
# @return [TTTLS13::Message::Extension::UnknownExtension]
|
31
|
+
def self.deserialize(binary, extension_type)
|
32
|
+
UnknownExtension.new(extension_type: extension_type,
|
33
|
+
extension_data: binary)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
Dir[File.dirname(__FILE__) + '/extension/*.rb'].each { |f| require f }
|
5
|
+
|
6
|
+
module TTTLS13
|
7
|
+
using Refinements
|
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
|
+
class Extensions < Hash
|
36
|
+
# @param extensions [Array of TTTLS13::Message::Extension::$Object]
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# Extensions.new([SupportedVersions.new, ServerName.new('example.com')]
|
40
|
+
def initialize(extensions = [])
|
41
|
+
extensions.each do |ex|
|
42
|
+
super[ex.extension_type] = ex
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
alias super_fetch fetch
|
47
|
+
|
48
|
+
# NOTE:
|
49
|
+
# "pre_shared_key" MUST be the last extension in the ClientHello
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def serialize
|
53
|
+
except_ch_psk = values.reject do |ex|
|
54
|
+
ex.extension_type == ExtensionType::PRE_SHARED_KEY &&
|
55
|
+
ex.msg_type == HandshakeType::CLIENT_HELLO
|
56
|
+
end
|
57
|
+
binary = except_ch_psk.map(&:serialize).join
|
58
|
+
|
59
|
+
psk = super_fetch(ExtensionType::PRE_SHARED_KEY, nil)
|
60
|
+
binary += psk.serialize if psk&.msg_type == HandshakeType::CLIENT_HELLO
|
61
|
+
|
62
|
+
binary.prefix_uint16_length
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param binary [String]
|
66
|
+
# @param msg_type [TTTLS13::Message::HandshakeType]
|
67
|
+
#
|
68
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
69
|
+
#
|
70
|
+
# @return [TTTLS13::Message::Extensions]
|
71
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
72
|
+
def self.deserialize(binary, msg_type)
|
73
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
74
|
+
|
75
|
+
extensions = []
|
76
|
+
i = 0
|
77
|
+
while i < binary.length
|
78
|
+
raise Error::ErrorAlerts, :decode_error if i + 4 > binary.length
|
79
|
+
|
80
|
+
extension_type = binary.slice(i, 2)
|
81
|
+
i += 2
|
82
|
+
ex_len = Convert.bin2i(binary.slice(i, 2))
|
83
|
+
i += 2
|
84
|
+
|
85
|
+
raise Error::ErrorAlerts, :decode_error if i + ex_len > binary.length
|
86
|
+
|
87
|
+
ex_bin = binary.slice(i, ex_len)
|
88
|
+
ex = deserialize_extension(ex_bin, extension_type, msg_type)
|
89
|
+
if ex.nil?
|
90
|
+
# ignore unparsable binary, but only transcript
|
91
|
+
ex = Extension::UnknownExtension.new(extension_type, ex_bin)
|
92
|
+
end
|
93
|
+
extensions << ex
|
94
|
+
i += ex_len
|
95
|
+
end
|
96
|
+
raise Error::ErrorAlerts, :decode_error unless i == binary.length
|
97
|
+
|
98
|
+
Extensions.new(extensions)
|
99
|
+
end
|
100
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
101
|
+
|
102
|
+
# @param key [TTTLS13::Message::ExtensionType]
|
103
|
+
#
|
104
|
+
# @return [TTTLS13::Message::Extension::$Object]
|
105
|
+
def [](key)
|
106
|
+
return nil if super_fetch(key, nil).is_a?(Extension::UnknownExtension)
|
107
|
+
|
108
|
+
super_fetch(key, nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param key [TTTLS13::Message::ExtensionType]
|
112
|
+
# @param default
|
113
|
+
#
|
114
|
+
# @return [TTTLS13::Message::Extension::$Object]
|
115
|
+
def fetch(key, default = nil)
|
116
|
+
return nil if super_fetch(key, nil).is_a?(Extension::UnknownExtension)
|
117
|
+
|
118
|
+
super_fetch(key, default)
|
119
|
+
end
|
120
|
+
|
121
|
+
class << self
|
122
|
+
private
|
123
|
+
|
124
|
+
# NOTE:
|
125
|
+
# deserialize_extension ignores unparsable extension.
|
126
|
+
# Received unparsable binary, returns nil, doesn't raise
|
127
|
+
# ErrorAlerts :decode_error.
|
128
|
+
#
|
129
|
+
# @param binary [String]
|
130
|
+
# @param extension_type [TTTLS13::Message::ExtensionType]
|
131
|
+
# @param msg_type [TTTLS13::Message::HandshakeType]
|
132
|
+
#
|
133
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
134
|
+
#
|
135
|
+
# @return [TTTLS13::Message::Extension::$Object, nil]
|
136
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
137
|
+
def deserialize_extension(binary, extension_type, msg_type)
|
138
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
139
|
+
|
140
|
+
case extension_type
|
141
|
+
when ExtensionType::SERVER_NAME
|
142
|
+
Extension::ServerName.deserialize(binary)
|
143
|
+
when ExtensionType::SUPPORTED_GROUPS
|
144
|
+
Extension::SupportedGroups.deserialize(binary)
|
145
|
+
when ExtensionType::SIGNATURE_ALGORITHMS
|
146
|
+
Extension::SignatureAlgorithms.deserialize(binary)
|
147
|
+
when ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION
|
148
|
+
Extension::Alpn..deserialize(binary)
|
149
|
+
when ExtensionType::RECORD_SIZE_LIMIT
|
150
|
+
Extension::RecordSizeLimit.deserialize(binary)
|
151
|
+
when ExtensionType::PRE_SHARED_KEY
|
152
|
+
Extension::PreSharedKey.deserialize(binary, msg_type)
|
153
|
+
when ExtensionType::EARLY_DATA
|
154
|
+
Extension::EarlyDataIndication.deserialize(binary, msg_type)
|
155
|
+
when ExtensionType::SUPPORTED_VERSIONS
|
156
|
+
Extension::SupportedVersions.deserialize(binary, msg_type)
|
157
|
+
when ExtensionType::COOKIE
|
158
|
+
Extension::Cookie.deserialize(binary)
|
159
|
+
when ExtensionType::PSK_KEY_EXCHANGE_MODES
|
160
|
+
Extension::PskKeyExchangeModes.deserialize(binary)
|
161
|
+
when ExtensionType::SIGNATURE_ALGORITHMS_CERT
|
162
|
+
Extension::SignatureAlgorithmsCert.deserialize(binary)
|
163
|
+
when ExtensionType::KEY_SHARE
|
164
|
+
Extension::KeyShare.deserialize(binary, msg_type)
|
165
|
+
else
|
166
|
+
Extension::UnknownExtension.deserialize(binary, extension_type)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
class Finished
|
8
|
+
attr_reader :msg_type
|
9
|
+
attr_reader :verify_data
|
10
|
+
|
11
|
+
# @param verify_data [String]
|
12
|
+
def initialize(verify_data)
|
13
|
+
@msg_type = HandshakeType::FINISHED
|
14
|
+
@verify_data = verify_data
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String]
|
18
|
+
def serialize
|
19
|
+
@msg_type + @verify_data.prefix_uint24_length
|
20
|
+
end
|
21
|
+
|
22
|
+
alias fragment serialize
|
23
|
+
|
24
|
+
# @param binary [String]
|
25
|
+
#
|
26
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
27
|
+
#
|
28
|
+
# @return [TTTLS13::Message::Finished]
|
29
|
+
def self.deserialize(binary)
|
30
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
31
|
+
raise Error::ErrorAlerts, :decode_error if binary.length < 4
|
32
|
+
raise Error::ErrorAlerts, :internal_error \
|
33
|
+
unless binary[0] == HandshakeType::FINISHED
|
34
|
+
|
35
|
+
msg_len = Convert.bin2i(binary.slice(1, 3))
|
36
|
+
verify_data = binary.slice(4, msg_len)
|
37
|
+
raise Error::ErrorAlerts, :decode_error \
|
38
|
+
unless msg_len + 4 == binary.length
|
39
|
+
|
40
|
+
Finished.new(verify_data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTTLS13
|
5
|
+
using Refinements
|
6
|
+
module Message
|
7
|
+
class NewSessionTicket
|
8
|
+
attr_reader :msg_type
|
9
|
+
attr_reader :ticket_lifetime
|
10
|
+
attr_reader :ticket_age_add
|
11
|
+
attr_reader :ticket_nonce
|
12
|
+
attr_reader :ticket
|
13
|
+
attr_reader :extensions
|
14
|
+
attr_reader :timestamp
|
15
|
+
|
16
|
+
# @param ticket_lifetime [Integer]
|
17
|
+
# @param ticket_age_add [String]
|
18
|
+
# @param ticket_nonce [String]
|
19
|
+
# @param ticket [String]
|
20
|
+
# @param extensions [TTTLS13::Message::Extensions]
|
21
|
+
#
|
22
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
23
|
+
def initialize(ticket_lifetime:, ticket_age_add:,
|
24
|
+
ticket_nonce:, ticket:, extensions: Extensions.new)
|
25
|
+
@msg_type = HandshakeType::NEW_SESSION_TICKET
|
26
|
+
@ticket_lifetime = ticket_lifetime
|
27
|
+
@ticket_age_add = ticket_age_add
|
28
|
+
raise Error::ErrorAlerts, :internal_error \
|
29
|
+
unless ticket_age_add.length == 4
|
30
|
+
|
31
|
+
@ticket_nonce = ticket_nonce
|
32
|
+
@ticket = ticket
|
33
|
+
@extensions = extensions || Extensions.new
|
34
|
+
@timestamp = Time.now.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
def serialize
|
39
|
+
binary = ''
|
40
|
+
binary += @ticket_lifetime.to_uint32
|
41
|
+
binary += @ticket_age_add
|
42
|
+
binary += @ticket_nonce.prefix_uint8_length
|
43
|
+
binary += @ticket.prefix_uint16_length
|
44
|
+
binary += @extensions.serialize
|
45
|
+
|
46
|
+
@msg_type + binary.prefix_uint24_length
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param binary [String]
|
50
|
+
#
|
51
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
52
|
+
#
|
53
|
+
# @return [TTTLS13::Message::NewSessionTicket]
|
54
|
+
# rubocop: disable Metrics/AbcSize
|
55
|
+
def self.deserialize(binary)
|
56
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
57
|
+
raise Error::ErrorAlerts, :decode_error if binary.length < 13
|
58
|
+
raise Error::ErrorAlerts, :internal_error \
|
59
|
+
unless binary[0] == HandshakeType::NEW_SESSION_TICKET
|
60
|
+
|
61
|
+
msg_len = Convert.bin2i(binary.slice(1, 3))
|
62
|
+
ticket_lifetime = Convert.bin2i(binary.slice(4, 4))
|
63
|
+
ticket_age_add = binary.slice(8, 4)
|
64
|
+
tn_len = Convert.bin2i(binary[12])
|
65
|
+
ticket_nonce = binary.slice(13, tn_len)
|
66
|
+
i = 13 + tn_len
|
67
|
+
ticket_len = Convert.bin2i(binary.slice(i, 2))
|
68
|
+
i += 2
|
69
|
+
ticket = binary.slice(i, ticket_len)
|
70
|
+
i += ticket_len
|
71
|
+
exs_len = Convert.bin2i(binary.slice(i, 2))
|
72
|
+
i += 2
|
73
|
+
exs_bin = binary.slice(i, exs_len)
|
74
|
+
extensions = Extensions.deserialize(exs_bin,
|
75
|
+
HandshakeType::NEW_SESSION_TICKET)
|
76
|
+
i += exs_len
|
77
|
+
raise Error::ErrorAlerts, :decode_error unless i == msg_len + 4 &&
|
78
|
+
i == binary.length
|
79
|
+
|
80
|
+
NewSessionTicket.new(ticket_lifetime: ticket_lifetime,
|
81
|
+
ticket_age_add: ticket_age_add,
|
82
|
+
ticket_nonce: ticket_nonce,
|
83
|
+
ticket: ticket,
|
84
|
+
extensions: extensions)
|
85
|
+
end
|
86
|
+
# rubocop: enable Metrics/AbcSize
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|