ssl-test 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -5
- data/README.md +38 -10
- data/lib/ssl-test/crl.rb +3 -3
- data/lib/ssl-test/ocsp.rb +3 -3
- data/lib/ssl-test.rb +67 -21
- data/spec/fixtures/digicert_com_ca_bundle.pem +94 -0
- data/spec/fixtures/digicert_com_client.pem +40 -0
- data/spec/fixtures/expired_cert_ca_bundle.pem +100 -0
- data/spec/fixtures/expired_cert_client.pem +31 -0
- data/spec/fixtures/google_com_ca_bundle.pem +139 -0
- data/spec/fixtures/google_com_client.pem +79 -0
- data/spec/fixtures/incomplete_chain_ca_bundle.pem +29 -0
- data/spec/fixtures/incomplete_chain_client.pem +29 -0
- data/spec/fixtures/revoked_badssl_ca_bundle.pem +81 -0
- data/spec/fixtures/revoked_badssl_client.pem +22 -0
- data/spec/fixtures/revoked_rsa_dv_ca_bundle.pem +114 -0
- data/spec/fixtures/revoked_rsa_dv_client.pem +41 -0
- data/spec/fixtures/self_signed_ca_bundle.pem +21 -0
- data/spec/fixtures/self_signed_client.pem +21 -0
- data/spec/fixtures/www_demarches-simplifiees_fr_ca_bundle.pem +108 -0
- data/spec/fixtures/www_demarches-simplifiees_fr_client.pem +52 -0
- data/spec/fixtures/www_github_com_ca_bundle.pem +67 -0
- data/spec/fixtures/www_github_com_client.pem +27 -0
- data/spec/fixtures/www_mycs_com_ca_bundle.pem +79 -0
- data/spec/fixtures/www_mycs_com_client.pem +33 -0
- data/spec/ssl-test_spec.rb +272 -35
- data/ssl-test.gemspec +1 -0
- metadata +57 -7
data/spec/ssl-test_spec.rb
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
require "ssl-test"
|
|
2
2
|
require "benchmark"
|
|
3
|
+
require 'webrick'
|
|
4
|
+
require 'webrick/httpproxy'
|
|
3
5
|
|
|
4
6
|
# Uncomment for debug logging:
|
|
5
7
|
# require "logger"
|
|
6
8
|
# SSLTest.logger = Logger.new(STDOUT)
|
|
7
9
|
|
|
8
10
|
describe SSLTest do
|
|
9
|
-
|
|
11
|
+
before { SSLTest.flush_cache }
|
|
12
|
+
|
|
13
|
+
let(:proxy_thread) { nil }
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
after(:each) { proxy_thread&.kill }
|
|
17
|
+
|
|
18
|
+
describe '.test_url' do
|
|
10
19
|
it "returns no error on valid SNI website" do
|
|
11
20
|
valid, error, cert = SSLTest.test("https://www.mycs.com")
|
|
12
21
|
expect(error).to be_nil
|
|
@@ -15,20 +24,22 @@ describe SSLTest do
|
|
|
15
24
|
end
|
|
16
25
|
|
|
17
26
|
it "returns no error on valid SAN" do
|
|
18
|
-
|
|
19
|
-
valid, error, cert = SSLTest.test("https://
|
|
27
|
+
# CN is updown.io, www.updown.io is an Alternative Name
|
|
28
|
+
valid, error, cert = SSLTest.test("https://www.updown.io/")
|
|
20
29
|
expect(error).to be_nil
|
|
21
30
|
expect(valid).to eq(true)
|
|
22
31
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
23
32
|
end
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
# Disabled: unlikely to be repaired anytime soon: https://github.com/chromium/badssl.com/issues/447
|
|
35
|
+
# Couldn't find a good alternative
|
|
36
|
+
# it "returns no error when no CN" do
|
|
37
|
+
# pending "Expired for the moment https://github.com/chromium/badssl.com/issues/447"
|
|
38
|
+
# valid, error, cert = SSLTest.test("https://no-common-name.badssl.com/")
|
|
39
|
+
# expect(error).to be_nil
|
|
40
|
+
# expect(valid).to eq(true)
|
|
41
|
+
# expect(cert).to be_a OpenSSL::X509::Certificate
|
|
42
|
+
# end
|
|
32
43
|
|
|
33
44
|
it "works with websites blocking http requests" do
|
|
34
45
|
valid, error, cert = SSLTest.test("https://obyava.ua")
|
|
@@ -74,21 +85,23 @@ describe SSLTest do
|
|
|
74
85
|
|
|
75
86
|
it "returns undetermined state on unhandled error" do
|
|
76
87
|
valid, error, cert = SSLTest.test("https://pijoinlrfgind.com")
|
|
77
|
-
expect(error).to
|
|
88
|
+
expect(error).to include("SSL certificate test failed: Failed to open TCP connection to pijoinlrfgind.com:443")
|
|
89
|
+
expect(error).to include(/name.*not known/i)
|
|
78
90
|
expect(valid).to be_nil
|
|
79
91
|
expect(cert).to be_nil
|
|
80
92
|
end
|
|
81
93
|
|
|
82
94
|
it "stops on timeouts" do
|
|
83
95
|
valid, error, cert = SSLTest.test("https://updown.io", open_timeout: 0)
|
|
84
|
-
expect(error).to
|
|
96
|
+
expect(error).to include("SSL certificate test failed")
|
|
97
|
+
expect(error).to include(/timeout/i)
|
|
85
98
|
expect(valid).to be_nil
|
|
86
99
|
expect(cert).to be_nil
|
|
87
100
|
end
|
|
88
101
|
|
|
89
102
|
it "reports revocation exceptions" do
|
|
90
103
|
expect(SSLTest).to receive(:follow_ocsp_redirects).and_raise(ArgumentError.new("test"))
|
|
91
|
-
valid, error, cert = SSLTest.test("https://
|
|
104
|
+
valid, error, cert = SSLTest.test("https://digicert.com")
|
|
92
105
|
expect(error).to eq ("SSL certificate test failed: test")
|
|
93
106
|
expect(valid).to be_nil
|
|
94
107
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
@@ -97,8 +110,8 @@ describe SSLTest do
|
|
|
97
110
|
it "returns error on revoked cert (OCSP)" do
|
|
98
111
|
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
99
112
|
expect(SSLTest).not_to receive(:follow_crl_redirects)
|
|
100
|
-
valid, error, cert = SSLTest.test("https://revoked.
|
|
101
|
-
expect(error).to eq ("SSL certificate revoked: The certificate was revoked for an unknown reason (revocation date:
|
|
113
|
+
valid, error, cert = SSLTest.test("https://revoked-rsa-dv.ssl.com/")
|
|
114
|
+
expect(error).to eq ("SSL certificate revoked: The certificate was revoked for an unknown reason (revocation date: 2025-06-09 15:07:39 UTC)")
|
|
102
115
|
expect(valid).to eq(false)
|
|
103
116
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
104
117
|
end
|
|
@@ -107,14 +120,15 @@ describe SSLTest do
|
|
|
107
120
|
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
108
121
|
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
109
122
|
valid, error, cert = SSLTest.test("https://revoked.badssl.com/")
|
|
110
|
-
expect(error).to eq ("SSL certificate revoked:
|
|
123
|
+
expect(error).to eq ("SSL certificate revoked: Key Compromise (revocation date: 2025-11-04 21:01:29 UTC)")
|
|
111
124
|
expect(valid).to eq(false)
|
|
112
125
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
113
126
|
end
|
|
114
127
|
|
|
115
128
|
it "stops following redirection after the limit for the revoked certs check" do
|
|
116
129
|
valid, error, cert = SSLTest.test("https://github.com/", redirection_limit: 0)
|
|
117
|
-
expect(error).to
|
|
130
|
+
expect(error).to include("Revocation test couldn't be performed: OCSP: Request failed")
|
|
131
|
+
expect(error).to include("Too many redirections (> 0)")
|
|
118
132
|
expect(valid).to eq(true)
|
|
119
133
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
120
134
|
end
|
|
@@ -123,7 +137,7 @@ describe SSLTest do
|
|
|
123
137
|
# Disable CRL fallback to see error message
|
|
124
138
|
expect(SSLTest).to receive(:test_crl_revocation).once.and_return([false, "skip CRL", nil])
|
|
125
139
|
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
126
|
-
valid, error, cert = SSLTest.test("https://
|
|
140
|
+
valid, error, cert = SSLTest.test("https://google.com")
|
|
127
141
|
expect(error).to eq ("Revocation test couldn't be performed: OCSP: Missing OCSP URI in authorityInfoAccess extension, CRL: skip CRL")
|
|
128
142
|
expect(valid).to eq(true)
|
|
129
143
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
@@ -143,29 +157,24 @@ describe SSLTest do
|
|
|
143
157
|
# Disable OCSP to see error message
|
|
144
158
|
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
145
159
|
expect(SSLTest).not_to receive(:follow_crl_redirects)
|
|
146
|
-
valid, error, cert = SSLTest.test("https://
|
|
160
|
+
valid, error, cert = SSLTest.test("https://github.com")
|
|
147
161
|
expect(error).to eq ("Revocation test couldn't be performed: OCSP: skip OCSP, CRL: Missing crlDistributionPoints extension")
|
|
148
162
|
expect(valid).to eq(true)
|
|
149
163
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
150
164
|
end
|
|
151
165
|
|
|
152
|
-
it "works with OCSP for first cert and CRL for intermediate (
|
|
166
|
+
it "works with OCSP for first cert and CRL for intermediate (Google)" do
|
|
153
167
|
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
154
168
|
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
155
|
-
valid, error, cert = SSLTest.test("https://
|
|
156
|
-
expect(error).to be_nil
|
|
157
|
-
expect(valid).to eq(true)
|
|
158
|
-
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it "works with OCSP for first cert and CRL for intermediate (Certigna Services CA)" do
|
|
162
|
-
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
163
|
-
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
164
|
-
# Similar chain: https://www.demarches-simplifiees.fr
|
|
165
|
-
valid, error, cert = SSLTest.test("https://www.anonymisation.gov.pf")
|
|
169
|
+
valid, error, cert = SSLTest.test("https://google.com")
|
|
166
170
|
expect(error).to be_nil
|
|
167
171
|
expect(valid).to eq(true)
|
|
168
172
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
173
|
+
# make sure both were used
|
|
174
|
+
expect(SSLTest.cache_size).to match({
|
|
175
|
+
crl: hash_including(lists: 1),
|
|
176
|
+
ocsp: hash_including(responses: 1, errors: 0)
|
|
177
|
+
})
|
|
169
178
|
end
|
|
170
179
|
|
|
171
180
|
it "accepts tcps scheme" do
|
|
@@ -174,6 +183,43 @@ describe SSLTest do
|
|
|
174
183
|
expect(valid).to eq(true)
|
|
175
184
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
176
185
|
end
|
|
186
|
+
|
|
187
|
+
context 'when specifying a proxy' do
|
|
188
|
+
context 'when the proxy is active' do
|
|
189
|
+
let(:proxy_thread) do
|
|
190
|
+
thread = Thread.new do
|
|
191
|
+
dev_null = WEBrick::Log::new("/dev/null", 7)
|
|
192
|
+
$proxy = WEBrick::HTTPProxyServer.new Port: 8080, :Logger => dev_null, :AccessLog => []
|
|
193
|
+
$proxy.start
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
sleep 0.1 # wait for the proxy to start!
|
|
197
|
+
allow($proxy).to receive(:do_GET).and_call_original
|
|
198
|
+
|
|
199
|
+
thread
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'uses the provided http proxy' do
|
|
203
|
+
proxy_thread
|
|
204
|
+
|
|
205
|
+
valid, error, cert = SSLTest.test("https://updown.io", proxy_host: '127.0.0.1', proxy_port: 8080)
|
|
206
|
+
expect(error).to be_nil
|
|
207
|
+
expect(valid).to eq(true)
|
|
208
|
+
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
209
|
+
|
|
210
|
+
expect($proxy).to have_received(:do_GET).twice
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context 'when the proxy is not reachable' do
|
|
215
|
+
it 'returns a http error' do
|
|
216
|
+
valid, error, cert = SSLTest.test("https://updown.io", proxy_host: '127.0.0.1', proxy_port: 55000)
|
|
217
|
+
expect(error).to include('(Connection refused - connect(2) for "127.0.0.1" port 55000)')
|
|
218
|
+
expect(valid).to be_nil
|
|
219
|
+
expect(cert).to be_nil
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
177
223
|
end
|
|
178
224
|
|
|
179
225
|
describe '.cache_size' do
|
|
@@ -190,11 +236,11 @@ describe SSLTest do
|
|
|
190
236
|
SSLTest.send(:follow_crl_redirects, URI("http://crl.certigna.fr/certigna.crl")) # 1.1k
|
|
191
237
|
SSLTest.send(:follow_crl_redirects, URI("http://crl3.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crl")) # 26k
|
|
192
238
|
expect(SSLTest.cache_size[:crl][:lists]).to eq(2)
|
|
193
|
-
expect(SSLTest.cache_size[:crl][:bytes]).to be >
|
|
239
|
+
expect(SSLTest.cache_size[:crl][:bytes]).to be > 6000
|
|
194
240
|
end
|
|
195
241
|
|
|
196
242
|
it "returns OCSP cache size properly" do
|
|
197
|
-
SSLTest.test("https://
|
|
243
|
+
SSLTest.test("https://google.com")
|
|
198
244
|
expect(SSLTest.cache_size[:ocsp][:responses]).to eq(1)
|
|
199
245
|
expect(SSLTest.cache_size[:ocsp][:errors]).to eq(0)
|
|
200
246
|
expect(SSLTest.cache_size[:ocsp][:bytes]).to be > 150
|
|
@@ -209,7 +255,7 @@ describe SSLTest do
|
|
|
209
255
|
it "fetch CRL list and updates cache" do
|
|
210
256
|
uri = URI("http://crl.certigna.fr/certigna.crl")
|
|
211
257
|
body, error = SSLTest.send(:follow_crl_redirects, uri)
|
|
212
|
-
expect(body.bytesize).to equal
|
|
258
|
+
expect(body.bytesize).to equal 1417
|
|
213
259
|
expect(error).to be_nil
|
|
214
260
|
|
|
215
261
|
# Check cache status
|
|
@@ -233,4 +279,195 @@ describe SSLTest do
|
|
|
233
279
|
expect(body2).to be(body) # but we're still using cache because it's a 304
|
|
234
280
|
end
|
|
235
281
|
end
|
|
236
|
-
|
|
282
|
+
|
|
283
|
+
describe '.test_cert' do
|
|
284
|
+
it "returns no error on valid SNI website" do
|
|
285
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/www_mycs_com_client.pem')))
|
|
286
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/www_mycs_com_ca_bundle.pem')))
|
|
287
|
+
|
|
288
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
289
|
+
expect(error).to be_nil
|
|
290
|
+
expect(valid).to eq(true)
|
|
291
|
+
expect(cert).to eq(cert)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it "returns no error on self signed certificates" do
|
|
295
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/self_signed_client.pem')))
|
|
296
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/self_signed_ca_bundle.pem')))
|
|
297
|
+
|
|
298
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
299
|
+
expect(error).to be_nil
|
|
300
|
+
expect(valid).to eq(true)
|
|
301
|
+
expect(cert).to eq(cert)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "returns error on expired cert" do
|
|
305
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/expired_cert_client.pem')))
|
|
306
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/expired_cert_ca_bundle.pem')))
|
|
307
|
+
|
|
308
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
309
|
+
expect(error).to eq ("error code 10: certificate has expired")
|
|
310
|
+
expect(valid).to eq(false)
|
|
311
|
+
expect(cert).to eq(cert)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "returns error on incomplete chain" do
|
|
315
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/incomplete_chain_client.pem')))
|
|
316
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/incomplete_chain_ca_bundle.pem')))
|
|
317
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
318
|
+
expect(error).to eq ("error code 20: unable to get local issuer certificate")
|
|
319
|
+
expect(valid).to eq(false)
|
|
320
|
+
expect(cert).to eq(cert)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "reports revocation exceptions" do
|
|
324
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/digicert_com_client.pem')))
|
|
325
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/digicert_com_ca_bundle.pem')))
|
|
326
|
+
expect(SSLTest).to receive(:follow_ocsp_redirects).and_raise(ArgumentError.new("test"))
|
|
327
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
328
|
+
expect(error).to eq("SSL certificate test failed: test")
|
|
329
|
+
expect(valid).to be_nil
|
|
330
|
+
expect(cert).to eq(cert)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "returns error on revoked cert (OCSP)" do
|
|
334
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/revoked_rsa_dv_client.pem')))
|
|
335
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/revoked_rsa_dv_ca_bundle.pem')))
|
|
336
|
+
|
|
337
|
+
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
338
|
+
expect(SSLTest).not_to receive(:follow_crl_redirects)
|
|
339
|
+
|
|
340
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
341
|
+
expect(error).to eq ("SSL certificate revoked: The certificate was revoked for an unknown reason (revocation date: 2025-06-09 15:07:39 UTC)")
|
|
342
|
+
expect(valid).to eq(false)
|
|
343
|
+
expect(cert).to eq(cert)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it "returns error on revoked cert (CRL)" do
|
|
347
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/revoked_badssl_client.pem')))
|
|
348
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/revoked_badssl_ca_bundle.pem')))
|
|
349
|
+
|
|
350
|
+
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
351
|
+
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
352
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
353
|
+
expect(error).to eq ("SSL certificate revoked: Key Compromise (revocation date: 2025-11-04 21:01:29 UTC)")
|
|
354
|
+
expect(valid).to eq(false)
|
|
355
|
+
expect(cert).to eq(cert)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it "stops following redirection after the limit for the revoked certs check" do
|
|
359
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/www_github_com_client.pem')))
|
|
360
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/www_github_com_ca_bundle.pem')))
|
|
361
|
+
|
|
362
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle, redirection_limit: 0)
|
|
363
|
+
expect(error).to include("Revocation test couldn't be performed: OCSP: Request failed")
|
|
364
|
+
expect(error).to include("Too many redirections (> 0)")
|
|
365
|
+
expect(valid).to eq(true)
|
|
366
|
+
expect(cert).to eq(cert)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
it "warns when the OCSP URI is missing" do
|
|
370
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/google_com_client.pem')))
|
|
371
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/google_com_ca_bundle.pem')))
|
|
372
|
+
|
|
373
|
+
# Disable CRL fallback to see error message
|
|
374
|
+
expect(SSLTest).to receive(:test_crl_revocation).once.and_return([false, "skip CRL", nil])
|
|
375
|
+
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
376
|
+
|
|
377
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
378
|
+
expect(error).to eq ("Revocation test couldn't be performed: OCSP: Missing OCSP URI in authorityInfoAccess extension, CRL: skip CRL")
|
|
379
|
+
expect(valid).to eq(true)
|
|
380
|
+
expect(cert).to eq(cert)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it "works with CRL only" do
|
|
384
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/www_demarches-simplifiees_fr_client.pem')))
|
|
385
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/www_demarches-simplifiees_fr_ca_bundle.pem')))
|
|
386
|
+
|
|
387
|
+
# Disable OCSP
|
|
388
|
+
expect(SSLTest).to receive(:test_ocsp_revocation).twice.and_return([false, "skip OCSP", nil])
|
|
389
|
+
expect(SSLTest).to receive(:follow_crl_redirects).twice.and_call_original
|
|
390
|
+
|
|
391
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
392
|
+
expect(error).to be_nil
|
|
393
|
+
expect(valid).to eq(true)
|
|
394
|
+
expect(cert).to eq(cert)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
it "warns when the CRL URI is missing" do
|
|
398
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/www_github_com_client.pem')))
|
|
399
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/www_github_com_ca_bundle.pem')))
|
|
400
|
+
|
|
401
|
+
# Disable OCSP to see error message
|
|
402
|
+
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
403
|
+
expect(SSLTest).not_to receive(:follow_crl_redirects)
|
|
404
|
+
|
|
405
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
406
|
+
expect(error).to eq ("Revocation test couldn't be performed: OCSP: skip OCSP, CRL: Missing crlDistributionPoints extension")
|
|
407
|
+
expect(valid).to eq(true)
|
|
408
|
+
expect(cert).to eq(cert)
|
|
409
|
+
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "works with OCSP for first cert and CRL for intermediate (Google)" do
|
|
413
|
+
expect(SSLTest).to receive(:follow_ocsp_redirects).once.and_call_original
|
|
414
|
+
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
415
|
+
|
|
416
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/google_com_client.pem')))
|
|
417
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/google_com_ca_bundle.pem')))
|
|
418
|
+
|
|
419
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
420
|
+
expect(error).to be_nil
|
|
421
|
+
expect(valid).to eq(true)
|
|
422
|
+
expect(cert).to eq(cert)
|
|
423
|
+
# make sure both were used
|
|
424
|
+
expect(SSLTest.cache_size).to match({
|
|
425
|
+
crl: hash_including(lists: 1),
|
|
426
|
+
ocsp: hash_including(responses: 1, errors: 0)
|
|
427
|
+
})
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
context 'when specifying a proxy' do
|
|
431
|
+
context 'when the proxy is active' do
|
|
432
|
+
let(:proxy_thread) do
|
|
433
|
+
thread = Thread.new do
|
|
434
|
+
dev_null = WEBrick::Log::new("/dev/null", 7)
|
|
435
|
+
$proxy = WEBrick::HTTPProxyServer.new Port: 8080, :Logger => dev_null, :AccessLog => []
|
|
436
|
+
$proxy.start
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
sleep 0.1 # wait for the proxy to start!
|
|
440
|
+
allow($proxy).to receive(:do_GET).and_call_original
|
|
441
|
+
|
|
442
|
+
thread
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
it 'uses the provided http proxy' do
|
|
446
|
+
proxy_thread
|
|
447
|
+
|
|
448
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/google_com_client.pem')))
|
|
449
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/google_com_ca_bundle.pem')))
|
|
450
|
+
|
|
451
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle, proxy_host: '127.0.0.1', proxy_port: 8080)
|
|
452
|
+
expect(error).to be_nil
|
|
453
|
+
expect(valid).to eq(true)
|
|
454
|
+
expect(cert).to eq(cert)
|
|
455
|
+
|
|
456
|
+
expect($proxy).to have_received(:do_GET).once
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
context 'when the proxy is not reachable' do
|
|
461
|
+
it 'returns a http error' do
|
|
462
|
+
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/google_com_client.pem')))
|
|
463
|
+
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/google_com_ca_bundle.pem')))
|
|
464
|
+
|
|
465
|
+
valid, error, cert = SSLTest.test_cert(cert, ca_bundle, proxy_host: '127.0.0.1', proxy_port: 55000)
|
|
466
|
+
expect(error).to include('(Connection refused - connect(2) for "127.0.0.1" port 55000)')
|
|
467
|
+
expect(valid).to be_nil
|
|
468
|
+
expect(cert).to eq(cert)
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
data/ssl-test.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ssl-test
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrien Rey-Jarthon
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-11-28 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bundler
|
|
@@ -52,7 +51,20 @@ dependencies:
|
|
|
52
51
|
- - ">="
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '0'
|
|
55
|
-
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: webrick
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
56
68
|
email:
|
|
57
69
|
- jobs@adrienjarthon.com
|
|
58
70
|
executables: []
|
|
@@ -70,13 +82,32 @@ files:
|
|
|
70
82
|
- lib/ssl-test/crl.rb
|
|
71
83
|
- lib/ssl-test/object_size.rb
|
|
72
84
|
- lib/ssl-test/ocsp.rb
|
|
85
|
+
- spec/fixtures/digicert_com_ca_bundle.pem
|
|
86
|
+
- spec/fixtures/digicert_com_client.pem
|
|
87
|
+
- spec/fixtures/expired_cert_ca_bundle.pem
|
|
88
|
+
- spec/fixtures/expired_cert_client.pem
|
|
89
|
+
- spec/fixtures/google_com_ca_bundle.pem
|
|
90
|
+
- spec/fixtures/google_com_client.pem
|
|
91
|
+
- spec/fixtures/incomplete_chain_ca_bundle.pem
|
|
92
|
+
- spec/fixtures/incomplete_chain_client.pem
|
|
93
|
+
- spec/fixtures/revoked_badssl_ca_bundle.pem
|
|
94
|
+
- spec/fixtures/revoked_badssl_client.pem
|
|
95
|
+
- spec/fixtures/revoked_rsa_dv_ca_bundle.pem
|
|
96
|
+
- spec/fixtures/revoked_rsa_dv_client.pem
|
|
97
|
+
- spec/fixtures/self_signed_ca_bundle.pem
|
|
98
|
+
- spec/fixtures/self_signed_client.pem
|
|
99
|
+
- spec/fixtures/www_demarches-simplifiees_fr_ca_bundle.pem
|
|
100
|
+
- spec/fixtures/www_demarches-simplifiees_fr_client.pem
|
|
101
|
+
- spec/fixtures/www_github_com_ca_bundle.pem
|
|
102
|
+
- spec/fixtures/www_github_com_client.pem
|
|
103
|
+
- spec/fixtures/www_mycs_com_ca_bundle.pem
|
|
104
|
+
- spec/fixtures/www_mycs_com_client.pem
|
|
73
105
|
- spec/ssl-test_spec.rb
|
|
74
106
|
- ssl-test.gemspec
|
|
75
107
|
homepage: https://github.com/jarthod/ssl-test
|
|
76
108
|
licenses:
|
|
77
109
|
- MIT
|
|
78
110
|
metadata: {}
|
|
79
|
-
post_install_message:
|
|
80
111
|
rdoc_options: []
|
|
81
112
|
require_paths:
|
|
82
113
|
- lib
|
|
@@ -91,9 +122,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
91
122
|
- !ruby/object:Gem::Version
|
|
92
123
|
version: '0'
|
|
93
124
|
requirements: []
|
|
94
|
-
rubygems_version: 3.
|
|
95
|
-
signing_key:
|
|
125
|
+
rubygems_version: 3.6.2
|
|
96
126
|
specification_version: 4
|
|
97
127
|
summary: Test website SSL certificate validity
|
|
98
128
|
test_files:
|
|
129
|
+
- spec/fixtures/digicert_com_ca_bundle.pem
|
|
130
|
+
- spec/fixtures/digicert_com_client.pem
|
|
131
|
+
- spec/fixtures/expired_cert_ca_bundle.pem
|
|
132
|
+
- spec/fixtures/expired_cert_client.pem
|
|
133
|
+
- spec/fixtures/google_com_ca_bundle.pem
|
|
134
|
+
- spec/fixtures/google_com_client.pem
|
|
135
|
+
- spec/fixtures/incomplete_chain_ca_bundle.pem
|
|
136
|
+
- spec/fixtures/incomplete_chain_client.pem
|
|
137
|
+
- spec/fixtures/revoked_badssl_ca_bundle.pem
|
|
138
|
+
- spec/fixtures/revoked_badssl_client.pem
|
|
139
|
+
- spec/fixtures/revoked_rsa_dv_ca_bundle.pem
|
|
140
|
+
- spec/fixtures/revoked_rsa_dv_client.pem
|
|
141
|
+
- spec/fixtures/self_signed_ca_bundle.pem
|
|
142
|
+
- spec/fixtures/self_signed_client.pem
|
|
143
|
+
- spec/fixtures/www_demarches-simplifiees_fr_ca_bundle.pem
|
|
144
|
+
- spec/fixtures/www_demarches-simplifiees_fr_client.pem
|
|
145
|
+
- spec/fixtures/www_github_com_ca_bundle.pem
|
|
146
|
+
- spec/fixtures/www_github_com_client.pem
|
|
147
|
+
- spec/fixtures/www_mycs_com_ca_bundle.pem
|
|
148
|
+
- spec/fixtures/www_mycs_com_client.pem
|
|
99
149
|
- spec/ssl-test_spec.rb
|