tttls1.3 0.3.1 → 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/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
|