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,205 @@
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
+ # struct {
10
+ # select (Handshake.msg_type) {
11
+ # case client_hello: OfferedPsks;
12
+ # case server_hello: uint16 selected_identity;
13
+ # };
14
+ # } PreSharedKeyExtension;
15
+ class PreSharedKey
16
+ attr_reader :extension_type
17
+ attr_reader :msg_type
18
+ attr_reader :offered_psks
19
+ attr_reader :selected_identity
20
+
21
+ # @param msg_type [TTTLS13::Message::ContentType]
22
+ # @param offered_psks [TTTLS13::Message::Extension::OfferedPsks]
23
+ # @param selected_identity [String]
24
+ #
25
+ # @raise [TTTLS13::Error::ErrorAlerts]
26
+ def initialize(msg_type:, offered_psks: nil, selected_identity: '')
27
+ @extension_type = ExtensionType::PRE_SHARED_KEY
28
+ @msg_type = msg_type
29
+ case @msg_type
30
+ when HandshakeType::CLIENT_HELLO
31
+ @offered_psks = offered_psks
32
+ when HandshakeType::SERVER_HELLO
33
+ @selected_identity = selected_identity || ''
34
+ raise Error::ErrorAlerts, :internal_error \
35
+ unless @selected_identity.length == 2
36
+ else
37
+ raise Error::ErrorAlerts, :internal_error
38
+ end
39
+ end
40
+
41
+ # @raise [TTTLS13::Error::ErrorAlerts]
42
+ #
43
+ # @return [String]
44
+ def serialize
45
+ binary = ''
46
+ case @msg_type
47
+ when HandshakeType::CLIENT_HELLO
48
+ binary += @offered_psks.serialize
49
+ when HandshakeType::SERVER_HELLO
50
+ binary += @selected_identity
51
+ else
52
+ raise Error::ErrorAlerts, :internal_error
53
+ end
54
+
55
+ @extension_type + binary.prefix_uint16_length
56
+ end
57
+
58
+ # @param binary [String]
59
+ # @param msg_type [TTTLS13::Message::ContentType]
60
+ #
61
+ # @raise [TTTLS13::Error::ErrorAlerts]
62
+ #
63
+ # @return [TTTLS13::Message::Extensions::PreSharedKey, nil]
64
+ def self.deserialize(binary, msg_type)
65
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
66
+
67
+ case msg_type
68
+ when HandshakeType::CLIENT_HELLO
69
+ offered_psks = OfferedPsks.deserialize(binary)
70
+ return nil if offered_psks.nil?
71
+
72
+ PreSharedKey.new(msg_type: HandshakeType::CLIENT_HELLO,
73
+ offered_psks: offered_psks)
74
+ when HandshakeType::SERVER_HELLO
75
+ return nil unless binary.length == 2
76
+
77
+ selected_identity = binary
78
+ PreSharedKey.new(msg_type: HandshakeType::SERVER_HELLO,
79
+ selected_identity: selected_identity)
80
+ else
81
+ raise Error::ErrorAlerts, :internal_error
82
+ end
83
+ end
84
+ end
85
+
86
+ # NOTE:
87
+ # opaque PskBinderEntry<32..255>;
88
+ #
89
+ # struct {
90
+ # PskIdentity identities<7..2^16-1>;
91
+ # PskBinderEntry binders<33..2^16-1>;
92
+ # } OfferedPsks;
93
+ class OfferedPsks
94
+ attr_reader :identities
95
+ attr_reader :binders
96
+
97
+ # @param identities [Array of PskIdentity]
98
+ # @param binders [Array of String]
99
+ #
100
+ # @raise [TTTLS13::Error::ErrorAlerts]
101
+ def initialize(identities: [], binders: [])
102
+ @identities = identities || []
103
+ @binders = binders || []
104
+ raise Error::ErrorAlerts, :internal_error \
105
+ if @identities.empty? || @binders.empty?
106
+ end
107
+
108
+ # @return [String]
109
+ def serialize
110
+ binary = @identities.map(&:serialize).join
111
+ identities_bin = binary.prefix_uint16_length
112
+
113
+ binary = @binders.map(&:prefix_uint8_length).join
114
+ binders_bin = binary.prefix_uint16_length
115
+
116
+ identities_bin + binders_bin
117
+ end
118
+
119
+ # @param binary [String]
120
+ #
121
+ # @return [TTTLS13::Message::Extensions::OfferedPsks, nil]
122
+ # rubocop: disable Metrics/AbcSize
123
+ # rubocop: disable Metrics/CyclomaticComplexity
124
+ # rubocop: disable Metrics/MethodLength
125
+ # rubocop: disable Metrics/PerceivedComplexity
126
+ def self.deserialize(binary)
127
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
128
+ return nil if binary.length < 2
129
+
130
+ pskids_len = Convert.bin2i(binary.slice(0, 2))
131
+ i = 2
132
+ identities = [] # Array of PskIdentity
133
+ while i < pskids_len + 2
134
+ return nil if i + 2 > binary.length
135
+
136
+ id_len = Convert.bin2i(binary.slice(i, 2))
137
+ return nil if id_len.zero?
138
+
139
+ i += 2
140
+ identity = binary.slice(i, id_len)
141
+ i += id_len
142
+
143
+ return nil if i + 4 > binary.length
144
+
145
+ obfuscated_ticket_age = Convert.bin2i(binary.slice(i, 4))
146
+ i += 4
147
+ identities << PskIdentity.new(
148
+ identity: identity,
149
+ obfuscated_ticket_age: obfuscated_ticket_age
150
+ )
151
+ end
152
+
153
+ i += 2
154
+ binders = [] # Array of String
155
+ while i < binary.length
156
+ return nil if i > binary.length
157
+
158
+ pbe_len = Convert.bin2i(binary[i])
159
+ return nil if pbe_len < 32
160
+
161
+ i += 1
162
+ binders << binary.slice(i, pbe_len)
163
+ i += pbe_len
164
+ end
165
+ return nil unless i == binary.length
166
+
167
+ OfferedPsks.new(identities: identities, binders: binders)
168
+ end
169
+ # rubocop: enable Metrics/AbcSize
170
+ # rubocop: enable Metrics/CyclomaticComplexity
171
+ # rubocop: enable Metrics/MethodLength
172
+ # rubocop: enable Metrics/PerceivedComplexity
173
+ end
174
+
175
+ # NOTE:
176
+ # struct {
177
+ # opaque identity<1..2^16-1>;
178
+ # uint32 obfuscated_ticket_age;
179
+ # } PskIdentity;
180
+ class PskIdentity
181
+ attr_reader :identity
182
+ attr_reader :obfuscated_ticket_age
183
+
184
+ # @param identity [String]
185
+ # @param obfuscated_ticket_age [Integer]
186
+ #
187
+ # @raise [TTTLS13::Error::ErrorAlerts]
188
+ def initialize(identity: '', obfuscated_ticket_age: 0)
189
+ @identity = identity || ''
190
+ @obfuscated_ticket_age = obfuscated_ticket_age
191
+ raise Error::ErrorAlerts, :internal_error \
192
+ if @identity.empty? || @obfuscated_ticket_age.negative?
193
+ end
194
+
195
+ # @return [String]
196
+ def serialize
197
+ binary = ''
198
+ binary += @identity.prefix_uint16_length
199
+ binary += @obfuscated_ticket_age.to_uint32
200
+ binary
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Message
7
+ module Extension
8
+ module PskKeyExchangeMode
9
+ PSK_KE = "\x00"
10
+ PSK_DHE_KE = "\x01"
11
+ end
12
+
13
+ class PskKeyExchangeModes
14
+ attr_reader :extension_type
15
+ attr_reader :ke_modes
16
+
17
+ # @param ke_modes [Array of PskKeyExchangeMode]
18
+ def initialize(ke_modes = [])
19
+ @extension_type = ExtensionType::PSK_KEY_EXCHANGE_MODES
20
+ @ke_modes = ke_modes || []
21
+ end
22
+
23
+ # @return [String]
24
+ def serialize
25
+ binary = @ke_modes.join.prefix_uint8_length
26
+
27
+ @extension_type + binary.prefix_uint16_length
28
+ end
29
+
30
+ # @param binary [String]
31
+ #
32
+ # @raise [TTTLS13::Error::ErrorAlerts]
33
+ #
34
+ # @return [TTTLS13::Message::Extensions::PskKeyExchangeModes, nil]
35
+ def self.deserialize(binary)
36
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
37
+
38
+ return nil if binary.empty?
39
+
40
+ kem_len = Convert.bin2i(binary[0])
41
+ ke_modes = []
42
+ i = 1
43
+ while i < kem_len + 1
44
+ ke_modes << binary[i]
45
+ i += 1
46
+ end
47
+ return nil unless kem_len + 1 == binary.length
48
+
49
+ PskKeyExchangeModes.new(ke_modes)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Message
7
+ module Extension
8
+ class RecordSizeLimit
9
+ attr_reader :extension_type
10
+ attr_reader :record_size_limit
11
+
12
+ # @param record_size_limit [Integer]
13
+ #
14
+ # @raise [TTTLS13::Error::ErrorAlerts]
15
+ def initialize(record_size_limit)
16
+ @extension_type = ExtensionType::RECORD_SIZE_LIMIT
17
+ @record_size_limit = record_size_limit
18
+ raise Error::ErrorAlerts, :internal_error if @record_size_limit < 64
19
+ end
20
+
21
+ # @return [String]
22
+ def serialize
23
+ binary = @record_size_limit.to_uint16
24
+
25
+ @extension_type + binary.prefix_uint16_length
26
+ end
27
+
28
+ # @param binary [String]
29
+ #
30
+ # @raise [TTTLS13::Error::ErrorAlerts]
31
+ #
32
+ # @return [TTTLS13::Message::Extensions::RecordSizeLimit, nil]
33
+ def self.deserialize(binary)
34
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
35
+
36
+ return nil if binary.length != 2
37
+
38
+ record_size_limit = Convert.bin2i(binary)
39
+ raise Error::ErrorAlerts, :illegal_parameter if record_size_limit < 64
40
+
41
+ RecordSizeLimit.new(record_size_limit)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Message
7
+ module Extension
8
+ module NameType
9
+ HOST_NAME = "\x00"
10
+ end
11
+
12
+ # NOTE:
13
+ # The extension_data field SHALL be empty when @server_name is empty.
14
+ # Then, serialized extension_data is
15
+ #
16
+ # 00 00 00 00
17
+ #
18
+ # https://tools.ietf.org/html/rfc6066#section-3
19
+ class ServerName
20
+ attr_reader :extension_type
21
+ attr_reader :server_name
22
+
23
+ # @param server_name [String]
24
+ #
25
+ # @raise [TTTLS13::Error::ErrorAlerts]
26
+ #
27
+ # @example
28
+ # ServerName.new('example.com')
29
+ def initialize(server_name)
30
+ @extension_type = ExtensionType::SERVER_NAME
31
+ @server_name = server_name || ''
32
+ raise Error::ErrorAlerts, :internal_error \
33
+ if @server_name.length > 2**16 - 5
34
+ end
35
+
36
+ # @return [String]
37
+ def serialize
38
+ return "\x00\x00\x00\x00" if @server_name.empty?
39
+
40
+ sn_len = @server_name.length
41
+ binary = ''
42
+ binary += @extension_type
43
+ binary += (sn_len + 5).to_uint16
44
+ binary += (sn_len + 3).to_uint16
45
+ binary += NameType::HOST_NAME
46
+ binary += sn_len.to_uint16
47
+ binary += @server_name
48
+ binary
49
+ end
50
+
51
+ # @param binary [String]
52
+ #
53
+ # @raise [TTTLS13::Error::ErrorAlerts]
54
+ #
55
+ # @return [TTTLS13::Message::Extension::ServerName, nil]
56
+ def self.deserialize(binary)
57
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
58
+
59
+ return nil if binary.length == 1
60
+ return ServerName.new('') if binary.empty?
61
+
62
+ deserialize_host_name(binary)
63
+ end
64
+
65
+ class << self
66
+ private
67
+
68
+ # @param binary [String]
69
+ #
70
+ # @raise [TTTLS13::Error::ErrorAlerts]
71
+ #
72
+ # @return [TTTLS13::Message::Extension::ServerName, nil]
73
+ def deserialize_host_name(binary)
74
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
75
+
76
+ return nil unless binary.length > 5 &&
77
+ binary[2] == NameType::HOST_NAME
78
+
79
+ snlist_len = Convert.bin2i(binary.slice(0, 2))
80
+ sn_len = Convert.bin2i(binary.slice(3, 2))
81
+ server_name = binary.slice(5, sn_len)
82
+ return nil unless snlist_len + 2 == binary.length &&
83
+ sn_len + 5 == binary.length
84
+
85
+ ServerName.new(server_name)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Message
7
+ module Extension
8
+ class SignatureAlgorithms
9
+ DEFAULT_SIGNATURE_ALGORITHMS = [
10
+ SignatureScheme::ECDSA_SECP256R1_SHA256,
11
+ SignatureScheme::ECDSA_SECP384R1_SHA384,
12
+ SignatureScheme::ECDSA_SECP521R1_SHA512,
13
+ SignatureScheme::RSA_PSS_PSS_SHA256,
14
+ SignatureScheme::RSA_PSS_PSS_SHA384,
15
+ SignatureScheme::RSA_PSS_PSS_SHA512,
16
+ SignatureScheme::RSA_PSS_RSAE_SHA256,
17
+ SignatureScheme::RSA_PSS_RSAE_SHA384,
18
+ SignatureScheme::RSA_PSS_RSAE_SHA512,
19
+ SignatureScheme::RSA_PKCS1_SHA256,
20
+ SignatureScheme::RSA_PKCS1_SHA384,
21
+ SignatureScheme::RSA_PKCS1_SHA512
22
+ ].freeze
23
+
24
+ attr_accessor :extension_type # for signature_algorithms_cert getter
25
+ attr_reader :supported_signature_algorithms
26
+
27
+ # @param supported_signature_algorithms [Array of SignatureScheme]
28
+ def initialize(supported_signature_algorithms)
29
+ @extension_type = ExtensionType::SIGNATURE_ALGORITHMS
30
+ @supported_signature_algorithms = supported_signature_algorithms || []
31
+ raise Error::ErrorAlerts, :internal_error \
32
+ if @supported_signature_algorithms.empty? ||
33
+ @supported_signature_algorithms.length * 2 > 2**16 - 3
34
+ end
35
+
36
+ # @return [String]
37
+ def serialize
38
+ binary = @supported_signature_algorithms.join
39
+
40
+ @extension_type + binary.prefix_uint16_length.prefix_uint16_length
41
+ end
42
+
43
+ # @param binary [String]
44
+ #
45
+ # @raise [TTTLS13::Error::ErrorAlerts]
46
+ #
47
+ # @return [TTTLS13::Message::Extensions::SignatureAlgorithms, nil]
48
+ def self.deserialize(binary)
49
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
50
+
51
+ return nil if binary.length < 2
52
+
53
+ ssa_len = Convert.bin2i(binary.slice(0, 2))
54
+ i = 2
55
+ supported_signature_algorithms = []
56
+ while i < ssa_len + 2
57
+ return nil if i + 2 > binary.length
58
+
59
+ supported_signature_algorithms << binary.slice(i, 2)
60
+ i += 2
61
+ end
62
+ return nil unless ssa_len + 2 == binary.length
63
+
64
+ SignatureAlgorithms.new(supported_signature_algorithms)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ module Message
6
+ module Extension
7
+ class SignatureAlgorithmsCert < SignatureAlgorithms
8
+ # @param versions [Array of SignatureScheme]
9
+ def initialize(supported_signature_algorithms)
10
+ super(supported_signature_algorithms)
11
+ @extension_type = ExtensionType::SIGNATURE_ALGORITHMS_CERT
12
+ end
13
+
14
+ # @param binary [String]
15
+ #
16
+ # @return [TTTLS13::Message::Extensions::SignatureAlgorithmsCert]
17
+ def self.deserialize(binary)
18
+ extension = SignatureAlgorithms.deserialize(binary)
19
+ extension.extension_type = ExtensionType::SIGNATURE_ALGORITHMS_CERT
20
+ extension
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,106 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Message
7
+ module Extension
8
+ module CertificateStatusType
9
+ OCSP = "\x01"
10
+ end
11
+
12
+ class StatusRequest
13
+ attr_reader :extension_type
14
+ attr_reader :responder_id_list
15
+ attr_reader :request_extensions
16
+
17
+ # @param responder_id_list [Array of String]
18
+ # @param request_extensions [String]
19
+ #
20
+ # @example
21
+ # StatusRequest.new(
22
+ # responder_id_list: [],
23
+ # request_extensions: []
24
+ # )
25
+ def initialize(responder_id_list: [], request_extensions: '')
26
+ @extension_type = ExtensionType::STATUS_REQUEST
27
+ @responder_id_list = responder_id_list || []
28
+ @request_extensions = request_extensions || ''
29
+ end
30
+
31
+ # @return [String]
32
+ def serialize
33
+ binary = ''
34
+ binary += CertificateStatusType::OCSP
35
+ binary += @responder_id_list.length.to_uint16
36
+ binary += @responder_id_list.map do |id|
37
+ id.length.to_uint16 + id
38
+ end.join
39
+ binary += @request_extensions.prefix_uint16_length
40
+
41
+ @extension_type + binary.prefix_uint16_length
42
+ end
43
+
44
+ # @param binary [String]
45
+ #
46
+ # @raise [TTTLS13::Error::ErrorAlerts]
47
+ #
48
+ # @return [TTTLS13::Message::Extension::StatusRequest, nil]
49
+ # rubocop: disable Metrics/CyclomaticComplexity
50
+ def self.deserialize(binary)
51
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
52
+ return nil if binary.length < 5 ||
53
+ binary[0] != CertificateStatusType::OCSP
54
+
55
+ ril_len = Convert.bin2i(binary.slice(1, 2))
56
+ i = 3
57
+ responder_id_list =
58
+ deserialize_request_ids(binary.slice(i, ril_len))
59
+ # unparsable responder_id_list
60
+ return nil if responder_id_list.nil?
61
+
62
+ i += ril_len
63
+ return nil if i + 2 > binary.length
64
+
65
+ re_len = Convert.bin2i(binary.slice(i, 2))
66
+ i += 2
67
+ request_extensions = binary.slice(i, re_len)
68
+ i += re_len
69
+ return nil unless i == binary.length
70
+
71
+ StatusRequest.new(responder_id_list: responder_id_list,
72
+ request_extensions: request_extensions)
73
+ end
74
+ # rubocop: enable Metrics/CyclomaticComplexity
75
+
76
+ class << self
77
+ private
78
+
79
+ # @param binary [String]
80
+ #
81
+ # @raise [TTTLS13::Error::ErrorAlerts]
82
+ #
83
+ # @return [Array of String, nil] received unparsable binary, nil
84
+ def deserialize_request_ids(binary)
85
+ raise Error::ErrorAlerts, :internal_error if binary.nil?
86
+
87
+ i = 0
88
+ request_ids = []
89
+ while i < binary.length
90
+ return nil if i + 2 > binary.length
91
+
92
+ id_len = Convert.bin2i(binary.slice(i, 2))
93
+ i += 2
94
+ id = binary.slice(i, id_len)
95
+ request_ids += id
96
+ i += id_len
97
+ end
98
+ return nil if i != binary.length
99
+
100
+ request_ids
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end