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,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