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,380 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ INITIAL = 0
6
+ EOF = -1
7
+
8
+ # rubocop: disable Metrics/ClassLength
9
+ class Connection
10
+ # @param socket [Socket]
11
+ def initialize(socket)
12
+ @socket = socket
13
+ @endpoint = nil # Symbol or String, :client or :server
14
+ @key_schedule = nil # TTTLS13::KeySchedule
15
+ @priv_keys = {} # Hash of NamedGroup => OpenSSL::PKey::$Object
16
+ @read_cipher = Cryptograph::Passer.new
17
+ @write_cipher = Cryptograph::Passer.new
18
+ @transcript = Transcript.new
19
+ @message_queue = [] # Array of TTTLS13::Message::$Object
20
+ @binary_buffer = '' # deposit Record.surplus_binary
21
+ @cipher_suite = nil # TTTLS13::CipherSuite
22
+ @notyet_application_secret = true
23
+ @state = 0 # ClientState or ServerState
24
+ @send_record_size = Message::DEFAULT_RECORD_SIZE_LIMIT
25
+ @psk = nil # String
26
+ end
27
+
28
+ # @raise [TTTLS13::Error::ConfigError]
29
+ #
30
+ # @return [String]
31
+ def read
32
+ # secure channel has not established yet
33
+ raise Error::ConfigError \
34
+ unless @endpoint == :client && @state == ClientState::CONNECTED
35
+ return '' if @state == EOF
36
+
37
+ message = nil
38
+ loop do
39
+ message = recv_message
40
+ # At any time after the server has received the client Finished
41
+ # message, it MAY send a NewSessionTicket message.
42
+ break unless message.is_a?(Message::NewSessionTicket)
43
+
44
+ process_new_session_ticket(message)
45
+ end
46
+ return '' if message.nil?
47
+
48
+ message.fragment
49
+ end
50
+
51
+ # @return [Boolean]
52
+ def eof?
53
+ @state == EOF
54
+ end
55
+
56
+ # @param binary [String]
57
+ #
58
+ # @raise [TTTLS13::Error::ConfigError]
59
+ def write(binary)
60
+ # secure channel has not established yet
61
+ raise Error::ConfigError \
62
+ unless @endpoint == :client && @state == ClientState::CONNECTED
63
+
64
+ ap = Message::ApplicationData.new(binary)
65
+ send_application_data(ap, @write_cipher)
66
+ end
67
+
68
+ def close
69
+ send_alert(:close_notify)
70
+ @state = EOF
71
+
72
+ nil
73
+ end
74
+
75
+ private
76
+
77
+ # @param cipher_suite [TTTLS13::CipherSuite]
78
+ # @param write_key [String]
79
+ # @param write_iv [String]
80
+ #
81
+ # @return [TTTLS13::Cryptograph::Aead]
82
+ def gen_cipher(cipher_suite, write_key, write_iv)
83
+ seq_num = SequenceNumber.new
84
+ Cryptograph::Aead.new(
85
+ cipher_suite: cipher_suite,
86
+ write_key: write_key,
87
+ write_iv: write_iv,
88
+ sequence_number: seq_num
89
+ )
90
+ end
91
+
92
+ # @param type [TTTLS13::Message::ContentType]
93
+ # @param messages [Array of TTTLS13::Message::$Object] handshake messages
94
+ # @param write_cipher [TTTLS13::Cryptograph::Aead]
95
+ def send_handshakes(type, messages, write_cipher)
96
+ record = Message::Record.new(
97
+ type: type,
98
+ messages: messages,
99
+ cipher: write_cipher
100
+ )
101
+ send_record(record)
102
+ end
103
+
104
+ def send_ccs
105
+ ccs_record = Message::Record.new(
106
+ type: Message::ContentType::CCS,
107
+ legacy_record_version: Message::ProtocolVersion::TLS_1_2,
108
+ messages: [Message::ChangeCipherSpec.new],
109
+ cipher: Cryptograph::Passer.new
110
+ )
111
+ send_record(ccs_record)
112
+ end
113
+
114
+ # @param message [TTTLS13::Message::ApplicationData]
115
+ # @param write_cipher [TTTLS13::Cryptograph::Aead]
116
+ def send_application_data(message, write_cipher)
117
+ ap_record = Message::Record.new(
118
+ type: Message::ContentType::APPLICATION_DATA,
119
+ legacy_record_version: Message::ProtocolVersion::TLS_1_2,
120
+ messages: [message],
121
+ cipher: write_cipher
122
+ )
123
+ send_record(ap_record)
124
+ end
125
+
126
+ # @param symbol [Symbol] key of ALERT_DESCRIPTION
127
+ def send_alert(symbol)
128
+ message = Message::Alert.new(
129
+ description: Message::ALERT_DESCRIPTION[symbol]
130
+ )
131
+ type = Message::ContentType::ALERT
132
+ type = Message::ContentType::APPLICATION_DATA \
133
+ if @write_cipher.is_a?(Cryptograph::Aead)
134
+ alert_record = Message::Record.new(
135
+ type: type,
136
+ legacy_record_version: Message::ProtocolVersion::TLS_1_2,
137
+ messages: [message],
138
+ cipher: @write_cipher
139
+ )
140
+ send_record(alert_record)
141
+ end
142
+
143
+ # @param record [TTTLS13::Message::Record]
144
+ def send_record(record)
145
+ @socket.write(record.serialize(@send_record_size))
146
+ end
147
+
148
+ # @raise [TTTLS13::Error::ErrorAlerts
149
+ #
150
+ # @return [TTTLS13::Message::$Object]
151
+ # rubocop: disable Metrics/CyclomaticComplexity
152
+ def recv_message
153
+ return @message_queue.shift unless @message_queue.empty?
154
+
155
+ messages = nil
156
+ loop do
157
+ record = recv_record
158
+ case record.type
159
+ when Message::ContentType::HANDSHAKE,
160
+ Message::ContentType::APPLICATION_DATA
161
+ messages = record.messages
162
+ break unless messages.empty?
163
+ when Message::ContentType::CCS
164
+ terminate(:unexpected_message) unless ccs_receivable?
165
+ next
166
+ when Message::ContentType::ALERT
167
+ handle_received_alert(record.messages.first)
168
+ return nil
169
+ else
170
+ terminate(:unexpected_message)
171
+ end
172
+ end
173
+
174
+ @message_queue += messages[1..]
175
+ message = messages.first
176
+ if message.is_a?(Message::Alert)
177
+ handle_received_alert(message)
178
+ return nil
179
+ end
180
+
181
+ message
182
+ end
183
+ # rubocop: enable Metrics/CyclomaticComplexity
184
+
185
+ # @return [TTTLS13::Message::Record]
186
+ def recv_record
187
+ binary = @socket.read(5)
188
+ record_len = Convert.bin2i(binary.slice(3, 2))
189
+ binary += @socket.read(record_len)
190
+
191
+ begin
192
+ buffer = @binary_buffer
193
+ record = Message::Record.deserialize(binary, @read_cipher, buffer)
194
+ @binary_buffer = record.surplus_binary
195
+ rescue Error::ErrorAlerts => e
196
+ terminate(e.message.to_sym)
197
+ end
198
+
199
+ # Received a protected ccs, peer MUST abort the handshake.
200
+ if record.type == Message::ContentType::APPLICATION_DATA &&
201
+ record.messages.first.is_a?(Message::ChangeCipherSpec)
202
+ terminate(:unexpected_message)
203
+ end
204
+
205
+ record
206
+ end
207
+
208
+ # @param digest [String] name of digest algorithm
209
+ #
210
+ # @return [String]
211
+ def do_sign_psk_binder(digest)
212
+ # TODO: ext binder
213
+ secret = @key_schedule.binder_key_res
214
+ hash_len = OpenSSL::Digest.new(digest).digest_length
215
+ # transcript-hash (CH1 + HRR +) truncated-CH
216
+ hash = @transcript.truncate_hash(digest, CH, hash_len + 3)
217
+ OpenSSL::HMAC.digest(digest, secret, hash)
218
+ end
219
+
220
+ # @param certificate_pem [String]
221
+ # @param signature_scheme [TTTLS13::SignatureScheme]
222
+ # @param signature [String]
223
+ # @param context [String]
224
+ # @param handshake_context_end [Integer]
225
+ #
226
+ # @raise [TTTLS13::Error::ErrorAlerts]
227
+ #
228
+ # @return [Boolean]
229
+ # rubocop: disable Metrics/CyclomaticComplexity
230
+ def do_verify_certificate_verify(certificate_pem:, signature_scheme:,
231
+ signature:, context:,
232
+ handshake_context_end:)
233
+ digest = CipherSuite.digest(@cipher_suite)
234
+ hash = @transcript.hash(digest, handshake_context_end)
235
+ content = "\x20" * 64 + context + "\x00" + hash
236
+ public_key = OpenSSL::X509::Certificate.new(certificate_pem).public_key
237
+
238
+ case signature_scheme
239
+ when SignatureScheme::RSA_PSS_RSAE_SHA256,
240
+ SignatureScheme::RSA_PSS_PSS_SHA256
241
+ public_key.verify_pss('SHA256', signature, content, salt_length: :auto,
242
+ mgf1_hash: 'SHA256')
243
+ when SignatureScheme::RSA_PSS_RSAE_SHA384,
244
+ SignatureScheme::RSA_PSS_PSS_SHA384
245
+ public_key.verify_pss('SHA384', signature, content, salt_length: :auto,
246
+ mgf1_hash: 'SHA384')
247
+ when SignatureScheme::RSA_PSS_RSAE_SHA512,
248
+ SignatureScheme::RSA_PSS_PSS_SHA512
249
+ public_key.verify_pss('SHA512', signature, content, salt_length: :auto,
250
+ mgf1_hash: 'SHA512')
251
+ when SignatureScheme::RSA_PKCS1_SHA256,
252
+ SignatureScheme::ECDSA_SECP256R1_SHA256
253
+ public_key.verify('SHA256', signature, content)
254
+ when SignatureScheme::RSA_PKCS1_SHA384,
255
+ SignatureScheme::ECDSA_SECP384R1_SHA384
256
+ public_key.verify('SHA384', signature, content)
257
+ when SignatureScheme::RSA_PKCS1_SHA512,
258
+ SignatureScheme::ECDSA_SECP521R1_SHA512
259
+ public_key.verify('SHA512', signature, content)
260
+ else # TODO: ED25519, ED448
261
+ terminate(:internal_error)
262
+ end
263
+ end
264
+ # rubocop: enable Metrics/CyclomaticComplexity
265
+
266
+ # @param digest [String] name of digest algorithm
267
+ # @param finished_key [String]
268
+ # @param handshake_context_end [Integer]
269
+ #
270
+ # @return [String]
271
+ def do_sign_finished(digest:, finished_key:, handshake_context_end:)
272
+ hash = @transcript.hash(digest, handshake_context_end)
273
+ OpenSSL::HMAC.digest(digest, finished_key, hash)
274
+ end
275
+
276
+ # @param digest [String] name of digest algorithm
277
+ # @param finished_key [String]
278
+ # @param handshake_context_end [Integer]
279
+ # @param signature [String]
280
+ #
281
+ # @return [Boolean]
282
+ def do_verify_finished(digest:, finished_key:, handshake_context_end:,
283
+ signature:)
284
+ do_sign_finished(
285
+ digest: digest,
286
+ finished_key: finished_key,
287
+ handshake_context_end: handshake_context_end
288
+ ) == signature
289
+ end
290
+
291
+ # @param key_exchange [String]
292
+ # @param priv_key [OpenSSL::PKey::$Object]
293
+ # @param group [TTTLS13::Message::ExtensionType::NamedGroup]
294
+ #
295
+ # @return [String]
296
+ def gen_shared_secret(key_exchange, priv_key, group)
297
+ curve = Message::Extension::NamedGroup.curve_name(group)
298
+ terminate(:internal_error) if curve.nil?
299
+
300
+ pub_key = OpenSSL::PKey::EC::Point.new(
301
+ OpenSSL::PKey::EC::Group.new(curve),
302
+ OpenSSL::BN.new(key_exchange, 2)
303
+ )
304
+
305
+ priv_key.dh_compute_key(pub_key)
306
+ end
307
+
308
+ # @return [Boolean]
309
+ #
310
+ # Received ccs before the first ClientHello message or after the peer's
311
+ # Finished message, peer MUST abort.
312
+ def ccs_receivable?
313
+ return false unless @transcript.include?(CH)
314
+ return false if @endpoint == :client && @transcript.include?(SF)
315
+ return false if @endpoint == :server && @transcript.include?(CF)
316
+
317
+ true
318
+ end
319
+
320
+ # @param symbol [Symbol] key of ALERT_DESCRIPTION
321
+ #
322
+ # @raise [TTTLS13::Error::ErrorAlerts]
323
+ def terminate(symbol)
324
+ send_alert(symbol)
325
+ raise Error::ErrorAlerts, symbol
326
+ end
327
+
328
+ def handle_received_alert(alert)
329
+ unless alert.description == Message::ALERT_DESCRIPTION[:close_notify] ||
330
+ alert.description == Message::ALERT_DESCRIPTION[:user_canceled]
331
+ raise alert.to_error
332
+ end
333
+
334
+ @state = EOF
335
+ end
336
+
337
+ # @param _nst [TTTLS13::Message::NewSessionTicket]
338
+ #
339
+ # @raise [TTTLS13::Error::ErrorAlerts]
340
+ def process_new_session_ticket(_nst)
341
+ terminate(:unexpected_message) if @endpoint == :server
342
+ end
343
+
344
+ # @param certificate_list [Array of CertificateEntry]
345
+ # @param ca_file [String] path to ca.crt
346
+ # @param hostname [String]
347
+ #
348
+ # @return [Boolean]
349
+ # rubocop: disable Metrics/AbcSize
350
+ def certified_certificate?(certificate_list, ca_file = nil, hostname = nil)
351
+ store = OpenSSL::X509::Store.new
352
+ store.set_default_paths
353
+ store.add_file(ca_file) unless ca_file.nil?
354
+
355
+ cert_bin = certificate_list.first.cert_data
356
+ cert = OpenSSL::X509::Certificate.new(cert_bin)
357
+
358
+ chain = certificate_list[1..].map(&:cert_data).map do |c|
359
+ OpenSSL::X509::Certificate.new(c)
360
+ end
361
+ # TODO: parse authorityInfoAccess::CA Issuers
362
+
363
+ ctx = OpenSSL::X509::StoreContext.new(store, cert, chain)
364
+
365
+ # not support CN matching, only support SAN matching
366
+ unless hostname.nil?
367
+ san = cert.extensions.find { |ex| ex.oid == 'subjectAltName' }
368
+ terminate(:bad_certificate) if san.nil?
369
+ ostr = OpenSSL::ASN1.decode(san.to_der).value.last
370
+ san_match = OpenSSL::ASN1.decode(ostr.value).map(&:value)
371
+ .map { |s| s.gsub('.', '\.').gsub('*', '.*') }
372
+ .any? { |s| hostname.match(/#{s}/) }
373
+ return san_match && ctx.verify
374
+ end
375
+ ctx.verify
376
+ end
377
+ # rubocop: enable Metrics/AbcSize
378
+ end
379
+ # rubocop: enable Metrics/ClassLength
380
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module Cryptograph
7
+ class Aead
8
+ # @param cipher_suite [TTTLS13::CipherSuite]
9
+ # @param write_key [String]
10
+ # @param write_iv [String]
11
+ # @param sequence_number [String] uint64
12
+ # @param length_of_padding [Integer]
13
+ def initialize(cipher_suite:, write_key:, write_iv:,
14
+ sequence_number:, length_of_padding: 0)
15
+ @cipher_suite = cipher_suite
16
+ case cipher_suite
17
+ when CipherSuite::TLS_AES_128_GCM_SHA256
18
+ @cipher = OpenSSL::Cipher::AES128.new(:GCM)
19
+ when CipherSuite::TLS_AES_256_GCM_SHA384
20
+ @cipher = OpenSSL::Cipher::AES256.new(:GCM)
21
+ when CipherSuite::TLS_CHACHA20_POLY1305_SHA256
22
+ @cipher = OpenSSL::Cipher.new('chacha20-poly1305')
23
+ else
24
+ # Note:
25
+ # not supported
26
+ # CipherSuite::TLS_AES_128_CCM_SHA256
27
+ # CipherSuite::TLS_AES_128_CCM_8_SHA256
28
+ raise Error::ErrorAlerts, :internal_error
29
+ end
30
+ @write_key = write_key
31
+ @write_iv = write_iv
32
+ @sequence_number = sequence_number
33
+ @length_of_padding = length_of_padding
34
+ end
35
+
36
+ # AEAD-Encrypt(write_key, nonce, additional_data, plaintext)
37
+ #
38
+ # @param content [String]
39
+ # @param type [TTTLS13::Message::ContentType]
40
+ #
41
+ # @return [String]
42
+ def encrypt(content, type)
43
+ reset_cipher
44
+ cipher = @cipher.encrypt
45
+ plaintext = content + type + "\x00" * @length_of_padding
46
+ cipher.auth_data = additional_data(plaintext.length)
47
+ encrypted_data = cipher.update(plaintext) + cipher.final
48
+ @sequence_number.succ
49
+
50
+ encrypted_data + cipher.auth_tag
51
+ end
52
+
53
+ # AEAD-Decrypt(peer_write_key, nonce,
54
+ # additional_data, AEADEncrypted)
55
+ #
56
+ # @param encrypted_record [String]
57
+ # @param auth_data [String]
58
+ #
59
+ # @raise [OpenSSL::Cipher::CipherError]
60
+ #
61
+ # @return [String and TTTLS13::Message::ContentType]
62
+ def decrypt(encrypted_record, auth_data)
63
+ reset_cipher
64
+ decipher = @cipher.decrypt
65
+ auth_tag = encrypted_record[-16..-1]
66
+ decipher.auth_tag = auth_tag
67
+ decipher.auth_data = auth_data # record header of TLSCiphertext
68
+ clear = decipher.update(encrypted_record[0...-16]) # auth_tag
69
+ decipher.final
70
+ zeros_len = scan_zeros(clear)
71
+ postfix_len = 1 + zeros_len # type || zeros
72
+ @sequence_number.succ
73
+
74
+ [clear[0...-postfix_len], clear[-postfix_len]]
75
+ end
76
+
77
+ # NOTE:
78
+ # struct {
79
+ # opaque content[TLSPlaintext.length];
80
+ # ContentType type;
81
+ # uint8 zeros[length_of_padding];
82
+ # } TLSInnerPlaintext;
83
+ #
84
+ # @param record_size_limit [Integer]
85
+ #
86
+ # @return [Integer]
87
+ def tlsplaintext_length_limit(record_size_limit)
88
+ record_size_limit - 1 - @length_of_padding
89
+ end
90
+
91
+ private
92
+
93
+ # @return [String]
94
+ def additional_data(plaintext_len)
95
+ ciphertext_len = plaintext_len + 16 # length of auth_tag is 16
96
+ Message::ContentType::APPLICATION_DATA \
97
+ + Message::ProtocolVersion::TLS_1_2 \
98
+ + ciphertext_len.to_uint16
99
+ end
100
+
101
+ def reset_cipher
102
+ @cipher.reset
103
+ @cipher.key = @write_key
104
+ iv_len = CipherSuite.iv_len(@cipher_suite)
105
+ @cipher.iv = @sequence_number.xor(@write_iv, iv_len)
106
+ end
107
+
108
+ # @param [String]
109
+ #
110
+ # @return [Integer]
111
+ def scan_zeros(clear)
112
+ i = 0
113
+ i += 1 while clear[-i] == "\x00"
114
+ i
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ module Cryptograph
6
+ class Passer
7
+ # @param content [String]
8
+ #
9
+ # @return [String]
10
+ def encrypt(content, _type)
11
+ content
12
+ end
13
+
14
+ # @param encrypted_record [String]
15
+ #
16
+ # @return [String and TTTLS13::Message::ContentType]
17
+ def decrypt(encrypted_record, _auth_data)
18
+ [encrypted_record, encrypted_record[0]]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.dirname(__FILE__) + '/cryptograph/*.rb'].each { |f| require f }
@@ -0,0 +1,22 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ module Error
6
+ # Generic error, common for all classes under TTTLS13::Error module.
7
+ class Error < StandardError; end
8
+
9
+ # Raised if configure is invalid.
10
+ class ConfigError < Error; end
11
+
12
+ # Raised on received Error Alerts message or invalid message.
13
+ # https://tools.ietf.org/html/rfc8446#section-6.2
14
+ # Terminated the connection, so you *cannot* recover from this exception.
15
+ class ErrorAlerts < Error
16
+ # @return [TTTLS13::Message::Alert]
17
+ def to_alert
18
+ Message::Alert.new(description: ALERT_DESCRIPTION[message.to_sym])
19
+ end
20
+ end
21
+ end
22
+ end