1require_relative "utils"
2
3if defined?(OpenSSL)
4
5class OpenSSL::TestX509Store < Test::Unit::TestCase
6  def setup
7    @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024
8    @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048
9    @dsa256  = OpenSSL::TestUtils::TEST_KEY_DSA256
10    @dsa512  = OpenSSL::TestUtils::TEST_KEY_DSA512
11    @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1")
12    @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2")
13    @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1")
14    @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2")
15  end
16
17  def teardown
18  end
19
20  def test_nosegv_on_cleanup
21    cert  = OpenSSL::X509::Certificate.new
22    store = OpenSSL::X509::Store.new
23    ctx   = OpenSSL::X509::StoreContext.new(store, cert, [])
24    ctx.cleanup
25    ctx.verify
26  end
27
28  def issue_cert(*args)
29    OpenSSL::TestUtils.issue_cert(*args)
30  end
31
32  def issue_crl(*args)
33    OpenSSL::TestUtils.issue_crl(*args)
34  end
35
36  def test_verify
37    now = Time.at(Time.now.to_i)
38    ca_exts = [
39      ["basicConstraints","CA:TRUE",true],
40      ["keyUsage","cRLSign,keyCertSign",true],
41    ]
42    ee_exts = [
43      ["keyUsage","keyEncipherment,digitalSignature",true],
44    ]
45    ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, ca_exts,
46                          nil, nil, OpenSSL::Digest::SHA1.new)
47    ca2_cert = issue_cert(@ca2, @rsa1024, 2, now, now+1800, ca_exts,
48                          ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new)
49    ee1_cert = issue_cert(@ee1, @dsa256, 10, now, now+1800, ee_exts,
50                          ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
51    ee2_cert = issue_cert(@ee2, @dsa512, 20, now, now+1800, ee_exts,
52                          ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
53    ee3_cert = issue_cert(@ee2, @dsa512, 30, now-100, now-1, ee_exts,
54                          ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
55    ee4_cert = issue_cert(@ee2, @dsa512, 40, now+1000, now+2000, ee_exts,
56                          ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
57
58    revoke_info = []
59    crl1   = issue_crl(revoke_info, 1, now, now+1800, [],
60                       ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new)
61    revoke_info = [ [2, now, 1], ]
62    crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [],
63                       ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new)
64    revoke_info = [ [20, now, 1], ]
65    crl2   = issue_crl(revoke_info, 1, now, now+1800, [],
66                       ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
67    revoke_info = []
68    crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [],
69                       ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new)
70
71    assert_equal(true, ca1_cert.verify(ca1_cert.public_key))   # self signed
72    assert_equal(true, ca2_cert.verify(ca1_cert.public_key))   # issued by ca1
73    assert_equal(true, ee1_cert.verify(ca2_cert.public_key))   # issued by ca2
74    assert_equal(true, ee2_cert.verify(ca2_cert.public_key))   # issued by ca2
75    assert_equal(true, ee3_cert.verify(ca2_cert.public_key))   # issued by ca2
76    assert_equal(true, crl1.verify(ca1_cert.public_key))       # issued by ca1
77    assert_equal(true, crl1_2.verify(ca1_cert.public_key))     # issued by ca1
78    assert_equal(true, crl2.verify(ca2_cert.public_key))       # issued by ca2
79    assert_equal(true, crl2_2.verify(ca2_cert.public_key))     # issued by ca2
80
81    store = OpenSSL::X509::Store.new
82    assert_equal(false, store.verify(ca1_cert))
83    assert_not_equal(OpenSSL::X509::V_OK, store.error)
84
85    assert_equal(false, store.verify(ca2_cert))
86    assert_not_equal(OpenSSL::X509::V_OK, store.error)
87
88    store.add_cert(ca1_cert)
89    assert_equal(true, store.verify(ca2_cert))
90    assert_equal(OpenSSL::X509::V_OK, store.error)
91    assert_equal("ok", store.error_string)
92    chain = store.chain
93    assert_equal(2, chain.size)
94    assert_equal(@ca2.to_der, chain[0].subject.to_der)
95    assert_equal(@ca1.to_der, chain[1].subject.to_der)
96
97    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
98    assert_equal(false, store.verify(ca2_cert))
99    assert_not_equal(OpenSSL::X509::V_OK, store.error)
100
101    store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN
102    assert_equal(true, store.verify(ca2_cert))
103    assert_equal(OpenSSL::X509::V_OK, store.error)
104
105    store.add_cert(ca2_cert)
106    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
107    assert_equal(true, store.verify(ee1_cert))
108    assert_equal(true, store.verify(ee2_cert))
109    assert_equal(OpenSSL::X509::V_OK, store.error)
110    assert_equal("ok", store.error_string)
111    chain = store.chain
112    assert_equal(3, chain.size)
113    assert_equal(@ee2.to_der, chain[0].subject.to_der)
114    assert_equal(@ca2.to_der, chain[1].subject.to_der)
115    assert_equal(@ca1.to_der, chain[2].subject.to_der)
116    assert_equal(false, store.verify(ee3_cert))
117    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
118    assert_match(/expire/i, store.error_string)
119    assert_equal(false, store.verify(ee4_cert))
120    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
121    assert_match(/not yet valid/i, store.error_string)
122
123    store = OpenSSL::X509::Store.new
124    store.add_cert(ca1_cert)
125    store.add_cert(ca2_cert)
126    store.time = now + 1500
127    assert_equal(true, store.verify(ca1_cert))
128    assert_equal(true, store.verify(ca2_cert))
129    assert_equal(true, store.verify(ee4_cert))
130    store.time = now + 1900
131    assert_equal(true, store.verify(ca1_cert))
132    assert_equal(false, store.verify(ca2_cert))
133    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
134    assert_equal(false, store.verify(ee4_cert))
135    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
136    store.time = now + 4000
137    assert_equal(false, store.verify(ee1_cert))
138    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
139    assert_equal(false, store.verify(ee4_cert))
140    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
141
142    # the underlying X509 struct caches the result of the last
143    # verification for signature and not-before. so the following code
144    # rebuilds new objects to avoid site effect.
145    store.time = Time.now - 4000
146    assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert)))
147    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
148    assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert)))
149    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
150
151    return unless defined?(OpenSSL::X509::V_FLAG_CRL_CHECK)
152
153    store = OpenSSL::X509::Store.new
154    store.purpose = OpenSSL::X509::PURPOSE_ANY
155    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
156    store.add_cert(ca1_cert)
157    store.add_crl(crl1)   # revoke no cert
158    store.add_crl(crl2)   # revoke ee2_cert
159    assert_equal(true,  store.verify(ca1_cert))
160    assert_equal(true,  store.verify(ca2_cert))
161    assert_equal(true,  store.verify(ee1_cert, [ca2_cert]))
162    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
163
164    store = OpenSSL::X509::Store.new
165    store.purpose = OpenSSL::X509::PURPOSE_ANY
166    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
167    store.add_cert(ca1_cert)
168    store.add_crl(crl1_2) # revoke ca2_cert
169    store.add_crl(crl2)   # revoke ee2_cert
170    assert_equal(true,  store.verify(ca1_cert))
171    assert_equal(false, store.verify(ca2_cert))
172    assert_equal(true,  store.verify(ee1_cert, [ca2_cert]),
173      "This test is expected to be success with OpenSSL 0.9.7c or later.")
174    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
175
176    store.flags =
177      OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
178    assert_equal(true,  store.verify(ca1_cert))
179    assert_equal(false, store.verify(ca2_cert))
180    assert_equal(false, store.verify(ee1_cert, [ca2_cert]))
181    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
182
183    store = OpenSSL::X509::Store.new
184    store.purpose = OpenSSL::X509::PURPOSE_ANY
185    store.flags =
186      OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
187    store.add_cert(ca1_cert)
188    store.add_cert(ca2_cert)
189    store.add_crl(crl1)
190    store.add_crl(crl2_2) # issued by ca2 but expired.
191    assert_equal(true, store.verify(ca1_cert))
192    assert_equal(true, store.verify(ca2_cert))
193    assert_equal(false, store.verify(ee1_cert))
194    assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error)
195    assert_equal(false, store.verify(ee2_cert))
196  end
197
198  def test_set_errors
199    now = Time.now
200    ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, [],
201                          nil, nil, OpenSSL::Digest::SHA1.new)
202    store = OpenSSL::X509::Store.new
203    store.add_cert(ca1_cert)
204    assert_raise(OpenSSL::X509::StoreError){
205      store.add_cert(ca1_cert)  # add same certificate twice
206    }
207
208    revoke_info = []
209    crl1 = issue_crl(revoke_info, 1, now, now+1800, [],
210                     ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new)
211    revoke_info = [ [2, now, 1], ]
212    crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [],
213                     ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new)
214    store.add_crl(crl1)
215    if /0\.9\.8.*-rhel/ =~ OpenSSL::OPENSSL_VERSION
216      # RedHat is distributing a patched version of OpenSSL that allows
217      # multiple CRL for a key (multi-crl.patch)
218      assert_nothing_raised do
219        store.add_crl(crl2) # add CRL issued by same CA twice.
220      end
221    else
222      assert_raise(OpenSSL::X509::StoreError){
223        store.add_crl(crl2) # add CRL issued by same CA twice.
224      }
225    end
226  end
227end
228
229end
230