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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +16 -0
  5. data/.travis.yml +8 -0
  6. data/Gemfile +13 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +52 -0
  9. data/Rakefile +133 -0
  10. data/example/helper.rb +17 -0
  11. data/example/https_client.rb +32 -0
  12. data/example/https_client_using_0rtt.rb +64 -0
  13. data/example/https_client_using_hrr.rb +35 -0
  14. data/example/https_client_using_ticket.rb +56 -0
  15. data/lib/tttls1.3/cipher_suites.rb +102 -0
  16. data/lib/tttls1.3/client.rb +745 -0
  17. data/lib/tttls1.3/connection.rb +380 -0
  18. data/lib/tttls1.3/cryptograph/aead.rb +118 -0
  19. data/lib/tttls1.3/cryptograph/passer.rb +22 -0
  20. data/lib/tttls1.3/cryptograph.rb +3 -0
  21. data/lib/tttls1.3/error.rb +22 -0
  22. data/lib/tttls1.3/key_schedule.rb +242 -0
  23. data/lib/tttls1.3/message/alert.rb +86 -0
  24. data/lib/tttls1.3/message/application_data.rb +27 -0
  25. data/lib/tttls1.3/message/certificate.rb +121 -0
  26. data/lib/tttls1.3/message/certificate_verify.rb +59 -0
  27. data/lib/tttls1.3/message/change_cipher_spec.rb +26 -0
  28. data/lib/tttls1.3/message/client_hello.rb +100 -0
  29. data/lib/tttls1.3/message/encrypted_extensions.rb +65 -0
  30. data/lib/tttls1.3/message/end_of_early_data.rb +29 -0
  31. data/lib/tttls1.3/message/extension/alpn.rb +70 -0
  32. data/lib/tttls1.3/message/extension/cookie.rb +47 -0
  33. data/lib/tttls1.3/message/extension/early_data_indication.rb +58 -0
  34. data/lib/tttls1.3/message/extension/key_share.rb +236 -0
  35. data/lib/tttls1.3/message/extension/pre_shared_key.rb +205 -0
  36. data/lib/tttls1.3/message/extension/psk_key_exchange_modes.rb +54 -0
  37. data/lib/tttls1.3/message/extension/record_size_limit.rb +46 -0
  38. data/lib/tttls1.3/message/extension/server_name.rb +91 -0
  39. data/lib/tttls1.3/message/extension/signature_algorithms.rb +69 -0
  40. data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +25 -0
  41. data/lib/tttls1.3/message/extension/status_request.rb +106 -0
  42. data/lib/tttls1.3/message/extension/supported_groups.rb +145 -0
  43. data/lib/tttls1.3/message/extension/supported_versions.rb +98 -0
  44. data/lib/tttls1.3/message/extension/unknown_extension.rb +38 -0
  45. data/lib/tttls1.3/message/extensions.rb +173 -0
  46. data/lib/tttls1.3/message/finished.rb +44 -0
  47. data/lib/tttls1.3/message/new_session_ticket.rb +89 -0
  48. data/lib/tttls1.3/message/record.rb +232 -0
  49. data/lib/tttls1.3/message/server_hello.rb +116 -0
  50. data/lib/tttls1.3/message.rb +48 -0
  51. data/lib/tttls1.3/sequence_number.rb +31 -0
  52. data/lib/tttls1.3/signature_scheme.rb +31 -0
  53. data/lib/tttls1.3/transcript.rb +69 -0
  54. data/lib/tttls1.3/utils.rb +91 -0
  55. data/lib/tttls1.3/version.rb +5 -0
  56. data/lib/tttls1.3.rb +16 -0
  57. data/spec/aead_spec.rb +95 -0
  58. data/spec/alert_spec.rb +54 -0
  59. data/spec/alpn_spec.rb +55 -0
  60. data/spec/application_data_spec.rb +26 -0
  61. data/spec/certificate_spec.rb +55 -0
  62. data/spec/certificate_verify_spec.rb +51 -0
  63. data/spec/change_cipher_spec_spec.rb +26 -0
  64. data/spec/cipher_suites_spec.rb +39 -0
  65. data/spec/client_hello_spec.rb +83 -0
  66. data/spec/client_spec.rb +319 -0
  67. data/spec/connection_spec.rb +114 -0
  68. data/spec/cookie_spec.rb +98 -0
  69. data/spec/early_data_indication_spec.rb +64 -0
  70. data/spec/encrypted_extensions_spec.rb +94 -0
  71. data/spec/error_spec.rb +18 -0
  72. data/spec/extensions_spec.rb +170 -0
  73. data/spec/finished_spec.rb +55 -0
  74. data/spec/key_schedule_spec.rb +198 -0
  75. data/spec/key_share_spec.rb +199 -0
  76. data/spec/new_session_ticket_spec.rb +80 -0
  77. data/spec/pre_shared_key_spec.rb +167 -0
  78. data/spec/psk_key_exchange_modes_spec.rb +45 -0
  79. data/spec/record_size_limit_spec.rb +61 -0
  80. data/spec/record_spec.rb +105 -0
  81. data/spec/server_hello_spec.rb +101 -0
  82. data/spec/server_name_spec.rb +110 -0
  83. data/spec/signature_algorithms_cert_spec.rb +73 -0
  84. data/spec/signature_algorithms_spec.rb +100 -0
  85. data/spec/spec_helper.rb +872 -0
  86. data/spec/status_request_spec.rb +73 -0
  87. data/spec/supported_groups_spec.rb +79 -0
  88. data/spec/supported_versions_spec.rb +136 -0
  89. data/spec/transcript_spec.rb +69 -0
  90. data/spec/unknown_extension_spec.rb +90 -0
  91. data/spec/utils_spec.rb +215 -0
  92. data/tttls1.3.gemspec +25 -0
  93. 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