tttls1.3 0.2.11 → 0.2.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|