Skip to content

Commit 842b794

Browse files
authored
RUBY-3694 Use correct CA when verifying OCSP endpoint (#2944)
* use the next cert in the chain as the CA when verifying OCSP * don't assume the issuer is at a particular position in the chain * Fix incorrect method description
1 parent 7d0f906 commit 842b794

File tree

2 files changed

+36
-102
lines changed

2 files changed

+36
-102
lines changed

lib/mongo/socket/ssl.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ def verify_ocsp_endpoint!(socket, timeout = nil)
460460
end
461461

462462
cert = socket.peer_cert
463-
ca_cert = socket.peer_cert_chain.last
463+
ca_cert = find_issuer(cert, socket.peer_cert_chain)
464464

465465
verifier = OcspVerifier.new(@host_name, cert, ca_cert, context.cert_store,
466466
**Utils.shallow_symbolize_keys(options).merge(timeout: timeout))
@@ -503,6 +503,11 @@ def extract_certs(text)
503503
end
504504
end
505505
end
506+
507+
# Find the issuer certificate in the chain.
508+
def find_issuer(cert, cert_chain)
509+
cert_chain.find { |c| c.subject == cert.issuer }
510+
end
506511
end
507512
end
508513
end

spec/integration/ocsp_verifier_spec.rb

Lines changed: 30 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
with_openssl_debug
1010
retry_test sleep: 5
1111

12+
def self.with_ocsp_responder(port = 8100, path = '/', &setup)
13+
around do |example|
14+
server = WEBrick::HTTPServer.new(Port: port)
15+
server.mount_proc path, &setup
16+
Thread.new { server.start }
17+
begin
18+
example.run
19+
ensure
20+
server.shutdown
21+
end
22+
23+
::Utils.wait_for_port_free(port, 5)
24+
end
25+
end
26+
1227
shared_examples 'verifies' do
1328
context 'mri' do
1429
fails_on_jruby
@@ -173,21 +188,10 @@
173188

174189
context 'one time' do
175190

176-
around do |example|
177-
server = WEBrick::HTTPServer.new(Port: 8100)
178-
server.mount_proc '/' do |req, res|
179-
res.status = 303
180-
res['locAtion'] = "http://localhost:8101#{req.path}"
181-
res.body = "See http://localhost:8101#{req.path}"
182-
end
183-
Thread.new { server.start }
184-
begin
185-
example.run
186-
ensure
187-
server.shutdown
188-
end
189-
190-
::Utils.wait_for_port_free(8100, 5)
191+
with_ocsp_responder do |req, res|
192+
res.status = 303
193+
res['locAtion'] = "http://localhost:8101#{req.path}"
194+
res.body = "See http://localhost:8101#{req.path}"
191195
end
192196

193197
include_context 'verifier', algorithm: algorithm
@@ -248,21 +252,10 @@
248252
port: 8101,
249253
)
250254

251-
around do |example|
252-
server = WEBrick::HTTPServer.new(Port: 8100)
253-
server.mount_proc '/' do |req, res|
254-
res.status = 303
255-
res['locAtion'] = req.path
256-
res.body = "See #{req.path} indefinitely"
257-
end
258-
Thread.new { server.start }
259-
begin
260-
example.run
261-
ensure
262-
server.shutdown
263-
end
264-
265-
::Utils.wait_for_port_free(8100, 5)
255+
with_ocsp_responder do |req, res|
256+
res.status = 303
257+
res['locAtion'] = req.path
258+
res.body = "See #{req.path} indefinitely"
266259
end
267260

268261
include_context 'verifier', algorithm: algorithm
@@ -274,87 +267,23 @@
274267

275268
include_context 'verifier', algorithm: 'rsa'
276269

277-
context '40x / 50x' do
278-
around do |example|
279-
server = WEBrick::HTTPServer.new(Port: 8100)
280-
server.mount_proc '/' do |req, res|
270+
[400, 404, 500, 503].each do |code|
271+
context "code #{code}" do
272+
with_ocsp_responder do |req, res|
281273
res.status = code
282274
res.body = "HTTP #{code}"
283275
end
284-
Thread.new { server.start }
285-
begin
286-
example.run
287-
ensure
288-
server.shutdown
289-
end
290-
291-
::Utils.wait_for_port_free(8100, 5)
292-
end
293-
294-
[400, 404, 500, 503].each do |_code|
295-
context "code #{_code}" do
296-
let(:code) { _code }
297-
include_examples 'does not verify'
298-
end
299-
end
300-
end
301276

302-
context '204' do
303-
around do |example|
304-
server = WEBrick::HTTPServer.new(Port: 8100)
305-
server.mount_proc '/' do |req, res|
306-
res.status = 204
307-
end
308-
Thread.new { server.start }
309-
begin
310-
example.run
311-
ensure
312-
server.shutdown
313-
end
314-
315-
::Utils.wait_for_port_free(8100, 5)
316-
end
317-
318-
context "code 204" do
319-
let(:code) { 204 }
320277
include_examples 'does not verify'
321278
end
322279
end
323-
end
324-
325-
context 'responder URI has no path' do
326-
require_external_connectivity
327280

328-
# https://github.com/jruby/jruby-openssl/issues/210
329-
fails_on_jruby
330-
331-
include_context 'basic verifier'
332-
333-
# The fake certificates all have paths in them for use with the ocsp mock.
334-
# Use real certificates retrieved from Atlas for this test as they don't
335-
# have a path in the OCSP URI (which the test also asserts).
336-
# Note that these certificates expire in 3 months and need to be replaced
337-
# with a more permanent solution.
338-
# Use the spec/support/certificates/retrieve-atlas-cert script to retrieve
339-
# current certificates from Atlas.
340-
let(:cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp.crt') }
341-
let(:ca_cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp-ca.crt') }
342-
let(:cert_store) do
343-
OpenSSL::X509::Store.new.tap do |store|
344-
store.set_default_paths
281+
context 'code 204' do
282+
with_ocsp_responder do |req, res|
283+
res.status = 204
345284
end
346-
end
347285

348-
before do
349-
skip "https://jira.mongodb.org/browse/RUBY-3684 (OCSP verifier needs non-Atlas certs)"
350-
351-
verifier.ocsp_uris.length.should > 0
352-
URI.parse(verifier.ocsp_uris.first).path.should == ''
353-
end
354-
355-
it 'verifies' do
356-
# TODO This test will fail if the certificate expires
357-
expect(verifier.verify).to be(true), "If atlas-ocsp certificates have expired, run spec/support/certificates/retrieve-atlas-cert to get a new ones"
286+
include_examples 'does not verify'
358287
end
359288
end
360289
end

0 commit comments

Comments
 (0)