File: ocsp_verifier_cache_spec.rb

package info (click to toggle)
ruby-mongo 2.21.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 14,764 kB
  • sloc: ruby: 108,806; makefile: 5; sh: 2
file content (191 lines) | stat: -rw-r--r-- 6,260 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# frozen_string_literal: true
# rubocop:todo all

require 'lite_spec_helper'
require 'webrick'

describe Mongo::Socket::OcspVerifier do
  require_ocsp_verifier

  shared_examples 'verifies' do
    context 'mri' do
      fails_on_jruby

      it 'verifies the first time and reads from cache the second time' do
        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          verifier.verify_with_cache.should be true
        end

        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).not_to receive(:do_verify)

          verifier.verify_with_cache.should be true
        end
      end
    end

    context 'jruby' do
      require_jruby

      # JRuby does not return OCSP endpoints, therefore we never perform
      # any validation.
      # https://github.com/jruby/jruby-openssl/issues/210
      it 'does not verify' do
        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          verifier.verify.should be false
        end

        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          verifier.verify.should be false
        end
      end
    end
  end

  shared_examples 'fails verification' do
    context 'mri' do
      fails_on_jruby

      it 'verifies the first time, reads from cache the second time, raises an exception in both cases' do
        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          lambda do
            verifier.verify
          # Redirect tests receive responses from port 8101,
          # tests without redirects receive responses from port 8100.
          end.should raise_error(Mongo::Error::ServerCertificateRevoked, %r,TLS certificate of 'foo' has been revoked according to 'http://localhost:810[01]/status',)
        end

        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).not_to receive(:do_verify)

          lambda do
            verifier.verify
          # Redirect tests receive responses from port 8101,
          # tests without redirects receive responses from port 8100.
          end.should raise_error(Mongo::Error::ServerCertificateRevoked, %r,TLS certificate of 'foo' has been revoked according to 'http://localhost:810[01]/status',)
        end
      end
    end

    context 'jruby' do
      require_jruby

      # JRuby does not return OCSP endpoints, therefore we never perform
      # any validation.
      # https://github.com/jruby/jruby-openssl/issues/210
      it 'does not verify' do
        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          verifier.verify.should be false
        end

        RSpec::Mocks.with_temporary_scope do
          expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

          verifier.verify.should be false
        end
      end
    end
  end

  shared_examples 'does not verify' do
    it 'does not verify and does not raise an exception' do
      RSpec::Mocks.with_temporary_scope do
        expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

        verifier.verify.should be false
      end

      RSpec::Mocks.with_temporary_scope do
        expect_any_instance_of(Mongo::Socket::OcspVerifier).to receive(:do_verify).and_call_original

        verifier.verify.should be false
      end
    end
  end

  shared_context 'verifier' do |opts|
    algorithm = opts[:algorithm]

    let(:cert_path) { SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/server.pem") }
    let(:ca_cert_path) { SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/ca.pem") }

    let(:cert) { OpenSSL::X509::Certificate.new(File.read(cert_path)) }
    let(:ca_cert) { OpenSSL::X509::Certificate.new(File.read(ca_cert_path)) }

    let(:cert_store) do
      OpenSSL::X509::Store.new.tap do |store|
        store.add_cert(ca_cert)
      end
    end

    let(:verifier) do
      described_class.new('foo', cert, ca_cert, cert_store, timeout: 3)
    end
  end

  include_context 'verifier', algorithm: 'rsa'
  algorithm = 'rsa'

  %w(ca delegate).each do |responder_cert|
    responder_cert_file_name = {
      'ca' => 'ca',
      'delegate' => 'ocsp-responder',
    }.fetch(responder_cert)

    context "when responder uses #{responder_cert} cert" do
      context 'good response' do
        with_ocsp_mock(
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/ca.pem"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.crt"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.key"),
        )

        include_examples 'verifies'

        it 'does not wait for the timeout' do
          lambda do
            verifier.verify
          end.should take_shorter_than 3
        end
      end

      context 'revoked response' do
        with_ocsp_mock(
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/ca.pem"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.crt"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.key"),
          fault: 'revoked'
        )

        include_examples 'fails verification'
      end

      context 'unknown response' do
        with_ocsp_mock(
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/ca.pem"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.crt"),
          SpecConfig.instance.ocsp_files_dir.join("#{algorithm}/#{responder_cert_file_name}.key"),
          fault: 'unknown',
        )

        include_examples 'does not verify'

        it 'does not wait for the timeout' do
          lambda do
            verifier.verify
          end.should take_shorter_than 3
        end
      end
    end
  end
end