tttls1.3 0.1.4 → 0.2.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/README.md +35 -13
  4. data/Rakefile +2 -4
  5. data/example/helper.rb +30 -7
  6. data/example/https_client.rb +3 -20
  7. data/example/https_client_using_0rtt.rb +10 -24
  8. data/example/https_client_using_hrr.rb +3 -20
  9. data/example/https_client_using_ticket.rb +3 -20
  10. data/example/https_server.rb +43 -0
  11. data/interop/client_spec.rb +111 -22
  12. data/interop/helper.rb +1 -0
  13. data/interop/server_spec.rb +182 -0
  14. data/lib/tttls1.3/client.rb +115 -98
  15. data/lib/tttls1.3/connection.rb +119 -32
  16. data/lib/tttls1.3/message/certificate.rb +18 -0
  17. data/lib/tttls1.3/message/client_hello.rb +38 -0
  18. data/lib/tttls1.3/message/encrypted_extensions.rb +20 -16
  19. data/lib/tttls1.3/message/extension/key_share.rb +24 -2
  20. data/lib/tttls1.3/message/extension/supported_groups.rb +0 -87
  21. data/lib/tttls1.3/message/extensions.rb +1 -27
  22. data/lib/tttls1.3/message/new_session_ticket.rb +14 -0
  23. data/lib/tttls1.3/message/record.rb +23 -20
  24. data/lib/tttls1.3/message/server_hello.rb +27 -0
  25. data/lib/tttls1.3/message.rb +35 -2
  26. data/lib/tttls1.3/named_group.rb +89 -0
  27. data/lib/tttls1.3/server.rb +439 -0
  28. data/lib/tttls1.3/transcript.rb +6 -0
  29. data/lib/tttls1.3/version.rb +1 -1
  30. data/lib/tttls1.3.rb +3 -0
  31. data/spec/certificate_spec.rb +28 -1
  32. data/spec/client_spec.rb +14 -10
  33. data/spec/connection_spec.rb +43 -13
  34. data/spec/encrypted_extensions_spec.rb +4 -4
  35. data/spec/fixtures/rsa_ca.crt +29 -0
  36. data/spec/fixtures/rsa_ca.key +51 -0
  37. data/spec/fixtures/rsa_rsa.crt +23 -0
  38. data/spec/fixtures/rsa_rsa.key +27 -0
  39. data/spec/fixtures/rsa_secp256r1.crt +19 -0
  40. data/spec/fixtures/rsa_secp256r1.key +5 -0
  41. data/spec/fixtures/rsa_secp384r1.crt +19 -0
  42. data/spec/fixtures/rsa_secp384r1.key +6 -0
  43. data/spec/fixtures/rsa_secp521r1.crt +20 -0
  44. data/spec/fixtures/rsa_secp521r1.key +7 -0
  45. data/spec/server_spec.rb +186 -0
  46. data/spec/spec_helper.rb +43 -0
  47. metadata +28 -2
@@ -4,11 +4,29 @@
4
4
  module TTTLS13
5
5
  using Refinements
6
6
  module Message
7
+ # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
8
+ APPEARABLE_SH_EXTENSIONS = [
9
+ ExtensionType::PRE_SHARED_KEY,
10
+ ExtensionType::PASSWORD_SALT,
11
+ ExtensionType::SUPPORTED_VERSIONS,
12
+ ExtensionType::KEY_SHARE
13
+ ].freeze
14
+ private_constant :APPEARABLE_SH_EXTENSIONS
15
+
16
+ APPEARABLE_HRR_EXTENSIONS = [
17
+ ExtensionType::COOKIE,
18
+ ExtensionType::PASSWORD_SALT,
19
+ ExtensionType::SUPPORTED_VERSIONS,
20
+ ExtensionType::KEY_SHARE
21
+ ].freeze
22
+ private_constant :APPEARABLE_HRR_EXTENSIONS
23
+
7
24
  class ServerHello
8
25
  # special value of the SHA-256 of "HelloRetryRequest"
9
26
  HRR_RANDOM \
10
27
  = "\xcf\x21\xad\x74\xe5\x9a\x61\x11\xbe\x1d\x8c\x02\x1e\x65\xb8\x91" \
11
28
  "\xc2\xa2\x11\x16\x7a\xbb\x8c\x5e\x07\x9e\x09\xe2\xc8\xa8\x33\x9c"
29
+ private_constant :HRR_RANDOM
12
30
 
13
31
  attr_reader :msg_type
14
32
  attr_reader :legacy_version
@@ -111,6 +129,15 @@ module TTTLS13
111
129
  def hrr?
112
130
  @hrr
113
131
  end
132
+
133
+ # @return [Boolean]
134
+ def only_appearable_extensions?
135
+ exs = @extensions.keys - APPEARABLE_SH_EXTENSIONS
136
+ exs = @extensions.keys - APPEARABLE_HRR_EXTENSIONS if hrr?
137
+ return true if exs.empty?
138
+
139
+ !(exs - DEFINED_EXTENSIONS).empty?
140
+ end
114
141
  end
115
142
  end
116
143
  end
@@ -1,8 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
  # frozen_string_literal: true
3
3
 
4
- Dir[File.dirname(__FILE__) + '/message/*.rb'].each { |f| require f }
5
-
6
4
  module TTTLS13
7
5
  module Message
8
6
  module ContentType
@@ -44,5 +42,40 @@ module TTTLS13
44
42
  KEY_UPDATE = "\x18"
45
43
  MESSAGE_HASH = "\xfe"
46
44
  end
45
+
46
+ module ExtensionType
47
+ SERVER_NAME = "\x00\x00"
48
+ MAX_FRAGMENT_LENGTH = "\x00\x01"
49
+ STATUS_REQUEST = "\x00\x05"
50
+ SUPPORTED_GROUPS = "\x00\x0a"
51
+ SIGNATURE_ALGORITHMS = "\x00\x0d"
52
+ USE_SRTP = "\x00\x0e"
53
+ HEARTBEAT = "\x00\x0f"
54
+ APPLICATION_LAYER_PROTOCOL_NEGOTIATION = "\x00\x10"
55
+ SIGNED_CERTIFICATE_TIMESTAMP = "\x00\x12"
56
+ CLIENT_CERTIFICATE_TYPE = "\x00\x13"
57
+ SERVER_CERTIFICATE_TYPE = "\x00\x14"
58
+ PADDING = "\x00\x15"
59
+ RECORD_SIZE_LIMIT = "\x00\x1c"
60
+ PWD_PROTECT = "\x00\x1d"
61
+ PWD_CLEAR = "\x00\x1e"
62
+ PASSWORD_SALT = "\x00\x1f"
63
+ PRE_SHARED_KEY = "\x00\x29"
64
+ EARLY_DATA = "\x00\x2a"
65
+ SUPPORTED_VERSIONS = "\x00\x2b"
66
+ COOKIE = "\x00\x2c"
67
+ PSK_KEY_EXCHANGE_MODES = "\x00\x2d"
68
+ CERTIFICATE_AUTHORITIES = "\x00\x2f"
69
+ OID_FILTERS = "\x00\x30"
70
+ POST_HANDSHAKE_AUTH = "\x00\x31"
71
+ SIGNATURE_ALGORITHMS_CERT = "\x00\x32"
72
+ KEY_SHARE = "\x00\x33"
73
+ end
74
+
75
+ DEFINED_EXTENSIONS = ExtensionType.constants.map do |c|
76
+ ExtensionType.const_get(c)
77
+ end.freeze
47
78
  end
48
79
  end
80
+
81
+ Dir[File.dirname(__FILE__) + '/message/*.rb'].each { |f| require f }
@@ -0,0 +1,89 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ module NamedGroup
6
+ SECP256R1 = "\x00\x17"
7
+ SECP384R1 = "\x00\x18"
8
+ SECP521R1 = "\x00\x19"
9
+ # X25519 = "\x00\x1d" # UNSUPPORTED
10
+ # X448 = "\x00\x1e" # UNSUPPORTED
11
+ # FFDHE2048 = "\x01\x00" # UNSUPPORTED
12
+ # FFDHE3072 = "\x01\x01" # UNSUPPORTED
13
+ # FFDHE4096 = "\x01\x02" # UNSUPPORTED
14
+ # FFDHE6144 = "\x01\x03" # UNSUPPORTED
15
+ # FFDHE8192 = "\x01\x04" # UNSUPPORTED
16
+ # ffdhe_private_use "\x01\xfc" ~ "\x01\xff"
17
+ # ecdhe_private_use "\xfe\x00" ~ "\xfe\xff"
18
+
19
+ class << self
20
+ # NOTE:
21
+ # For secp256r1, secp384r1, and secp521r1
22
+ #
23
+ # struct {
24
+ # uint8 legacy_form = 4;
25
+ # opaque X[coordinate_length];
26
+ # opaque Y[coordinate_length];
27
+ # } UncompressedPointRepresentation;
28
+ #
29
+ # @param group [TTTLS13::Message::Extension::NamedGroup]
30
+ #
31
+ # @raise [TTTLS13::Error::ErrorAlerts]
32
+ #
33
+ # @return [Integer]
34
+ def key_exchange_len(group)
35
+ case group
36
+ when SECP256R1
37
+ 65
38
+ when SECP384R1
39
+ 97
40
+ when SECP521R1
41
+ 133
42
+ # not supported other NamedGroup
43
+ # when X25519
44
+ # 32
45
+ # when X448
46
+ # 56
47
+ # when FFDHE2048
48
+ # 256
49
+ # when FFDHE4096
50
+ # 512
51
+ # when FFDHE6144
52
+ # 768
53
+ # when FFDHE8192
54
+ # 1024
55
+ else
56
+ raise Error::ErrorAlerts, :internal_error
57
+ end
58
+ end
59
+
60
+ # NOTE:
61
+ # SECG | ANSI X9.62 | NIST
62
+ # ------------+---------------+-------------
63
+ # secp256r1 | prime256v1 | NIST P-256
64
+ # secp384r1 | | NIST P-384
65
+ # secp521r1 | | NIST P-521
66
+ #
67
+ # https://tools.ietf.org/html/rfc4492#appendix-A
68
+ #
69
+ # @param groups [Array of TTTLS13::Message::Extension::NamedGroup]
70
+ #
71
+ # @raise [TTTLS13::Error::ErrorAlerts]
72
+ #
73
+ # @return [String] EC_builtin_curves
74
+ def curve_name(group)
75
+ case group
76
+ when SECP256R1
77
+ 'prime256v1'
78
+ when SECP384R1
79
+ 'secp384r1'
80
+ when SECP521R1
81
+ 'secp521r1'
82
+ else
83
+ # not supported other NamedGroup
84
+ raise Error::ErrorAlerts, :internal_error
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,439 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ module TTTLS13
5
+ using Refinements
6
+ module ServerState
7
+ # initial value is 0, eof value is -1
8
+ START = 1
9
+ RECVD_CH = 2
10
+ NEGOTIATED = 3
11
+ WAIT_EOED = 4
12
+ WAIT_FLIGHT2 = 5
13
+ WAIT_CERT = 6
14
+ WAIT_CV = 7
15
+ WAIT_FINISHED = 8
16
+ CONNECTED = 9
17
+ end
18
+
19
+ DEFAULT_SP_CIPHER_SUITES = [
20
+ CipherSuite::TLS_AES_256_GCM_SHA384,
21
+ CipherSuite::TLS_CHACHA20_POLY1305_SHA256,
22
+ CipherSuite::TLS_AES_128_GCM_SHA256
23
+ ].freeze
24
+ private_constant :DEFAULT_SP_CIPHER_SUITES
25
+
26
+ DEFAULT_SP_SIGNATURE_ALGORITHMS = [
27
+ SignatureScheme::ECDSA_SECP256R1_SHA256,
28
+ SignatureScheme::ECDSA_SECP384R1_SHA384,
29
+ SignatureScheme::ECDSA_SECP521R1_SHA512,
30
+ SignatureScheme::RSA_PSS_RSAE_SHA256,
31
+ SignatureScheme::RSA_PSS_RSAE_SHA384,
32
+ SignatureScheme::RSA_PSS_RSAE_SHA512,
33
+ SignatureScheme::RSA_PKCS1_SHA256,
34
+ SignatureScheme::RSA_PKCS1_SHA384,
35
+ SignatureScheme::RSA_PKCS1_SHA512
36
+ ].freeze
37
+ private_constant :DEFAULT_SP_SIGNATURE_ALGORITHMS
38
+
39
+ DEFAULT_SP_NAMED_GROUP_LIST = [
40
+ NamedGroup::SECP256R1,
41
+ NamedGroup::SECP384R1,
42
+ NamedGroup::SECP521R1
43
+ ].freeze
44
+ private_constant :DEFAULT_SP_NAMED_GROUP_LIST
45
+
46
+ DEFAULT_SERVER_SETTINGS = {
47
+ crt_file: nil,
48
+ key_file: nil,
49
+ cipher_suites: DEFAULT_SP_CIPHER_SUITES,
50
+ signature_algorithms: DEFAULT_SP_SIGNATURE_ALGORITHMS,
51
+ supported_groups: DEFAULT_SP_NAMED_GROUP_LIST,
52
+ loglevel: Logger::WARN
53
+ }.freeze
54
+ private_constant :DEFAULT_SERVER_SETTINGS
55
+
56
+ # rubocop: disable Metrics/ClassLength
57
+ class Server < Connection
58
+ # @param socket [Socket]
59
+ # @param settings [Hash]
60
+ def initialize(socket, **settings)
61
+ super(socket)
62
+
63
+ @endpoint = :server
64
+ @settings = DEFAULT_SERVER_SETTINGS.merge(settings)
65
+ logger.level = @settings[:loglevel]
66
+
67
+ raise Error::ConfigError unless valid_settings?
68
+ return if @settings[:crt_file].nil?
69
+
70
+ crt_str = File.read(@settings[:crt_file])
71
+ @crt = OpenSSL::X509::Certificate.new(crt_str) # TODO: spki rsassaPss
72
+ klass = @crt.public_key.class
73
+ @key = klass.new(File.read(@settings[:key_file]))
74
+ raise Error::ConfigError unless @crt.check_private_key(@key)
75
+ end
76
+
77
+ # NOTE:
78
+ # START <-----+
79
+ # Recv ClientHello | | Send HelloRetryRequest
80
+ # v |
81
+ # RECVD_CH ----+
82
+ # | Select parameters
83
+ # v
84
+ # NEGOTIATED
85
+ # | Send ServerHello
86
+ # | K_send = handshake
87
+ # | Send EncryptedExtensions
88
+ # | [Send CertificateRequest]
89
+ # Can send | [Send Certificate + CertificateVerify]
90
+ # app data | Send Finished
91
+ # after --> | K_send = application
92
+ # here +--------+--------+
93
+ # No 0-RTT | | 0-RTT
94
+ # | |
95
+ # K_recv = handshake | | K_recv = early data
96
+ # [Skip decrypt errors] | +------> WAIT_EOED -+
97
+ # | | Recv | | Recv EndOfEarlyData
98
+ # | | early data | | K_recv = handshake
99
+ # | +------------+ |
100
+ # | |
101
+ # +> WAIT_FLIGHT2 <--------+
102
+ # |
103
+ # +--------+--------+
104
+ # No auth | | Client auth
105
+ # | |
106
+ # | v
107
+ # | WAIT_CERT
108
+ # | Recv | | Recv Certificate
109
+ # | empty | v
110
+ # | Certificate | WAIT_CV
111
+ # | | | Recv
112
+ # | v | CertificateVerify
113
+ # +-> WAIT_FINISHED <---+
114
+ # | Recv Finished
115
+ # | K_recv = application
116
+ # v
117
+ # CONNECTED
118
+ #
119
+ # https://tools.ietf.org/html/rfc8446#appendix-A.2
120
+ #
121
+ # rubocop: disable Metrics/AbcSize
122
+ # rubocop: disable Metrics/BlockLength
123
+ # rubocop: disable Metrics/CyclomaticComplexity
124
+ # rubocop: disable Metrics/MethodLength
125
+ # rubocop: disable Metrics/PerceivedComplexity
126
+ def accept
127
+ @state = ServerState::START
128
+ loop do
129
+ case @state
130
+ when ServerState::START
131
+ logger.debug('ServerState::START')
132
+
133
+ ch = @transcript[CH] = recv_client_hello
134
+ terminate(:illegal_parameter) unless ch.only_appearable_extensions?
135
+ @state = ServerState::RECVD_CH
136
+ when ServerState::RECVD_CH
137
+ logger.debug('ServerState::RECVD_CH')
138
+
139
+ # support only TLS 1.3
140
+ terminate(:protocol_version) unless negotiated_tls_1_3?
141
+
142
+ # validate/select parameters
143
+ @cipher_suite = select_cipher_suite
144
+ @named_group = select_named_group
145
+ @signature_scheme = select_signature_scheme
146
+ terminate(:handshake_failure) \
147
+ if @cipher_suite.nil? || @named_group.nil? || @signature_scheme.nil?
148
+ terminamte(:illegal_parameter) unless valid_ch_compression_methods?
149
+ terminate(:unrecognized_name) unless recognized_server_name?
150
+
151
+ @state = ServerState::NEGOTIATED
152
+ when ServerState::NEGOTIATED
153
+ logger.debug('ServerState::NEGOTIATED')
154
+
155
+ exs, @priv_key = gen_sh_extensions
156
+ @transcript[SH] = send_server_hello(exs)
157
+ send_ccs # compatibility mode
158
+
159
+ # generate shared secret
160
+ terminate(:illegal_parameter) unless valid_ch_key_share?
161
+ ke = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
162
+ &.key_share_entry
163
+ &.find { |e| e.group == @named_group }
164
+ &.key_exchange
165
+ # TODO: Send HelloRetryRequest
166
+ shared_secret = gen_shared_secret(ke, @priv_key, @named_group)
167
+ @key_schedule = KeySchedule.new(psk: @psk,
168
+ shared_secret: shared_secret,
169
+ cipher_suite: @cipher_suite,
170
+ transcript: @transcript)
171
+ @write_cipher = gen_cipher(@cipher_suite,
172
+ @key_schedule.server_handshake_write_key,
173
+ @key_schedule.server_handshake_write_iv)
174
+ @read_cipher = gen_cipher(@cipher_suite,
175
+ @key_schedule.client_handshake_write_key,
176
+ @key_schedule.client_handshake_write_iv)
177
+ @state = ServerState::WAIT_FLIGHT2
178
+ when ServerState::WAIT_EOED
179
+ logger.debug('ServerState::WAIT_EOED')
180
+ when ServerState::WAIT_FLIGHT2
181
+ logger.debug('ServerState::WAIT_FLIGHT2')
182
+
183
+ ee = @transcript[EE] = gen_encrypted_extensions
184
+ # TODO: [Send CertificateRequest]
185
+ ct = @transcript[CT] = gen_certificate
186
+ cv = @transcript[CV] = gen_certificate_verify
187
+ sf = @transcript[SF] = gen_finished
188
+ send_server_parameters([ee, ct, cv, sf])
189
+ @state = ServerState::WAIT_FINISHED
190
+ when ServerState::WAIT_CERT
191
+ logger.debug('ServerState::WAIT_CERT')
192
+ when ServerState::WAIT_CV
193
+ logger.debug('ServerState::WAIT_CV')
194
+ when ServerState::WAIT_FINISHED
195
+ logger.debug('ServerState::WAIT_FINISHED')
196
+
197
+ @transcript[CF] = recv_finished
198
+ terminate(:decrypt_error) unless verified_finished?
199
+ @write_cipher = gen_cipher(@cipher_suite,
200
+ @key_schedule.server_application_write_key,
201
+ @key_schedule.server_application_write_iv)
202
+ @read_cipher = gen_cipher(@cipher_suite,
203
+ @key_schedule.client_application_write_key,
204
+ @key_schedule.client_application_write_iv)
205
+ @state = ServerState::CONNECTED
206
+ when ServerState::CONNECTED
207
+ logger.debug('ServerState::CONNECTED')
208
+
209
+ break
210
+ end
211
+ end
212
+ end
213
+ # rubocop: enable Metrics/AbcSize
214
+ # rubocop: enable Metrics/BlockLength
215
+ # rubocop: enable Metrics/CyclomaticComplexity
216
+ # rubocop: enable Metrics/MethodLength
217
+ # rubocop: enable Metrics/PerceivedComplexity
218
+
219
+ private
220
+
221
+ # @return [Boolean]
222
+ def valid_settings?
223
+ mod = CipherSuite
224
+ defined = mod.constants.map { |c| mod.const_get(c) }
225
+ return false unless (@settings[:cipher_suites] - defined).empty?
226
+
227
+ mod = SignatureScheme
228
+ defined = mod.constants.map { |c| mod.const_get(c) }
229
+ return false unless (@settings[:signature_algorithms] - defined).empty?
230
+
231
+ mod = NamedGroup
232
+ defined = mod.constants.map { |c| mod.const_get(c) }
233
+ return false unless (@settings[:supported_groups] - defined).empty?
234
+
235
+ true
236
+ end
237
+
238
+ # @raise [TTTLS13::Error::ErrorAlerts]
239
+ #
240
+ # @return [TTTLS13::Message::ClientHello]
241
+ def recv_client_hello
242
+ ch = recv_message
243
+ terminate(:unexpected_message) unless ch.is_a?(Message::ClientHello)
244
+
245
+ ch
246
+ end
247
+
248
+ # @param exs [TTTLS13::Message::Extensions]
249
+ #
250
+ # @return [TTTLS13::Message::ServerHello]
251
+ def send_server_hello(exs)
252
+ ch_session_id = @transcript[CH].legacy_session_id
253
+ sh = Message::ServerHello.new(
254
+ legacy_session_id_echo: ch_session_id,
255
+ cipher_suite: @cipher_suite,
256
+ extensions: exs
257
+ )
258
+ send_handshakes(Message::ContentType::HANDSHAKE, [sh], @write_cipher)
259
+
260
+ sh
261
+ end
262
+
263
+ # @param messages [Array of TTTLS13::Message::$Object]
264
+ #
265
+ # @return [Array of TTTLS13::Message::$Object]
266
+ def send_server_parameters(messages)
267
+ send_handshakes(Message::ContentType::APPLICATION_DATA,
268
+ messages.reject(&:nil?),
269
+ @write_cipher)
270
+
271
+ messages
272
+ end
273
+
274
+ # @return [TTTLS13::Message::EncryptedExtensions]
275
+ def gen_encrypted_extensions
276
+ Message::EncryptedExtensions.new(gen_ee_extensions)
277
+ end
278
+
279
+ # @return [TTTLS13::Message::Certificate, nil]
280
+ def gen_certificate
281
+ return nil if @crt.nil?
282
+
283
+ ce = Message::CertificateEntry.new(@crt)
284
+ Message::Certificate.new(certificate_list: [ce])
285
+ end
286
+
287
+ # @return [TTTLS13::Message::CertificateVerify, nil]
288
+ def gen_certificate_verify
289
+ return nil if @key.nil?
290
+
291
+ Message::CertificateVerify.new(signature_scheme: @signature_scheme,
292
+ signature: sign_certificate_verify)
293
+ end
294
+
295
+ # @return [TTTLS13::Message::Finished]
296
+ def gen_finished
297
+ Message::Finished.new(sign_finished)
298
+ end
299
+
300
+ # @raise [TTTLS13::Error::ErrorAlerts]
301
+ #
302
+ # @return [TTTLS13::Message::Finished]
303
+ def recv_finished
304
+ cf = recv_message
305
+ terminate(:unexpected_message) unless cf.is_a?(Message::Finished)
306
+
307
+ cf
308
+ end
309
+
310
+ # @return [TTTLS13::Message::Extensions]
311
+ # @return [OpenSSL::PKey::EC.$Object]
312
+ def gen_sh_extensions
313
+ exs = []
314
+ # supported_versions: only TLS 1.3
315
+ exs << Message::Extension::SupportedVersions.new(
316
+ msg_type: Message::HandshakeType::SERVER_HELLO
317
+ )
318
+
319
+ # key_share
320
+ key_share, priv_key \
321
+ = Message::Extension::KeyShare.gen_sh_key_share(@named_group)
322
+ exs << key_share
323
+
324
+ [Message::Extensions.new(exs), priv_key]
325
+ end
326
+
327
+ # @return [TTTLS13::Message::Extensions]
328
+ def gen_ee_extensions
329
+ exs = []
330
+
331
+ # server_name
332
+ exs << Message::Extension::ServerName.new('') \
333
+ if @transcript[CH].extensions
334
+ .include?(Message::ExtensionType::SERVER_NAME)
335
+
336
+ # supported_groups
337
+ exs \
338
+ << Message::Extension::SupportedGroups.new(@settings[:supported_groups])
339
+
340
+ Message::Extensions.new(exs)
341
+ end
342
+
343
+ # @return [String]
344
+ def sign_certificate_verify
345
+ context = 'TLS 1.3, server CertificateVerify'
346
+ do_sign_certificate_verify(private_key: @key,
347
+ signature_scheme: @signature_scheme,
348
+ context: context,
349
+ handshake_context_end: CT)
350
+ end
351
+
352
+ # @return [String]
353
+ def sign_finished
354
+ digest = CipherSuite.digest(@cipher_suite)
355
+ finished_key = @key_schedule.server_finished_key
356
+ do_sign_finished(digest: digest,
357
+ finished_key: finished_key,
358
+ handshake_context_end: CV)
359
+ end
360
+
361
+ # @return [Boolean]
362
+ def verified_finished?
363
+ digest = CipherSuite.digest(@cipher_suite)
364
+ finished_key = @key_schedule.client_finished_key
365
+ signature = @transcript[CF].verify_data
366
+ do_verified_finished?(digest: digest,
367
+ finished_key: finished_key,
368
+ handshake_context_end: EOED,
369
+ signature: signature)
370
+ end
371
+
372
+ # @return [Boolean]
373
+ def negotiated_tls_1_3?
374
+ ch = @transcript[CH]
375
+ ch_lv = ch.legacy_version
376
+ ch_sv = ch.extensions[Message::ExtensionType::SUPPORTED_VERSIONS]
377
+ &.versions || []
378
+
379
+ ch_lv == Message::ProtocolVersion::TLS_1_2 &&
380
+ ch_sv.include?(Message::ProtocolVersion::TLS_1_3)
381
+ end
382
+
383
+ # @return [TTTLS13::CipherSuite, nil]
384
+ def select_cipher_suite
385
+ @transcript[CH].cipher_suites.find do |cs|
386
+ @settings[:cipher_suites].include?(cs)
387
+ end
388
+ end
389
+
390
+ # @return [TTTLS13::NamedGroup, nil]
391
+ def select_named_group
392
+ groups \
393
+ = @transcript[CH].extensions[Message::ExtensionType::SUPPORTED_GROUPS]
394
+ &.named_group_list || []
395
+
396
+ groups.find do |sg|
397
+ @settings[:supported_groups].include?(sg)
398
+ end
399
+ end
400
+
401
+ # @return [TTTLS13::SignatureScheme, nil]
402
+ def select_signature_scheme
403
+ algorithms \
404
+ = @transcript[CH].extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
405
+ &.supported_signature_algorithms || []
406
+
407
+ do_select_signature_algorithms(algorithms, @crt).find do |ss|
408
+ @settings[:signature_algorithms].include?(ss)
409
+ end
410
+ end
411
+
412
+ # @return [Boolean]
413
+ def valid_ch_compression_methods?
414
+ @transcript[CH].legacy_compression_methods == ["\x00"]
415
+ end
416
+
417
+ # @return [Boolean]
418
+ def recognized_server_name?
419
+ server_name \
420
+ = @transcript[CH].extensions[Message::ExtensionType::SERVER_NAME]
421
+ &.server_name
422
+
423
+ return true if server_name.nil?
424
+
425
+ matching_san?(@crt, server_name)
426
+ end
427
+
428
+ # @return [Boolean]
429
+ def valid_ch_key_share?
430
+ ks = @transcript[CH].extensions[Message::ExtensionType::KEY_SHARE]
431
+ ks_groups = ks&.key_share_entry&.map(&:group) || []
432
+ sg = @transcript[CH].extensions[Message::ExtensionType::SUPPORTED_GROUPS]
433
+ sp_groups = sg&.named_group_list || []
434
+
435
+ ks_groups.uniq == ks_groups && (ks_groups - sp_groups).empty?
436
+ end
437
+ end
438
+ # rubocop: enable Metrics/ClassLength
439
+ end
@@ -23,6 +23,8 @@ module TTTLS13
23
23
  super
24
24
  end
25
25
 
26
+ alias super_include? include?
27
+
26
28
  # @param digest [String] name of digest algorithm
27
29
  # @param end_index [Integer]
28
30
  #
@@ -43,6 +45,10 @@ module TTTLS13
43
45
  OpenSSL::Digest.digest(digest, truncated)
44
46
  end
45
47
 
48
+ def include?(key)
49
+ super_include?(key) && !self[key].nil?
50
+ end
51
+
46
52
  private
47
53
 
48
54
  # @param digest [String] name of digest algorithm
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.1.4'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/tttls1.3.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openssl'
4
+ require 'pp'
4
5
  require 'logger'
5
6
 
6
7
  require 'tttls1.3/version'
@@ -9,6 +10,7 @@ require 'tttls1.3/logging'
9
10
  require 'tttls1.3/error'
10
11
  require 'tttls1.3/cipher_suites'
11
12
  require 'tttls1.3/signature_scheme'
13
+ require 'tttls1.3/named_group'
12
14
  require 'tttls1.3/cryptograph'
13
15
  require 'tttls1.3/transcript'
14
16
  require 'tttls1.3/key_schedule'
@@ -16,3 +18,4 @@ require 'tttls1.3/message'
16
18
  require 'tttls1.3/sequence_number'
17
19
  require 'tttls1.3/connection'
18
20
  require 'tttls1.3/client'
21
+ require 'tttls1.3/server'