tttls1.3 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/example/helper.rb +21 -0
- data/example/https_client_using_0rtt.rb +1 -1
- 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
- metadata +7 -6
- data/lib/tttls1.3/hpke.rb +0 -91
data/lib/tttls1.3/connection.rb
CHANGED
@@ -5,42 +5,42 @@ module TTTLS13
|
|
5
5
|
INITIAL = 0
|
6
6
|
EOF = -1
|
7
7
|
|
8
|
-
SUPPORTED_ECHCONFIG_VERSIONS = ["\xfe\x0d"].freeze
|
9
|
-
private_constant :SUPPORTED_ECHCONFIG_VERSIONS
|
10
|
-
|
11
8
|
# rubocop: disable Metrics/ClassLength
|
12
9
|
class Connection
|
13
10
|
include Logging
|
14
11
|
|
12
|
+
attr_accessor :state
|
13
|
+
attr_accessor :ap_wcipher
|
14
|
+
attr_accessor :ap_rcipher
|
15
|
+
attr_accessor :alert_wcipher
|
16
|
+
|
15
17
|
# @param socket [Socket]
|
16
|
-
|
18
|
+
# @param side [:client or :server]
|
19
|
+
def initialize(socket, side)
|
17
20
|
@socket = socket
|
18
|
-
@
|
21
|
+
@side = side
|
22
|
+
@state = INITIAL
|
19
23
|
@ap_wcipher = Cryptograph::Passer.new
|
20
24
|
@ap_rcipher = Cryptograph::Passer.new
|
21
25
|
@alert_wcipher = Cryptograph::Passer.new
|
22
26
|
@message_queue = [] # Array of [TTTLS13::Message::$Object, String]
|
23
27
|
@binary_buffer = '' # deposit Record.surplus_binary
|
24
|
-
@cipher_suite = nil # TTTLS13::CipherSuite
|
25
|
-
@named_group = nil # TTTLS13::NamedGroup
|
26
|
-
@signature_scheme = nil # TTTLS13::SignatureScheme
|
27
|
-
@state = 0 # ClientState or ServerState
|
28
28
|
@send_record_size = Message::DEFAULT_RECORD_SIZE_LIMIT
|
29
29
|
@recv_record_size = Message::DEFAULT_RECORD_SIZE_LIMIT
|
30
|
-
@alpn = nil # String
|
31
|
-
@exporter_secret = nil # String
|
32
30
|
end
|
33
31
|
|
32
|
+
# @param nst_process [Method]
|
33
|
+
#
|
34
34
|
# @raise [TTTLS13::Error::ConfigError]
|
35
35
|
#
|
36
36
|
# @return [String]
|
37
37
|
# rubocop: disable Metrics/CyclomaticComplexity
|
38
38
|
# rubocop: disable Metrics/PerceivedComplexity
|
39
|
-
def read
|
39
|
+
def read(nst_process)
|
40
40
|
# secure channel has not established yet
|
41
41
|
raise Error::ConfigError \
|
42
|
-
unless (@
|
43
|
-
(@
|
42
|
+
unless (@side == :client && @state == ClientState::CONNECTED) ||
|
43
|
+
(@side == :server && @state == ServerState::CONNECTED)
|
44
44
|
return '' if @state == EOF
|
45
45
|
|
46
46
|
message = nil
|
@@ -50,7 +50,9 @@ module TTTLS13
|
|
50
50
|
# message, it MAY send a NewSessionTicket message.
|
51
51
|
break unless message.is_a?(Message::NewSessionTicket)
|
52
52
|
|
53
|
-
|
53
|
+
terminate(:unexpected_message) if @side == :server
|
54
|
+
|
55
|
+
nst_process.call(message)
|
54
56
|
end
|
55
57
|
return '' if message.nil?
|
56
58
|
|
@@ -70,8 +72,8 @@ module TTTLS13
|
|
70
72
|
def write(binary)
|
71
73
|
# secure channel has not established yet
|
72
74
|
raise Error::ConfigError \
|
73
|
-
unless (@
|
74
|
-
(@
|
75
|
+
unless (@side == :client && @state == ClientState::CONNECTED) ||
|
76
|
+
(@side == :server && @state == ServerState::CONNECTED)
|
75
77
|
|
76
78
|
ap = Message::ApplicationData.new(binary)
|
77
79
|
send_application_data(ap, @ap_wcipher)
|
@@ -82,82 +84,6 @@ module TTTLS13
|
|
82
84
|
|
83
85
|
send_alert(:close_notify)
|
84
86
|
@state = EOF
|
85
|
-
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
|
89
|
-
# @return [TTTLS13::CipherSuite, nil]
|
90
|
-
def negotiated_cipher_suite
|
91
|
-
@cipher_suite
|
92
|
-
end
|
93
|
-
|
94
|
-
# @return [TTTLS13::NamedGroup, nil]
|
95
|
-
def negotiated_named_group
|
96
|
-
@named_group
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [TTTLS13::SignatureScheme, nil]
|
100
|
-
def negotiated_signature_scheme
|
101
|
-
@signature_scheme
|
102
|
-
end
|
103
|
-
|
104
|
-
# @return [String]
|
105
|
-
def negotiated_alpn
|
106
|
-
@alpn
|
107
|
-
end
|
108
|
-
|
109
|
-
# @param label [String]
|
110
|
-
# @param context [String]
|
111
|
-
# @param key_length [Integer]
|
112
|
-
#
|
113
|
-
# @return [String, nil]
|
114
|
-
def exporter(label, context, key_length)
|
115
|
-
return nil if @exporter_secret.nil? || @cipher_suite.nil?
|
116
|
-
|
117
|
-
digest = CipherSuite.digest(@cipher_suite)
|
118
|
-
do_exporter(@exporter_secret, digest, label, context, key_length)
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
# @param secret [String] (early_)exporter_secret
|
124
|
-
# @param digest [String] name of digest algorithm
|
125
|
-
# @param label [String]
|
126
|
-
# @param context [String]
|
127
|
-
# @param key_length [Integer]
|
128
|
-
#
|
129
|
-
# @return [String]
|
130
|
-
def do_exporter(secret, digest, label, context, key_length)
|
131
|
-
derived_secret = KeySchedule.hkdf_expand_label(
|
132
|
-
secret,
|
133
|
-
label,
|
134
|
-
OpenSSL::Digest.digest(digest, ''),
|
135
|
-
OpenSSL::Digest.new(digest).digest_length,
|
136
|
-
digest
|
137
|
-
)
|
138
|
-
|
139
|
-
KeySchedule.hkdf_expand_label(
|
140
|
-
derived_secret,
|
141
|
-
'exporter',
|
142
|
-
OpenSSL::Digest.digest(digest, context),
|
143
|
-
key_length,
|
144
|
-
digest
|
145
|
-
)
|
146
|
-
end
|
147
|
-
|
148
|
-
# @param cipher_suite [TTTLS13::CipherSuite]
|
149
|
-
# @param write_key [String]
|
150
|
-
# @param write_iv [String]
|
151
|
-
#
|
152
|
-
# @return [TTTLS13::Cryptograph::Aead]
|
153
|
-
def gen_cipher(cipher_suite, write_key, write_iv)
|
154
|
-
seq_num = SequenceNumber.new
|
155
|
-
Cryptograph::Aead.new(
|
156
|
-
cipher_suite: cipher_suite,
|
157
|
-
write_key: write_key,
|
158
|
-
write_iv: write_iv,
|
159
|
-
sequence_number: seq_num
|
160
|
-
)
|
161
87
|
end
|
162
88
|
|
163
89
|
# @param type [TTTLS13::Message::ContentType]
|
@@ -213,7 +139,7 @@ module TTTLS13
|
|
213
139
|
|
214
140
|
# @param record [TTTLS13::Message::Record]
|
215
141
|
def send_record(record)
|
216
|
-
logger.
|
142
|
+
logger.info(Convert.obj2html(record))
|
217
143
|
@socket.write(record.serialize(@send_record_size))
|
218
144
|
end
|
219
145
|
|
@@ -288,167 +214,10 @@ module TTTLS13
|
|
288
214
|
terminate(:unexpected_message)
|
289
215
|
end
|
290
216
|
|
291
|
-
logger.
|
217
|
+
logger.info(Convert.obj2html(record))
|
292
218
|
[record, orig_msgs]
|
293
219
|
end
|
294
220
|
|
295
|
-
# @param ch1 [TTTLS13::Message::ClientHello]
|
296
|
-
# @param hrr [TTTLS13::Message::ServerHello]
|
297
|
-
# @param ch [TTTLS13::Message::ClientHello]
|
298
|
-
# @param binder_key [String]
|
299
|
-
# @param digest [String] name of digest algorithm
|
300
|
-
#
|
301
|
-
# @return [String]
|
302
|
-
def do_sign_psk_binder(ch1:, hrr:, ch:, binder_key:, digest:)
|
303
|
-
# TODO: ext binder
|
304
|
-
hash_len = OpenSSL::Digest.new(digest).digest_length
|
305
|
-
tt = Transcript.new
|
306
|
-
tt[CH1] = [ch1, ch1.serialize] unless ch1.nil?
|
307
|
-
tt[HRR] = [hrr, hrr.serialize] unless hrr.nil?
|
308
|
-
tt[CH] = [ch, ch.serialize]
|
309
|
-
# transcript-hash (CH1 + HRR +) truncated-CH
|
310
|
-
hash = tt.truncate_hash(digest, CH, hash_len + 3)
|
311
|
-
OpenSSL::HMAC.digest(digest, binder_key, hash)
|
312
|
-
end
|
313
|
-
|
314
|
-
# @param key [OpenSSL::PKey::PKey]
|
315
|
-
# @param signature_scheme [TTTLS13::SignatureScheme]
|
316
|
-
# @param context [String]
|
317
|
-
# @param hash [String]
|
318
|
-
#
|
319
|
-
# @raise [TTTLS13::Error::ErrorAlerts]
|
320
|
-
#
|
321
|
-
# @return [String]
|
322
|
-
# rubocop: disable Metrics/CyclomaticComplexity
|
323
|
-
def do_sign_certificate_verify(key:, signature_scheme:, context:, hash:)
|
324
|
-
content = "\x20" * 64 + context + "\x00" + hash
|
325
|
-
|
326
|
-
# RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether
|
327
|
-
# RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms".
|
328
|
-
case signature_scheme
|
329
|
-
when SignatureScheme::RSA_PKCS1_SHA256,
|
330
|
-
SignatureScheme::RSA_PSS_RSAE_SHA256,
|
331
|
-
SignatureScheme::RSA_PSS_PSS_SHA256
|
332
|
-
key.sign_pss('SHA256', content, salt_length: :digest,
|
333
|
-
mgf1_hash: 'SHA256')
|
334
|
-
when SignatureScheme::RSA_PKCS1_SHA384,
|
335
|
-
SignatureScheme::RSA_PSS_RSAE_SHA384,
|
336
|
-
SignatureScheme::RSA_PSS_PSS_SHA384
|
337
|
-
key.sign_pss('SHA384', content, salt_length: :digest,
|
338
|
-
mgf1_hash: 'SHA384')
|
339
|
-
when SignatureScheme::RSA_PKCS1_SHA512,
|
340
|
-
SignatureScheme::RSA_PSS_RSAE_SHA512,
|
341
|
-
SignatureScheme::RSA_PSS_PSS_SHA512
|
342
|
-
key.sign_pss('SHA512', content, salt_length: :digest,
|
343
|
-
mgf1_hash: 'SHA512')
|
344
|
-
when SignatureScheme::ECDSA_SECP256R1_SHA256
|
345
|
-
key.sign('SHA256', content)
|
346
|
-
when SignatureScheme::ECDSA_SECP384R1_SHA384
|
347
|
-
key.sign('SHA384', content)
|
348
|
-
when SignatureScheme::ECDSA_SECP521R1_SHA512
|
349
|
-
key.sign('SHA512', content)
|
350
|
-
else # TODO: ED25519, ED448
|
351
|
-
terminate(:internal_error)
|
352
|
-
end
|
353
|
-
end
|
354
|
-
# rubocop: enable Metrics/CyclomaticComplexity
|
355
|
-
|
356
|
-
# @param public_key [OpenSSL::PKey::PKey]
|
357
|
-
# @param signature_scheme [TTTLS13::SignatureScheme]
|
358
|
-
# @param signature [String]
|
359
|
-
# @param context [String]
|
360
|
-
# @param hash [String]
|
361
|
-
#
|
362
|
-
# @raise [TTTLS13::Error::ErrorAlerts]
|
363
|
-
#
|
364
|
-
# @return [Boolean]
|
365
|
-
# rubocop: disable Metrics/CyclomaticComplexity
|
366
|
-
def do_verified_certificate_verify?(public_key:, signature_scheme:,
|
367
|
-
signature:, context:, hash:)
|
368
|
-
content = "\x20" * 64 + context + "\x00" + hash
|
369
|
-
|
370
|
-
# RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether
|
371
|
-
# RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms".
|
372
|
-
case signature_scheme
|
373
|
-
when SignatureScheme::RSA_PKCS1_SHA256,
|
374
|
-
SignatureScheme::RSA_PSS_RSAE_SHA256,
|
375
|
-
SignatureScheme::RSA_PSS_PSS_SHA256
|
376
|
-
public_key.verify_pss('SHA256', signature, content, salt_length: :auto,
|
377
|
-
mgf1_hash: 'SHA256')
|
378
|
-
when SignatureScheme::RSA_PKCS1_SHA384,
|
379
|
-
SignatureScheme::RSA_PSS_RSAE_SHA384,
|
380
|
-
SignatureScheme::RSA_PSS_PSS_SHA384
|
381
|
-
public_key.verify_pss('SHA384', signature, content, salt_length: :auto,
|
382
|
-
mgf1_hash: 'SHA384')
|
383
|
-
when SignatureScheme::RSA_PKCS1_SHA512,
|
384
|
-
SignatureScheme::RSA_PSS_RSAE_SHA512,
|
385
|
-
SignatureScheme::RSA_PSS_PSS_SHA512
|
386
|
-
public_key.verify_pss('SHA512', signature, content, salt_length: :auto,
|
387
|
-
mgf1_hash: 'SHA512')
|
388
|
-
when SignatureScheme::ECDSA_SECP256R1_SHA256
|
389
|
-
public_key.verify('SHA256', signature, content)
|
390
|
-
when SignatureScheme::ECDSA_SECP384R1_SHA384
|
391
|
-
public_key.verify('SHA384', signature, content)
|
392
|
-
when SignatureScheme::ECDSA_SECP521R1_SHA512
|
393
|
-
public_key.verify('SHA512', signature, content)
|
394
|
-
else # TODO: ED25519, ED448
|
395
|
-
terminate(:internal_error)
|
396
|
-
end
|
397
|
-
end
|
398
|
-
# rubocop: enable Metrics/CyclomaticComplexity
|
399
|
-
|
400
|
-
# @param digest [String] name of digest algorithm
|
401
|
-
# @param finished_key [String]
|
402
|
-
# @param hash [String]
|
403
|
-
#
|
404
|
-
# @return [String]
|
405
|
-
def sign_finished(digest:, finished_key:, hash:)
|
406
|
-
OpenSSL::HMAC.digest(digest, finished_key, hash)
|
407
|
-
end
|
408
|
-
|
409
|
-
# @param finished [TTTLS13::Message::Finished]
|
410
|
-
# @param digest [String] name of digest algorithm
|
411
|
-
# @param finished_key [String]
|
412
|
-
# @param hash [String]
|
413
|
-
#
|
414
|
-
# @return [Boolean]
|
415
|
-
def verified_finished?(finished:, digest:, finished_key:, hash:)
|
416
|
-
sign_finished(digest: digest, finished_key: finished_key, hash: hash) \
|
417
|
-
== finished.verify_data
|
418
|
-
end
|
419
|
-
|
420
|
-
# @param key_exchange [String]
|
421
|
-
# @param priv_key [OpenSSL::PKey::$Object]
|
422
|
-
# @param group [TTTLS13::NamedGroup]
|
423
|
-
#
|
424
|
-
# @return [String]
|
425
|
-
def gen_shared_secret(key_exchange, priv_key, group)
|
426
|
-
curve = NamedGroup.curve_name(group)
|
427
|
-
terminate(:internal_error) if curve.nil?
|
428
|
-
|
429
|
-
pub_key = OpenSSL::PKey::EC::Point.new(
|
430
|
-
OpenSSL::PKey::EC::Group.new(curve),
|
431
|
-
OpenSSL::BN.new(key_exchange, 2)
|
432
|
-
)
|
433
|
-
|
434
|
-
priv_key.dh_compute_key(pub_key)
|
435
|
-
end
|
436
|
-
|
437
|
-
# @param transcript [TTTLS13::Transcript]
|
438
|
-
#
|
439
|
-
# @return [Boolean]
|
440
|
-
def receivable_ccs?(transcript)
|
441
|
-
# Received ccs before the first ClientHello message or after the peer's
|
442
|
-
# Finished message, peer MUST abort.
|
443
|
-
#
|
444
|
-
# Server may receive an unprotected record of type change_cipher_spec
|
445
|
-
# between the first and second ClientHello
|
446
|
-
finished = (@endpoint == :client ? SF : CF)
|
447
|
-
|
448
|
-
(transcript.include?(CH) || transcript.include?(CH1)) &&
|
449
|
-
!transcript.include?(finished)
|
450
|
-
end
|
451
|
-
|
452
221
|
# @param symbol [Symbol] key of ALERT_DESCRIPTION
|
453
222
|
#
|
454
223
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
@@ -467,116 +236,6 @@ module TTTLS13
|
|
467
236
|
end
|
468
237
|
|
469
238
|
@state = EOF
|
470
|
-
nil
|
471
|
-
end
|
472
|
-
|
473
|
-
# @param _nst [TTTLS13::Message::NewSessionTicket]
|
474
|
-
#
|
475
|
-
# @raise [TTTLS13::Error::ErrorAlerts]
|
476
|
-
def process_new_session_ticket(_nst)
|
477
|
-
terminate(:unexpected_message) if @endpoint == :server
|
478
|
-
end
|
479
|
-
|
480
|
-
# @param certificate_list [Array of CertificateEntry]
|
481
|
-
# @param ca_file [String] path to ca.crt
|
482
|
-
# @param hostname [String]
|
483
|
-
#
|
484
|
-
# @return [Boolean]
|
485
|
-
def trusted_certificate?(certificate_list, ca_file = nil, hostname = nil)
|
486
|
-
chain = certificate_list.map(&:cert_data).map do |c|
|
487
|
-
OpenSSL::X509::Certificate.new(c)
|
488
|
-
end
|
489
|
-
cert = chain.shift
|
490
|
-
|
491
|
-
# not support CN matching, only support SAN matching
|
492
|
-
return false if !hostname.nil? && !matching_san?(cert, hostname)
|
493
|
-
|
494
|
-
store = OpenSSL::X509::Store.new
|
495
|
-
store.set_default_paths
|
496
|
-
store.add_file(ca_file) unless ca_file.nil?
|
497
|
-
# TODO: parse authorityInfoAccess::CA Issuers
|
498
|
-
ctx = OpenSSL::X509::StoreContext.new(store, cert, chain)
|
499
|
-
now = Time.now
|
500
|
-
ctx.verify && cert.not_before < now && now < cert.not_after
|
501
|
-
end
|
502
|
-
|
503
|
-
# @param cert [OpenSSL::X509::Certificate]
|
504
|
-
# @param name [String]
|
505
|
-
#
|
506
|
-
# @return [Boolean]
|
507
|
-
def matching_san?(cert, name)
|
508
|
-
san = cert.extensions.find { |ex| ex.oid == 'subjectAltName' }
|
509
|
-
return false if san.nil?
|
510
|
-
|
511
|
-
ostr = OpenSSL::ASN1.decode(san.to_der).value.last
|
512
|
-
OpenSSL::ASN1.decode(ostr.value)
|
513
|
-
.map(&:value)
|
514
|
-
.map { |s| s.gsub('.', '\.').gsub('*', '.*') }
|
515
|
-
.any? { |s| name.match(/#{s}/) }
|
516
|
-
end
|
517
|
-
|
518
|
-
# @param signature_algorithms [Array of SignatureAlgorithms]
|
519
|
-
# @param crt [OpenSSL::X509::Certificate]
|
520
|
-
#
|
521
|
-
# @return [Array of TTTLS13::Message::Extension::SignatureAlgorithms]
|
522
|
-
def do_select_signature_algorithms(signature_algorithms, crt)
|
523
|
-
pka = OpenSSL::ASN1.decode(crt.public_key.to_der)
|
524
|
-
.value.first.value.first.value
|
525
|
-
signature_algorithms.select do |sa|
|
526
|
-
case sa
|
527
|
-
when SignatureScheme::ECDSA_SECP256R1_SHA256,
|
528
|
-
SignatureScheme::ECDSA_SECP384R1_SHA384,
|
529
|
-
SignatureScheme::ECDSA_SECP521R1_SHA512
|
530
|
-
pka == 'id-ecPublicKey'
|
531
|
-
when SignatureScheme::RSA_PSS_PSS_SHA256,
|
532
|
-
SignatureScheme::RSA_PSS_PSS_SHA384,
|
533
|
-
SignatureScheme::RSA_PSS_PSS_SHA512
|
534
|
-
pka == 'rsassaPss'
|
535
|
-
when SignatureScheme::RSA_PSS_RSAE_SHA256,
|
536
|
-
SignatureScheme::RSA_PSS_RSAE_SHA384,
|
537
|
-
SignatureScheme::RSA_PSS_RSAE_SHA512
|
538
|
-
pka == 'rsaEncryption'
|
539
|
-
else
|
540
|
-
# RSASSA-PKCS1-v1_5 algorithms refer solely to signatures which appear
|
541
|
-
# in certificates and are not defined for use in signed TLS handshake
|
542
|
-
# messages
|
543
|
-
false
|
544
|
-
end
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
class << self
|
549
|
-
# @param cid [OpenSSL::OCSP::CertificateId]
|
550
|
-
#
|
551
|
-
# @return [OpenSSL::OCSP::Request]
|
552
|
-
def gen_ocsp_request(cid)
|
553
|
-
ocsp_request = OpenSSL::OCSP::Request.new
|
554
|
-
ocsp_request.add_certid(cid)
|
555
|
-
ocsp_request.add_nonce
|
556
|
-
ocsp_request
|
557
|
-
end
|
558
|
-
|
559
|
-
# @param ocsp_request [OpenSSL::OCSP::Request]
|
560
|
-
# @param uri_string [String]
|
561
|
-
#
|
562
|
-
# @raise [Net::OpenTimeout, OpenSSL::OCSP::OCSPError, URI::$Exception]
|
563
|
-
#
|
564
|
-
# @return [OpenSSL::OCSP::Response, n
|
565
|
-
def send_ocsp_request(ocsp_request, uri_string)
|
566
|
-
# send HTTP POST
|
567
|
-
uri = URI.parse(uri_string)
|
568
|
-
path = uri.path
|
569
|
-
path = '/' if path.nil? || path.empty?
|
570
|
-
http_response = Net::HTTP.start(uri.host, uri.port) do |http|
|
571
|
-
http.post(
|
572
|
-
path,
|
573
|
-
ocsp_request.to_der,
|
574
|
-
'content-type' => 'application/ocsp-request'
|
575
|
-
)
|
576
|
-
end
|
577
|
-
|
578
|
-
OpenSSL::OCSP::Response.new(http_response.body)
|
579
|
-
end
|
580
239
|
end
|
581
240
|
end
|
582
241
|
# rubocop: enable Metrics/ClassLength
|