ssl-test 2.1.1 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/ssl-test/crl.rb +12 -4
- data/lib/ssl-test.rb +1 -1
- data/spec/memory_store_spec.rb +1 -1
- data/spec/ssl-test_spec.rb +16 -10
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 36325440b8b451a3a2820ab4c597ed765a9d7787ff613ea36aeea671892a9882
|
|
4
|
+
data.tar.gz: 794733e1186c7a03f9b04823a165637cf7c559554e84b478d7b3fb57fe2e9e0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 682c775642e4dbae339d37afe3c059f2e34511c942d199eb09b3090a73f65840e09c0df904d2790893752cc7ad4db2f2c7cbdf68f17765cbee4015967d665282
|
|
7
|
+
data.tar.gz: 9bf3c4f4d6113d2884fd33041310a22cb5b6610aebb5e44b62a3cffa3396e56e6e7b6091dab907dcbf0fdec6d2ccdb00eac5f60a5018045ace13d334f0b1d581
|
data/README.md
CHANGED
|
@@ -200,6 +200,7 @@ But also **revoked certs** like most browsers (not handled by `curl`)
|
|
|
200
200
|
|
|
201
201
|
## Changelog
|
|
202
202
|
|
|
203
|
+
* 2.1.2 - 2026-06-23: Add support for faster `CRL#by_serial` method I just added to OpenSSL (https://github.com/ruby/openssl/pull/1065)
|
|
203
204
|
* 2.1.1 - 2026-06-21: Refactor CRL code to use newer OpenSSL `crl_uris` helper
|
|
204
205
|
* 2.1.0 - 2026-06-20: Check revocation with OCSP first and fall back to CRL (was CRL first since 1.6) because CRLs can be large and checking them is significantly more memory- and CPU-intensive. Set `SSLTest.revocation_order = %i[crl ocsp]` to restore the previous order.
|
|
205
206
|
* 2.0.1 - 2026-06-19: Speed up and shrink the memory use of CRL checks with a fast path that scans the raw CRL for the certificate's serial before parsing, avoiding instantiating the entire revocation list (>1M Ruby objects for busy CAs) when the cert isn't revoked. Send both `If-None-Match` and `If-Modified-Since` on CRL revalidation so CDN-backed CAs that don't honor their own ETag (e.g. DigiCert) still return a `304` instead of re-downloading the whole list.
|
data/lib/ssl-test/crl.rb
CHANGED
|
@@ -40,10 +40,18 @@ module SSLTest
|
|
|
40
40
|
serial_der = OpenSSL::ASN1::Integer.new(cert.serial).to_der
|
|
41
41
|
return :crl_ok unless response.to_der.include?(serial_der)
|
|
42
42
|
|
|
43
|
-
# The serial's bytes appear (a real hit, or a rare collision):
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
revoked =
|
|
43
|
+
# The serial's bytes appear (a real hit, or a rare collision): confirm
|
|
44
|
+
# authoritatively and pull the reason/date. This only runs for the few
|
|
45
|
+
# certs that look revoked, so we can afford the lookup here.
|
|
46
|
+
revoked =
|
|
47
|
+
if response.respond_to?(:by_serial)
|
|
48
|
+
# O(log n) C-level lookup, no full-list materialisation. Only on recent
|
|
49
|
+
# openssl gems (https://github.com/ruby/openssl/pull/1065).
|
|
50
|
+
response.by_serial(cert.serial)
|
|
51
|
+
else
|
|
52
|
+
response.revoked.find { |r| r.serial == cert.serial }
|
|
53
|
+
end
|
|
54
|
+
|
|
47
55
|
if revoked
|
|
48
56
|
reason = revoked.extensions.find {|e| e.oid == "CRLReason"}&.value
|
|
49
57
|
return [true, reason || "Unknown reason", revoked.time]
|
data/lib/ssl-test.rb
CHANGED
data/spec/memory_store_spec.rb
CHANGED
|
@@ -52,7 +52,7 @@ describe SSLTest::MemoryStore do
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# #size as reported through the default store after real CRL/OCSP fetches.
|
|
55
|
-
describe "SSLTest.cache.size", retry:
|
|
55
|
+
describe "SSLTest.cache.size", retry: 2 do # examples hit live CRL/OCSP endpoints
|
|
56
56
|
before { SSLTest.cache.clear }
|
|
57
57
|
|
|
58
58
|
it "returns 0 by default" do
|
data/spec/ssl-test_spec.rb
CHANGED
|
@@ -12,7 +12,7 @@ RSpec.configure do |config|
|
|
|
12
12
|
# The error/revocation examples below hit several public TLS test endpoints
|
|
13
13
|
# (badssl.com, testserver.host, ssl.com) which intermittently reset connections
|
|
14
14
|
# under load. They're spread across a few providers to avoid hammering a single
|
|
15
|
-
# one, and the network-hitting describe blocks are tagged `retry:
|
|
15
|
+
# one, and the network-hitting describe blocks are tagged `retry: 2` (via
|
|
16
16
|
# rspec-retry) so transient network blips don't fail the suite.
|
|
17
17
|
config.verbose_retry = true
|
|
18
18
|
config.display_try_failure_messages = true
|
|
@@ -27,7 +27,7 @@ describe SSLTest do
|
|
|
27
27
|
|
|
28
28
|
after(:each) { proxy_thread&.kill }
|
|
29
29
|
|
|
30
|
-
describe '.test_url', retry:
|
|
30
|
+
describe '.test_url', retry: 2 do # examples hit live TLS/CRL/OCSP endpoints
|
|
31
31
|
it "returns no error on valid SNI website" do
|
|
32
32
|
valid, error, cert = SSLTest.test("https://www.mycs.com")
|
|
33
33
|
expect(error).to be_nil
|
|
@@ -67,7 +67,7 @@ describe SSLTest do
|
|
|
67
67
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
it "returns error on incomplete chain" do
|
|
70
|
+
it "returns error on incomplete chain", retry: 5 do
|
|
71
71
|
valid, error, cert = SSLTest.test("https://incomplete-chain.badssl.com/")
|
|
72
72
|
expect(error).to eq ("error code 20: unable to get local issuer certificate")
|
|
73
73
|
expect(valid).to eq(false)
|
|
@@ -133,8 +133,10 @@ describe SSLTest do
|
|
|
133
133
|
# Disable OCSP (tried first) so the CRL performs the revocation check
|
|
134
134
|
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
135
135
|
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
136
|
-
# On a serial byte-match we
|
|
137
|
-
|
|
136
|
+
# On a serial byte-match we confirm via #by_serial (recent openssl) or, as a
|
|
137
|
+
# fallback, #revoked, to extract the reason/date.
|
|
138
|
+
confirm = OpenSSL::X509::CRL.method_defined?(:by_serial) ? :by_serial : :revoked
|
|
139
|
+
expect_any_instance_of(OpenSSL::X509::CRL).to receive(confirm).and_call_original
|
|
138
140
|
valid, error, cert = SSLTest.test("https://revoked.testserver.host/")
|
|
139
141
|
expect(error).to match(/SSL certificate revoked: Unknown reason \(revocation date:/)
|
|
140
142
|
expect(valid).to eq(false)
|
|
@@ -164,8 +166,9 @@ describe SSLTest do
|
|
|
164
166
|
expect(SSLTest).to receive(:test_ocsp_revocation).twice.and_return([false, "skip OCSP", nil])
|
|
165
167
|
expect(SSLTest).to receive(:follow_crl_redirects).twice.and_call_original
|
|
166
168
|
# Both certs are absent from their CRL, so the serial byte-search short-circuits
|
|
167
|
-
# and we never
|
|
169
|
+
# and we never reach a per-serial lookup (let alone materialise the revoked list).
|
|
168
170
|
expect_any_instance_of(OpenSSL::X509::CRL).not_to receive(:revoked)
|
|
171
|
+
expect_any_instance_of(OpenSSL::X509::CRL).not_to receive(:by_serial) if OpenSSL::X509::CRL.method_defined?(:by_serial)
|
|
169
172
|
valid, error, cert = SSLTest.test("https://www.demarches-simplifiees.fr")
|
|
170
173
|
expect(error).to be_nil
|
|
171
174
|
expect(valid).to eq(true)
|
|
@@ -226,7 +229,7 @@ describe SSLTest do
|
|
|
226
229
|
expect(valid).to eq(true)
|
|
227
230
|
expect(cert).to be_a OpenSSL::X509::Certificate
|
|
228
231
|
|
|
229
|
-
expect($proxy).to have_received(:do_GET).
|
|
232
|
+
expect($proxy).to have_received(:do_GET).thrice
|
|
230
233
|
end
|
|
231
234
|
end
|
|
232
235
|
|
|
@@ -241,7 +244,7 @@ describe SSLTest do
|
|
|
241
244
|
end
|
|
242
245
|
end
|
|
243
246
|
|
|
244
|
-
describe '.follow_crl_redirects', retry:
|
|
247
|
+
describe '.follow_crl_redirects', retry: 2 do # fetches a live CRL
|
|
245
248
|
before { SSLTest.cache.clear }
|
|
246
249
|
# 19MB: http://crl3.digicert.com/ssca-sha2-g6.crl
|
|
247
250
|
it "fetch CRL list and updates cache" do
|
|
@@ -272,7 +275,7 @@ describe SSLTest do
|
|
|
272
275
|
end
|
|
273
276
|
end
|
|
274
277
|
|
|
275
|
-
describe '.cache', retry:
|
|
278
|
+
describe '.cache', retry: 2 do # some examples hit live CRL/OCSP endpoints
|
|
276
279
|
# Restore the default in-process store after tests that swap the backend so
|
|
277
280
|
# global state doesn't leak between examples.
|
|
278
281
|
after { SSLTest.cache = SSLTest::MemoryStore.new }
|
|
@@ -299,7 +302,7 @@ describe SSLTest do
|
|
|
299
302
|
end
|
|
300
303
|
end
|
|
301
304
|
|
|
302
|
-
describe '.test_cert', retry:
|
|
305
|
+
describe '.test_cert', retry: 2 do # revocation checks hit live CRL/OCSP endpoints
|
|
303
306
|
it "returns no error on valid SNI website" do
|
|
304
307
|
cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, 'fixtures/www_mycs_com_client.pem')))
|
|
305
308
|
ca_bundle = OpenSSL::X509::Certificate.load(File.read(File.join(__dir__, 'fixtures/www_mycs_com_ca_bundle.pem')))
|
|
@@ -370,6 +373,9 @@ describe SSLTest do
|
|
|
370
373
|
# Disable OCSP (tried first) so the CRL performs the revocation check
|
|
371
374
|
expect(SSLTest).to receive(:test_ocsp_revocation).once.and_return([false, "skip OCSP", nil])
|
|
372
375
|
expect(SSLTest).to receive(:follow_crl_redirects).once.and_call_original
|
|
376
|
+
# On a serial byte-match we confirm via #by_serial (recent openssl) or #revoked
|
|
377
|
+
confirm = OpenSSL::X509::CRL.method_defined?(:by_serial) ? :by_serial : :revoked
|
|
378
|
+
expect_any_instance_of(OpenSSL::X509::CRL).to receive(confirm).and_call_original
|
|
373
379
|
valid, error, cert = SSLTest.test_cert(cert, ca_bundle)
|
|
374
380
|
expect(error).to eq ("SSL certificate revoked: Key Compromise (revocation date: 2026-05-12 21:01:31 UTC)")
|
|
375
381
|
expect(valid).to eq(false)
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ssl-test
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrien Rey-Jarthon
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-06-
|
|
10
|
+
date: 2026-06-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bundler
|