tttls1.3 0.2.1 → 0.2.2

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