tttls1.3 0.3.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -1
- data/Gemfile +1 -0
- data/README.md +2 -2
- data/example/README.md +1 -1
- data/example/helper.rb +22 -0
- data/example/https_client.rb +4 -4
- data/example/https_client_using_0rtt.rb +6 -5
- data/example/https_client_using_ech.rb +5 -6
- data/example/https_client_using_grease_ech.rb +3 -5
- data/example/https_client_using_grease_psk.rb +8 -16
- data/example/https_client_using_hrr.rb +5 -4
- data/example/https_client_using_hrr_and_ech.rb +6 -6
- data/example/https_client_using_hrr_and_ticket.rb +5 -4
- data/example/https_client_using_status_request.rb +4 -5
- data/example/https_client_using_ticket.rb +5 -4
- data/example/https_server.rb +14 -1
- data/lib/tttls1.3/client.rb +205 -418
- data/lib/tttls1.3/connection.rb +21 -362
- data/lib/tttls1.3/ech.rb +410 -0
- data/lib/tttls1.3/endpoint.rb +276 -0
- data/lib/tttls1.3/message/certificate_verify.rb +1 -1
- data/lib/tttls1.3/message/extension/ech.rb +12 -10
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +2 -2
- data/lib/tttls1.3/message/extension/supported_versions.rb +3 -3
- data/lib/tttls1.3/message/extension/unknown_extension.rb +2 -2
- data/lib/tttls1.3/server.rb +125 -63
- data/lib/tttls1.3/utils.rb +37 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +2 -1
- data/spec/client_spec.rb +21 -60
- data/spec/ech_spec.rb +39 -0
- data/spec/{connection_spec.rb → endpoint_spec.rb} +41 -49
- data/spec/server_spec.rb +12 -12
- data/tttls1.3.gemspec +1 -1
- metadata +8 -7
- data/lib/tttls1.3/hpke.rb +0 -91
@@ -99,9 +99,10 @@ module TTTLS13
|
|
99
99
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
100
100
|
#
|
101
101
|
# @return [TTTLS13::Message::Extensions::ECHClientHello]
|
102
|
+
# rubocop: disable Metrics/AbcSize
|
102
103
|
def deserialize_outer_ech(binary)
|
103
|
-
raise Error::ErrorAlerts, :internal_error
|
104
|
-
|
104
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
105
|
+
raise Error::ErrorAlerts, :decode_error if binary.length < 5
|
105
106
|
|
106
107
|
kdf_id = \
|
107
108
|
HpkeSymmetricCipherSuite::HpkeKdfId.decode(binary.slice(0, 2))
|
@@ -111,16 +112,16 @@ module TTTLS13
|
|
111
112
|
cid = Convert.bin2i(binary.slice(4, 1))
|
112
113
|
enc_len = Convert.bin2i(binary.slice(5, 2))
|
113
114
|
i = 7
|
114
|
-
raise Error::ErrorAlerts, :
|
115
|
+
raise Error::ErrorAlerts, :decode_error \
|
115
116
|
if i + enc_len > binary.length
|
116
117
|
|
117
118
|
enc = binary.slice(i, enc_len)
|
118
119
|
i += enc_len
|
119
|
-
raise Error::ErrorAlerts, :
|
120
|
+
raise Error::ErrorAlerts, :decode_error \
|
120
121
|
if i + 2 > binary.length
|
121
122
|
|
122
123
|
payload_len = Convert.bin2i(binary.slice(i, 2))
|
123
|
-
raise Error::ErrorAlerts, :
|
124
|
+
raise Error::ErrorAlerts, :decode_error \
|
124
125
|
if i + payload_len > binary.length
|
125
126
|
|
126
127
|
payload = binary.slice(i, payload_len)
|
@@ -132,6 +133,7 @@ module TTTLS13
|
|
132
133
|
payload: payload
|
133
134
|
)
|
134
135
|
end
|
136
|
+
# rubocop: enable Metrics/AbcSize
|
135
137
|
|
136
138
|
# @param binary [String]
|
137
139
|
#
|
@@ -139,7 +141,7 @@ module TTTLS13
|
|
139
141
|
#
|
140
142
|
# @return [TTTLS13::Message::Extensions::ECHClientHello]
|
141
143
|
def deserialize_inner_ech(binary)
|
142
|
-
raise Error::ErrorAlerts, :
|
144
|
+
raise Error::ErrorAlerts, :illegal_parameter unless binary.empty?
|
143
145
|
|
144
146
|
ECHClientHello.new(type: ECHClientHelloType::INNER)
|
145
147
|
end
|
@@ -195,9 +197,9 @@ module TTTLS13
|
|
195
197
|
#
|
196
198
|
# @return [TTTLS13::Message::Extensions::ECHEncryptedExtensions]
|
197
199
|
def self.deserialize(binary)
|
200
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
198
201
|
raise Error::ErrorAlerts, :decode_error \
|
199
|
-
if binary.
|
200
|
-
binary.length != binary.slice(0, 2).unpack1('n') + 2
|
202
|
+
if binary.length != binary.slice(0, 2).unpack1('n') + 2
|
201
203
|
|
202
204
|
ECHEncryptedExtensions.new(
|
203
205
|
ECHConfig.decode_vectors(binary.slice(2..))
|
@@ -230,8 +232,8 @@ module TTTLS13
|
|
230
232
|
#
|
231
233
|
# @return [TTTLS13::Message::Extensions::ECHHelloRetryRequest]
|
232
234
|
def self.deserialize(binary)
|
233
|
-
raise Error::ErrorAlerts, :
|
234
|
-
|
235
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
236
|
+
raise Error::ErrorAlerts, :decode_error if binary.length != 8
|
235
237
|
|
236
238
|
ECHHelloRetryRequest.new(binary)
|
237
239
|
end
|
@@ -21,8 +21,8 @@ module TTTLS13
|
|
21
21
|
SignatureScheme::RSA_PKCS1_SHA512
|
22
22
|
].freeze
|
23
23
|
|
24
|
-
|
25
|
-
attr_reader
|
24
|
+
attr_reader :extension_type # for signature_algorithms_cert getter
|
25
|
+
attr_reader :supported_signature_algorithms
|
26
26
|
|
27
27
|
# @param supported_signature_algorithms [Array of SignatureScheme]
|
28
28
|
def initialize(supported_signature_algorithms)
|
@@ -6,9 +6,9 @@ module TTTLS13
|
|
6
6
|
module Message
|
7
7
|
module Extension
|
8
8
|
class SupportedVersions
|
9
|
-
attr_reader
|
10
|
-
|
11
|
-
|
9
|
+
attr_reader :extension_type
|
10
|
+
attr_reader :msg_type
|
11
|
+
attr_reader :versions
|
12
12
|
|
13
13
|
# @param msg_type [TTTLS13::Message::ContentType]
|
14
14
|
# @param versions [Array of ProtocolVersion]
|
@@ -9,8 +9,8 @@ module TTTLS13
|
|
9
9
|
# Client/Server MUST ignore unrecognized extensions,
|
10
10
|
# but transcript MUST include unrecognized extensions.
|
11
11
|
class UnknownExtension
|
12
|
-
|
13
|
-
|
12
|
+
attr_reader :extension_type
|
13
|
+
attr_reader :extension_data
|
14
14
|
|
15
15
|
# @param extension_type [String]
|
16
16
|
# @param extension_data [String]
|
data/lib/tttls1.3/server.rb
CHANGED
@@ -66,13 +66,15 @@ module TTTLS13
|
|
66
66
|
private_constant :DEFAULT_SERVER_SETTINGS
|
67
67
|
|
68
68
|
# rubocop: disable Metrics/ClassLength
|
69
|
-
class Server
|
69
|
+
class Server
|
70
|
+
include Logging
|
71
|
+
|
72
|
+
attr_reader :transcript
|
73
|
+
|
70
74
|
# @param socket [Socket]
|
71
75
|
# @param settings [Hash]
|
72
76
|
def initialize(socket, **settings)
|
73
|
-
|
74
|
-
|
75
|
-
@endpoint = :server
|
77
|
+
@connection = Connection.new(socket, :server)
|
76
78
|
@settings = DEFAULT_SERVER_SETTINGS.merge(settings)
|
77
79
|
logger.level = @settings[:loglevel]
|
78
80
|
|
@@ -144,7 +146,7 @@ module TTTLS13
|
|
144
146
|
# rubocop: disable Metrics/MethodLength
|
145
147
|
# rubocop: disable Metrics/PerceivedComplexity
|
146
148
|
def accept
|
147
|
-
transcript = Transcript.new
|
149
|
+
@transcript = Transcript.new
|
148
150
|
key_schedule = nil # TTTLS13::KeySchedule
|
149
151
|
priv_key = nil # OpenSSL::PKey::$Object
|
150
152
|
hs_wcipher = nil # TTTLS13::Cryptograph::$Object
|
@@ -159,24 +161,27 @@ module TTTLS13
|
|
159
161
|
end
|
160
162
|
end
|
161
163
|
|
162
|
-
@state = ServerState::START
|
164
|
+
@connection.state = ServerState::START
|
163
165
|
loop do
|
164
|
-
case @state
|
166
|
+
case @connection.state
|
165
167
|
when ServerState::START
|
166
168
|
logger.debug('ServerState::START')
|
167
169
|
|
168
|
-
receivable_ccs = transcript.include?(CH1)
|
169
|
-
ch, = transcript[CH] = recv_client_hello(receivable_ccs)
|
170
|
+
receivable_ccs = @transcript.include?(CH1)
|
171
|
+
ch, = @transcript[CH] = recv_client_hello(receivable_ccs)
|
170
172
|
|
171
173
|
# support only TLS 1.3
|
172
|
-
terminate(:protocol_version) unless ch.negotiated_tls_1_3?
|
174
|
+
@connection.terminate(:protocol_version) unless ch.negotiated_tls_1_3?
|
173
175
|
|
174
176
|
# validate parameters
|
175
|
-
terminate(:illegal_parameter)
|
176
|
-
|
177
|
+
@connection.terminate(:illegal_parameter) \
|
178
|
+
unless ch.appearable_extensions?
|
179
|
+
@connection.terminate(:illegal_parameter) \
|
177
180
|
unless ch.legacy_compression_methods == ["\x00"]
|
178
|
-
terminate(:illegal_parameter)
|
179
|
-
|
181
|
+
@connection.terminate(:illegal_parameter) \
|
182
|
+
unless ch.valid_key_share?
|
183
|
+
@connection.terminate(:unrecognized_name) \
|
184
|
+
unless recognized_server_name?(ch, @crt)
|
180
185
|
|
181
186
|
# alpn
|
182
187
|
ch_alpn = ch.extensions[
|
@@ -186,109 +191,109 @@ module TTTLS13
|
|
186
191
|
@alpn = ch_alpn.protocol_name_list
|
187
192
|
.find { |p| @settings[:alpn].include?(p) }
|
188
193
|
|
189
|
-
terminate(:no_application_protocol) if @alpn.nil?
|
194
|
+
@connection.terminate(:no_application_protocol) if @alpn.nil?
|
190
195
|
end
|
191
196
|
|
192
197
|
# record_size_limit
|
193
198
|
ch_rsl = ch.extensions[Message::ExtensionType::RECORD_SIZE_LIMIT]
|
194
199
|
@send_record_size = ch_rsl.record_size_limit unless ch_rsl.nil?
|
195
200
|
|
196
|
-
@state = ServerState::RECVD_CH
|
201
|
+
@connection.state = ServerState::RECVD_CH
|
197
202
|
when ServerState::RECVD_CH
|
198
203
|
logger.debug('ServerState::RECVD_CH')
|
199
204
|
|
200
205
|
# select parameters
|
201
|
-
ch, = transcript[CH]
|
206
|
+
ch, = @transcript[CH]
|
202
207
|
@cipher_suite = select_cipher_suite(ch)
|
203
208
|
@named_group = select_named_group(ch)
|
204
209
|
@signature_scheme = select_signature_scheme(ch, @crt)
|
205
|
-
terminate(:handshake_failure) \
|
210
|
+
@connection.terminate(:handshake_failure) \
|
206
211
|
if @cipher_suite.nil? || @signature_scheme.nil?
|
207
212
|
|
208
213
|
# send HRR
|
209
214
|
if @named_group.nil?
|
210
|
-
ch1, = transcript[CH1] = transcript.delete(CH)
|
215
|
+
ch1, = @transcript[CH1] = @transcript.delete(CH)
|
211
216
|
hrr = send_hello_retry_request(ch1, @cipher_suite)
|
212
|
-
transcript[HRR] = [hrr, hrr.serialize]
|
213
|
-
@state = ServerState::START
|
217
|
+
@transcript[HRR] = [hrr, hrr.serialize]
|
218
|
+
@connection.state = ServerState::START
|
214
219
|
next
|
215
220
|
end
|
216
|
-
@state = ServerState::NEGOTIATED
|
221
|
+
@connection.state = ServerState::NEGOTIATED
|
217
222
|
when ServerState::NEGOTIATED
|
218
223
|
logger.debug('ServerState::NEGOTIATED')
|
219
224
|
|
220
|
-
ch, = transcript[CH]
|
225
|
+
ch, = @transcript[CH]
|
221
226
|
extensions, priv_key = gen_sh_extensions(@named_group)
|
222
227
|
sh = send_server_hello(
|
223
228
|
extensions,
|
224
229
|
@cipher_suite,
|
225
230
|
ch.legacy_session_id
|
226
231
|
)
|
227
|
-
transcript[SH] = [sh, sh.serialize]
|
228
|
-
send_ccs if @settings[:compatibility_mode]
|
232
|
+
@transcript[SH] = [sh, sh.serialize]
|
233
|
+
@connection.send_ccs if @settings[:compatibility_mode]
|
229
234
|
|
230
235
|
# generate shared secret
|
231
236
|
ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
|
232
237
|
&.key_share_entry
|
233
238
|
&.find { |kse| kse.group == @named_group }
|
234
239
|
&.key_exchange
|
235
|
-
shared_secret = gen_shared_secret(ke, priv_key, @named_group)
|
240
|
+
shared_secret = Endpoint.gen_shared_secret(ke, priv_key, @named_group)
|
236
241
|
key_schedule = KeySchedule.new(
|
237
242
|
psk: @psk,
|
238
243
|
shared_secret: shared_secret,
|
239
244
|
cipher_suite: @cipher_suite,
|
240
|
-
transcript: transcript
|
245
|
+
transcript: @transcript
|
241
246
|
)
|
242
|
-
@alert_wcipher = hs_wcipher = gen_cipher(
|
247
|
+
@connection.alert_wcipher = hs_wcipher = Endpoint.gen_cipher(
|
243
248
|
@cipher_suite,
|
244
249
|
key_schedule.server_handshake_write_key,
|
245
250
|
key_schedule.server_handshake_write_iv
|
246
251
|
)
|
247
252
|
sslkeylogfile&.write_server_handshake_traffic_secret(
|
248
|
-
transcript[CH].first.random,
|
253
|
+
@transcript[CH].first.random,
|
249
254
|
key_schedule.server_handshake_traffic_secret
|
250
255
|
)
|
251
|
-
hs_rcipher = gen_cipher(
|
256
|
+
hs_rcipher = Endpoint.gen_cipher(
|
252
257
|
@cipher_suite,
|
253
258
|
key_schedule.client_handshake_write_key,
|
254
259
|
key_schedule.client_handshake_write_iv
|
255
260
|
)
|
256
261
|
sslkeylogfile&.write_client_handshake_traffic_secret(
|
257
|
-
transcript[CH].first.random,
|
262
|
+
@transcript[CH].first.random,
|
258
263
|
key_schedule.client_handshake_traffic_secret
|
259
264
|
)
|
260
|
-
@state = ServerState::WAIT_FLIGHT2
|
265
|
+
@connection.state = ServerState::WAIT_FLIGHT2
|
261
266
|
when ServerState::WAIT_EOED
|
262
267
|
logger.debug('ServerState::WAIT_EOED')
|
263
268
|
when ServerState::WAIT_FLIGHT2
|
264
269
|
logger.debug('ServerState::WAIT_FLIGHT2')
|
265
270
|
|
266
|
-
ch, = transcript[CH]
|
271
|
+
ch, = @transcript[CH]
|
267
272
|
rsl = @send_record_size \
|
268
273
|
if ch.extensions.include?(Message::ExtensionType::RECORD_SIZE_LIMIT)
|
269
274
|
ee = gen_encrypted_extensions(ch, @alpn, rsl)
|
270
|
-
transcript[EE] = [ee, ee.serialize]
|
275
|
+
@transcript[EE] = [ee, ee.serialize]
|
271
276
|
# TODO: [Send CertificateRequest]
|
272
277
|
|
273
278
|
# status_request
|
274
279
|
ocsp_response = fetch_ocsp_response \
|
275
280
|
if ch.extensions.include?(Message::ExtensionType::STATUS_REQUEST)
|
276
281
|
ct = gen_certificate(@crt, ch, @chain, ocsp_response)
|
277
|
-
transcript[CT] = [ct, ct.serialize]
|
282
|
+
@transcript[CT] = [ct, ct.serialize]
|
278
283
|
digest = CipherSuite.digest(@cipher_suite)
|
279
|
-
hash = transcript.hash(digest, CT)
|
284
|
+
hash = @transcript.hash(digest, CT)
|
280
285
|
cv = gen_certificate_verify(@key, @signature_scheme, hash)
|
281
|
-
transcript[CV] = [cv, cv.serialize]
|
286
|
+
@transcript[CV] = [cv, cv.serialize]
|
282
287
|
finished_key = key_schedule.server_finished_key
|
283
|
-
signature = sign_finished(
|
288
|
+
signature = Endpoint.sign_finished(
|
284
289
|
digest: digest,
|
285
290
|
finished_key: finished_key,
|
286
|
-
hash: transcript.hash(digest, CV)
|
291
|
+
hash: @transcript.hash(digest, CV)
|
287
292
|
)
|
288
293
|
sf = Message::Finished.new(signature)
|
289
|
-
transcript[SF] = [sf, sf.serialize]
|
294
|
+
@transcript[SF] = [sf, sf.serialize]
|
290
295
|
send_server_parameters([ee, ct, cv, sf], hs_wcipher)
|
291
|
-
@state = ServerState::WAIT_FINISHED
|
296
|
+
@connection.state = ServerState::WAIT_FINISHED
|
292
297
|
when ServerState::WAIT_CERT
|
293
298
|
logger.debug('ServerState::WAIT_CERT')
|
294
299
|
when ServerState::WAIT_CV
|
@@ -296,35 +301,36 @@ module TTTLS13
|
|
296
301
|
when ServerState::WAIT_FINISHED
|
297
302
|
logger.debug('ServerState::WAIT_FINISHED')
|
298
303
|
|
299
|
-
cf, = transcript[CF] = recv_finished(hs_rcipher)
|
304
|
+
cf, = @transcript[CF] = recv_finished(hs_rcipher)
|
300
305
|
digest = CipherSuite.digest(@cipher_suite)
|
301
|
-
verified = verified_finished?(
|
306
|
+
verified = Endpoint.verified_finished?(
|
302
307
|
finished: cf,
|
303
308
|
digest: digest,
|
304
309
|
finished_key: key_schedule.client_finished_key,
|
305
|
-
hash: transcript.hash(digest, EOED)
|
310
|
+
hash: @transcript.hash(digest, EOED)
|
306
311
|
)
|
307
|
-
terminate(:decrypt_error) unless verified
|
308
|
-
@
|
312
|
+
@connection.terminate(:decrypt_error) unless verified
|
313
|
+
@connection.ap_wcipher = Endpoint.gen_cipher(
|
309
314
|
@cipher_suite,
|
310
315
|
key_schedule.server_application_write_key,
|
311
316
|
key_schedule.server_application_write_iv
|
312
317
|
)
|
318
|
+
@connection.alert_wcipher = @connection.ap_wcipher
|
313
319
|
sslkeylogfile&.write_server_traffic_secret_0(
|
314
|
-
transcript[CH].first.random,
|
320
|
+
@transcript[CH].first.random,
|
315
321
|
key_schedule.server_application_traffic_secret
|
316
322
|
)
|
317
|
-
@ap_rcipher = gen_cipher(
|
323
|
+
@connection.ap_rcipher = Endpoint.gen_cipher(
|
318
324
|
@cipher_suite,
|
319
325
|
key_schedule.client_application_write_key,
|
320
326
|
key_schedule.client_application_write_iv
|
321
327
|
)
|
322
328
|
sslkeylogfile&.write_client_traffic_secret_0(
|
323
|
-
transcript[CH].first.random,
|
329
|
+
@transcript[CH].first.random,
|
324
330
|
key_schedule.client_application_traffic_secret
|
325
331
|
)
|
326
332
|
@exporter_secret = key_schedule.exporter_secret
|
327
|
-
@state = ServerState::CONNECTED
|
333
|
+
@connection.state = ServerState::CONNECTED
|
328
334
|
when ServerState::CONNECTED
|
329
335
|
logger.debug('ServerState::CONNECTED')
|
330
336
|
|
@@ -339,6 +345,59 @@ module TTTLS13
|
|
339
345
|
# rubocop: enable Metrics/MethodLength
|
340
346
|
# rubocop: enable Metrics/PerceivedComplexity
|
341
347
|
|
348
|
+
# @raise [TTTLS13::Error::ConfigError]
|
349
|
+
#
|
350
|
+
# @return [String]
|
351
|
+
def read
|
352
|
+
@connection.read(nil)
|
353
|
+
end
|
354
|
+
|
355
|
+
# @param binary [String]
|
356
|
+
def write(binary)
|
357
|
+
@connection.write(binary)
|
358
|
+
end
|
359
|
+
|
360
|
+
# @return [Boolean]
|
361
|
+
def eof?
|
362
|
+
@connection.eof?
|
363
|
+
end
|
364
|
+
|
365
|
+
def close
|
366
|
+
@connection.close
|
367
|
+
end
|
368
|
+
|
369
|
+
# @return [TTTLS13::CipherSuite, nil]
|
370
|
+
def negotiated_cipher_suite
|
371
|
+
@cipher_suite
|
372
|
+
end
|
373
|
+
|
374
|
+
# @return [TTTLS13::NamedGroup, nil]
|
375
|
+
def negotiated_named_group
|
376
|
+
@named_group
|
377
|
+
end
|
378
|
+
|
379
|
+
# @return [TTTLS13::SignatureScheme, nil]
|
380
|
+
def negotiated_signature_scheme
|
381
|
+
@signature_scheme
|
382
|
+
end
|
383
|
+
|
384
|
+
# @return [String]
|
385
|
+
def negotiated_alpn
|
386
|
+
@alpn
|
387
|
+
end
|
388
|
+
|
389
|
+
# @param label [String]
|
390
|
+
# @param context [String]
|
391
|
+
# @param key_length [Integer]
|
392
|
+
#
|
393
|
+
# @return [String, nil]
|
394
|
+
def exporter(label, context, key_length)
|
395
|
+
return nil if @exporter_secret.nil? || @cipher_suite.nil?
|
396
|
+
|
397
|
+
digest = CipherSuite.digest(@cipher_suite)
|
398
|
+
Endpoint.exporter(@exporter_secret, digest, label, context, key_length)
|
399
|
+
end
|
400
|
+
|
342
401
|
private
|
343
402
|
|
344
403
|
# @return [Boolean]
|
@@ -365,11 +424,12 @@ module TTTLS13
|
|
365
424
|
# @return [TTTLS13::Message::ClientHello]
|
366
425
|
# @return [String]
|
367
426
|
def recv_client_hello(receivable_ccs)
|
368
|
-
ch, orig_msg = recv_message(
|
427
|
+
ch, orig_msg = @connection.recv_message(
|
369
428
|
receivable_ccs: receivable_ccs,
|
370
429
|
cipher: Cryptograph::Passer.new
|
371
430
|
)
|
372
|
-
terminate(:unexpected_message)
|
431
|
+
@connection.terminate(:unexpected_message) \
|
432
|
+
unless ch.is_a?(Message::ClientHello)
|
373
433
|
|
374
434
|
[ch, orig_msg]
|
375
435
|
end
|
@@ -385,8 +445,8 @@ module TTTLS13
|
|
385
445
|
cipher_suite: cipher_suite,
|
386
446
|
extensions: extensions
|
387
447
|
)
|
388
|
-
send_handshakes(Message::ContentType::HANDSHAKE, [sh],
|
389
|
-
|
448
|
+
@connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
|
449
|
+
Cryptograph::Passer.new)
|
390
450
|
|
391
451
|
sh
|
392
452
|
end
|
@@ -420,8 +480,8 @@ module TTTLS13
|
|
420
480
|
cipher_suite: cipher_suite,
|
421
481
|
extensions: exs
|
422
482
|
)
|
423
|
-
send_handshakes(Message::ContentType::HANDSHAKE, [sh],
|
424
|
-
|
483
|
+
@connection.send_handshakes(Message::ContentType::HANDSHAKE, [sh],
|
484
|
+
Cryptograph::Passer.new)
|
425
485
|
|
426
486
|
sh
|
427
487
|
end
|
@@ -431,8 +491,8 @@ module TTTLS13
|
|
431
491
|
#
|
432
492
|
# @return [Array of TTTLS13::Message::$Object]
|
433
493
|
def send_server_parameters(messages, cipher)
|
434
|
-
send_handshakes(Message::ContentType::APPLICATION_DATA,
|
435
|
-
|
494
|
+
@connection.send_handshakes(Message::ContentType::APPLICATION_DATA,
|
495
|
+
messages.reject(&:nil?), cipher)
|
436
496
|
|
437
497
|
messages
|
438
498
|
end
|
@@ -505,8 +565,10 @@ module TTTLS13
|
|
505
565
|
# @return [TTTLS13::Message::Finished]
|
506
566
|
# @return [String]
|
507
567
|
def recv_finished(cipher)
|
508
|
-
cf, orig_msg
|
509
|
-
|
568
|
+
cf, orig_msg \
|
569
|
+
= @connection.recv_message(receivable_ccs: true, cipher: cipher)
|
570
|
+
@connection.terminate(:unexpected_message) \
|
571
|
+
unless cf.is_a?(Message::Finished)
|
510
572
|
|
511
573
|
[cf, orig_msg]
|
512
574
|
end
|
@@ -563,7 +625,7 @@ module TTTLS13
|
|
563
625
|
#
|
564
626
|
# @return [String]
|
565
627
|
def sign_certificate_verify(key:, signature_scheme:, hash:)
|
566
|
-
|
628
|
+
Endpoint.sign_certificate_verify(
|
567
629
|
key: key,
|
568
630
|
signature_scheme: signature_scheme,
|
569
631
|
context: 'TLS 1.3, server CertificateVerify',
|
@@ -600,7 +662,7 @@ module TTTLS13
|
|
600
662
|
algorithms = ch.extensions[Message::ExtensionType::SIGNATURE_ALGORITHMS]
|
601
663
|
&.supported_signature_algorithms || []
|
602
664
|
|
603
|
-
|
665
|
+
Endpoint.select_signature_algorithms(algorithms, crt).find do |ss|
|
604
666
|
@settings[:signature_algorithms].include?(ss)
|
605
667
|
end
|
606
668
|
end
|
@@ -614,7 +676,7 @@ module TTTLS13
|
|
614
676
|
&.server_name
|
615
677
|
return true if server_name.nil?
|
616
678
|
|
617
|
-
matching_san?(crt, server_name)
|
679
|
+
Endpoint.matching_san?(crt, server_name)
|
618
680
|
end
|
619
681
|
|
620
682
|
# @return [OpenSSL::OCSP::Response, nil]
|
data/lib/tttls1.3/utils.rb
CHANGED
@@ -91,6 +91,43 @@ module TTTLS13
|
|
91
91
|
def bin2i(binary)
|
92
92
|
OpenSSL::BN.new(binary, 2).to_i
|
93
93
|
end
|
94
|
+
|
95
|
+
# rubocop: disable Metrics/AbcSize
|
96
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
97
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
98
|
+
def obj2html(obj)
|
99
|
+
if obj.is_a?(OpenSSL::X509::Certificate)
|
100
|
+
obj.to_pem.gsub("\n", '<br>')
|
101
|
+
elsif obj.is_a?(Numeric) ||
|
102
|
+
obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
|
103
|
+
obj.pretty_print_inspect
|
104
|
+
elsif obj.is_a?(String) && obj.empty?
|
105
|
+
''
|
106
|
+
elsif obj.is_a? String
|
107
|
+
'0x' + obj.unpack1('H*')
|
108
|
+
elsif obj.is_a? NilClass
|
109
|
+
''
|
110
|
+
elsif obj.is_a? Array
|
111
|
+
'<ul>' + obj.map { |i| '<li>' + obj2html(i) + '</li>' }.join + '</ul>'
|
112
|
+
elsif obj.is_a? Hash
|
113
|
+
obj.map do |k, v|
|
114
|
+
'<details><summary>' + obj2html(k) + '</summary>' \
|
115
|
+
+ obj2html(v) \
|
116
|
+
+ '</details>'
|
117
|
+
end.join
|
118
|
+
elsif obj.is_a?(Object) && !obj.instance_variables.empty?
|
119
|
+
obj.instance_variables.map do |i|
|
120
|
+
'<details><summary>' + i[1..] + '</summary>' \
|
121
|
+
+ obj2html(obj.instance_variable_get(i)) \
|
122
|
+
+ '</details>'
|
123
|
+
end.join
|
124
|
+
else
|
125
|
+
obj.class.name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
# rubocop: enable Metrics/AbcSize
|
129
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
130
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
94
131
|
end
|
95
132
|
end
|
96
133
|
end
|
data/lib/tttls1.3/version.rb
CHANGED
data/lib/tttls1.3.rb
CHANGED
@@ -21,7 +21,8 @@ require 'tttls1.3/key_schedule'
|
|
21
21
|
require 'tttls1.3/message'
|
22
22
|
require 'tttls1.3/sequence_number'
|
23
23
|
require 'tttls1.3/sslkeylogfile'
|
24
|
-
require 'tttls1.3/
|
24
|
+
require 'tttls1.3/ech'
|
25
25
|
require 'tttls1.3/connection'
|
26
|
+
require 'tttls1.3/endpoint'
|
26
27
|
require 'tttls1.3/client'
|
27
28
|
require 'tttls1.3/server'
|
data/spec/client_spec.rb
CHANGED
@@ -129,10 +129,11 @@ RSpec.describe Client do
|
|
129
129
|
client = Client.new(mock_socket, 'localhost')
|
130
130
|
digest = CipherSuite.digest(cipher_suite)
|
131
131
|
hash = transcript.hash(digest, EOED)
|
132
|
-
signature =
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
signature = Endpoint.sign_finished(
|
133
|
+
digest: digest,
|
134
|
+
finished_key: finished_key,
|
135
|
+
hash: hash
|
136
|
+
)
|
136
137
|
hs_wcipher = Cryptograph::Aead.new(
|
137
138
|
cipher_suite: cipher_suite,
|
138
139
|
write_key: TESTBINARY_CLIENT_FINISHED_WRITE_KEY,
|
@@ -215,20 +216,22 @@ RSpec.describe Client do
|
|
215
216
|
it 'should verify server Finished' do
|
216
217
|
digest = CipherSuite.digest(cipher_suite)
|
217
218
|
hash = transcript.hash(digest, CV)
|
218
|
-
expect(
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
219
|
+
expect(Endpoint.verified_finished?(
|
220
|
+
finished: sf,
|
221
|
+
digest: digest,
|
222
|
+
finished_key: key_schedule.server_finished_key,
|
223
|
+
hash: hash
|
224
|
+
)).to be true
|
223
225
|
end
|
224
226
|
|
225
227
|
it 'should sign client Finished' do
|
226
228
|
digest = CipherSuite.digest(cipher_suite)
|
227
229
|
hash = transcript.hash(digest, EOED)
|
228
|
-
expect(
|
229
|
-
|
230
|
-
|
231
|
-
|
230
|
+
expect(Endpoint.sign_finished(
|
231
|
+
digest: digest,
|
232
|
+
finished_key: key_schedule.client_finished_key,
|
233
|
+
hash: hash
|
234
|
+
)).to eq cf.verify_data
|
232
235
|
end
|
233
236
|
end
|
234
237
|
|
@@ -240,18 +243,16 @@ RSpec.describe Client do
|
|
240
243
|
Certificate.new(certificate_list: [CertificateEntry.new(server_crt)])
|
241
244
|
end
|
242
245
|
|
243
|
-
let(:client) do
|
244
|
-
Client.new(nil, 'localhost')
|
245
|
-
end
|
246
|
-
|
247
246
|
it 'should not certify certificate' do
|
248
|
-
expect(
|
247
|
+
expect(Endpoint.trusted_certificate?(certificate.certificate_list))
|
249
248
|
.to be false
|
250
249
|
end
|
251
250
|
|
252
251
|
it 'should certify certificate, received path to private ca.crt' do
|
253
|
-
expect(
|
254
|
-
|
252
|
+
expect(Endpoint.trusted_certificate?(
|
253
|
+
certificate.certificate_list,
|
254
|
+
__dir__ + '/fixtures/rsa_ca.crt'
|
255
|
+
)).to be true
|
255
256
|
end
|
256
257
|
end
|
257
258
|
|
@@ -270,44 +271,4 @@ RSpec.describe Client do
|
|
270
271
|
'SHA256')).to eq TESTBINARY_0_RTT_PSK
|
271
272
|
end
|
272
273
|
end
|
273
|
-
|
274
|
-
context 'EncodedClientHelloInner length' do
|
275
|
-
let(:server_name) do
|
276
|
-
'localhost'
|
277
|
-
end
|
278
|
-
|
279
|
-
let(:client) do
|
280
|
-
Client.new(nil, server_name)
|
281
|
-
end
|
282
|
-
|
283
|
-
let(:maximum_name_length) do
|
284
|
-
0
|
285
|
-
end
|
286
|
-
|
287
|
-
let(:encoded) do
|
288
|
-
extensions, = client.send(:gen_ch_extensions)
|
289
|
-
inner_ech = Message::Extension::ECHClientHello.new_inner
|
290
|
-
Message::ClientHello.new(
|
291
|
-
legacy_session_id: '',
|
292
|
-
cipher_suites: CipherSuites.new(DEFAULT_CH_CIPHER_SUITES),
|
293
|
-
extensions: extensions.merge(
|
294
|
-
Message::ExtensionType::ENCRYPTED_CLIENT_HELLO => inner_ech
|
295
|
-
)
|
296
|
-
)
|
297
|
-
end
|
298
|
-
|
299
|
-
let(:padding_encoded_ch_inner) do
|
300
|
-
client.send(
|
301
|
-
:padding_encoded_ch_inner,
|
302
|
-
encoded.serialize[4..],
|
303
|
-
server_name.length,
|
304
|
-
maximum_name_length
|
305
|
-
)
|
306
|
-
end
|
307
|
-
|
308
|
-
it 'should be equal placeholder_encoded_ch_inner_len' do
|
309
|
-
expect(client.send(:placeholder_encoded_ch_inner_len))
|
310
|
-
.to eq padding_encoded_ch_inner.length
|
311
|
-
end
|
312
|
-
end
|
313
274
|
end
|