tttls1.3 0.1.0

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