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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48563a079839f759ca0f765c768fa7280af962036d2e1e9acd81aaa2dd8967fb
4
- data.tar.gz: 2a51edf744b6116222f52ea1b72b502805f2a2c78beab94620b408a8c7b05d07
3
+ metadata.gz: 36325440b8b451a3a2820ab4c597ed765a9d7787ff613ea36aeea671892a9882
4
+ data.tar.gz: 794733e1186c7a03f9b04823a165637cf7c559554e84b478d7b3fb57fe2e9e0e
5
5
  SHA512:
6
- metadata.gz: bd2cb2d7de4d133df831932a4d8a44974fc49dd592765fa7669f9d272c1e169d8ea90c728109824dafc89d20a11d83da135f9a7852466781bc58890dcc3a322a
7
- data.tar.gz: b96a5c2515c952f25ebe823c88d5daf2e8bcc60024d76a7ea715fc854b199bb4e1e06f4d3f787490a6f9bfb987eaba3f4be5692a063a74b4f55fa605e3e8c7e4
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
- # confirm authoritatively and pull the reason/date. The costly revoked-list
45
- # materialisation only happens here, i.e. for actually-revoked certs.
46
- revoked = response.revoked.find { |r| r.serial == cert.serial }
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
@@ -11,7 +11,7 @@ module SSLTest
11
11
  extend OCSP
12
12
  extend CRL
13
13
 
14
- VERSION = -"2.1.1"
14
+ VERSION = -"2.1.2"
15
15
 
16
16
  # Prefix for all cache keys so SSLTest entries coexist cleanly inside a shared
17
17
  # cache (e.g. Rails.cache).
@@ -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: 5 do # examples hit live CRL/OCSP endpoints
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
@@ -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: 5` (via
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: 5 do # examples hit live TLS/CRL/OCSP endpoints
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 fall back to #revoked to extract the reason/date
137
- expect_any_instance_of(OpenSSL::X509::CRL).to receive(:revoked).and_call_original
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 materialise the (potentially huge) revoked list.
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).twice
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: 5 do # fetches a live CRL
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: 5 do # some examples hit live CRL/OCSP endpoints
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: 5 do # revocation checks hit live CRL/OCSP endpoints
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.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-21 00:00:00.000000000 Z
10
+ date: 2026-06-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler