tttls1.3 0.2.1 → 0.2.2

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.
@@ -3,6 +3,7 @@
3
3
 
4
4
  module TTTLS13
5
5
  using Refinements
6
+
6
7
  module ServerState
7
8
  # initial value is 0, eof value is -1
8
9
  START = 1
@@ -124,35 +125,48 @@ module TTTLS13
124
125
  # rubocop: disable Metrics/MethodLength
125
126
  # rubocop: disable Metrics/PerceivedComplexity
126
127
  def accept
128
+ transcript = Transcript.new
129
+ key_schedule = nil # TTTLS13::KeySchedule
130
+ priv_key = nil # OpenSSL::PKey::$Object
131
+
132
+ hs_wcipher = nil # TTTLS13::Cryptograph::$Object
133
+ hs_rcipher = nil # TTTLS13::Cryptograph::$Object
134
+
127
135
  @state = ServerState::START
128
136
  loop do
129
137
  case @state
130
138
  when ServerState::START
131
139
  logger.debug('ServerState::START')
132
140
 
133
- ch = @transcript[CH] = recv_client_hello
134
- terminate(:illegal_parameter) unless ch.only_appearable_extensions?
141
+ receivable_ccs = transcript.include?(CH1)
142
+ ch = transcript[CH] = recv_client_hello(receivable_ccs)
143
+
144
+ # support only TLS 1.3
145
+ terminate(:protocol_version) unless ch.negotiated_tls_1_3?
146
+
147
+ # validate parameters
148
+ terminate(:illegal_parameter) unless ch.appearable_extensions?
149
+ terminamte(:illegal_parameter) \
150
+ unless ch.legacy_compression_methods == ["\x00"]
151
+ terminate(:illegal_parameter) unless ch.valid_key_share?
152
+ terminate(:unrecognized_name) unless recognized_server_name?(ch, @crt)
153
+
135
154
  @state = ServerState::RECVD_CH
136
155
  when ServerState::RECVD_CH
137
156
  logger.debug('ServerState::RECVD_CH')
138
157
 
139
- # support only TLS 1.3
140
- terminate(:protocol_version) unless negotiated_tls_1_3?
141
-
142
- # validate/select parameters
143
- terminamte(:illegal_parameter) unless valid_ch_compression_methods?
144
- terminate(:illegal_parameter) unless valid_ch_key_share?
145
- terminate(:unrecognized_name) unless recognized_server_name?
146
- @cipher_suite = select_cipher_suite
147
- @named_group = select_named_group
148
- @signature_scheme = select_signature_scheme
158
+ # select parameters
159
+ ch = transcript[CH]
160
+ @cipher_suite = select_cipher_suite(ch)
161
+ @named_group = select_named_group(ch)
162
+ @signature_scheme = select_signature_scheme(ch, @crt)
149
163
  terminate(:handshake_failure) \
150
164
  if @cipher_suite.nil? || @signature_scheme.nil?
151
165
 
152
166
  # send HRR
153
167
  if @named_group.nil?
154
- @transcript[CH1] = @transcript.delete(CH)
155
- @transcript[HRR] = send_hello_retry_request
168
+ ch1 = transcript[CH1] = transcript.delete(CH)
169
+ transcript[HRR] = send_hello_retry_request(ch1, @cipher_suite)
156
170
  @state = ServerState::START
157
171
  next
158
172
  end
@@ -160,38 +174,58 @@ module TTTLS13
160
174
  when ServerState::NEGOTIATED
161
175
  logger.debug('ServerState::NEGOTIATED')
162
176
 
163
- exs, @priv_key = gen_sh_extensions
164
- @transcript[SH] = send_server_hello(exs)
177
+ ch = transcript[CH]
178
+ extensions, priv_key = gen_sh_extensions(@named_group)
179
+ transcript[SH] = send_server_hello(extensions, @cipher_suite,
180
+ ch.legacy_session_id)
165
181
  send_ccs # compatibility mode
166
182
 
167
183
  # generate shared secret
168
- ke = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
169
- &.key_share_entry
170
- &.find { |e| e.group == @named_group }
171
- &.key_exchange
172
- shared_secret = gen_shared_secret(ke, @priv_key, @named_group)
173
- @key_schedule = KeySchedule.new(psk: @psk,
174
- shared_secret: shared_secret,
175
- cipher_suite: @cipher_suite,
176
- transcript: @transcript)
177
- @write_cipher = gen_cipher(@cipher_suite,
178
- @key_schedule.server_handshake_write_key,
179
- @key_schedule.server_handshake_write_iv)
180
- @read_cipher = gen_cipher(@cipher_suite,
181
- @key_schedule.client_handshake_write_key,
182
- @key_schedule.client_handshake_write_iv)
184
+ ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
185
+ &.key_share_entry
186
+ &.find { |e| e.group == @named_group }
187
+ &.key_exchange
188
+ shared_secret = gen_shared_secret(ke, priv_key, @named_group)
189
+ key_schedule = KeySchedule.new(
190
+ psk: @psk,
191
+ shared_secret: shared_secret,
192
+ cipher_suite: @cipher_suite,
193
+ transcript: transcript
194
+ )
195
+ @alert_wcipher = hs_wcipher = gen_cipher(
196
+ @cipher_suite,
197
+ key_schedule.server_handshake_write_key,
198
+ key_schedule.server_handshake_write_iv
199
+ )
200
+ hs_rcipher = gen_cipher(
201
+ @cipher_suite,
202
+ key_schedule.client_handshake_write_key,
203
+ key_schedule.client_handshake_write_iv
204
+ )
183
205
  @state = ServerState::WAIT_FLIGHT2
184
206
  when ServerState::WAIT_EOED
185
207
  logger.debug('ServerState::WAIT_EOED')
186
208
  when ServerState::WAIT_FLIGHT2
187
209
  logger.debug('ServerState::WAIT_FLIGHT2')
188
210
 
189
- ee = @transcript[EE] = gen_encrypted_extensions
211
+ ch = transcript[CH]
212
+ ee = transcript[EE] = gen_encrypted_extensions(ch)
190
213
  # TODO: [Send CertificateRequest]
191
- ct = @transcript[CT] = gen_certificate
192
- cv = @transcript[CV] = gen_certificate_verify
193
- sf = @transcript[SF] = gen_finished
194
- send_server_parameters([ee, ct, cv, sf])
214
+ ct = transcript[CT] = gen_certificate(@crt)
215
+ digest = CipherSuite.digest(@cipher_suite)
216
+ cv = transcript[CV] = gen_certificate_verify(
217
+ @key,
218
+ @signature_scheme,
219
+ transcript.hash(digest, CT)
220
+ )
221
+ finished_key = key_schedule.server_finished_key
222
+ signature = sign_finished(
223
+ digest: digest,
224
+ finished_key: finished_key,
225
+ hash: transcript.hash(digest, CV)
226
+ )
227
+ sf = transcript[SF] = Message::Finished.new(signature)
228
+ send_server_parameters([ee, ct, cv, sf], hs_wcipher)
195
229
  @state = ServerState::WAIT_FINISHED
196
230
  when ServerState::WAIT_CERT
197
231
  logger.debug('ServerState::WAIT_CERT')
@@ -200,14 +234,25 @@ module TTTLS13
200
234
  when ServerState::WAIT_FINISHED
201
235
  logger.debug('ServerState::WAIT_FINISHED')
202
236
 
203
- @transcript[CF] = recv_finished
204
- terminate(:decrypt_error) unless verified_finished?
205
- @write_cipher = gen_cipher(@cipher_suite,
206
- @key_schedule.server_application_write_key,
207
- @key_schedule.server_application_write_iv)
208
- @read_cipher = gen_cipher(@cipher_suite,
209
- @key_schedule.client_application_write_key,
210
- @key_schedule.client_application_write_iv)
237
+ cf = transcript[CF] = recv_finished(hs_rcipher)
238
+ digest = CipherSuite.digest(@cipher_suite)
239
+ verified = verified_finished?(
240
+ finished: cf,
241
+ digest: digest,
242
+ finished_key: key_schedule.client_finished_key,
243
+ hash: transcript.hash(digest, EOED)
244
+ )
245
+ terminate(:decrypt_error) unless verified
246
+ @alert_wcipher = @ap_wcipher = gen_cipher(
247
+ @cipher_suite,
248
+ key_schedule.server_application_write_key,
249
+ key_schedule.server_application_write_iv
250
+ )
251
+ @ap_rcipher = gen_cipher(
252
+ @cipher_suite,
253
+ key_schedule.client_application_write_key,
254
+ key_schedule.client_application_write_iv
255
+ )
211
256
  @state = ServerState::CONNECTED
212
257
  when ServerState::CONNECTED
213
258
  logger.debug('ServerState::CONNECTED')
@@ -241,33 +286,41 @@ module TTTLS13
241
286
  true
242
287
  end
243
288
 
289
+ # @param receivable_ccs [Boolean]
290
+ #
244
291
  # @raise [TTTLS13::Error::ErrorAlerts]
245
292
  #
246
293
  # @return [TTTLS13::Message::ClientHello]
247
- def recv_client_hello
248
- ch = recv_message
294
+ def recv_client_hello(receivable_ccs)
295
+ ch = recv_message(receivable_ccs: receivable_ccs,
296
+ cipher: Cryptograph::Passer.new)
249
297
  terminate(:unexpected_message) unless ch.is_a?(Message::ClientHello)
250
298
 
251
299
  ch
252
300
  end
253
301
 
254
- # @param exs [TTTLS13::Message::Extensions]
302
+ # @param extensions [TTTLS13::Message::Extensions]
303
+ # @param cipher_suite [TTTLS13::CipherSuite]
304
+ # @param session_id [String]
255
305
  #
256
306
  # @return [TTTLS13::Message::ServerHello]
257
- def send_server_hello(exs)
258
- ch_session_id = @transcript[CH].legacy_session_id
307
+ def send_server_hello(extensions, cipher_suite, session_id)
259
308
  sh = Message::ServerHello.new(
260
- legacy_session_id_echo: ch_session_id,
261
- cipher_suite: @cipher_suite,
262
- extensions: exs
309
+ legacy_session_id_echo: session_id,
310
+ cipher_suite: cipher_suite,
311
+ extensions: extensions
263
312
  )
264
- send_handshakes(Message::ContentType::HANDSHAKE, [sh], @write_cipher)
313
+ send_handshakes(Message::ContentType::HANDSHAKE, [sh],
314
+ Cryptograph::Passer.new)
265
315
 
266
316
  sh
267
317
  end
268
318
 
319
+ # @param ch1 [TTTLS13::Message::ClientHello]
320
+ # @param cipher_suite [TTTLS13::CipherSuite]
321
+ #
269
322
  # @return [TTTLS13::Message::ServerHello]
270
- def send_hello_retry_request
323
+ def send_hello_retry_request(ch1, cipher_suite)
271
324
  exs = []
272
325
  # supported_versions
273
326
  exs << Message::Extension::SupportedVersions.new(
@@ -275,7 +328,6 @@ module TTTLS13
275
328
  )
276
329
 
277
330
  # key_share
278
- ch1 = @transcript[CH1]
279
331
  sp_groups = ch1.extensions[Message::ExtensionType::SUPPORTED_GROUPS]
280
332
  &.named_group_list || []
281
333
  ks_groups = ch1.extensions[Message::ExtensionType::KEY_SHARE]
@@ -290,64 +342,73 @@ module TTTLS13
290
342
  sh = Message::ServerHello.new(
291
343
  random: Message::HRR_RANDOM,
292
344
  legacy_session_id_echo: ch1.legacy_session_id,
293
- cipher_suite: @cipher_suite,
345
+ cipher_suite: cipher_suite,
294
346
  extensions: Message::Extensions.new(exs)
295
347
  )
296
- send_handshakes(Message::ContentType::HANDSHAKE, [sh], @write_cipher)
348
+ send_handshakes(Message::ContentType::HANDSHAKE, [sh],
349
+ Cryptograph::Passer.new)
297
350
 
298
351
  sh
299
352
  end
300
353
 
301
354
  # @param messages [Array of TTTLS13::Message::$Object]
355
+ # @param cipher [TTTLS13::Cryptograph::Aead]
302
356
  #
303
357
  # @return [Array of TTTLS13::Message::$Object]
304
- def send_server_parameters(messages)
358
+ def send_server_parameters(messages, cipher)
305
359
  send_handshakes(Message::ContentType::APPLICATION_DATA,
306
- messages.reject(&:nil?),
307
- @write_cipher)
360
+ messages.reject(&:nil?), cipher)
308
361
 
309
362
  messages
310
363
  end
311
364
 
365
+ # @param ch [TTTLS13::Message::ClientHello]
366
+ #
312
367
  # @return [TTTLS13::Message::EncryptedExtensions]
313
- def gen_encrypted_extensions
314
- Message::EncryptedExtensions.new(gen_ee_extensions)
368
+ def gen_encrypted_extensions(ch)
369
+ Message::EncryptedExtensions.new(gen_ee_extensions(ch))
315
370
  end
316
371
 
372
+ # @param crt [OpenSSL::X509::Certificate]
373
+ #
317
374
  # @return [TTTLS13::Message::Certificate, nil]
318
- def gen_certificate
319
- return nil if @crt.nil?
320
-
321
- ce = Message::CertificateEntry.new(@crt)
375
+ def gen_certificate(crt)
376
+ ce = Message::CertificateEntry.new(crt)
322
377
  Message::Certificate.new(certificate_list: [ce])
323
378
  end
324
379
 
380
+ # @param key [OpenSSL::PKey::PKey]
381
+ # @param signature_scheme [TTTLS13::SignatureScheme]
382
+ # @param hash [String]
383
+ #
325
384
  # @return [TTTLS13::Message::CertificateVerify, nil]
326
- def gen_certificate_verify
327
- return nil if @key.nil?
328
-
329
- Message::CertificateVerify.new(signature_scheme: @signature_scheme,
330
- signature: sign_certificate_verify)
331
- end
332
-
333
- # @return [TTTLS13::Message::Finished]
334
- def gen_finished
335
- Message::Finished.new(sign_finished)
385
+ def gen_certificate_verify(key, signature_scheme, hash)
386
+ signature = sign_certificate_verify(
387
+ key: key,
388
+ signature_scheme: signature_scheme,
389
+ hash: hash
390
+ )
391
+ Message::CertificateVerify.new(signature_scheme: signature_scheme,
392
+ signature: signature)
336
393
  end
337
394
 
395
+ # @param cipher [TTTLS13::Cryptograph::Aead]
396
+ #
338
397
  # @raise [TTTLS13::Error::ErrorAlerts]
339
398
  #
340
399
  # @return [TTTLS13::Message::Finished]
341
- def recv_finished
342
- cf = recv_message
400
+ def recv_finished(cipher)
401
+ cf = recv_message(receivable_ccs: true, cipher: cipher)
343
402
  terminate(:unexpected_message) unless cf.is_a?(Message::Finished)
344
403
 
345
404
  cf
346
405
  end
347
406
 
407
+ # @param named_group [TTTLS13::NamedGroup]
408
+ #
348
409
  # @return [TTTLS13::Message::Extensions]
349
410
  # @return [OpenSSL::PKey::EC.$Object]
350
- def gen_sh_extensions
411
+ def gen_sh_extensions(named_group)
351
412
  exs = []
352
413
  # supported_versions: only TLS 1.3
353
414
  exs << Message::Extension::SupportedVersions.new(
@@ -356,20 +417,21 @@ module TTTLS13
356
417
 
357
418
  # key_share
358
419
  key_share, priv_key \
359
- = Message::Extension::KeyShare.gen_sh_key_share(@named_group)
420
+ = Message::Extension::KeyShare.gen_sh_key_share(named_group)
360
421
  exs << key_share
361
422
 
362
423
  [Message::Extensions.new(exs), priv_key]
363
424
  end
364
425
 
426
+ # @param ch [TTTLS13::Message::ClientHello]
427
+ #
365
428
  # @return [TTTLS13::Message::Extensions]
366
- def gen_ee_extensions
429
+ def gen_ee_extensions(ch)
367
430
  exs = []
368
431
 
369
432
  # server_name
370
433
  exs << Message::Extension::ServerName.new('') \
371
- if @transcript[CH].extensions
372
- .include?(Message::ExtensionType::SERVER_NAME)
434
+ if ch.extensions.include?(Message::ExtensionType::SERVER_NAME)
373
435
 
374
436
  # supported_groups
375
437
  exs \
@@ -378,104 +440,64 @@ module TTTLS13
378
440
  Message::Extensions.new(exs)
379
441
  end
380
442
 
443
+ # @param key [OpenSSL::PKey::PKey]
444
+ # @param signature_scheme [TTTLS13::SignatureScheme]
445
+ # @param hash [String]
446
+ #
381
447
  # @return [String]
382
- def sign_certificate_verify
383
- context = 'TLS 1.3, server CertificateVerify'
384
- do_sign_certificate_verify(private_key: @key,
385
- signature_scheme: @signature_scheme,
386
- context: context,
387
- handshake_context_end: CT)
388
- end
389
-
390
- # @return [String]
391
- def sign_finished
392
- digest = CipherSuite.digest(@cipher_suite)
393
- finished_key = @key_schedule.server_finished_key
394
- do_sign_finished(digest: digest,
395
- finished_key: finished_key,
396
- handshake_context_end: CV)
397
- end
398
-
399
- # @return [Boolean]
400
- def verified_finished?
401
- digest = CipherSuite.digest(@cipher_suite)
402
- finished_key = @key_schedule.client_finished_key
403
- signature = @transcript[CF].verify_data
404
- do_verified_finished?(digest: digest,
405
- finished_key: finished_key,
406
- handshake_context_end: EOED,
407
- signature: signature)
408
- end
409
-
410
- # @return [Boolean]
411
- def negotiated_tls_1_3?
412
- ch = @transcript[CH]
413
- ch_lv = ch.legacy_version
414
- ch_sv = ch.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
415
- &.versions || []
416
-
417
- ch_lv == Message::ProtocolVersion::TLS_1_2 &&
418
- ch_sv.include?(Message::ProtocolVersion::TLS_1_3)
448
+ def sign_certificate_verify(key:, signature_scheme:, hash:)
449
+ do_sign_certificate_verify(
450
+ key: key,
451
+ signature_scheme: signature_scheme,
452
+ context: 'TLS 1.3, server CertificateVerify',
453
+ hash: hash
454
+ )
419
455
  end
420
456
 
457
+ # @param ch [TTTLS13::Message::ClientHello]
458
+ #
421
459
  # @return [TTTLS13::CipherSuite, nil]
422
- def select_cipher_suite
423
- @transcript[CH].cipher_suites.find do |cs|
460
+ def select_cipher_suite(ch)
461
+ ch.cipher_suites.find do |cs|
424
462
  @settings[:cipher_suites].include?(cs)
425
463
  end
426
464
  end
427
465
 
466
+ # @param ch [TTTLS13::Message::ClientHello]
467
+ #
428
468
  # @return [TTTLS13::NamedGroup, nil]
429
- def select_named_group
430
- ks_groups = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
431
- &.key_share_entry&.map(&:group) || []
469
+ def select_named_group(ch)
470
+ ks_groups = ch.extensions[Message::ExtensionType::KEY_SHARE]
471
+ &.key_share_entry&.map(&:group) || []
432
472
 
433
473
  ks_groups.find do |g|
434
474
  @settings[:supported_groups].include?(g)
435
475
  end
436
476
  end
437
477
 
478
+ # @param ch [TTTLS13::Message::ClientHello]
479
+ # @param crt [OpenSSL::X509::Certificate]
480
+ #
438
481
  # @return [TTTLS13::SignatureScheme, nil]
439
- def select_signature_scheme
440
- algorithms \
441
- = @transcript[CH].extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
442
- &.supported_signature_algorithms || []
482
+ def select_signature_scheme(ch, crt)
483
+ algorithms = ch.extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
484
+ &.supported_signature_algorithms || []
443
485
 
444
- do_select_signature_algorithms(algorithms, @crt).find do |ss|
486
+ do_select_signature_algorithms(algorithms, crt).find do |ss|
445
487
  @settings[:signature_algorithms].include?(ss)
446
488
  end
447
489
  end
448
490
 
491
+ # @param ch [TTTLS13::Message::ClientHello]
492
+ # @param crt [OpenSSL::X509::Certificate]
493
+ #
449
494
  # @return [Boolean]
450
- def valid_ch_compression_methods?
451
- @transcript[CH].legacy_compression_methods == ["\x00"]
452
- end
453
-
454
- # @return [Boolean]
455
- def recognized_server_name?
456
- server_name \
457
- = @transcript[CH].extensions[Message::ExtensionType::SERVER_NAME]
458
- &.server_name
459
-
495
+ def recognized_server_name?(ch, crt)
496
+ server_name = ch.extensions[Message::ExtensionType::SERVER_NAME]
497
+ &.server_name
460
498
  return true if server_name.nil?
461
499
 
462
- matching_san?(@crt, server_name)
463
- end
464
-
465
- # @return [Boolean]
466
- def valid_ch_key_share?
467
- ks = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
468
- ks_groups = ks&.key_share_entry&.map(&:group) || []
469
- sg = @transcript[CH].extensions[Message::ExtensionType::SUPPORTED_GROUPS]
470
- sp_groups = sg&.named_group_list || []
471
-
472
- # Each KeyShareEntry value MUST correspond to a group offered in the
473
- # "supported_groups" extension and MUST appear in the same order.
474
- #
475
- # Clients MUST NOT offer multiple KeyShareEntry values for the same group.
476
- (ks_groups - sp_groups).empty? &&
477
- sp_groups.filter { |g| ks_groups.include?(g) } == ks_groups &&
478
- ks_groups.uniq == ks_groups
500
+ matching_san?(crt, server_name)
479
501
  end
480
502
  end
481
503
  # rubocop: enable Metrics/ClassLength
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.2'
5
5
  end
@@ -27,10 +27,10 @@ RSpec.describe Certificate do
27
27
 
28
28
  it 'should be serialized' do
29
29
  expect(message.serialize).to eq HandshakeType::CERTIFICATE \
30
- + 990.to_uint24 \
30
+ + 742.to_uint24 \
31
31
  + 0.to_uint8 \
32
- + 986.to_uint24 \
33
- + 981.to_uint24 \
32
+ + 738.to_uint24 \
33
+ + 733.to_uint24 \
34
34
  + certificate.to_der \
35
35
  + 0.to_uint16
36
36
  end
@@ -76,7 +76,7 @@ RSpec.describe Certificate do
76
76
 
77
77
  it 'should be generated' do
78
78
  expect(message.msg_type).to eq HandshakeType::CERTIFICATE
79
- expect(message.only_appearable_extensions?).to be false
79
+ expect(message.appearable_extensions?).to be false
80
80
  end
81
81
  end
82
82
  end
@@ -36,6 +36,7 @@ RSpec.describe ClientHello do
36
36
  TLS_AES_128_GCM_SHA256]
37
37
  expect(message.legacy_compression_methods).to eq ["\x00"]
38
38
  expect(message.extensions).to be_empty
39
+ expect(message.negotiated_tls_1_3?).to be false
39
40
  end
40
41
 
41
42
  it 'should be serialized' do
@@ -59,6 +60,7 @@ RSpec.describe ClientHello do
59
60
  it 'should generate valid object' do
60
61
  expect(message.msg_type).to eq HandshakeType::CLIENT_HELLO
61
62
  expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
63
+ expect(message.negotiated_tls_1_3?).to be true
62
64
  end
63
65
 
64
66
  it 'should generate valid serializable object' do
@@ -74,6 +76,7 @@ RSpec.describe ClientHello do
74
76
  it 'should generate valid object' do
75
77
  expect(message.msg_type).to eq HandshakeType::CLIENT_HELLO
76
78
  expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
79
+ expect(message.negotiated_tls_1_3?).to be true
77
80
  end
78
81
 
79
82
  it 'should generate valid serializable object' do