tttls1.3 0.2.11 → 0.2.12
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/.rubocop.yml +4 -1
- data/README.md +3 -1
- data/Rakefile +66 -7
- data/example/https_client_using_0rtt.rb +1 -1
- data/example/https_client_using_status_request.rb +31 -0
- data/example/https_server.rb +1 -0
- data/lib/tttls1.3.rb +1 -0
- data/lib/tttls1.3/client.rb +95 -8
- data/lib/tttls1.3/connection.rb +31 -6
- data/lib/tttls1.3/message/extension/status_request.rb +73 -17
- data/lib/tttls1.3/message/extensions.rb +13 -0
- data/lib/tttls1.3/utils.rb +15 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/spec/fixtures/rsa_rsa_ocsp.crt +18 -0
- data/spec/fixtures/rsa_rsa_ocsp.key +27 -0
- data/spec/spec_helper.rb +35 -1
- data/spec/status_request_spec.rb +77 -10
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9677aea746ca98f9d18cfc1e841d836291b7692088cea9fcc3122e88b0bcb32a
|
4
|
+
data.tar.gz: e156e172215e1b76c45a4a43c85e6066499f65e0b0bf8a28c2d6fb524fd8940e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f12cffcb976c740136afd8fa7b139400f58cb1a3795e7e7347192630e90b0c8e6c5138e9b98214bbc2a7f88a91ecd58332390ef1c1239ccf9d56a71f3f342743
|
7
|
+
data.tar.gz: 5ab10fcdab0e5cac1c4940bb92753c06db1656f615a3146b552b54c119b28483388bbe8b725b8a412b13df0fa3f1f668eaebc7cfb537e10753a3f2e686cf2279
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -100,6 +100,8 @@ tttls1.3 client is configurable using keyword arguments.
|
|
100
100
|
| `:ticket_age_add` | String | nil | The ticket\_age\_add for PSK. |
|
101
101
|
| `:ticket_timestamp` | Integer | nil | The ticket\_timestamp for PSK. |
|
102
102
|
| `:record_size_limit` | Integer | nil | The record\_size\_limit offerd in ClientHello extensions. If not needed to be present, set nil. |
|
103
|
+
| `:check_certificate_status` | Boolean | false | If needed to check certificate status, set true. |
|
104
|
+
| `:process_certificate_status` | Proc | `TTTLS13::Client.method(:softfail_check_certificate_status)` | Proc(or Method) that checks received OCSPResponse. Its 3 arguments are OpenSSL::OCSP::Response, end-entity certificate(OpenSSL::X509::Certificate) and certificates chain(Array of Certificate) used for verification and it returns Boolean. |
|
103
105
|
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
104
106
|
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
105
107
|
|
@@ -111,7 +113,7 @@ tttls1.3 server is configurable using keyword arguments.
|
|
111
113
|
| key | type | default value | description |
|
112
114
|
|-----|------|---------------|-------------|
|
113
115
|
| `:crt_file` | String | nil | Path to the certificate file. This is a required setting. |
|
114
|
-
| `:chain_files` | Array of
|
116
|
+
| `:chain_files` | Array of String | nil | Paths to the itermediate certificate files. |
|
115
117
|
| `:key_file` | String | nil | Path to the private key file. This is a required setting. |
|
116
118
|
| `:cipher_suites` | Array of TTTLS13::CipherSuite constant | `TLS_AES_256_GCM_SHA384`, `TLS_CHACHA20_POLY1305_SHA256`, `TLS_AES_128_GCM_SHA256` | List of supported cipher suites. |
|
117
119
|
| `:signature_algorithms` | Array of TTTLS13::SignatureScheme constant | `ECDSA_SECP256R1_SHA256`, `ECDSA_SECP384R1_SHA384`, `ECDSA_SECP521R1_SHA512`, `RSA_PSS_RSAE_SHA256`, `RSA_PSS_RSAE_SHA384`, `RSA_PSS_RSAE_SHA512`, `RSA_PKCS1_SHA256`, `RSA_PKCS1_SHA384`, `RSA_PKCS1_SHA512` | List of supported signature algorithms. |
|
data/Rakefile
CHANGED
@@ -9,9 +9,11 @@ require 'fileutils'
|
|
9
9
|
TMP_DIR = __dir__ + '/tmp'
|
10
10
|
CA_KEY = TMP_DIR + '/ca.key'
|
11
11
|
CA_CRT = TMP_DIR + '/ca.crt'
|
12
|
+
INTER_KEY = TMP_DIR + '/intermediate.key'
|
13
|
+
INTER_CRT = TMP_DIR + '/intermediate.crt'
|
12
14
|
SERVER_KEY = TMP_DIR + '/server.key'
|
13
15
|
SERVER_CRT = TMP_DIR + '/server.crt'
|
14
|
-
certs = [CA_KEY, CA_CRT, SERVER_KEY, SERVER_CRT]
|
16
|
+
certs = [CA_KEY, CA_CRT, INTER_KEY, INTER_CRT, SERVER_KEY, SERVER_CRT]
|
15
17
|
|
16
18
|
directory TMP_DIR
|
17
19
|
|
@@ -64,15 +66,66 @@ file CA_CRT => [TMP_DIR, CA_KEY] do
|
|
64
66
|
File.write(CA_CRT, ca_crt.to_pem)
|
65
67
|
end
|
66
68
|
|
69
|
+
file INTER_KEY => TMP_DIR do
|
70
|
+
puts "generate #{INTER_KEY}..."
|
71
|
+
inter_key = OpenSSL::PKey::RSA.generate(2048)
|
72
|
+
File.write(INTER_KEY, inter_key.to_pem)
|
73
|
+
end
|
74
|
+
|
75
|
+
file INTER_CRT => [TMP_DIR, INTER_KEY] do
|
76
|
+
ca_key = OpenSSL::PKey::RSA.new(File.read(CA_KEY))
|
77
|
+
ca_crt = OpenSSL::X509::Certificate.new(File.read(CA_CRT))
|
78
|
+
inter_key = OpenSSL::PKey::RSA.new(File.read(INTER_KEY))
|
79
|
+
|
80
|
+
puts "generate #{INTER_CRT}..."
|
81
|
+
sub = OpenSSL::X509::Name.new
|
82
|
+
sub.add_entry('CN', 'test-intermediate')
|
83
|
+
|
84
|
+
inter_crt = OpenSSL::X509::Certificate.new
|
85
|
+
inter_crt.not_before = Time.now
|
86
|
+
inter_crt.not_after = Time.now + (60 * 60 * 24 * 365 * 10)
|
87
|
+
inter_crt.public_key = inter_key.public_key
|
88
|
+
inter_crt.serial = OpenSSL::BN.rand(64)
|
89
|
+
inter_crt.version = 2
|
90
|
+
inter_crt.issuer = ca_crt.subject
|
91
|
+
inter_crt.subject = sub
|
92
|
+
|
93
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
94
|
+
factory.subject_certificate = inter_crt
|
95
|
+
factory.issuer_certificate = ca_crt
|
96
|
+
inter_crt.add_extension(
|
97
|
+
factory.create_extension(
|
98
|
+
'keyUsage',
|
99
|
+
'critical, cRLSign, keyCertSign'
|
100
|
+
)
|
101
|
+
)
|
102
|
+
inter_crt.add_extension(
|
103
|
+
factory.create_extension(
|
104
|
+
'basicConstraints',
|
105
|
+
'critical, CA:true'
|
106
|
+
)
|
107
|
+
)
|
108
|
+
inter_crt.add_extension(
|
109
|
+
factory.create_extension(
|
110
|
+
'subjectKeyIdentifier',
|
111
|
+
'hash'
|
112
|
+
)
|
113
|
+
)
|
114
|
+
|
115
|
+
digest = OpenSSL::Digest::SHA256.new
|
116
|
+
inter_crt.sign(ca_key, digest)
|
117
|
+
File.write(INTER_CRT, inter_crt.to_pem)
|
118
|
+
end
|
119
|
+
|
67
120
|
file SERVER_KEY => TMP_DIR do
|
68
121
|
puts "generate #{SERVER_KEY}..."
|
69
122
|
server_key = OpenSSL::PKey::RSA.generate(2048)
|
70
123
|
File.write(SERVER_KEY, server_key.to_pem)
|
71
124
|
end
|
72
125
|
|
73
|
-
file SERVER_CRT => [TMP_DIR,
|
74
|
-
|
75
|
-
|
126
|
+
file SERVER_CRT => [TMP_DIR, INTER_CRT, SERVER_KEY] do
|
127
|
+
inter_key = OpenSSL::PKey::RSA.new(File.read(INTER_KEY))
|
128
|
+
inter_crt = OpenSSL::X509::Certificate.new(File.read(INTER_CRT))
|
76
129
|
server_key = OpenSSL::PKey::RSA.new(File.read(SERVER_KEY))
|
77
130
|
|
78
131
|
puts "generate #{SERVER_CRT}..."
|
@@ -85,12 +138,12 @@ file SERVER_CRT => [TMP_DIR, CA_CRT, SERVER_KEY] do
|
|
85
138
|
server_crt.public_key = server_key.public_key
|
86
139
|
server_crt.serial = OpenSSL::BN.rand(64)
|
87
140
|
server_crt.version = 2
|
88
|
-
server_crt.issuer =
|
141
|
+
server_crt.issuer = inter_crt.subject
|
89
142
|
server_crt.subject = sub
|
90
143
|
|
91
144
|
factory = OpenSSL::X509::ExtensionFactory.new
|
92
145
|
factory.subject_certificate = server_crt
|
93
|
-
factory.issuer_certificate =
|
146
|
+
factory.issuer_certificate = inter_crt
|
94
147
|
server_crt.add_extension(
|
95
148
|
factory.create_extension(
|
96
149
|
'basicConstraints',
|
@@ -109,9 +162,15 @@ file SERVER_CRT => [TMP_DIR, CA_CRT, SERVER_KEY] do
|
|
109
162
|
'DNS:localhost'
|
110
163
|
)
|
111
164
|
)
|
165
|
+
server_crt.add_extension(
|
166
|
+
factory.create_extension(
|
167
|
+
'authorityInfoAccess',
|
168
|
+
'caIssuers;URI:http://localhost:8080,OCSP;URI:http://localhost:8080'
|
169
|
+
)
|
170
|
+
)
|
112
171
|
|
113
172
|
digest = OpenSSL::Digest::SHA256.new
|
114
|
-
server_crt.sign(
|
173
|
+
server_crt.sign(inter_key, digest)
|
115
174
|
File.write(SERVER_CRT, server_crt.to_pem)
|
116
175
|
end
|
117
176
|
|
@@ -22,7 +22,7 @@ process_new_session_ticket = proc do |nst, rms, cs|
|
|
22
22
|
settings_2nd[:ticket_timestamp] = nst.timestamp
|
23
23
|
end
|
24
24
|
settings_1st = {
|
25
|
-
ca_file:
|
25
|
+
ca_file: File.exist?(ca_file) ? ca_file : nil,
|
26
26
|
alpn: ['http/1.1'],
|
27
27
|
process_new_session_ticket: process_new_session_ticket
|
28
28
|
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'helper'
|
5
|
+
|
6
|
+
hostname, port = (ARGV[0] || 'localhost:4433').split(':')
|
7
|
+
ca_file = __dir__ + '/../tmp/ca.crt'
|
8
|
+
req = simple_http_request(hostname)
|
9
|
+
|
10
|
+
process_certificate_status = proc do |res, cert, chain|
|
11
|
+
puts 'stapled OCSPResponse: '
|
12
|
+
puts res.basic.status.pretty_inspect unless res.nil?
|
13
|
+
puts '-' * 10
|
14
|
+
|
15
|
+
TTTLS13::Client.softfail_check_certificate_status(res, cert, chain)
|
16
|
+
end
|
17
|
+
|
18
|
+
socket = TCPSocket.new(hostname, port)
|
19
|
+
settings = {
|
20
|
+
ca_file: File.exist?(ca_file) ? ca_file : nil,
|
21
|
+
alpn: ['http/1.1'],
|
22
|
+
check_certificate_status: true,
|
23
|
+
process_certificate_status: process_certificate_status
|
24
|
+
}
|
25
|
+
client = TTTLS13::Client.new(socket, hostname, settings)
|
26
|
+
client.connect
|
27
|
+
client.write(req)
|
28
|
+
|
29
|
+
print recv_http_response(client)
|
30
|
+
client.close unless client.eof?
|
31
|
+
socket.close
|
data/example/https_server.rb
CHANGED
data/lib/tttls1.3.rb
CHANGED
data/lib/tttls1.3/client.rb
CHANGED
@@ -59,6 +59,8 @@ module TTTLS13
|
|
59
59
|
ticket_age_add: nil,
|
60
60
|
ticket_timestamp: nil,
|
61
61
|
record_size_limit: nil,
|
62
|
+
check_certificate_status: false,
|
63
|
+
process_certificate_status: nil,
|
62
64
|
compatibility_mode: true,
|
63
65
|
loglevel: Logger::WARN
|
64
66
|
}.freeze
|
@@ -300,7 +302,8 @@ module TTTLS13
|
|
300
302
|
message = recv_message(receivable_ccs: true, cipher: hs_rcipher)
|
301
303
|
if message.msg_type == Message::HandshakeType::CERTIFICATE
|
302
304
|
ct = transcript[CT] = message
|
303
|
-
|
305
|
+
alert = check_invalid_certificate(ct, transcript[CH])
|
306
|
+
terminate(alert) unless alert.nil?
|
304
307
|
|
305
308
|
@state = ClientState::WAIT_CV
|
306
309
|
elsif message.msg_type == Message::HandshakeType::CERTIFICATE_REQUEST
|
@@ -314,7 +317,8 @@ module TTTLS13
|
|
314
317
|
logger.debug('ClientState::WAIT_CERT')
|
315
318
|
|
316
319
|
ct = transcript[CT] = recv_certificate(hs_rcipher)
|
317
|
-
|
320
|
+
alert = check_invalid_certificate(ct, transcript[CH])
|
321
|
+
terminate(alert) unless alert.nil?
|
318
322
|
|
319
323
|
@state = ClientState::WAIT_CV
|
320
324
|
when ClientState::WAIT_CV
|
@@ -392,6 +396,58 @@ module TTTLS13
|
|
392
396
|
@succeed_early_data
|
393
397
|
end
|
394
398
|
|
399
|
+
# @param res [OpenSSL::OCSP::Response]
|
400
|
+
# @param cert [OpenSSL::X509::Certificate]
|
401
|
+
# @param chain [Array of OpenSSL::X509::Certificate, nil]
|
402
|
+
#
|
403
|
+
# @return [Boolean]
|
404
|
+
#
|
405
|
+
# @example
|
406
|
+
# meth = Client.method(:softfail_check_certificate_status)
|
407
|
+
# Client.new(
|
408
|
+
# socket,
|
409
|
+
# hostname,
|
410
|
+
# check_certificate_status: true,
|
411
|
+
# process_certificate_status: meth
|
412
|
+
# )
|
413
|
+
# rubocop: disable Metrics/AbcSize
|
414
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
415
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
416
|
+
def self.softfail_check_certificate_status(res, cert, chain)
|
417
|
+
ocsp_response = res
|
418
|
+
store = OpenSSL::X509::Store.new
|
419
|
+
store.set_default_paths
|
420
|
+
context = OpenSSL::X509::StoreContext.new(store, cert, chain)
|
421
|
+
context.verify
|
422
|
+
cid = OpenSSL::OCSP::CertificateId.new(cert, context.chain[1])
|
423
|
+
|
424
|
+
# When NOT received OCSPResponse in TLS handshake, this method will
|
425
|
+
# send OCSPRequest. If ocsp_uri is NOT presented in Certificate, return
|
426
|
+
# true. Also, if it sends OCSPRequest and does NOT receive a HTTPresponse
|
427
|
+
# within 2 seconds, return true.
|
428
|
+
if ocsp_response.nil?
|
429
|
+
uri = cert.ocsp_uris&.find { |u| URI::DEFAULT_PARSER.make_regexp =~ u }
|
430
|
+
return true if uri.nil?
|
431
|
+
|
432
|
+
begin
|
433
|
+
Timeout.timeout(2) { ocsp_response = send_ocsp_request(cid, uri) }
|
434
|
+
rescue StandardError
|
435
|
+
return true
|
436
|
+
end
|
437
|
+
end
|
438
|
+
return false \
|
439
|
+
if ocsp_response.status != OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL
|
440
|
+
|
441
|
+
status = ocsp_response.basic.status.find { |s| s.first.cmp(cid) }
|
442
|
+
return false if status[1] != OpenSSL::OCSP::V_CERTSTATUS_GOOD
|
443
|
+
return false if !status[3].nil? && status[3] < Time.now
|
444
|
+
|
445
|
+
ocsp_response.basic.verify(chain, store)
|
446
|
+
end
|
447
|
+
# rubocop: enable Metrics/AbcSize
|
448
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
449
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
450
|
+
|
395
451
|
private
|
396
452
|
|
397
453
|
# @return [Boolean]
|
@@ -471,6 +527,7 @@ module TTTLS13
|
|
471
527
|
# @return [Hash of NamedGroup => OpenSSL::PKey::EC.$Object]
|
472
528
|
# rubocop: disable Metrics/AbcSize
|
473
529
|
# rubocop: disable Metrics/CyclomaticComplexity
|
530
|
+
# rubocop: disable Metrics/MethodLength
|
474
531
|
# rubocop: disable Metrics/PerceivedComplexity
|
475
532
|
def gen_ch_extensions
|
476
533
|
exs = []
|
@@ -519,10 +576,15 @@ module TTTLS13
|
|
519
576
|
exs << Message::Extension::Alpn.new(@settings[:alpn].reject(&:empty?)) \
|
520
577
|
if !@settings[:alpn].nil? && !@settings[:alpn].empty?
|
521
578
|
|
579
|
+
# status_request
|
580
|
+
exs << Message::Extension::OCSPStatusRequest.new \
|
581
|
+
if @settings[:check_certificate_status]
|
582
|
+
|
522
583
|
[Message::Extensions.new(exs), priv_keys]
|
523
584
|
end
|
524
585
|
# rubocop: enable Metrics/AbcSize
|
525
586
|
# rubocop: enable Metrics/CyclomaticComplexity
|
587
|
+
# rubocop: enable Metrics/MethodLength
|
526
588
|
# rubocop: enable Metrics/PerceivedComplexity
|
527
589
|
|
528
590
|
# @param extensions [TTTLS13::Message::Extensions]
|
@@ -753,16 +815,32 @@ module TTTLS13
|
|
753
815
|
|
754
816
|
# @param ct [TTTLS13::Message::Certificate]
|
755
817
|
# @param ch [TTTLS13::Message::ClientHello]
|
756
|
-
|
757
|
-
|
818
|
+
#
|
819
|
+
# @return [Symbol, nil] return key of ALERT_DESCRIPTION, if invalid
|
820
|
+
def check_invalid_certificate(ct, ch)
|
821
|
+
return :illegal_parameter unless ct.appearable_extensions?
|
758
822
|
|
759
|
-
|
823
|
+
return :unsupported_extension \
|
760
824
|
unless ct.certificate_list.map(&:extensions)
|
761
825
|
.all? { |e| (e.keys - ch.extensions.keys).empty? }
|
762
826
|
|
763
|
-
|
764
|
-
|
765
|
-
|
827
|
+
return :certificate_unknown unless trusted_certificate?(
|
828
|
+
ct.certificate_list,
|
829
|
+
@settings[:ca_file],
|
830
|
+
@hostname
|
831
|
+
)
|
832
|
+
|
833
|
+
if @settings[:check_certificate_status]
|
834
|
+
ee = ct.certificate_list.first
|
835
|
+
ocsp_response = ee.extensions[Message::ExtensionType::STATUS_REQUEST]
|
836
|
+
&.ocsp_response
|
837
|
+
cert = ee.cert_data
|
838
|
+
chain = ct.certificate_list[1..]&.map(&:cert_data)
|
839
|
+
return :bad_certificate_status_response \
|
840
|
+
unless satisfactory_certificate_status?(ocsp_response, cert, chain)
|
841
|
+
end
|
842
|
+
|
843
|
+
nil
|
766
844
|
end
|
767
845
|
|
768
846
|
# @param ct [TTTLS13::Message::Certificate]
|
@@ -784,6 +862,15 @@ module TTTLS13
|
|
784
862
|
)
|
785
863
|
end
|
786
864
|
|
865
|
+
# @param ocsp_response [OpenSSL::OCSP::Response]
|
866
|
+
# @param cert [OpenSSL::X509::Certificate]
|
867
|
+
# @param chain [Array of OpenSSL::X509::Certificate, nil]
|
868
|
+
#
|
869
|
+
# @return [Boolean]
|
870
|
+
def satisfactory_certificate_status?(ocsp_response, cert, chain)
|
871
|
+
@settings[:process_certificate_status]&.call(ocsp_response, cert, chain)
|
872
|
+
end
|
873
|
+
|
787
874
|
# @param nst [TTTLS13::Message::NewSessionTicket]
|
788
875
|
#
|
789
876
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
data/lib/tttls1.3/connection.rb
CHANGED
@@ -273,7 +273,7 @@ module TTTLS13
|
|
273
273
|
|
274
274
|
# Received a protected ccs, peer MUST abort the handshake.
|
275
275
|
if record.type == Message::ContentType::APPLICATION_DATA &&
|
276
|
-
record.messages.
|
276
|
+
record.messages.any? { |m| m.is_a?(Message::ChangeCipherSpec) }
|
277
277
|
terminate(:unexpected_message)
|
278
278
|
end
|
279
279
|
|
@@ -474,8 +474,10 @@ module TTTLS13
|
|
474
474
|
#
|
475
475
|
# @return [Boolean]
|
476
476
|
def trusted_certificate?(certificate_list, ca_file = nil, hostname = nil)
|
477
|
-
|
478
|
-
|
477
|
+
chain = certificate_list.map(&:cert_data).map do |c|
|
478
|
+
OpenSSL::X509::Certificate.new(c)
|
479
|
+
end
|
480
|
+
cert = chain.shift
|
479
481
|
|
480
482
|
# not support CN matching, only support SAN matching
|
481
483
|
return false if !hostname.nil? && !matching_san?(cert, hostname)
|
@@ -483,9 +485,6 @@ module TTTLS13
|
|
483
485
|
store = OpenSSL::X509::Store.new
|
484
486
|
store.set_default_paths
|
485
487
|
store.add_file(ca_file) unless ca_file.nil?
|
486
|
-
chain = certificate_list[1..].map(&:cert_data).map do |c|
|
487
|
-
OpenSSL::X509::Certificate.new(c)
|
488
|
-
end
|
489
488
|
# TODO: parse authorityInfoAccess::CA Issuers
|
490
489
|
ctx = OpenSSL::X509::StoreContext.new(store, cert, chain)
|
491
490
|
now = Time.now
|
@@ -539,6 +538,32 @@ module TTTLS13
|
|
539
538
|
end
|
540
539
|
end
|
541
540
|
end
|
541
|
+
|
542
|
+
class << self
|
543
|
+
# @param cid [OpenSSL::OCSP::CertificateId]
|
544
|
+
# @param uri [String]
|
545
|
+
#
|
546
|
+
# @return [OpenSSL::OCSP::Response]
|
547
|
+
def send_ocsp_request(cid, uri)
|
548
|
+
# generate OCSPRequest
|
549
|
+
ocsp_request = OpenSSL::OCSP::Request.new
|
550
|
+
ocsp_request.add_certid(cid)
|
551
|
+
ocsp_request.add_nonce
|
552
|
+
# send HTTP POST
|
553
|
+
uri = URI.parse(uri)
|
554
|
+
path = uri.path
|
555
|
+
path = '/' if path.nil? || path.empty?
|
556
|
+
http_response = Net::HTTP.start uri.host, uri.port do |http|
|
557
|
+
http.post(
|
558
|
+
path,
|
559
|
+
ocsp_request.to_der,
|
560
|
+
'content-type' => 'application/ocsp-request'
|
561
|
+
)
|
562
|
+
end
|
563
|
+
|
564
|
+
OpenSSL::OCSP::Response.new(http_response.body)
|
565
|
+
end
|
566
|
+
end
|
542
567
|
end
|
543
568
|
# rubocop: enable Metrics/ClassLength
|
544
569
|
end
|
@@ -9,23 +9,20 @@ module TTTLS13
|
|
9
9
|
OCSP = "\x01"
|
10
10
|
end
|
11
11
|
|
12
|
-
class
|
12
|
+
class OCSPStatusRequest
|
13
13
|
attr_reader :extension_type
|
14
14
|
attr_reader :responder_id_list
|
15
15
|
attr_reader :request_extensions
|
16
16
|
|
17
|
-
# @param responder_id_list [Array of
|
18
|
-
# @param request_extensions [
|
17
|
+
# @param responder_id_list [Array of OpenSSL::ASN1::ASN1Data]
|
18
|
+
# @param request_extensions [Array of OpenSSL::ASN1::ASN1Data]
|
19
19
|
#
|
20
20
|
# @example
|
21
|
-
#
|
22
|
-
|
23
|
-
# request_extensions: []
|
24
|
-
# )
|
25
|
-
def initialize(responder_id_list: [], request_extensions: '')
|
21
|
+
# OCSPStatusRequest.new
|
22
|
+
def initialize(responder_id_list: [], request_extensions: [])
|
26
23
|
@extension_type = ExtensionType::STATUS_REQUEST
|
27
24
|
@responder_id_list = responder_id_list || []
|
28
|
-
@request_extensions = request_extensions ||
|
25
|
+
@request_extensions = request_extensions || []
|
29
26
|
end
|
30
27
|
|
31
28
|
# @return [String]
|
@@ -34,9 +31,9 @@ module TTTLS13
|
|
34
31
|
binary += CertificateStatusType::OCSP
|
35
32
|
binary += @responder_id_list.length.to_uint16
|
36
33
|
binary += @responder_id_list.map do |id|
|
37
|
-
id.
|
34
|
+
id.to_der.prefix_uint16_length
|
38
35
|
end.join
|
39
|
-
binary += @request_extensions.prefix_uint16_length
|
36
|
+
binary += @request_extensions.map(&:to_der).join.prefix_uint16_length
|
40
37
|
|
41
38
|
@extension_type + binary.prefix_uint16_length
|
42
39
|
end
|
@@ -45,8 +42,9 @@ module TTTLS13
|
|
45
42
|
#
|
46
43
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
47
44
|
#
|
48
|
-
# @return [TTTLS13::Message::Extension::
|
45
|
+
# @return [TTTLS13::Message::Extension::OCSPStatusRequest, nil]
|
49
46
|
# rubocop: disable Metrics/CyclomaticComplexity
|
47
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
50
48
|
def self.deserialize(binary)
|
51
49
|
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
52
50
|
return nil if binary.length < 5 ||
|
@@ -64,14 +62,20 @@ module TTTLS13
|
|
64
62
|
|
65
63
|
re_len = Convert.bin2i(binary.slice(i, 2))
|
66
64
|
i += 2
|
67
|
-
|
65
|
+
exs_bin = binary.slice(i, re_len)
|
66
|
+
begin
|
67
|
+
request_extensions = OpenSSL::ASN1.decode_all(exs_bin)
|
68
|
+
rescue OpenSSL::ASN1::ASN1Error
|
69
|
+
return nil
|
70
|
+
end
|
68
71
|
i += re_len
|
69
72
|
return nil unless i == binary.length
|
70
73
|
|
71
|
-
|
72
|
-
|
74
|
+
OCSPStatusRequest.new(responder_id_list: responder_id_list,
|
75
|
+
request_extensions: request_extensions)
|
73
76
|
end
|
74
77
|
# rubocop: enable Metrics/CyclomaticComplexity
|
78
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
75
79
|
|
76
80
|
class << self
|
77
81
|
private
|
@@ -80,7 +84,7 @@ module TTTLS13
|
|
80
84
|
#
|
81
85
|
# @raise [TTTLS13::Error::ErrorAlerts]
|
82
86
|
#
|
83
|
-
# @return [Array of
|
87
|
+
# @return [Array of ASN1Data, nil] received unparsable binary, nil
|
84
88
|
def deserialize_request_ids(binary)
|
85
89
|
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
86
90
|
|
@@ -92,7 +96,11 @@ module TTTLS13
|
|
92
96
|
id_len = Convert.bin2i(binary.slice(i, 2))
|
93
97
|
i += 2
|
94
98
|
id = binary.slice(i, id_len)
|
95
|
-
|
99
|
+
begin
|
100
|
+
request_ids += OpenSSL::ASN1.decode(id)
|
101
|
+
rescue OpenSSL::ASN1::ASN1Error
|
102
|
+
return nil
|
103
|
+
end
|
96
104
|
i += id_len
|
97
105
|
end
|
98
106
|
return nil if i != binary.length
|
@@ -101,6 +109,54 @@ module TTTLS13
|
|
101
109
|
end
|
102
110
|
end
|
103
111
|
end
|
112
|
+
|
113
|
+
class OCSPResponse
|
114
|
+
attr_reader :extension_type
|
115
|
+
attr_reader :ocsp_response
|
116
|
+
|
117
|
+
# @param ocsp_response [OpenSSL::OCSP::Response]
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# OCSPResponse.new(
|
121
|
+
# OpenSSL::OCSP::Response.create(status, basic_resp)
|
122
|
+
# )
|
123
|
+
def initialize(ocsp_response)
|
124
|
+
@extension_type = ExtensionType::STATUS_REQUEST
|
125
|
+
@ocsp_response = ocsp_response
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [String]
|
129
|
+
def serialize
|
130
|
+
binary = ''
|
131
|
+
binary += CertificateStatusType::OCSP
|
132
|
+
binary += @ocsp_response.to_der.prefix_uint24_length
|
133
|
+
|
134
|
+
@extension_type + binary.prefix_uint16_length
|
135
|
+
end
|
136
|
+
|
137
|
+
# @param binary [String]
|
138
|
+
#
|
139
|
+
# @raise [TTTLS13::Error::ErrorAlerts]
|
140
|
+
#
|
141
|
+
# @return [TTTLS13::Message::Extension::OCSPResponse, nil]
|
142
|
+
def self.deserialize(binary)
|
143
|
+
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
144
|
+
return nil if binary.length < 4 ||
|
145
|
+
binary[0] != CertificateStatusType::OCSP
|
146
|
+
|
147
|
+
res_len = Convert.bin2i(binary.slice(1, 3))
|
148
|
+
res = binary.slice(4, res_len)
|
149
|
+
ocsp_response = nil
|
150
|
+
begin
|
151
|
+
ocsp_response = OpenSSL::OCSP::Response.new(res)
|
152
|
+
rescue OpenSSL::OCSP::OCSPError
|
153
|
+
return nil
|
154
|
+
end
|
155
|
+
return nil if 4 + res_len != binary.length
|
156
|
+
|
157
|
+
OCSPResponse.new(ocsp_response)
|
158
|
+
end
|
159
|
+
end
|
104
160
|
end
|
105
161
|
end
|
106
162
|
end
|
@@ -110,12 +110,23 @@ module TTTLS13
|
|
110
110
|
#
|
111
111
|
# @return [TTTLS13::Message::Extension::$Object, nil]
|
112
112
|
# rubocop: disable Metrics/CyclomaticComplexity
|
113
|
+
# rubocop: disable Metrics/MethodLength
|
114
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
113
115
|
def deserialize_extension(binary, extension_type, msg_type)
|
114
116
|
raise Error::ErrorAlerts, :internal_error if binary.nil?
|
115
117
|
|
116
118
|
case extension_type
|
117
119
|
when ExtensionType::SERVER_NAME
|
118
120
|
Extension::ServerName.deserialize(binary)
|
121
|
+
when ExtensionType::STATUS_REQUEST
|
122
|
+
if msg_type == HandshakeType::CLIENT_HELLO # ||
|
123
|
+
# msg_type == HandshakeType::CERTIFICATE_REQUEST
|
124
|
+
Extension::OCSPStatusRequest.deserialize(binary)
|
125
|
+
elsif msg_type == HandshakeType::CERTIFICATE
|
126
|
+
Extension::OCSPResponse.deserialize(binary)
|
127
|
+
else
|
128
|
+
return nil
|
129
|
+
end
|
119
130
|
when ExtensionType::SUPPORTED_GROUPS
|
120
131
|
Extension::SupportedGroups.deserialize(binary)
|
121
132
|
when ExtensionType::SIGNATURE_ALGORITHMS
|
@@ -143,6 +154,8 @@ module TTTLS13
|
|
143
154
|
end
|
144
155
|
end
|
145
156
|
# rubocop: enable Metrics/CyclomaticComplexity
|
157
|
+
# rubocop: enable Metrics/MethodLength
|
158
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
146
159
|
end
|
147
160
|
end
|
148
161
|
end
|
data/lib/tttls1.3/utils.rb
CHANGED
@@ -61,6 +61,21 @@ module TTTLS13
|
|
61
61
|
length.to_uint64 + self
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
refine OpenSSL::X509::Certificate do
|
66
|
+
unless method_defined?(:ocsp_uris)
|
67
|
+
define_method(:ocsp_uris) do
|
68
|
+
aia = extensions.find { |ex| ex.oid == 'authorityInfoAccess' }
|
69
|
+
return nil if aia.nil?
|
70
|
+
|
71
|
+
ostr = OpenSSL::ASN1.decode(aia.to_der).value.last
|
72
|
+
ocsp = OpenSSL::ASN1.decode(ostr.value)
|
73
|
+
.map(&:value)
|
74
|
+
.select { |des| des.first.value == 'OCSP' }
|
75
|
+
ocsp&.map { |o| o[1].value }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
64
79
|
end
|
65
80
|
|
66
81
|
module Convert
|
data/lib/tttls1.3/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIC4TCCAcmgAwIBAgIJALkL6IyOlMwWMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
|
3
|
+
BAMMB3Rlc3QtY2EwHhcNMTkxMTI2MDczMzExWhcNMjkxMTIzMDczMzExWjAUMRIw
|
4
|
+
EAYDVQQDDAl0ZXN0LW9jc3AwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
5
|
+
AQDapLrB5S2yXQ9Wt/O9SZzoMW8IChsPgtZYC8h4Z/bcbqRb/6Bq5YfcYxq84cD/
|
6
|
+
8xn7e8R2OCNgva8GBlMy7d0czt3ysLnNlZ+dPu7MU4yS/R40LOhMGEf71mf6PLqj
|
7
|
+
1ecaEclgbIhyIGHlUXQIAnhhpAwzHxKVAhcgBgQFs8NgNViAE3BpjyUW0qXE5RUY
|
8
|
+
BQ7V9/Kn/fnsfOk6jMF20V2Kxn5Sj/c+D59+vFX3FmQyqsTKoAKoUuNsFOvHGV0d
|
9
|
+
gxLggE5wq4AodrA40MY95HgCZ2rDfEKgfc9rKhLGz6s0etGFMVtjqK6YvpQYUOaS
|
10
|
+
8JStLrGF1eINoJJFibIf69v9AgMBAAGjODA2MAkGA1UdEwQCMAAwEwYDVR0lBAww
|
11
|
+
CgYIKwYBBQUHAwkwFAYDVR0RBA0wC4IJdGVzdC1vY3NwMA0GCSqGSIb3DQEBCwUA
|
12
|
+
A4IBAQBHC6jRQyZhBJIdfP9CGpNO1dNHicwpFJ61ofwgzW1jEkVfBtVpqvEaEbYE
|
13
|
+
LVxru1s8VY281trhwRuZkDRv5hB/CUUbdPICwQlkyCdUoYURrJEm/mirK9494AGh
|
14
|
+
f33S+bMXZGAYLYoPYlSGj8EpL1Do3nvJK8//coRJlTEBcfgIIUlRMaeOiGrg3zpM
|
15
|
+
1KGxO3GtG1mpod7BEMv3ZGI85p8wXF4N2Z+phBoAyRGW+R4VW3tF5bbqiKlRr3Lt
|
16
|
+
HNsuXHSQykKpxD085eeQLTZGVESrCcmNv8XvVxwGE1r0kmlwexADNvP3HDXseie+
|
17
|
+
8QFIt+zvJb/lDy4xbCT/M4a7L9Gn
|
18
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEpAIBAAKCAQEA2qS6weUtsl0PVrfzvUmc6DFvCAobD4LWWAvIeGf23G6kW/+g
|
3
|
+
auWH3GMavOHA//MZ+3vEdjgjYL2vBgZTMu3dHM7d8rC5zZWfnT7uzFOMkv0eNCzo
|
4
|
+
TBhH+9Zn+jy6o9XnGhHJYGyIciBh5VF0CAJ4YaQMMx8SlQIXIAYEBbPDYDVYgBNw
|
5
|
+
aY8lFtKlxOUVGAUO1ffyp/357HzpOozBdtFdisZ+Uo/3Pg+ffrxV9xZkMqrEyqAC
|
6
|
+
qFLjbBTrxxldHYMS4IBOcKuAKHawONDGPeR4Amdqw3xCoH3PayoSxs+rNHrRhTFb
|
7
|
+
Y6iumL6UGFDmkvCUrS6xhdXiDaCSRYmyH+vb/QIDAQABAoIBAQC/s1D/siYHzeol
|
8
|
+
+XFelI1bVARqwxmI1wmB9wrU7yqViPjYpN+M+iTNyaLm2vUyNH6ibZkKohv6tTUh
|
9
|
+
DiiibcXBfWtCX0r5gueIomYThmmpcv6pdnpSRbPPjeRqlhZ6kZBn3hJ3VZGoptXO
|
10
|
+
j0UxxKCx03jS1bqgJU4LSNr7+OojjeKh8D9bxwCizhGx9239QwChtQTPr4U3aeTb
|
11
|
+
Qwx8WtNH/2zvpdylyXW/eg8MO4WPYXpxWSGQnRJG5knPa7hF+iRnszysbUPNBVUd
|
12
|
+
TUQJHBdtukt+7hDbPyMpMu0DwpqhOqsEk2avacWuCYEEE/SWmJ/mvLokbfECSUpy
|
13
|
+
ZqfXJPLNAoGBAPtd+m2YVmLJmjO2skv+zGG5KhHNF2cY6xLQWuHW/yChNjSzpLYm
|
14
|
+
YygyOd4hBH39ieQkBRs0QOX9S5Dzv6ERU1cr0CVDJeb9TQ9UTxXc01paJ+aoZNr5
|
15
|
+
uHoGO16xBR4tmidc4HmbHDFSwmRAFhkooHM9MVACUFABIdWqwEwSZa/HAoGBAN6s
|
16
|
+
WhPrsDyRAfKFV9bwD1P5aMPu6pjWOFO3bRIisPRtVzilamCkKvXCh1SyYHaNRjjG
|
17
|
+
fQYEZeCZTxHi7GxZltRG5DRsmm8rDz6E4OrTQMHfQNDiuw78uZZ9+YYwaIM3nt1i
|
18
|
+
/lN2hs79zj/HPf5qX9rw+CarOL0bdW97a/Monx4bAoGAeMqXXfT3hi9E15bypQxD
|
19
|
+
IK6/JaC9n0BdLkRLd/09ymtNxhORkipuOdGw9yo8o2Kj0arxfTol+Z83oedP7dGK
|
20
|
+
j/gw5McYvqB4WGZ2PpZIRkHOrMu883FPEexOuVktkWvuiP3brPQ5nwYa/dvCAsMA
|
21
|
+
H4CHYuBJwbhZjvinwaaRkN8CgYA9sQh/zmOUVCRy+Yh9jyLgBBCHgDDUyTzvzLjW
|
22
|
+
NnBKN+TbV9DiF3mjfxKZX5YkIj3bSvqmaR+Em1Txwqn31tZX15AwCgq7U/W0P4JE
|
23
|
+
7ORbEixV8wsaOuB8FkjEabL677T+5wdJPmRZAq5asyu0yenmsa4+oF9m3S2rBknB
|
24
|
+
I3b6EwKBgQD1+0+xdGomMeKHg8jWuDytdlWmNXmbiV0g2yOm533jG67vGDPfgd0H
|
25
|
+
PNC62d7r5EhIVJwQZmW/GdOfZ7tI91XN+GjNyslr9t299hoMeRMT+Db2U+mQvKuS
|
26
|
+
Oz+MHhO8YnOz9GFbQShqiCFj4zTU/0Ga/BY8Y52lURftt/QIXo+7Vg==
|
27
|
+
-----END RSA PRIVATE KEY-----
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
RSpec.configure(&:disable_monkey_patching!)
|
5
5
|
|
6
6
|
# rubocop: disable Style/MixinUsage
|
7
|
+
require 'date'
|
7
8
|
require 'tttls1.3'
|
8
9
|
include TTTLS13
|
9
10
|
include TTTLS13::Error
|
@@ -41,10 +42,43 @@ TESTBINARY_SERVER_NAME = <<BIN.split.map(&:hex).map(&:chr).join
|
|
41
42
|
00 0d 00 00 0a 67 69 74 68 75 62 2e 63 6f 6d
|
42
43
|
BIN
|
43
44
|
|
44
|
-
|
45
|
+
TESTBINARY_OCSP_STATUS_REQUEST = <<BIN.split.map(&:hex).map(&:chr).join
|
45
46
|
01 00 00 00 00
|
46
47
|
BIN
|
47
48
|
|
49
|
+
TESTBINARY_OCSP_RESPONSE = <<BIN.split.map(&:hex).map(&:chr).join
|
50
|
+
01 00 01 d0 30 82 01 cc 0a 01 00 a0 82 01 c5 30
|
51
|
+
82 01 c1 06 09 2b 06 01 05 05 07 30 01 01 04 82
|
52
|
+
01 b2 30 82 01 ae 30 81 97 a1 16 30 14 31 12 30
|
53
|
+
10 06 03 55 04 03 0c 09 74 65 73 74 2d 6f 63 73
|
54
|
+
70 18 0f 32 30 31 39 31 31 32 38 32 30 34 32 32
|
55
|
+
38 5a 30 6c 30 6a 30 42 30 09 06 05 2b 0e 03 02
|
56
|
+
1a 05 00 04 14 71 02 ca 0e ca 3e be d8 31 e6 37
|
57
|
+
40 80 9e 37 f6 da 9f a5 27 04 14 ac c2 63 89 fe
|
58
|
+
4d c6 08 1f 1f 4d 77 9e 12 7a bf 32 b6 d6 12 02
|
59
|
+
09 00 cf 1a 4c 8a cc cc 78 33 80 00 18 0f 32 30
|
60
|
+
31 39 31 31 32 38 32 30 34 32 32 38 5a a0 11 18
|
61
|
+
0f 32 30 32 39 31 31 32 38 32 30 34 32 32 38 5a
|
62
|
+
30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03
|
63
|
+
82 01 01 00 42 90 e2 2f f0 25 3b cf 11 75 56 83
|
64
|
+
c2 dc 10 d1 e8 d3 74 67 9e df db 0e 03 36 9f 64
|
65
|
+
48 61 8b 50 ca 2c dd fc 82 5b 52 d5 9b 06 64 86
|
66
|
+
70 08 c2 0b ca c9 50 b8 42 42 19 80 8f 6e f0 42
|
67
|
+
92 ac 67 4f 74 fa 2a d2 f4 2f 82 15 11 71 4b bd
|
68
|
+
54 d0 21 fb 0a 91 d3 ba 67 5e cb 7d b2 e6 a2 da
|
69
|
+
30 3d b3 92 3d a9 4e 2c f6 4a 0b 22 96 b2 1d 06
|
70
|
+
c3 0a c7 41 5f 9e 22 c0 e0 3f 52 cc ff be dd 52
|
71
|
+
80 3f 68 36 ce c0 02 df ae ab 96 a9 be d8 51 b2
|
72
|
+
bd ec f9 e7 98 5e 8a 77 69 b6 f1 60 19 49 f0 58
|
73
|
+
26 70 2f 7b 19 cc d0 13 9e 9c ed 8a 5c 87 34 4c
|
74
|
+
fd bd 0f 41 3f 5c d8 1e 26 ce bb dd 17 a7 a4 37
|
75
|
+
8f d8 19 39 5b c9 17 18 ca c3 7a eb 5d e7 ba a1
|
76
|
+
12 23 d6 cb 22 0e e1 bf 9e 40 9b e3 5c b5 6b e3
|
77
|
+
aa 6e 93 56 4f da da a1 c6 79 13 9d 5c d6 87 2b
|
78
|
+
f7 6a 0f fc 2c 03 b2 41 c4 90 b8 3d 50 1c 8a 9b
|
79
|
+
11 1b 41 83
|
80
|
+
BIN
|
81
|
+
|
48
82
|
TESTBINARY_SUPPORTED_GROUPS = <<BIN.split.map(&:hex).map(&:chr).join
|
49
83
|
00 06 00 17 00 18 00 19
|
50
84
|
BIN
|
data/spec/status_request_spec.rb
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
require_relative 'spec_helper'
|
5
5
|
using Refinements
|
6
6
|
|
7
|
-
RSpec.describe
|
8
|
-
context 'default
|
7
|
+
RSpec.describe OCSPStatusRequest do
|
8
|
+
context 'default OCSPStatusRequest' do
|
9
9
|
let(:extension) do
|
10
|
-
|
10
|
+
OCSPStatusRequest.new
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should be generated' do
|
@@ -21,9 +21,9 @@ RSpec.describe StatusRequest do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
context 'valid
|
24
|
+
context 'valid OCSPStatusRequest' do
|
25
25
|
let(:extension) do
|
26
|
-
|
26
|
+
OCSPStatusRequest.new(responder_id_list: [], request_extensions: [])
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should be generated' do
|
@@ -37,9 +37,9 @@ RSpec.describe StatusRequest do
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
context 'valid
|
40
|
+
context 'valid OCSPStatusRequest, 0 length request ' do
|
41
41
|
let(:extension) do
|
42
|
-
|
42
|
+
OCSPStatusRequest.new(responder_id_list: nil, request_extensions: nil)
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'should be generated' do
|
@@ -53,9 +53,9 @@ RSpec.describe StatusRequest do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
context 'valid
|
56
|
+
context 'valid OCSPStatusRequest binary' do
|
57
57
|
let(:extension) do
|
58
|
-
|
58
|
+
OCSPStatusRequest.deserialize(TESTBINARY_OCSP_STATUS_REQUEST)
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'should generate valid object' do
|
@@ -67,7 +67,74 @@ RSpec.describe StatusRequest do
|
|
67
67
|
it 'should generate serializable object' do
|
68
68
|
expect(extension.serialize)
|
69
69
|
.to eq ExtensionType::STATUS_REQUEST \
|
70
|
-
+
|
70
|
+
+ TESTBINARY_OCSP_STATUS_REQUEST.prefix_uint16_length
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
RSpec.describe OCSPResponse do
|
76
|
+
context 'valid OCSPResponse whose status is good' do
|
77
|
+
let(:basic_resp) do
|
78
|
+
server_crt = OpenSSL::X509::Certificate.new(
|
79
|
+
File.read(__dir__ + '/fixtures/rsa_rsa.crt')
|
80
|
+
)
|
81
|
+
ca_crt = OpenSSL::X509::Certificate.new(
|
82
|
+
File.read(__dir__ + '/fixtures/rsa_ca.crt')
|
83
|
+
)
|
84
|
+
ocsp_crt = OpenSSL::X509::Certificate.new(
|
85
|
+
File.read(__dir__ + '/fixtures/rsa_rsa_ocsp.crt')
|
86
|
+
)
|
87
|
+
ocsp_key = OpenSSL::PKey.read(
|
88
|
+
File.read(__dir__ + '/fixtures/rsa_rsa_ocsp.key')
|
89
|
+
)
|
90
|
+
|
91
|
+
br = OpenSSL::OCSP::BasicResponse.new
|
92
|
+
cid = OpenSSL::OCSP::CertificateId.new(server_crt, ca_crt)
|
93
|
+
br.add_status(
|
94
|
+
cid,
|
95
|
+
OpenSSL::OCSP::V_CERTSTATUS_GOOD,
|
96
|
+
0,
|
97
|
+
nil,
|
98
|
+
Time.now,
|
99
|
+
DateTime.now.next_day(1).to_time,
|
100
|
+
[]
|
101
|
+
)
|
102
|
+
br.sign(ocsp_crt, ocsp_key)
|
103
|
+
br
|
104
|
+
end
|
105
|
+
|
106
|
+
let(:ocsp_response) do
|
107
|
+
OpenSSL::OCSP::Response.create(
|
108
|
+
OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL,
|
109
|
+
basic_resp
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
let(:extension) do
|
114
|
+
OCSPResponse.new(ocsp_response)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should be generated' do
|
118
|
+
expect(extension.extension_type).to eq ExtensionType::STATUS_REQUEST
|
119
|
+
expect(extension.ocsp_response).to eq ocsp_response
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should be serialized' do
|
123
|
+
binary = CertificateStatusType::OCSP \
|
124
|
+
+ ocsp_response.to_der.prefix_uint24_length
|
125
|
+
|
126
|
+
expect(extension.serialize).to eq ExtensionType::STATUS_REQUEST \
|
127
|
+
+ binary.prefix_uint16_length
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'valid OCSPResponse binary' do
|
132
|
+
let(:extension) do
|
133
|
+
OCSPResponse.deserialize(TESTBINARY_OCSP_RESPONSE)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should generate valid object' do
|
137
|
+
expect(extension.extension_type).to eq ExtensionType::STATUS_REQUEST
|
71
138
|
end
|
72
139
|
end
|
73
140
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tttls1.3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekuwayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- example/https_client_using_0rtt.rb
|
74
74
|
- example/https_client_using_hrr.rb
|
75
75
|
- example/https_client_using_hrr_and_ticket.rb
|
76
|
+
- example/https_client_using_status_request.rb
|
76
77
|
- example/https_client_using_ticket.rb
|
77
78
|
- example/https_server.rb
|
78
79
|
- interop/client_spec.rb
|
@@ -144,6 +145,8 @@ files:
|
|
144
145
|
- spec/fixtures/rsa_ca.key
|
145
146
|
- spec/fixtures/rsa_rsa.crt
|
146
147
|
- spec/fixtures/rsa_rsa.key
|
148
|
+
- spec/fixtures/rsa_rsa_ocsp.crt
|
149
|
+
- spec/fixtures/rsa_rsa_ocsp.key
|
147
150
|
- spec/fixtures/rsa_rsassaPss.crt
|
148
151
|
- spec/fixtures/rsa_rsassaPss.key
|
149
152
|
- spec/fixtures/rsa_secp256r1.crt
|
@@ -217,6 +220,8 @@ test_files:
|
|
217
220
|
- spec/fixtures/rsa_ca.key
|
218
221
|
- spec/fixtures/rsa_rsa.crt
|
219
222
|
- spec/fixtures/rsa_rsa.key
|
223
|
+
- spec/fixtures/rsa_rsa_ocsp.crt
|
224
|
+
- spec/fixtures/rsa_rsa_ocsp.key
|
220
225
|
- spec/fixtures/rsa_rsassaPss.crt
|
221
226
|
- spec/fixtures/rsa_rsassaPss.key
|
222
227
|
- spec/fixtures/rsa_secp256r1.crt
|