From bd0cd7f92b7d7856b315bbc0342de8b3e0ad3b5a Mon Sep 17 00:00:00 2001 From: gotoyuzo Date: Mon, 17 May 2004 20:23:28 +0000 Subject: * test for OpenSSL::X509 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6350 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- MANIFEST | 5 + test/openssl/test_x509cert.rb | 168 +++++++++++++++++++++++++++++++++ test/openssl/test_x509crl.rb | 209 ++++++++++++++++++++++++++++++++++++++++++ test/openssl/test_x509name.rb | 155 +++++++++++++++++++++++++++++++ test/openssl/test_x509req.rb | 133 +++++++++++++++++++++++++++ test/openssl/utils.rb | 134 +++++++++++++++++++++++++++ 6 files changed, 804 insertions(+) create mode 100644 test/openssl/test_x509cert.rb create mode 100644 test/openssl/test_x509crl.rb create mode 100644 test/openssl/test_x509name.rb create mode 100644 test/openssl/test_x509req.rb create mode 100644 test/openssl/utils.rb diff --git a/MANIFEST b/MANIFEST index 2139c59b1a..fd08ad099f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -802,6 +802,11 @@ test/inlinetest.rb test/logger/test_logger.rb test/monitor/test_monitor.rb test/net/http/test_httpheader.rb +test/openssl/test_x509cert.rb +test/openssl/test_x509crl.rb +test/openssl/test_x509name.rb +test/openssl/test_x509req.rb +test/openssl/utils.rb test/optparse/test_noarg.rb test/optparse/test_optarg.rb test/optparse/test_optparse.rb diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb new file mode 100644 index 0000000000..66dd84c245 --- /dev/null +++ b/test/openssl/test_x509cert.rb @@ -0,0 +1,168 @@ +require "openssl" +require "test/unit" +require File.join(File.dirname(__FILE__), "utils.rb") + +class OpenSSL::TestX509Certificate < Test::Unit::TestCase + def setup + @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 + @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") + end + + def teardown + end + + def issue_cert(*args) + OpenSSL::TestUtils.issue_cert(*args) + end + + def test_serial + [1, 2**32, 2**100].each{|s| + cert = issue_cert(@ca, @rsa2048, s, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(s, cert.serial) + cert = OpenSSL::X509::Certificate.new(cert.to_der) + assert_equal(s, cert.serial) + } + end + + def test_public_key + exts = [ + ["basicConstraints","CA:TRUE",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + + sha1 = OpenSSL::Digest::SHA1.new + dss1 = OpenSSL::Digest::DSS1.new + [ + [@rsa1024, sha1], [@rsa2048, sha1], [@dsa256, dss1], [@dsa512, dss1], + ].each{|pk, digest| + cert = issue_cert(@ca, pk, 1, Time.now, Time.now+3600, exts, + nil, nil, digest) + assert_equal(cert.extensions[1].value, + OpenSSL::TestUtils.get_subject_key_id(cert)) + cert = OpenSSL::X509::Certificate.new(cert.to_der) + assert_equal(cert.extensions[1].value, + OpenSSL::TestUtils.get_subject_key_id(cert)) + } + end + + def test_validity + now = Time.now until now && now.usec != 0 + cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_not_equal(now, cert.not_before) + assert_not_equal(now+3600, cert.not_after) + + now = Time.at(now.to_i) + cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(now.getutc, cert.not_before) + assert_equal((now+3600).getutc, cert.not_after) + + now = Time.at(0) + cert = issue_cert(@ca, @rsa2048, 1, now, now, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(now.getutc, cert.not_before) + assert_equal(now.getutc, cert.not_after) + + now = Time.at(0x7fffffff) + cert = issue_cert(@ca, @rsa2048, 1, now, now, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(now.getutc, cert.not_before) + assert_equal(now.getutc, cert.not_after) + end + + def test_extension + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + ca_cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, ca_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + ca_cert.extensions.each_with_index{|ext, i| + assert_equal(ca_exts[i].first, ext.oid) + assert_equal(ca_exts[i].last, ext.critical?) + } + + ee1_exts = [ + ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], + ["subjectAltName","email:ee1@ruby-lang.org",false], + ] + ee1_cert = issue_cert(@ee1, @rsa1024, 2, Time.now, Time.now+1800, ee1_exts, + ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der) + ee1_cert.extensions.each_with_index{|ext, i| + assert_equal(ee1_exts[i].first, ext.oid) + assert_equal(ee1_exts[i].last, ext.critical?) + } + + ee2_exts = [ + ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","issuer:always",false], + ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], + ["subjectAltName","email:ee2@ruby-lang.org",false], + ] + ee2_cert = issue_cert(@ee2, @rsa1024, 3, Time.now, Time.now+1800, ee2_exts, + ca_cert, @rsa2048, OpenSSL::Digest::MD5.new) + assert_equal(ca_cert.subject.to_der, ee2_cert.issuer.to_der) + ee2_cert.extensions.each_with_index{|ext, i| + assert_equal(ee2_exts[i].first, ext.oid) + assert_equal(ee2_exts[i].last, ext.critical?) + } + + end + + def test_sign_and_verify + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, cert.verify(@dsa256)) + assert_equal(false, cert.verify(@dsa512)) + cert.serial = 2 + assert_equal(false, cert.verify(@rsa2048)) + + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::MD5.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, cert.verify(@dsa256)) + assert_equal(false, cert.verify(@dsa512)) + cert.subject = @ee1 + assert_equal(false, cert.verify(@rsa2048)) + + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(false, cert.verify(@rsa2048)) + assert_equal(false, cert.verify(@dsa256)) + assert_equal(true, cert.verify(@dsa512)) + cert.not_after = Time.now + assert_equal(false, cert.verify(@dsa512)) + + assert_raises(OpenSSL::X509::CertificateError){ + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + } + assert_raises(OpenSSL::X509::CertificateError){ + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::MD5.new) + } + assert_raises(OpenSSL::X509::CertificateError){ + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + } + end +end diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb new file mode 100644 index 0000000000..201a79e503 --- /dev/null +++ b/test/openssl/test_x509crl.rb @@ -0,0 +1,209 @@ +require "openssl" +require "test/unit" +require File.join(File.dirname(__FILE__), "utils.rb") + +class OpenSSL::TestX509CRL < Test::Unit::TestCase + def setup + @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 + @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1") + @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2") + end + + def teardown + end + + def issue_crl(*args) + OpenSSL::TestUtils.issue_crl(*args) + end + + def issue_cert(*args) + OpenSSL::TestUtils.issue_cert(*args) + end + + def test_basic + now = Time.at(Time.now.to_i) + + cert = issue_cert(@ca, @rsa2048, 1, now, now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + crl = issue_crl([], 1, now, now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal(1, crl.version) + assert_equal(now, crl.last_update) + assert_equal(now+1600, crl.next_update) + + crl = OpenSSL::X509::CRL.new(crl.to_der) + assert_equal(1, crl.version) + assert_equal(now, crl.last_update) + assert_equal(now+1600, crl.next_update) + end + + def test_revoked + + # CRLReason ::= ENUMERATED { + # unspecified (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # removeFromCRL (8), + # privilegeWithdrawn (9), + # aACompromise (10) } + + now = Time.at(Time.now.to_i) + revoke_info = [ + [1, Time.at(0), 1], + [2, Time.at(0x7fffffff), 2], + [3, now, 3], + [4, now, 4], + [5, now, 5], + ] + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoked = crl.revoked + assert_equal(5, revoked.size) + assert_equal(1, revoked[0].serial) + assert_equal(2, revoked[1].serial) + assert_equal(3, revoked[2].serial) + assert_equal(4, revoked[3].serial) + assert_equal(5, revoked[4].serial) + + assert_equal(Time.at(0), revoked[0].time) + assert_equal(Time.at(0x7fffffff), revoked[1].time) + assert_equal(now, revoked[2].time) + assert_equal(now, revoked[3].time) + assert_equal(now, revoked[4].time) + + assert_equal("CRLReason", revoked[0].extensions[0].oid) + assert_equal("CRLReason", revoked[1].extensions[0].oid) + assert_equal("CRLReason", revoked[2].extensions[0].oid) + assert_equal("CRLReason", revoked[3].extensions[0].oid) + assert_equal("CRLReason", revoked[4].extensions[0].oid) + + assert_equal("Key Compromise", revoked[0].extensions[0].value) + assert_equal("CA Compromise", revoked[1].extensions[0].value) + assert_equal("Affiliation Changed", revoked[2].extensions[0].value) + assert_equal("Superseded", revoked[3].extensions[0].value) + assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) + + assert_equal(false, revoked[0].extensions[0].critical?) + assert_equal(false, revoked[1].extensions[0].critical?) + assert_equal(false, revoked[2].extensions[0].critical?) + assert_equal(false, revoked[3].extensions[0].critical?) + assert_equal(false, revoked[4].extensions[0].critical?) + + crl = OpenSSL::X509::CRL.new(crl.to_der) + assert_equal("Key Compromise", revoked[0].extensions[0].value) + assert_equal("CA Compromise", revoked[1].extensions[0].value) + assert_equal("Affiliation Changed", revoked[2].extensions[0].value) + assert_equal("Superseded", revoked[3].extensions[0].value) + assert_equal("Cessation Of Operation", revoked[4].extensions[0].value) + + revoke_info = (1..1000).collect{|i| [i, now, 0] } + crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoked = crl.revoked + assert_equal(1000, revoked.size) + assert_equal(1, revoked[0].serial) + assert_equal(1000, revoked[999].serial) + end + + def test_extension + cert_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["subjectKeyIdentifier", "hash", false], + ["authorityKeyIdentifier", "keyid:always", false], + ["subjectAltName", "email:xyzzy@ruby-lang.org", false], + ["keyUsage", "cRLSign, keyCertSign", true], + ] + crl_exts = [ + ["authorityKeyIdentifier", "keyid:always", false], + ["issuerAltName", "issuer:copy", false], + ] + + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, cert_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + exts = crl.extensions + assert_equal(3, exts.size) + assert_equal("1", exts[0].value) + assert_equal("crlNumber", exts[0].oid) + assert_equal(false, exts[0].critical?) + + assert_equal("authorityKeyIdentifier", exts[1].oid) + keyid = OpenSSL::TestUtils.get_subject_key_id(cert) + assert_match(/^keyid:#{keyid}/, exts[1].value) + assert_equal(false, exts[1].critical?) + + assert_equal("issuerAltName", exts[2].oid) + assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) + assert_equal(false, exts[2].critical?) + + crl = OpenSSL::X509::CRL.new(crl.to_der) + exts = crl.extensions + assert_equal(3, exts.size) + assert_equal("1", exts[0].value) + assert_equal("crlNumber", exts[0].oid) + assert_equal(false, exts[0].critical?) + + assert_equal("authorityKeyIdentifier", exts[1].oid) + keyid = OpenSSL::TestUtils.get_subject_key_id(cert) + assert_match(/^keyid:#{keyid}/, exts[1].value) + assert_equal(false, exts[1].critical?) + + assert_equal("issuerAltName", exts[2].oid) + assert_equal("email:xyzzy@ruby-lang.org", exts[2].value) + assert_equal(false, exts[2].critical?) + end + + def test_crlnumber + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match(1.to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{1}/m, crl.to_text) + + crl = issue_crl([], 2**32, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match((2**32).to_s, crl.extensions[0].value) + assert_match(/X509v3 CRL Number:\s+#{2**32}/m, crl.to_text) + + crl = issue_crl([], 2**100, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) + assert_match((2**100).to_s, crl.extensions[0].value) + end + + def test_sign_and_verify + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal(false, crl.verify(@rsa1024)) + assert_equal(true, crl.verify(@rsa2048)) + assert_equal(false, crl.verify(@dsa256)) + assert_equal(false, crl.verify(@dsa512)) + crl.version = 0 + assert_equal(false, crl.verify(@rsa2048)) + + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @dsa512, OpenSSL::Digest::DSS1.new) + assert_equal(false, crl.verify(@rsa1024)) + assert_equal(false, crl.verify(@rsa2048)) + assert_equal(false, crl.verify(@dsa256)) + assert_equal(true, crl.verify(@dsa512)) + crl.version = 0 + assert_equal(false, crl.verify(@dsa512)) + end +end diff --git a/test/openssl/test_x509name.rb b/test/openssl/test_x509name.rb new file mode 100644 index 0000000000..85cc5ca2f9 --- /dev/null +++ b/test/openssl/test_x509name.rb @@ -0,0 +1,155 @@ +require "openssl" +require "test/unit" + +class OpenSSL::TestX509Name < Test::Unit::TestCase + def setup + @obj_type_tmpl = Hash.new(OpenSSL::ASN1::PRINTABLESTRING) + @obj_type_tmpl.update(OpenSSL::X509::Name::OBJECT_TYPE_TEMPLATE) + end + + def teardown + end + + def test_s_new + dn = [ ["C", "JP"], ["O", "example"], ["CN", "www.example.jp"] ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal("C", ary[0][0]) + assert_equal("O", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("JP", ary[0][1]) + assert_equal("example", ary[1][1]) + assert_equal("www.example.jp", ary[2][1]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + + dn = [ + ["countryName", "JP"], + ["organizationName", "example"], + ["commonName", "www.example.jp"] + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal("C", ary[0][0]) + assert_equal("O", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("JP", ary[0][1]) + assert_equal("example", ary[1][1]) + assert_equal("www.example.jp", ary[2][1]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + + name = OpenSSL::X509::Name.new(dn, @obj_type_tmpl) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + + dn = [ + ["countryName", "JP", OpenSSL::ASN1::PRINTABLESTRING], + ["organizationName", "example", OpenSSL::ASN1::PRINTABLESTRING], + ["commonName", "www.example.jp", OpenSSL::ASN1::PRINTABLESTRING] + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/C=JP/O=example/CN=www.example.jp", name.to_s) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ] + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("emailAddress", ary[3][0]) + assert_equal("serialNumber", ary[4][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("GOTOU Yuuzou", ary[2][1]) + assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) + assert_equal("123", ary[4][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) + + name_from_der = OpenSSL::X509::Name.new(name.to_der) + assert_equal(name_from_der.to_s, name.to_s) + assert_equal(name_from_der.to_a, name.to_a) + assert_equal(name_from_der.to_der, name.to_der) + end + + def test_s_parse + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + assert_equal(dn, name.to_s) + ary = name.to_a + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("www.ruby-lang.org", ary[2][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + + dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + ary = name.to_a + assert_equal(dn, name.to_s) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("www.ruby-lang.org", ary[2][1]) + + name = OpenSSL::X509::Name.parse(dn, @obj_type_tmpl) + ary = name.to_a + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + end + + def test_add_entry + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ] + name = OpenSSL::X509::Name.new + dn.each{|attr| name.add_entry(*attr) } + ary = name.to_a + assert_equal("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123", name.to_s) + assert_equal("DC", ary[0][0]) + assert_equal("DC", ary[1][0]) + assert_equal("CN", ary[2][0]) + assert_equal("emailAddress", ary[3][0]) + assert_equal("serialNumber", ary[4][0]) + assert_equal("org", ary[0][1]) + assert_equal("ruby-lang", ary[1][1]) + assert_equal("GOTOU Yuuzou", ary[2][1]) + assert_equal("gotoyuzo@ruby-lang.org", ary[3][1]) + assert_equal("123", ary[4][1]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) + assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) + end +end diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb new file mode 100644 index 0000000000..6f0f8bac6d --- /dev/null +++ b/test/openssl/test_x509req.rb @@ -0,0 +1,133 @@ +require "openssl" +require "test/unit" +require File.join(File.dirname(__FILE__), "utils.rb") + +class OpenSSL::TestX509Request < Test::Unit::TestCase + def setup + @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @dsa256 = OpenSSL::TestUtils::TEST_KEY_DSA256 + @dsa512 = OpenSSL::TestUtils::TEST_KEY_DSA512 + @dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou") + end + + def issue_csr(ver, dn, key, digest) + req = OpenSSL::X509::Request.new + req.version = ver + req.subject = dn + req.public_key = key.public_key + req.sign(key, digest) + req + end + + def test_public_key + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::DSS1.new) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + end + + def test_version + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(0, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(0, req.version) + + req = issue_csr(1, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(1, req.version) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(1, req.version) + end + + def test_subject + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(@dn.to_der, req.subject.to_der) + req = OpenSSL::X509::Request.new(req.to_der) + assert_equal(@dn.to_der, req.subject.to_der) + end + + def create_ext_req(exts) + ef = OpenSSL::X509::ExtensionFactory.new + exts = exts.collect{|e| ef.create_extension(*e) } + return OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)]) + end + + def get_ext_req(ext_req_value) + set = OpenSSL::ASN1.decode(ext_req_value) + seq = set.value[0] + seq.value.collect{|asn1ext| + OpenSSL::X509::Extension.new(asn1ext).to_a + } + end + + def test_attr + exts = [ + ["keyUsage", "Digital Signature, Key Encipherment", true], + ["subjectAltName", "email:gotoyuzo@ruby-lang.org", false], + ] + attrval = create_ext_req(exts) + attrs = [ + OpenSSL::X509::Attribute.new("extReq", attrval), + OpenSSL::X509::Attribute.new("msExtReq", attrval), + ] + + req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + attrs.each{|attr| req0.add_attribute(attr) } + req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + req1.attributes = attrs + assert_equal(req0.to_der, req1.to_der) + + attrs = req0.attributes + assert_equal(2, attrs.size) + assert_equal("extReq", attrs[0].oid) + assert_equal("msExtReq", attrs[1].oid) + assert_equal(exts, get_ext_req(attrs[0].value)) + assert_equal(exts, get_ext_req(attrs[1].value)) + + req = OpenSSL::X509::Request.new(req0.to_der) + attrs = req.attributes + assert_equal(2, attrs.size) + assert_equal("extReq", attrs[0].oid) + assert_equal("msExtReq", attrs[1].oid) + assert_equal(exts, get_ext_req(attrs[0].value)) + assert_equal(exts, get_ext_req(attrs[1].value)) + end + + def test_sign_and_verify + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) + assert_equal(true, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, req.verify(@dsa256)) + assert_equal(false, req.verify(@dsa512)) + req.version = 1 + assert_equal(false, req.verify(@rsa1024)) + + req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest::MD5.new) + assert_equal(false, req.verify(@rsa1024)) + assert_equal(true, req.verify(@rsa2048)) + assert_equal(false, req.verify(@dsa256)) + assert_equal(false, req.verify(@dsa512)) + req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar") + assert_equal(false, req.verify(@rsa2048)) + + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::DSS1.new) + assert_equal(false, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, req.verify(@dsa256)) + assert_equal(true, req.verify(@dsa512)) + req.public_key = @rsa1024.public_key + assert_equal(false, req.verify(@dsa512)) + + assert_raise(OpenSSL::X509::RequestError){ + issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) } + assert_raise(OpenSSL::X509::RequestError){ + issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) } + assert_raise(OpenSSL::X509::RequestError){ + issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } + end +end diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb new file mode 100644 index 0000000000..6d95b787a7 --- /dev/null +++ b/test/openssl/utils.rb @@ -0,0 +1,134 @@ +require "openssl" +require "test/unit" + +module OpenSSL::TestUtils + TEST_KEY_RSA1024 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx +aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/ +Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB +AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0 +maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T +gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572 +74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE +JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX +sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII +8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA +wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi +qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD +dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA== +-----END RSA PRIVATE KEY----- + _end_of_pem_ + + TEST_KEY_RSA2048 = OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN +s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign +4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D +kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl +NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J +DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb +I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq +PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V +seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0 +Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc +VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW +wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G +0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj +XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb +aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n +h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw +Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k +IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb +v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId +U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr +vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS +Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC +9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41 +gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG +4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw== +-----END RSA PRIVATE KEY----- + _end_of_pem_ + + TEST_KEY_DSA256 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ +-----BEGIN DSA PRIVATE KEY----- +MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE +9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed +AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM +3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT +b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn +ISNX5cMzFHRW3Q== +-----END DSA PRIVATE KEY----- + _end_of_pem_ + + TEST_KEY_DSA512 = OpenSSL::PKey::DSA.new <<-_end_of_pem_ +-----BEGIN DSA PRIVATE KEY----- +MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok +RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D +AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR +S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++ +Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S +55jreJD3Se3slps= +-----END DSA PRIVATE KEY----- + _end_of_pem_ + + module_function + + def issue_cert(dn, key, serial, not_before, not_after, extensions, + issuer, issuer_key, digest) + cert = OpenSSL::X509::Certificate.new + issuer = cert unless issuer + issuer_key = key unless issuer_key + cert.version = 2 + cert.serial = serial + cert.subject = dn + cert.issuer = issuer.subject + cert.public_key = key.public_key + cert.not_before = not_before + cert.not_after = not_after + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = cert + ef.issuer_certificate = issuer + extensions.each{|oid, value, critical| + cert.add_extension(ef.create_extension(oid, value, critical)) + } + cert.sign(issuer_key, digest) + cert + end + + def issue_crl(revoke_info, serial, lastup, nextup, extensions, + issuer, issuer_key, digest) + crl = OpenSSL::X509::CRL.new + crl.version = 1 + crl.last_update = lastup + crl.next_update = nextup + revoke_info.each{|serial, time, reason_code| + revoked = OpenSSL::X509::Revoked.new + revoked.serial = serial + revoked.time = time + enum = OpenSSL::ASN1::Enumerated(reason_code) + ext = OpenSSL::X509::Extension.new("CRLReason", enum) + revoked.add_extension(ext) + crl.add_revoked(revoked) + } + ef = OpenSSL::X509::ExtensionFactory.new + ef.issuer_certificate = issuer + ef.crl = crl + crlnum = OpenSSL::ASN1::Integer(serial) + crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum)) + extensions.each{|oid, value, critical| + crl.add_extension(ef.create_extension(oid, value, critical)) + } + crl.sign(issuer_key, digest) + crl + end + + def get_subject_key_id(cert) + asn1_cert = OpenSSL::ASN1.decode(cert) + tbscert = asn1_cert.value[0] + pkinfo = tbscert.value[6] + publickey = pkinfo.value[1] + pkvalue = publickey.value + OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase + end +end -- cgit v1.2.3