diff options
Diffstat (limited to 'test/openssl/test_ocsp.rb')
-rw-r--r-- | test/openssl/test_ocsp.rb | 159 |
1 files changed, 104 insertions, 55 deletions
diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb index f3e7c65dca..a69fd60fda 100644 --- a/test/openssl/test_ocsp.rb +++ b/test/openssl/test_ocsp.rb @@ -5,33 +5,47 @@ if defined?(OpenSSL::TestUtils) class OpenSSL::TestOCSP < OpenSSL::TestCase def setup + now = Time.at(Time.now.to_i) # suppress usec + dgst = OpenSSL::Digest::SHA1.new + + # @ca_cert + # | + # @cert + # |----------| + # @cert2 @ocsp_cert + ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - ca_serial = 0xabcabcabcabc + @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 ca_exts = [ ["basicConstraints", "CA:TRUE", true], ["keyUsage", "cRLSign,keyCertSign", true], ] - - subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert") - @key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - serial = 0xabcabcabcabd - - now = Time.at(Time.now.to_i) # suppress usec - dgst = OpenSSL::Digest::SHA1.new - @ca_cert = OpenSSL::TestUtils.issue_cert( - ca_subj, ca_key, ca_serial, now, now+3600, ca_exts, nil, nil, dgst) + ca_subj, @ca_key, 1, now, now+3600, ca_exts, nil, nil, dgst) + + cert_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA2") + @cert_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + cert_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign,keyCertSign", true], + ] @cert = OpenSSL::TestUtils.issue_cert( - subj, @key, serial, now, now+3600, [], @ca_cert, ca_key, dgst) + cert_subj, @cert_key, 5, now, now+3600, cert_exts, @ca_cert, @ca_key, dgst) - @key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + cert2_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert") + @cert2_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 cert2_exts = [ - ["extendedKeyUsage", "OCSPSigning", true], ] @cert2 = OpenSSL::TestUtils.issue_cert( - OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert2"), - @key2, serial+1, now, now+3600, cert2_exts, @ca_cert, ca_key, "SHA256") + cert2_subj, @cert2_key, 10, now, now+3600, cert2_exts, @cert, @cert_key, dgst) + + ocsp_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCAOCSP") + @ocsp_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 + ocsp_exts = [ + ["extendedKeyUsage", "OCSPSigning", true], + ] + @ocsp_cert = OpenSSL::TestUtils.issue_cert( + ocsp_subj, @ocsp_key, 100, now, now+3600, ocsp_exts, @cert, @cert_key, "SHA256") end def test_new_certificate_id @@ -63,12 +77,13 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase end def test_certificate_id_der - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) # hash algorithm defaults to SHA-1 + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) der = cid.to_der asn1 = OpenSSL::ASN1.decode(der) + # hash algorithm defaults to SHA-1 assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der - assert_equal OpenSSL::Digest::SHA1.digest(@cert.issuer.to_der), asn1.value[1].value - assert_equal OpenSSL::Digest::SHA1.digest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), asn1.value[2].value + assert_equal [cid.issuer_name_hash].pack("H*"), asn1.value[1].value + assert_equal [cid.issuer_key_hash].pack("H*"), asn1.value[2].value assert_equal @cert.serial, asn1.value[3].value assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der end @@ -82,7 +97,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase request = OpenSSL::OCSP::Request.new cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) request.add_certid(cid) - request.sign(@cert, @key, [@ca_cert], 0) + request.sign(@cert, @cert_key, [@ca_cert], 0) asn1 = OpenSSL::ASN1.decode(request.to_der) assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der @@ -92,40 +107,51 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase end def test_request_sign_verify - request = OpenSSL::OCSP::Request.new - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - request.add_certid(cid) - request.sign(@cert, @key, nil, 0, "SHA1") - assert_equal cid.to_der, request.certid.first.to_der - store1 = OpenSSL::X509::Store.new; store1.add_cert(@ca_cert) - assert_equal true, request.verify([@cert], store1) - assert_equal true, request.verify([], store1) - store2 = OpenSSL::X509::Store.new; store1.add_cert(@cert2) - assert_equal false, request.verify([], store2) - assert_equal true, request.verify([], store2, OpenSSL::OCSP::NOVERIFY) + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + store = OpenSSL::X509::Store.new.add_cert(@ca_cert) + + # with signer cert + req = OpenSSL::OCSP::Request.new.add_certid(cid) + req.sign(@cert, @cert_key, []) + assert_equal true, req.verify([], store) + + # without signer cert + req = OpenSSL::OCSP::Request.new.add_certid(cid) + req.sign(@cert, @cert_key, nil) + assert_equal false, req.verify([@cert2], store) + assert_equal false, req.verify([], store) # no signer + assert_equal false, req.verify([], store, OpenSSL::OCSP::NOVERIFY) + + assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) + ret = req.verify([@cert], store) + if ret || OpenSSL::OPENSSL_VERSION =~ /OpenSSL/ && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10002000 + assert_equal true, ret + else + # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when + # OCSP_NOINTERN is not specified. + # fixed by OpenSSL 1.0.1j, 1.0.2 and LibreSSL 2.4.2 + pend "RT2560: ocsp_req_find_signer" + end end def test_request_nonce req0 = OpenSSL::OCSP::Request.new - req1 = OpenSSL::OCSP::Request.new - req1.add_nonce("NONCE") - req2 = OpenSSL::OCSP::Request.new - req2.add_nonce("NONCF") + req1 = OpenSSL::OCSP::Request.new.add_nonce("NONCE") + req2 = OpenSSL::OCSP::Request.new.add_nonce("ABCDE") bres = OpenSSL::OCSP::BasicResponse.new assert_equal 2, req0.check_nonce(bres) bres.copy_nonce(req1) + assert_equal 3, req0.check_nonce(bres) assert_equal 1, req1.check_nonce(bres) bres.add_nonce("NONCE") assert_equal 1, req1.check_nonce(bres) assert_equal 0, req2.check_nonce(bres) - assert_equal 3, req0.check_nonce(bres) end def test_request_dup request = OpenSSL::OCSP::Request.new cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) request.add_certid(cid) - request.sign(@cert, @key, nil, 0, "SHA1") assert_equal request.to_der, request.dup.to_der end @@ -134,37 +160,49 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) bres.add_nonce("NONCE") - bres.sign(@cert2, @key2, [@ca_cert], 0) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) der = bres.to_der asn1 = OpenSSL::ASN1.decode(der) - assert_equal cid.to_der, asn1.value[0].value.find { |a| a.class == OpenSSL::ASN1::Sequence }.value[0].value[0].to_der - assert_equal OpenSSL::ASN1.Sequence([@cert2, @ca_cert]).to_der, asn1.value[3].value[0].to_der + assert_equal OpenSSL::ASN1.Sequence([@ocsp_cert, @ca_cert]).to_der, asn1.value[3].value[0].to_der assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der rescue TypeError if /GENERALIZEDTIME/ =~ $!.message - skip "OCSP_basic_sign() is broken" + pend "OCSP_basic_sign() is broken" else raise end end def test_basic_response_sign_verify - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) + store = OpenSSL::X509::Store.new.add_cert(@ca_cert) + + # signed by CA + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, "SHA256") + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) + bres.sign(@ca_cert, @ca_key, nil, 0, "SHA256") + assert_equal false, bres.verify([], store) # signer not found + assert_equal true, bres.verify([@ca_cert], store) + bres.sign(@ca_cert, @ca_key, [], 0, "SHA256") + assert_equal true, bres.verify([], store) + + # signed by OCSP signer bres = OpenSSL::OCSP::BasicResponse.new - bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, 500, []) - bres.sign(@cert2, @key2, [], 0, "SHA256") # how can I check the algorithm? - store1 = OpenSSL::X509::Store.new; store1.add_cert(@ca_cert) - assert_equal true, bres.verify([], store1) - store2 = OpenSSL::X509::Store.new; store2.add_cert(@cert) - assert_equal false, bres.verify([], store2) - assert_equal true, bres.verify([], store2, OpenSSL::OCSP::NOVERIFY) + cid = OpenSSL::OCSP::CertificateId.new(@cert2, @cert) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, [@cert]) + assert_equal true, bres.verify([], store) + assert_equal false, bres.verify([], store, OpenSSL::OCSP::NOCHAIN) + # OpenSSL had a bug on this; test that our workaround works + bres.sign(@ocsp_cert, @ocsp_key, []) + assert_equal true, bres.verify([@cert], store) end def test_basic_response_dup bres = OpenSSL::OCSP::BasicResponse.new cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.sign(@cert2, @key2, [@ca_cert], 0) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) assert_equal bres.to_der, bres.dup.to_der end @@ -172,7 +210,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase bres = OpenSSL::OCSP::BasicResponse.new now = Time.at(Time.now.to_i) cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid2 = OpenSSL::OCSP::CertificateId.new(@cert2, @ca_cert, OpenSSL::Digest::SHA1.new) + cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest::SHA1.new) bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, []) @@ -206,14 +244,14 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase def test_single_response_check_validity bres = OpenSSL::OCSP::BasicResponse.new cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) - cid2 = OpenSSL::OCSP::CertificateId.new(@cert2, @ca_cert, OpenSSL::Digest::SHA1.new) + cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest::SHA1.new) bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, -50, []) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) if bres.responses[2].check_validity # thisUpdate is in future; must fail # LibreSSL bug; skip for now - skip "OCSP_check_validity() is broken" + pend "OCSP_check_validity() is broken" end single1 = bres.responses[0] @@ -226,11 +264,22 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal false, single2.check_validity(0, 200) end + def test_response + bres = OpenSSL::OCSP::BasicResponse.new + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) + bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) + bres.sign(@ocsp_cert, @ocsp_key, []) + res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) + + assert_equal bres.to_der, res.basic.to_der + assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, res.status + end + def test_response_der bres = OpenSSL::OCSP::BasicResponse.new cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new) bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, []) - bres.sign(@cert2, @key2, [@ca_cert], 0) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) der = res.to_der asn1 = OpenSSL::ASN1.decode(der) @@ -242,7 +291,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase def test_response_dup bres = OpenSSL::OCSP::BasicResponse.new - bres.sign(@cert2, @key2, [@ca_cert], 0) + bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0) res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres) assert_equal res.to_der, res.dup.to_der end |