From 44162194d62e4b12f13858831a329ae71f330419 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 28 Apr 2011 19:54:49 +0900 Subject: [PATCH 01/66] Add comments. Add comments in for X509_verify_cert in OpenSSL 1.0.0d. This will help source readers understand the verification logic of OpenSSL. --- .../ext/openssl/x509store/StoreContext.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/java/org/jruby/ext/openssl/x509store/StoreContext.java index e0d73c8..caae9a2 100644 --- a/src/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ b/src/java/org/jruby/ext/openssl/x509store/StoreContext.java @@ -660,12 +660,17 @@ public int verifyCertificate() throws Exception { } cb=verifyCallback; + /* first we make sure the chain we are going to build is + * present and that the first entry is in place */ + if(null == chain) { chain = new ArrayList(); chain.add(certificate); lastUntrusted = 1; } + /* We use a temporary STACK so we can chop and hack at it */ + if(untrusted != null) { sktmp = new ArrayList(untrusted); } @@ -695,11 +700,24 @@ public int verifyCertificate() throws Exception { break; } + /* at this point, chain should contain a list of untrusted + * certificates. We now need to add at least one trusted one, + * if possible, otherwise we complain. */ + + /* Examine last certificate in chain and see if it + * is self signed. + */ + i = chain.size(); x = chain.get(i-1); - + if(checkIssued.call(this,x,x) != 0) { + /* we have a self signed certificate */ if(chain.size() == 1) { + /* We have a single self signed certificate: see if + * we can find it in the store. We must have an exact + * match to avoid possible impersonation. + */ X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{xtmp}; ok = getIssuer.call(p_xtmp,this,x); xtmp = p_xtmp[0]; @@ -713,22 +731,29 @@ public int verifyCertificate() throws Exception { return ok; } } else { + /* We have a match: replace certificate with store version + * so we get any trust settings. + */ x = xtmp; chain.set(i-1,x); lastUntrusted = 0; } } else { + /* extract and save self signed certificate for later use */ chain_ss = chain.remove(chain.size()-1); lastUntrusted--; num--; x = chain.get(num-1); } } + /* We now lookup certs from the certificate store */ for(;;) { + /* If we have enough, we break */ if(depth= num) { @@ -771,11 +799,15 @@ public int verifyCertificate() throws Exception { } } + /* We have the chain complete: now we need to check its purpose */ ok = checkChainExtensions(); if(ok == 0) { return ok; } + /* TODO: Check name constraints (from 1.0.0) */ + + /* The chain extensions are OK: check trust */ if(param.trust > 0) { ok = checkTrust(); } @@ -783,11 +815,15 @@ public int verifyCertificate() throws Exception { return ok; } + /* Check revocation status: we do this after copying parameters + * because they may be needed for CRL signature verification. + */ ok = checkRevocation.call(this); if(ok == 0) { return ok; } + /* At this point, we have a chain and need to verify it */ if(verify != null && verify != Store.VerifyFunction.EMPTY) { ok = verify.call(this); } else { @@ -796,7 +832,10 @@ public int verifyCertificate() throws Exception { if(ok == 0) { return ok; } + + /* TODO: RFC 3779 path validation, now that CRL check has been done (from 1.0.0) */ + /* If we get this far evaluate policies */ if(bad_chain == 0 && (param.flags & X509Utils.V_FLAG_POLICY_CHECK) != 0) { ok = checkPolicy.call(this); } From 7d178734e89bba90ca2d6c6a9f1d7737451246cf Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 28 Apr 2011 20:15:02 +0900 Subject: [PATCH 02/66] Version bump to 0.7.4. --- History.txt | 6 ++++++ jruby-openssl.gemspec | 8 ++++---- lib/jopenssl/version.rb | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/History.txt b/History.txt index 00b0967..4ffc8de 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 0.7.4 + +- JRUBY-5519: Avoid String encoding dependency in DER loading. PEM loading failed on JRuby 1.6.x. Fixed. +- JRUBY-5510: Add debug information to released jar +- JRUBY-5478: Update bouncycastle jars to the latest version. (1.46) + == 0.7.3 - JRUBY-5200: Net::IMAP + SSL(imaps) login could hang. Fixed. diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index ae01819..7fedd83 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,15 +2,15 @@ Gem::Specification.new do |s| s.name = %q{jruby-openssl} - s.version = "0.7.4.dev" + s.version = "0.7.4" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = %q{2011-03-05} + s.date = %q{2011-04-28} s.description = %q{JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library.} s.email = %q{ola.bini@gmail.com} s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/jopenssl.jar", "lib/openssl", "lib/jopenssl", "lib/openssl.rb", "lib/openssl/dummy.rb", "lib/openssl/dummyssl.rb", "lib/openssl/config.rb", "lib/openssl/cipher.rb", "lib/openssl/ssl.rb", "lib/openssl/bn.rb", "lib/openssl/x509.rb", "lib/openssl/digest.rb", "lib/openssl/buffering.rb", "lib/openssl/pkcs7.rb", "lib/jopenssl/version.rb", "test/test_imaps.rb", "test/test_all.rb", "test/test_integration.rb", "test/ut_eof.rb", "test/openssl", "test/test_java.rb", "test/test_openssl.rb", "test/test_pkey.rb", "test/ref", "test/test_cipher.rb", "test/cert_with_ec_pk.cer", "test/fixture", "test/test_pkcs7.rb", "test/test_x509store.rb", "test/test_certificate.rb", "test/test_parse_certificate.rb", "test/test_ssl.rb", "test/java", "test/openssl/test_x509name.rb", "test/openssl/test_ns_spki.rb", "test/openssl/test_x509cert.rb", "test/openssl/ssl_server.rb", "test/openssl/test_pair.rb", "test/openssl/test_ec.rb", "test/openssl/test_config.rb", "test/openssl/utils.rb", "test/openssl/test_x509req.rb", "test/openssl/test_cipher.rb", "test/openssl/test_digest.rb", "test/openssl/test_x509ext.rb", "test/openssl/test_asn1.rb", "test/openssl/test_pkcs7.rb", "test/openssl/test_x509store.rb", "test/openssl/test_pkey_rsa.rb", "test/openssl/test_ssl.rb", "test/openssl/test_x509crl.rb", "test/openssl/test_hmac.rb", "test/ref/compile.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/fixture/cacert.pem", "test/fixture/ca-bundle.crt", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/localhost_keypair.pem", "test/fixture/verisign_c3.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/keypair.pem", "test/fixture/purpose", "test/fixture/imaps", "test/fixture/ca_path", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslclient", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/sslserver.pem", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/ca_path/verisign.pem", "test/fixture/ca_path/72fa7371.0", "test/java/pkcs7_mime_enveloped.message", "test/java/pkcs7_mime_signed.message", "test/java/test_java_pkcs7.rb", "test/java/test_java_bio.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_mime.rb", "test/java/test_java_attribute.rb", "test/java/test_java_smime.rb"] + s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/jopenssl.jar", "lib/openssl.rb", "lib/openssl/dummy.rb", "lib/openssl/dummyssl.rb", "lib/openssl/config.rb", "lib/openssl/cipher.rb", "lib/openssl/ssl.rb", "lib/openssl/bn.rb", "lib/openssl/x509.rb", "lib/openssl/digest.rb", "lib/openssl/buffering.rb", "lib/openssl/pkcs7.rb", "lib/jopenssl/version.rb", "test/test_imaps.rb", "test/test_all.rb", "test/test_integration.rb", "test/ut_eof.rb", "test/test_java.rb", "test/test_openssl.rb", "test/test_pkey.rb", "test/test_cipher.rb", "test/cert_with_ec_pk.cer", "test/test_pkcs7.rb", "test/test_x509store.rb", "test/test_certificate.rb", "test/test_parse_certificate.rb", "test/test_ssl.rb", "test/openssl/test_x509name.rb", "test/openssl/test_ns_spki.rb", "test/openssl/test_x509cert.rb", "test/openssl/ssl_server.rb", "test/openssl/test_pair.rb", "test/openssl/test_ec.rb", "test/openssl/test_config.rb", "test/openssl/utils.rb", "test/openssl/test_x509req.rb", "test/openssl/test_cipher.rb", "test/openssl/test_digest.rb", "test/openssl/test_x509ext.rb", "test/openssl/test_asn1.rb", "test/openssl/test_pkcs7.rb", "test/openssl/test_x509store.rb", "test/openssl/test_pkey_rsa.rb", "test/openssl/test_ssl.rb", "test/openssl/test_x509crl.rb", "test/openssl/test_hmac.rb", "test/ref/compile.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/fixture/cacert.pem", "test/fixture/ca-bundle.crt", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/localhost_keypair.pem", "test/fixture/verisign_c3.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/keypair.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/sslserver.pem", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/ca_path/verisign.pem", "test/fixture/ca_path/72fa7371.0", "test/java/pkcs7_mime_enveloped.message", "test/java/pkcs7_mime_signed.message", "test/java/test_java_pkcs7.rb", "test/java/test_java_bio.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_mime.rb", "test/java/test_java_attribute.rb", "test/java/test_java_smime.rb"] s.homepage = %q{http://jruby-extras.rubyforge.org/jruby-openssl} s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib"] diff --git a/lib/jopenssl/version.rb b/lib/jopenssl/version.rb index 81d4cb6..6ce8cf7 100644 --- a/lib/jopenssl/version.rb +++ b/lib/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.4.dev" + VERSION = "0.7.4" end end From cdfcbf701558f34bddbe3394bb2db1f647168e01 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 31 May 2011 15:53:40 +0900 Subject: [PATCH 03/66] JRUBY-5833: Fix X509Name handling X509Name RDN can include multiple elements in a set. Could not connect to ics2ws.ic3.com since the certificate includes SN + CN component in subject. --- src/java/org/jruby/ext/openssl/X509Name.java | 20 +++++++++++--------- test/test_certificate.rb | 9 +++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/X509Name.java b/src/java/org/jruby/ext/openssl/X509Name.java index 08d9c8a..2b2d30e 100644 --- a/src/java/org/jruby/ext/openssl/X509Name.java +++ b/src/java/org/jruby/ext/openssl/X509Name.java @@ -131,19 +131,21 @@ void fromASN1Sequence(ASN1Sequence seq) { oids = new ArrayList(); values = new ArrayList(); types = new ArrayList(); - for(Enumeration enm = seq.getObjects();enm.hasMoreElements();) { - ASN1Sequence value = (ASN1Sequence)(((ASN1Set)enm.nextElement()).getObjectAt(0)); - oids.add(value.getObjectAt(0)); - if(value.getObjectAt(1) instanceof DERString) { - values.add(((DERString)value.getObjectAt(1)).getString()); - } else { - values.add(null); + for (Enumeration enumRdn = seq.getObjects(); enumRdn.hasMoreElements();) { + ASN1Set rdn = (ASN1Set) enumRdn.nextElement(); + for (Enumeration enumTypeAndValue = rdn.getObjects(); enumTypeAndValue.hasMoreElements();) { + ASN1Sequence typeAndValue = (ASN1Sequence) enumTypeAndValue.nextElement(); + oids.add(typeAndValue.getObjectAt(0)); + if (typeAndValue.getObjectAt(1) instanceof DERString) { + values.add(((DERString) typeAndValue.getObjectAt(1)).getString()); + } else { + values.add(null); + } + types.add(getRuntime().newFixnum(ASN1.idForClass(typeAndValue.getObjectAt(1).getClass()))); } - types.add(getRuntime().newFixnum(ASN1.idForClass(value.getObjectAt(1).getClass()))); } } - @JRubyMethod(rest=true, frame=true) public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,0,2) == 0) { diff --git a/test/test_certificate.rb b/test/test_certificate.rb index f44496a..eb8a4c4 100644 --- a/test/test_certificate.rb +++ b/test/test_certificate.rb @@ -120,4 +120,13 @@ def test_load_key_and_cert_in_one_file assert_equal("Tue Dec 7 04:34:54 2010", cert.not_before.asctime) assert_equal(155138628173305760586484923990788939560020632428367464748448028799529480209574373402763304069949574437177088605664104864141770364385183263453740781162330879666907894314877641447552442838727890327086630369910941911916802731723019019303432276515402934176273116832204529025371212188573318159421452591783377914839, key.n) end + + # JRUBY-5834 + def test_foo + cert_file = File.expand_path('fixture/ids_in_subject_rdn_set.pem', File.dirname(__FILE__)) + cert = OpenSSL::X509::Certificate.new(File.read(cert_file)) + keys = cert.subject.to_a.map { |k, v| k }.sort + assert_equal(10, keys.size) + assert_equal(true, keys.include?("CN")) + end end From 26268e41bf74d2699ecdda380ebeb67ce0e46ba5 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 31 May 2011 15:57:45 +0900 Subject: [PATCH 04/66] Version bump to 0.7.5.dev. --- Rakefile | 2 +- jruby-openssl.gemspec | 2 +- lib/jopenssl/version.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index f0115d8..6c489d0 100644 --- a/Rakefile +++ b/Rakefile @@ -64,7 +64,7 @@ begin p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n") p.description = p.paragraphs_of('README.txt', 3...4).join("\n\n") p.test_globs = ENV["TEST"] || ["test/test_all.rb"] - p.extra_deps << ['bouncy-castle-java', '>= 0'] + p.extra_deps << ['bouncy-castle-java', '>= 1.5.0146.1'] end hoe.spec.dependencies.delete_if { |dep| dep.name == "hoe" } diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 7fedd83..b872599 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{jruby-openssl} - s.version = "0.7.4" + s.version = "0.7.5.dev" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] diff --git a/lib/jopenssl/version.rb b/lib/jopenssl/version.rb index 6ce8cf7..ea579b0 100644 --- a/lib/jopenssl/version.rb +++ b/lib/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.4" + VERSION = "0.7.5.dev" end end From 1c618c8afe2a1e3a95b5a0c996fbf6afcc6b309b Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 31 May 2011 15:58:07 +0900 Subject: [PATCH 05/66] Add deprecation comment. We should remove it for JRuby. --- src/java/org/jruby/ext/openssl/ASN1.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/org/jruby/ext/openssl/ASN1.java b/src/java/org/jruby/ext/openssl/ASN1.java index e88ac6e..87a4607 100644 --- a/src/java/org/jruby/ext/openssl/ASN1.java +++ b/src/java/org/jruby/ext/openssl/ASN1.java @@ -907,6 +907,7 @@ ASN1Encodable toASN1() { .newInstance(new Object[] { vec }); return result; } catch (Exception e) { + // TODO: deprecated throw RaiseException.createNativeRaiseException(getRuntime(), e); } } From 3fcf1c6359a113fbea3b858b2723eb7c325eb993 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 31 May 2011 15:59:49 +0900 Subject: [PATCH 06/66] Add test fixture Slipped in the commit cdfcbf701558f34bddbe3394bb2db1f647168e01 --- test/fixture/ids_in_subject_rdn_set.pem | 31 +++++++++++++++++++++++++ test/test_certificate.rb | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/fixture/ids_in_subject_rdn_set.pem diff --git a/test/fixture/ids_in_subject_rdn_set.pem b/test/fixture/ids_in_subject_rdn_set.pem new file mode 100644 index 0000000..9e0be47 --- /dev/null +++ b/test/fixture/ids_in_subject_rdn_set.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFTDCCBDSgAwIBAgIESx/XYjANBgkqhkiG9w0BAQUFADCBsTELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9ycGEgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDkgRW50cnVzdCwgSW5jLjEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAtIEwxRTAeFw0xMDAxMjExNzU2NDhaFw0xMjAzMDEx +ODI1MzhaMIHxMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG +A1UEBxMNTW91bnRhaW4gVmlldzETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysG +AQQBgjc8AgECEwhEZWxhd2FyZTEgMB4GA1UEChMXQ3liZXJzb3VyY2UgQ29ycG9y +YXRpb24xGzAZBgNVBA8TElYxLjAsIENsYXVzZSA1LihiKTEdMBsGA1UECxMUVGVj +aG5pY2FsIE9wZXJhdGlvbnMxJzAOBgNVBAUTBzI4Mzg5MjEwFQYDVQQDEw5pY3My +d3MuaWMzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJuWvZiS +4PjHFT3uSJIQ4JLHIiMyH6a5UrWv3fvfcrhrzuIpmeZMrQeInVDohU6pWIlfYhgh +/FKXA2uJI2deKZLu0Iw7x45EVNbtt2I0oSoAyvukJ0/4SSWsYbPw2AzKxvMxiDuW +6aWHHVXAZ6XRRg+F8mrH8qyMKsZPPzEn5p6Wgr8W/W0k1jveznxPrXHOqqg8V3uF +gQohMHlyk7ybCFyThbF2Vn3ri21ZZoUSjjU/1J2LWkYpplWkGatkv9R7TRHMsVFK +mZiVCRi1dVK90rq5efaAf28WrweA9reUaigMFfVG0f0QoV9eZ8syqwUBwVqUJaq4 +bAKTQIz75jJ8xKsCAwEAAaOCASgwggEkMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAU +BggrBgEFBQcDAQYIKwYBBQUHAwIwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB +hhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRw +Oi8vY3JsLmVudHJ1c3QubmV0L2xldmVsMWUuY3JsMEEGA1UdIAQ6MDgwNgYKYIZI +AYb6bAoBAjAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3Jw +YTAfBgNVHSMEGDAWgBRbQYqyxEPBvb/IVEFVneCWrf+5oTAdBgNVHQ4EFgQUxwn0 +c2hWU57BkDqWQIHAQMMEW1UwCQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEA +JyyyuN5xhmn60ikyQ38xCEFIglghuteljnKzUDz0++7wSlP/4qkD7/y2dk3dPY1x +BzS4nfAtqlUV6cr2atQZkG12F+qc58o3qTfdh3WSQBk4bhb0kl18hNnOQHWVUQg3 +H728BqwAbuSyal9VAAExdIhIx2l70+g1BiEcEUswfFIZJ7PEkeafmlRmLjhOb8MF +y4JdYmZ82+4lDM5ScME9F/5782cRscYDbn5ODXkMp6YdN3aurMWYYmCRGzkj0UfL +UhGX2EWjEi0PZSJN0dNpckHEu8rxth/4gf6rUEUXXG2yrvUD6t+keelH9LEttyf4 +5b7k0dbmTWmgjkgoi1gqWg== +-----END CERTIFICATE----- diff --git a/test/test_certificate.rb b/test/test_certificate.rb index eb8a4c4..364ae18 100644 --- a/test/test_certificate.rb +++ b/test/test_certificate.rb @@ -122,7 +122,7 @@ def test_load_key_and_cert_in_one_file end # JRUBY-5834 - def test_foo + def test_ids_in_subject_rdn_set cert_file = File.expand_path('fixture/ids_in_subject_rdn_set.pem', File.dirname(__FILE__)) cert = OpenSSL::X509::Certificate.new(File.read(cert_file)) keys = cert.subject.to_a.map { |k, v| k }.sort From b72e51d84c1be2b97edbbd1eb27966e35eea773b Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 7 Sep 2011 15:33:21 +0900 Subject: [PATCH 07/66] JRUBY-4992: warn if loaded by non JRuby interpreter Applied the patch from Hiro Asari, with a little modification (removed 'return nil' which causes SyntaxError.) --- lib/openssl.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/openssl.rb b/lib/openssl.rb index 6a35fe3..8f62544 100644 --- a/lib/openssl.rb +++ b/lib/openssl.rb @@ -14,6 +14,10 @@ $Id: openssl.rb 12496 2007-06-08 15:02:04Z technorama $ =end +unless defined? JRUBY_VERSION + warn 'Loading jruby-openssl in a non-JRuby interpreter' +end + # TODO: remove this chunk after 1.4 support is dropped require 'digest' unless defined?(::Digest::Class) From 887d1810e25090391893de3b3eb31c68b8418774 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 8 Sep 2011 15:07:53 +0900 Subject: [PATCH 08/66] JRUBY-5972: allow to load/dump empty PKCS7 data OpenSSL seems to allow to dump empty PKCS7 data which has "0.0" as an ObjectId. Follow it. --- src/java/org/jruby/ext/openssl/PKCS7.java | 10 ++++ .../org/jruby/ext/openssl/impl/PKCS7.java | 48 +++++++++++++------ test/test_pkcs7.rb | 16 +++++++ 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/PKCS7.java b/src/java/org/jruby/ext/openssl/PKCS7.java index ab4a6de..14919bc 100644 --- a/src/java/org/jruby/ext/openssl/PKCS7.java +++ b/src/java/org/jruby/ext/openssl/PKCS7.java @@ -37,6 +37,10 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyBignum; @@ -260,6 +264,12 @@ public IRubyObject getData() { public IRubyObject _initialize(IRubyObject[] args) { IRubyObject arg = null; if(Arity.checkArgumentCount(getRuntime(), args, 0, 1) == 0) { + p7 = new org.jruby.ext.openssl.impl.PKCS7(); + try { + p7.setType(ASN1Registry.NID_undef); + } catch (PKCS7Exception pkcs7e) { + throw newPKCS7Exception(getRuntime(), pkcs7e); + } return this; } arg = args[0]; diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7.java b/src/java/org/jruby/ext/openssl/impl/PKCS7.java index 4b4118c..82132fe 100644 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7.java +++ b/src/java/org/jruby/ext/openssl/impl/PKCS7.java @@ -79,6 +79,9 @@ * @author Ola Bini */ public class PKCS7 { + // OpenSSL behavior: PKCS#7 ObjectId for "ITU-T" + "0" + private static final String EMPTY_PKCS7_OID = "0.0"; + /* content as defined by the type */ /* all encryption/message digests are applied to the 'contents', * leaving out the 'type' field. */ @@ -112,22 +115,27 @@ private void initiateWith(Integer nid, DEREncodable content) throws PKCS7Excepti * ContentType ::= OBJECT IDENTIFIER */ public static PKCS7 fromASN1(DEREncodable obj) throws PKCS7Exception { - int size = ((ASN1Sequence)obj).size(); - if(size == 0) { - return new PKCS7(); + PKCS7 p7 = new PKCS7(); + + int size = ((ASN1Sequence) obj).size(); + if (size == 0) { + return p7; } - DERObjectIdentifier contentType = (DERObjectIdentifier)(((ASN1Sequence)obj).getObjectAt(0)); - int nid = ASN1Registry.obj2nid(contentType); - - DEREncodable content = size == 1 ? (DEREncodable)null : ((ASN1Sequence)obj).getObjectAt(1); + DERObjectIdentifier contentType = (DERObjectIdentifier) (((ASN1Sequence) obj).getObjectAt(0)); + if (EMPTY_PKCS7_OID.equals(contentType.getId())) { + // OpenSSL behavior + p7.setType(ASN1Registry.NID_undef); + } else { + int nid = ASN1Registry.obj2nid(contentType); - if(content != null && content instanceof DERTaggedObject && ((DERTaggedObject)content).getTagNo() == 0) { - content = ((DERTaggedObject)content).getObject(); + DEREncodable content = size == 1 ? (DEREncodable) null : ((ASN1Sequence) obj).getObjectAt(1); + + if (content != null && content instanceof DERTaggedObject && ((DERTaggedObject) content).getTagNo() == 0) { + content = ((DERTaggedObject) content).getObject(); + } + p7.initiateWith(nid, content); } - - PKCS7 p7 = new PKCS7(); - p7.initiateWith(nid, content); return p7; } @@ -141,10 +149,17 @@ public static PKCS7 fromASN1(BIO bio) throws IOException, PKCS7Exception { public ASN1Encodable asASN1() { ASN1EncodableVector vector = new ASN1EncodableVector(); - DERObjectIdentifier contentType = ASN1Registry.nid2obj(getType()); + DERObjectIdentifier contentType; + if (data == null) { + // OpenSSL behavior + contentType = new DERObjectIdentifier(EMPTY_PKCS7_OID); + } else { + contentType = ASN1Registry.nid2obj(getType()); + } vector.add(contentType); - vector.add(new DERTaggedObject(0, data.asASN1())); - + if (data != null) { + vector.add(new DERTaggedObject(0, data.asASN1())); + } return new DERSequence(vector); } @@ -498,6 +513,9 @@ public void decrypt(PrivateKey pkey, X509AuxCertificate cert, BIO data, int flag */ public void setType(int type) throws PKCS7Exception { switch(type) { + case ASN1Registry.NID_undef: + this.data = null; + break; case ASN1Registry.NID_pkcs7_signed: this.data = new PKCS7DataSigned(); break; diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb index 024c8e6..93b62ce 100644 --- a/test/test_pkcs7.rb +++ b/test/test_pkcs7.rb @@ -37,4 +37,20 @@ def test_pkcs7_des3_key_generation_for_encrypt p7 = OpenSSL::PKCS7.encrypt(certs, msg, cipher, OpenSSL::PKCS7::BINARY) assert_equal(msg, p7.data) end + + EMPTY_PEM = < Date: Thu, 8 Sep 2011 19:52:51 +0900 Subject: [PATCH 09/66] JRUBY-6044: Improve Ecrypted RSA pem support DSA and DH are not yet supported. --- src/java/org/jruby/ext/openssl/Cipher.java | 106 +++++++----- src/java/org/jruby/ext/openssl/PKeyRSA.java | 8 +- .../ext/openssl/x509store/PEMInputOutput.java | 111 ++++++------- test/test_pkey.rb | 153 ++++++++++++++++++ 4 files changed, 273 insertions(+), 105 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java index 6876163..2e25c2c 100644 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ b/src/java/org/jruby/ext/openssl/Cipher.java @@ -89,7 +89,7 @@ public static IRubyObject ciphers(IRubyObject recv) { return recv.getRuntime().newArray(result); } - static boolean isSupportedCipher(String name) { + public static boolean isSupportedCipher(String name) { initializeCiphers(); return CIPHERS.indexOf(name.toUpperCase()) != -1; } @@ -231,6 +231,60 @@ public static String[] osslToJsse(String inName, String padding) { return new String[]{cryptoBase, cryptoVersion, cryptoMode, realName, paddingType}; } + + public static int[] osslKeyIvLength(String name) { + String[] values = Algorithm.osslToJsse(name); + String cryptoBase = values[0]; + String cryptoVersion = values[1]; + String cryptoMode = values[2]; + String realName = values[3]; + + int keyLen = -1; + int ivLen = -1; + + if (hasLen(cryptoBase) && null != cryptoVersion) { + try { + keyLen = Integer.parseInt(cryptoVersion) / 8; + } catch (NumberFormatException e) { + keyLen = -1; + } + } + if (keyLen == -1) { + if ("DES".equalsIgnoreCase(cryptoBase)) { + ivLen = 8; + if ("EDE3".equalsIgnoreCase(cryptoVersion)) { + keyLen = 24; + } else { + keyLen = 8; + } + } else if ("RC4".equalsIgnoreCase(cryptoBase)) { + ivLen = 0; + keyLen = 16; + } else { + keyLen = 16; + try { + if ((javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8) < keyLen) { + keyLen = javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8; + } + } catch (Exception e) { + // I hate checked exceptions + } + } + } + + if (ivLen == -1) { + if ("AES".equalsIgnoreCase(cryptoBase)) { + ivLen = 16; + } else { + ivLen = 8; + } + } + return new int[] { keyLen, ivLen }; + } + + public static boolean hasLen(String cryptoBase) { + return "AES".equalsIgnoreCase(cryptoBase) || "RC2".equalsIgnoreCase(cryptoBase) || "RC4".equalsIgnoreCase(cryptoBase); + } } private static boolean tryCipher(final String rubyName) { @@ -306,43 +360,11 @@ public IRubyObject initialize(IRubyObject str) { padding_type = values[4]; ciph = getCipher(); - if (hasLen(cryptoBase) && null != cryptoVersion) { - try { - keyLen = Integer.parseInt(cryptoVersion) / 8; - } catch (NumberFormatException e) { - keyLen = -1; - } - } - if (keyLen == -1) { - if ("DES".equalsIgnoreCase(cryptoBase)) { - ivLen = 8; - if ("EDE3".equalsIgnoreCase(cryptoVersion)) { - keyLen = 24; - } else { - keyLen = 8; - } - generateKeyLen = keyLen / 8 * 7; - } else if ("RC4".equalsIgnoreCase(cryptoBase)) { - ivLen = 0; - keyLen = 16; - } else { - keyLen = 16; - try { - if ((javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8) < keyLen) { - keyLen = javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8; - } - } catch (Exception e) { - // I hate checked exceptions - } - } - } - - if (ivLen == -1) { - if ("AES".equalsIgnoreCase(cryptoBase)) { - ivLen = 16; - } else { - ivLen = 8; - } + int[] lengths = Algorithm.osslKeyIvLength(name); + keyLen = lengths[0]; + ivLen = lengths[1]; + if ("DES".equalsIgnoreCase(cryptoBase)) { + generateKeyLen = keyLen / 8 * 7; } // given 'rc4' must be 'RC4' here. OpenSSL checks it as a LN of object @@ -551,10 +573,6 @@ javax.crypto.Cipher getCipher() { } } - private static boolean hasLen(String cryptoBase) { - return "AES".equalsIgnoreCase(cryptoBase) || "RC2".equalsIgnoreCase(cryptoBase) || "RC4".equalsIgnoreCase(cryptoBase); - } - @JRubyMethod(required = 1, optional = 3) public IRubyObject pkcs5_keyivgen(IRubyObject[] args) { org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 4); @@ -742,6 +760,10 @@ String getCryptoMode() { return this.cryptoMode; } + int getKeyLen() { + return keyLen; + } + int getGenerateKeyLen() { return (generateKeyLen == -1) ? keyLen : generateKeyLen; } diff --git a/src/java/org/jruby/ext/openssl/PKeyRSA.java b/src/java/org/jruby/ext/openssl/PKeyRSA.java index 242a035..5e76c0d 100644 --- a/src/java/org/jruby/ext/openssl/PKeyRSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyRSA.java @@ -59,6 +59,7 @@ import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.exceptions.RaiseException; +import org.jruby.ext.openssl.impl.CipherSpec; import org.jruby.ext.openssl.x509store.PEMInputOutput; import org.jruby.runtime.Arity; import org.jruby.runtime.Block; @@ -379,17 +380,18 @@ public IRubyObject to_text() { public IRubyObject export(IRubyObject[] args) { StringWriter w = new StringWriter(); org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); + CipherSpec ciph = null; char[] passwd = null; - String algo = null; if (args.length > 0 && !args[0].isNil()) { - algo = ((org.jruby.ext.openssl.Cipher) args[0]).getAlgorithm(); + org.jruby.ext.openssl.Cipher c = (org.jruby.ext.openssl.Cipher) args[0]; + ciph = new CipherSpec(c.getCipher(), c.getName(), c.getKeyLen() * 8); if (args.length > 1 && !args[1].isNil()) { passwd = args[1].toString().toCharArray(); } } try { if (privKey != null) { - PEMInputOutput.writeRSAPrivateKey(w, privKey, algo, passwd); + PEMInputOutput.writeRSAPrivateKey(w, privKey, ciph, passwd); } else { PEMInputOutput.writeRSAPublicKey(w, pubKey); } diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index 1e28766..32fa07e 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -75,7 +75,10 @@ import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure; import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; import org.bouncycastle.crypto.PBEParametersGenerator; +import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; +import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; @@ -106,7 +109,9 @@ import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.jruby.ext.openssl.Cipher.CipherModule; import org.jruby.ext.openssl.impl.ASN1Registry; +import org.jruby.ext.openssl.impl.CipherSpec; /** * Helper class to read and write PEM files correctly. @@ -824,7 +829,7 @@ public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, String alg } } - public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, String algo, char[] f) throws IOException { + public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, CipherSpec cipher, char[] passwd) throws IOException { assert(obj != null); BufferedWriter out = makeBuffered(_out); RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure( @@ -846,33 +851,26 @@ public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, String byte[] encoding = bOut.toByteArray(); - if(algo != null && f != null) { + if(cipher != null && passwd != null) { + Cipher c = cipher.getCipher(); + String algoBase = c.getAlgorithm(); + if (algoBase.indexOf('/') != -1) { + algoBase = algoBase.split("/")[0]; + } + byte[] iv = new byte[c.getBlockSize()]; + random.nextBytes(iv); byte[] salt = new byte[8]; - byte[] encData = null; - random.nextBytes(salt); + System.arraycopy(iv, 0, salt, 0, 8); OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(f), salt); - SecretKey secretKey = null; - - if (algo.startsWith("DES")) { - // generate key - int keyLength = 24; - if (algo.equalsIgnoreCase("DESEDE")) { - algo = "DESede/CBC/PKCS5Padding"; - } - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8); - secretKey = new SecretKeySpec(param.getKey(), algo.split("/")[0]); - } else { - throw new IOException("unknown algorithm `" + algo + "' in write_DSAPrivateKey"); - } - - // cipher + pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); + KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits()); + SecretKey secretKey = new SecretKeySpec(param.getKey(), algoBase); + byte[] encData = null; try { - Cipher c = Cipher.getInstance(algo); - c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(salt)); + c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); encData = c.doFinal(encoding); - } catch (Exception e) { - throw new IOException("exception using cipher: " + e.toString()); + } catch (GeneralSecurityException gse) { + throw new IOException("exception using cipher: " + gse.toString()); } // write the data @@ -880,8 +878,8 @@ public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, String out.newLine(); out.write("Proc-Type: 4,ENCRYPTED"); out.newLine(); - out.write("DEK-Info: DES-EDE3-CBC,"); - writeHexEncoded(out,salt); + out.write("DEK-Info: " + cipher.getOsslName() + ","); + writeHexEncoded(out,iv); out.newLine(); out.newLine(); writeEncoded(out,encData); @@ -949,20 +947,6 @@ private static byte[] readBytes(BufferedReader in, String endMarker) throws IOEx return Base64.decode(buf.toString()); } - /** - * create the secret key needed for this object, fetching the password - */ - private static SecretKey getKey(char[] k1, String algorithm, int keyLength, byte[] salt) throws IOException { - char[] password = k1; - if (password == null) { - throw new IOException("Password is null, but a password is required"); - } - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt); - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8); - return new javax.crypto.spec.SecretKeySpec(param.getKey(), algorithm); - } - private static RSAPublicKey readRSAPublicKey(BufferedReader in, String endMarker) throws IOException { ByteArrayInputStream bAIS = new ByteArrayInputStream(readBytes(in,endMarker)); ASN1InputStream ais = new ASN1InputStream(bAIS); @@ -1037,30 +1021,37 @@ private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String typ buf.append(line.trim()); } } - byte[] keyBytes = null; + byte[] keyBytes = null; + byte[] decoded = Base64.decode(buf.toString()); if (isEncrypted) { + if (passwd == null) { + throw new IOException("Password is null, but a password is required"); + } StringTokenizer tknz = new StringTokenizer(dekInfo, ","); - String encoding = tknz.nextToken(); - - if (encoding.equals("DES-EDE3-CBC")) { - String alg = "DESede"; - byte[] iv = Hex.decode(tknz.nextToken()); - Key sKey = getKey(passwd,alg, 24, iv); - Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding"); - c.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(iv)); - keyBytes = c.doFinal(Base64.decode(buf.toString())); - } else if (encoding.equals("DES-CBC")) { - String alg = "DES"; - byte[] iv = Hex.decode(tknz.nextToken()); - Key sKey = getKey(passwd,alg, 8, iv); - Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding"); - c.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(iv)); - keyBytes = c.doFinal(Base64.decode(buf.toString())); - } else { - throw new IOException("unknown encryption with private key"); + String algorithm = tknz.nextToken(); + byte[] iv = Hex.decode(tknz.nextToken()); + if (!CipherModule.isSupportedCipher(algorithm)) { + throw new IOException("Unknown algorithm: " + algorithm); + } + String[] cipher = org.jruby.ext.openssl.Cipher.Algorithm.osslToJsse(algorithm); + String realName = cipher[3]; + int[] lengths = org.jruby.ext.openssl.Cipher.Algorithm.osslKeyIvLength(algorithm); + int keyLen = lengths[0]; + int ivLen = lengths[1]; + if (iv.length != ivLen) { + throw new IOException("Illegal IV length"); } + byte[] salt = new byte[8]; + System.arraycopy(iv, 0, salt, 0, 8); + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); + KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLen * 8); + SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(param.getKey(), realName); + Cipher c = Cipher.getInstance(realName); + c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); + keyBytes = c.doFinal(decoded); } else { - keyBytes = Base64.decode(buf.toString()); + keyBytes = decoded; } return readPrivateKeySequence(keyBytes, type); } diff --git a/test/test_pkey.rb b/test/test_pkey.rb index 16a856c..a4e178d 100644 --- a/test/test_pkey.rb +++ b/test/test_pkey.rb @@ -201,4 +201,157 @@ def test_load_pkey_dsa_net_ssh pkey = OpenSSL::PKey::DSA.new(blob) assert_equal(blob, pkey.to_der) end + + CRUBY_DES_PEM = < Date: Thu, 8 Sep 2011 21:43:12 +0900 Subject: [PATCH 10/66] JRUBY-6044: Improve Ecrypted DSA pem support --- src/java/org/jruby/ext/openssl/PKeyDSA.java | 10 +- src/java/org/jruby/ext/openssl/PKeyRSA.java | 2 +- .../ext/openssl/x509store/PEMInputOutput.java | 188 +++++++----------- test/test_pkey_dsa.rb | 180 +++++++++++++++++ test/{test_pkey.rb => test_pkey_rsa.rb} | 129 ++++-------- 5 files changed, 293 insertions(+), 216 deletions(-) create mode 100644 test/test_pkey_dsa.rb rename test/{test_pkey.rb => test_pkey_rsa.rb} (79%) diff --git a/src/java/org/jruby/ext/openssl/PKeyDSA.java b/src/java/org/jruby/ext/openssl/PKeyDSA.java index 4aa3fd3..69522f6 100644 --- a/src/java/org/jruby/ext/openssl/PKeyDSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyDSA.java @@ -55,6 +55,7 @@ import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.exceptions.RaiseException; +import org.jruby.ext.openssl.impl.CipherSpec; import org.jruby.ext.openssl.x509store.PEMInputOutput; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.builtin.IRubyObject; @@ -305,21 +306,22 @@ public IRubyObject public_key() { return val; } - @JRubyMethod(name = {"export", "to_pem", "to_s"}, rest = true) + @JRubyMethod(name = { "export", "to_pem", "to_s" }, rest = true) public IRubyObject export(IRubyObject[] args) { StringWriter w = new StringWriter(); org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); + CipherSpec ciph = null; char[] passwd = null; - String algo = null; if (args.length > 0 && !args[0].isNil()) { - algo = ((Cipher) args[0]).getAlgorithm(); + org.jruby.ext.openssl.Cipher c = (org.jruby.ext.openssl.Cipher) args[0]; + ciph = new CipherSpec(c.getCipher(), c.getName(), c.getKeyLen() * 8); if (args.length > 1 && !args[1].isNil()) { passwd = args[1].toString().toCharArray(); } } try { if (privKey != null) { - PEMInputOutput.writeDSAPrivateKey(w, privKey, algo, passwd); + PEMInputOutput.writeDSAPrivateKey(w, privKey, ciph, passwd); } else { PEMInputOutput.writeDSAPublicKey(w, pubKey); } diff --git a/src/java/org/jruby/ext/openssl/PKeyRSA.java b/src/java/org/jruby/ext/openssl/PKeyRSA.java index 5e76c0d..49e145b 100644 --- a/src/java/org/jruby/ext/openssl/PKeyRSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyRSA.java @@ -376,7 +376,7 @@ public IRubyObject to_text() { return getRuntime().newString(result.toString()); } - @JRubyMethod(name = {"export", "to_pem", "to_s"}, rest = true) + @JRubyMethod(name = { "export", "to_pem", "to_s" }, rest = true) public IRubyObject export(IRubyObject[] args) { StringWriter w = new StringWriter(); org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index 32fa07e..b22f31d 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -757,142 +757,97 @@ public static void writeX509Request(Writer _out, PKCS10CertificationRequestExt o } } - public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, String algo, char[] f) throws IOException { + public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, CipherSpec cipher, char[] passwd) throws IOException { BufferedWriter out = makeBuffered(_out); - ByteArrayInputStream bIn = new ByteArrayInputStream(getEncoded(obj)); - ASN1InputStream aIn = new ASN1InputStream(bIn); - PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence)aIn.readObject()); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); + ByteArrayInputStream bIn = new ByteArrayInputStream(getEncoded(obj)); + ASN1InputStream aIn = new ASN1InputStream(bIn); + PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) aIn.readObject()); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); - DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters()); + DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters()); ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new DERInteger(0)); v.add(new DERInteger(p.getP())); v.add(new DERInteger(p.getQ())); v.add(new DERInteger(p.getG())); - + BigInteger x = obj.getX(); BigInteger y = p.getG().modPow(x, p.getP()); - + v.add(new DERInteger(y)); v.add(new DERInteger(x)); - + aOut.writeObject(new DERSequence(v)); byte[] encoding = bOut.toByteArray(); - if(algo != null && f != null) { - byte[] salt = new byte[8]; - byte[] encData = null; - random.nextBytes(salt); - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(f), salt); - SecretKey secretKey = null; - if (algo.equalsIgnoreCase("DESede/CBC/PKCS5Padding")) { - // generate key - int keyLength = 24; - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8); - secretKey = new SecretKeySpec(param.getKey(), "DESede"); - } else { - throw new IOException("unknown algorithm in write_DSAPrivateKey: " + algo); - } - - // cipher - try { - Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding"); - c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(salt)); - encData = c.doFinal(encoding); - } catch (Exception e) { - throw new IOException("exception using cipher: " + e.toString()); - } - - // write the data - out.write(BEF_G + PEM_STRING_DSA + AFT); - out.newLine(); - out.write("Proc-Type: 4,ENCRYPTED"); - out.newLine(); - out.write("DEK-Info: DES-EDE3-CBC,"); - writeHexEncoded(out,salt); - out.newLine(); - out.newLine(); - writeEncoded(out,encData); - out.write(BEF_E + PEM_STRING_DSA + AFT); - out.flush(); + if (cipher != null && passwd != null) { + writePemEncrypted(out, PEM_STRING_DSA, encoding, cipher, passwd); } else { - out.write(BEF_G + PEM_STRING_DSA + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_DSA + AFT); - out.newLine(); - out.flush(); + writePemPlain(out, PEM_STRING_DSA, encoding); } } public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, CipherSpec cipher, char[] passwd) throws IOException { - assert(obj != null); + assert (obj != null); BufferedWriter out = makeBuffered(_out); - RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure( - obj.getModulus(), - obj.getPublicExponent(), - obj.getPrivateExponent(), - obj.getPrimeP(), - obj.getPrimeQ(), - obj.getPrimeExponentP(), - obj.getPrimeExponentQ(), - obj.getCrtCoefficient()); - - // convert to bytearray + RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(obj.getModulus(), obj.getPublicExponent(), obj.getPrivateExponent(), obj.getPrimeP(), + obj.getPrimeQ(), obj.getPrimeExponentP(), obj.getPrimeExponentQ(), obj.getCrtCoefficient()); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - + ASN1OutputStream aOut = new ASN1OutputStream(bOut); aOut.writeObject(keyStruct); aOut.close(); - byte[] encoding = bOut.toByteArray(); - if(cipher != null && passwd != null) { - Cipher c = cipher.getCipher(); - String algoBase = c.getAlgorithm(); - if (algoBase.indexOf('/') != -1) { - algoBase = algoBase.split("/")[0]; - } - byte[] iv = new byte[c.getBlockSize()]; - random.nextBytes(iv); - byte[] salt = new byte[8]; - System.arraycopy(iv, 0, salt, 0, 8); - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits()); - SecretKey secretKey = new SecretKeySpec(param.getKey(), algoBase); - byte[] encData = null; - try { - c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); - encData = c.doFinal(encoding); - } catch (GeneralSecurityException gse) { - throw new IOException("exception using cipher: " + gse.toString()); - } - - // write the data - out.write(BEF_G + PEM_STRING_RSA + AFT); - out.newLine(); - out.write("Proc-Type: 4,ENCRYPTED"); - out.newLine(); - out.write("DEK-Info: " + cipher.getOsslName() + ","); - writeHexEncoded(out,iv); - out.newLine(); - out.newLine(); - writeEncoded(out,encData); - out.write(BEF_E + PEM_STRING_RSA + AFT); - out.flush(); + if (cipher != null && passwd != null) { + writePemEncrypted(out, PEM_STRING_RSA, encoding, cipher, passwd); } else { - out.write(BEF_G + PEM_STRING_RSA + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_RSA + AFT); - out.newLine(); - out.flush(); + writePemPlain(out, PEM_STRING_RSA, encoding); + } + } + + private static void writePemPlain(BufferedWriter out, String pemHeader, byte[] encoding) throws IOException { + out.write(BEF_G + pemHeader + AFT); + out.newLine(); + writeEncoded(out, encoding); + out.write(BEF_E + pemHeader + AFT); + out.newLine(); + out.flush(); + } + + private static void writePemEncrypted(BufferedWriter out, String pemHeader, byte[] encoding, CipherSpec cipher, char[] passwd) throws IOException { + Cipher c = cipher.getCipher(); + String algoBase = c.getAlgorithm(); + if (algoBase.indexOf('/') != -1) { + algoBase = algoBase.split("/")[0]; } + byte[] iv = new byte[c.getBlockSize()]; + random.nextBytes(iv); + byte[] salt = new byte[8]; + System.arraycopy(iv, 0, salt, 0, 8); + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); + KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits()); + SecretKey secretKey = new SecretKeySpec(param.getKey(), algoBase); + byte[] encData = null; + try { + c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); + encData = c.doFinal(encoding); + } catch (GeneralSecurityException gse) { + throw new IOException("exception using cipher: " + gse.toString()); + } + out.write(BEF_G + pemHeader + AFT); + out.newLine(); + out.write("Proc-Type: 4,ENCRYPTED"); + out.newLine(); + out.write("DEK-Info: " + cipher.getOsslName() + ","); + writeHexEncoded(out, iv); + out.newLine(); + out.newLine(); + writeEncoded(out, encData); + out.write(BEF_E + pemHeader + AFT); + out.flush(); } public static void writeDHParameters(Writer _out, DHParameterSpec params) throws IOException { @@ -1003,12 +958,11 @@ private static PublicKey readPublicKey(BufferedReader in, String endMarker) thro /** * Read a Key Pair */ - private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String type,String endMarker) - throws Exception { - boolean isEncrypted = false; - String line = null; - String dekInfo = null; - StringBuffer buf = new StringBuffer(); + private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String type, String endMarker) throws Exception { + boolean isEncrypted = false; + String line = null; + String dekInfo = null; + StringBuffer buf = new StringBuffer(); while ((line = _in.readLine()) != null) { if (line.startsWith("Proc-Type: 4,ENCRYPTED")) { @@ -1042,8 +996,8 @@ private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String typ throw new IOException("Illegal IV length"); } byte[] salt = new byte[8]; - System.arraycopy(iv, 0, salt, 0, 8); - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + System.arraycopy(iv, 0, salt, 0, 8); + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLen * 8); SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(param.getKey(), realName); diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb new file mode 100644 index 0000000..b4458fe --- /dev/null +++ b/test/test_pkey_dsa.rb @@ -0,0 +1,180 @@ +require "openssl" +require "test/unit" + +class TestPKeyDSA < Test::Unit::TestCase + def test_can_generate_dsa_key + OpenSSL::PKey::DSA.generate(512) + end + + # jruby-openssl/0.6 causes NPE + def test_generate_pkey_dsa_empty + assert_nothing_raised do + OpenSSL::PKey::DSA.new.to_pem + end + end + + # jruby-openssl/0.6 ignores fixnum arg => to_pem returned 65 bytes with 'MAA=' + def test_generate_pkey_dsa_length + assert(OpenSSL::PKey::DSA.new(512).to_pem.size > 100) + end + + # jruby-openssl/0.6 returns nil for DSA#to_text + def test_generate_pkey_dsa_to_text + assert_match( + /Private-Key: \(512 bit\)/, + OpenSSL::PKey::DSA.new(512).to_text + ) + end + + def test_load_pkey_dsa + pkey = OpenSSL::PKey::DSA.new(512) + assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) + end + + def test_load_pkey_dsa_public + pkey = OpenSSL::PKey::DSA.new(512).public_key + assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) + end + + def test_load_pkey_dsa_der + pkey = OpenSSL::PKey::DSA.new(512) + assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) + end + + def test_load_pkey_dsa_public_der + pkey = OpenSSL::PKey::DSA.new(512).public_key + assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) + end + + def test_load_pkey_dsa_net_ssh + blob = "0\201\367\002\001\000\002A\000\203\316/\037u\272&J\265\003l3\315d\324h\372{\t8\252#\331_\026\006\035\270\266\255\343\353Z\302\276\335\336\306\220\375\202L\244\244J\206>\346\b\315\211\302L\246x\247u\a\376\366\345\302\016#\002\025\000\244\274\302\221Og\275/\302+\356\346\360\024\373wI\2573\361\002@\027\215\270r*\f\213\350C\245\021:\350 \006\\\376\345\022`\210b\262\3643\023XLKS\320\370\002\276\347A\nU\204\276\324\256`=\026\240\330\306J\316V\213\024\e\030\215\355\006\037q\337\356ln\002@\017\257\034\f\260\333'S\271#\237\230E\321\312\027\021\226\331\251Vj\220\305\316\036\v\266+\000\230\270\177B\003?t\a\305]e\344\261\334\023\253\323\251\223M\2175)a(\004\"lI8\312\303\307\a\002\024_\aznW\345\343\203V\326\246ua\203\376\201o\350\302\002" + pkey = OpenSSL::PKey::DSA.new(blob) + assert_equal(blob, pkey.to_der) + end + + def test_load_dsa_des_encrypted + password = 'pass' + pkey = OpenSSL::PKey::DSA.generate(512) + cipher = OpenSSL::Cipher::Cipher.new('des-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) + end + + def test_load_dsa_3des_encrypted + password = 'pass' + pkey = OpenSSL::PKey::DSA.generate(512) + cipher = OpenSSL::Cipher::Cipher.new('des-ede3-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) + end + + def test_load_dsa_aes_encrypted + password = 'pass' + pkey = OpenSSL::PKey::DSA.generate(512) + cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) + end + + CRUBY_DES_DSA_PEM = < to_pem returned 65 bytes with 'MAA=' - def test_generate_pkey_dsa_length - assert(OpenSSL::PKey::DSA.new(512).to_pem.size > 100) - end - - # jruby-openssl/0.6 returns nil for DSA#to_text - def test_generate_pkey_dsa_to_text - assert_match( - /Private-Key: \(512 bit\)/, - OpenSSL::PKey::DSA.new(512).to_text - ) - end - - def test_load_pkey_dsa - pkey = OpenSSL::PKey::DSA.new(512) - assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) - end - - def test_load_pkey_dsa_public - pkey = OpenSSL::PKey::DSA.new(512).public_key - assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) - end - - def test_load_pkey_dsa_der - pkey = OpenSSL::PKey::DSA.new(512) - assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) + def test_load_rsa_des_encrypted + password = 'pass' + pkey = OpenSSL::PKey::RSA.generate(1024) + cipher = OpenSSL::Cipher::Cipher.new('des-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.n, OpenSSL::PKey::RSA.new(pem, password).n) end - def test_load_pkey_dsa_public_der - pkey = OpenSSL::PKey::DSA.new(512).public_key - assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) + def test_load_rsa_3des_encrypted + password = 'pass' + pkey = OpenSSL::PKey::RSA.generate(1024) + cipher = OpenSSL::Cipher::Cipher.new('des-ede3-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.n, OpenSSL::PKey::RSA.new(pem, password).n) end - def test_load_pkey_dsa_net_ssh - blob = "0\201\367\002\001\000\002A\000\203\316/\037u\272&J\265\003l3\315d\324h\372{\t8\252#\331_\026\006\035\270\266\255\343\353Z\302\276\335\336\306\220\375\202L\244\244J\206>\346\b\315\211\302L\246x\247u\a\376\366\345\302\016#\002\025\000\244\274\302\221Og\275/\302+\356\346\360\024\373wI\2573\361\002@\027\215\270r*\f\213\350C\245\021:\350 \006\\\376\345\022`\210b\262\3643\023XLKS\320\370\002\276\347A\nU\204\276\324\256`=\026\240\330\306J\316V\213\024\e\030\215\355\006\037q\337\356ln\002@\017\257\034\f\260\333'S\271#\237\230E\321\312\027\021\226\331\251Vj\220\305\316\036\v\266+\000\230\270\177B\003?t\a\305]e\344\261\334\023\253\323\251\223M\2175)a(\004\"lI8\312\303\307\a\002\024_\aznW\345\343\203V\326\246ua\203\376\201o\350\302\002" - pkey = OpenSSL::PKey::DSA.new(blob) - assert_equal(blob, pkey.to_der) + def test_load_rsa_aes_encrypted + password = 'pass' + pkey = OpenSSL::PKey::RSA.generate(1024) + cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') + pem = pkey.to_pem(cipher, password) + assert_equal(pkey.n, OpenSSL::PKey::RSA.new(pem, password).n) end - CRUBY_DES_PEM = < Date: Thu, 13 Oct 2011 16:57:38 +0900 Subject: [PATCH 11/66] Reorganize lib/ for 1.8/1.9 dual mode support Move lib/openssl dir to lib/1.8/openssl and add lib/shared dir. Common definition for 1.8/1.9 mode is located in this new lib/shared dir. For dual mode support, lib/shared/openssl.rb, which is loaded by 'require "openssl"', adds lib/1.8 or lib/1.9 to $LOAD_PATH at runtime. Current RubyGems implementation does not allow change Gem::Specification#require_paths at runtime. lib/1.9 dir comes later. When JRuby changes its gem dir management policy, which uses lib/ruby/gems/1.8 directory both for 1.8/1.9 modes, we need to change this implementation. --- Rakefile | 20 +++++++++++----- jruby-openssl.gemspec | 24 +++++++++---------- lib/{ => 1.8}/openssl.rb | 17 ++----------- lib/{ => 1.8}/openssl/bn.rb | 4 ++-- lib/{ => 1.8}/openssl/buffering.rb | 4 +++- lib/{ => 1.8}/openssl/cipher.rb | 0 lib/{ => 1.8}/openssl/config.rb | 2 +- lib/{ => 1.8}/openssl/digest.rb | 4 ++-- lib/{ => 1.8}/openssl/pkcs7.rb | 0 .../ssl.rb => 1.8/openssl/ssl-internal.rb} | 4 ++-- lib/1.8/openssl/ssl.rb | 1 + .../x509.rb => 1.8/openssl/x509-internal.rb} | 17 +++++++------ lib/1.8/openssl/x509.rb | 1 + lib/{ => shared}/jopenssl/version.rb | 0 lib/shared/openssl.rb | 18 ++++++++++++++ lib/{ => shared}/openssl/dummy.rb | 0 lib/{ => shared}/openssl/dummyssl.rb | 0 lib/shared/openssl/ssl.rb | 1 + lib/shared/openssl/x509.rb | 1 + test/{openssl => 1.8}/ssl_server.rb | 0 test/{openssl => 1.8}/test_asn1.rb | 14 +++++++++++ test/{openssl => 1.8}/test_cipher.rb | 0 test/{openssl => 1.8}/test_config.rb | 0 test/{openssl => 1.8}/test_digest.rb | 0 test/{openssl => 1.8}/test_ec.rb | 0 test/{openssl => 1.8}/test_hmac.rb | 0 test/{openssl => 1.8}/test_ns_spki.rb | 0 test/{openssl => 1.8}/test_pair.rb | 0 test/{openssl => 1.8}/test_pkcs7.rb | 0 test/{openssl => 1.8}/test_pkey_rsa.rb | 0 test/{openssl => 1.8}/test_ssl.rb | 0 test/{openssl => 1.8}/test_x509cert.rb | 0 test/{openssl => 1.8}/test_x509crl.rb | 0 test/{openssl => 1.8}/test_x509ext.rb | 0 test/{openssl => 1.8}/test_x509name.rb | 0 test/{openssl => 1.8}/test_x509req.rb | 0 test/{openssl => 1.8}/test_x509store.rb | 0 test/{openssl => 1.8}/utils.rb | 0 test/test_openssl.rb | 2 +- test/test_ssl.rb | 2 +- 40 files changed, 84 insertions(+), 52 deletions(-) rename lib/{ => 1.8}/openssl.rb (83%) rename lib/{ => 1.8}/openssl/bn.rb (86%) rename lib/{ => 1.8}/openssl/buffering.rb (97%) rename lib/{ => 1.8}/openssl/cipher.rb (100%) rename lib/{ => 1.8}/openssl/config.rb (99%) rename lib/{ => 1.8}/openssl/digest.rb (93%) rename lib/{ => 1.8}/openssl/pkcs7.rb (100%) rename lib/{openssl/ssl.rb => 1.8/openssl/ssl-internal.rb} (98%) create mode 100644 lib/1.8/openssl/ssl.rb rename lib/{openssl/x509.rb => 1.8/openssl/x509-internal.rb} (95%) create mode 100644 lib/1.8/openssl/x509.rb rename lib/{ => shared}/jopenssl/version.rb (100%) create mode 100644 lib/shared/openssl.rb rename lib/{ => shared}/openssl/dummy.rb (100%) rename lib/{ => shared}/openssl/dummyssl.rb (100%) create mode 100644 lib/shared/openssl/ssl.rb create mode 100644 lib/shared/openssl/x509.rb rename test/{openssl => 1.8}/ssl_server.rb (100%) rename test/{openssl => 1.8}/test_asn1.rb (96%) rename test/{openssl => 1.8}/test_cipher.rb (100%) rename test/{openssl => 1.8}/test_config.rb (100%) rename test/{openssl => 1.8}/test_digest.rb (100%) rename test/{openssl => 1.8}/test_ec.rb (100%) rename test/{openssl => 1.8}/test_hmac.rb (100%) rename test/{openssl => 1.8}/test_ns_spki.rb (100%) rename test/{openssl => 1.8}/test_pair.rb (100%) rename test/{openssl => 1.8}/test_pkcs7.rb (100%) rename test/{openssl => 1.8}/test_pkey_rsa.rb (100%) rename test/{openssl => 1.8}/test_ssl.rb (100%) rename test/{openssl => 1.8}/test_x509cert.rb (100%) rename test/{openssl => 1.8}/test_x509crl.rb (100%) rename test/{openssl => 1.8}/test_x509ext.rb (100%) rename test/{openssl => 1.8}/test_x509name.rb (100%) rename test/{openssl => 1.8}/test_x509req.rb (100%) rename test/{openssl => 1.8}/test_x509store.rb (100%) rename test/{openssl => 1.8}/utils.rb (100%) diff --git a/Rakefile b/Rakefile index 6c489d0..54d69ab 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ require 'rake' require 'rake/testtask' -MANIFEST = FileList["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/jopenssl.jar", "lib/**/*", "test/**/*"] +MANIFEST = FileList["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/**/*", "test/**/*"] BC_JARS = FileList["build_lib/bc*.jar"] task :default => [:java_compile, :test] @@ -38,23 +38,29 @@ task :java_compile do end sh "javac @pkg/compile_options @pkg/compile_classpath @pkg/compile_sourcefiles" - sh "jar cf lib/jopenssl.jar -C pkg/classes/ ." + sh "jar cf lib/shared/jopenssl.jar -C pkg/classes/ ." end -file "lib/jopenssl.jar" => :java_compile +file "lib/shared/jopenssl.jar" => :java_compile task :more_clean do - rm_f FileList['lib/jopenssl.jar'] + rm_f FileList['lib/shared/jopenssl.jar'] end task :clean => :more_clean File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f.puts n } } begin + # easiest way to configure ruby_flags for Hoe. + ENV['RUBY_FLAGS'] ||= [ + (RUBY_VERSION >= '1.9.0' ? '--1.9' : '--1.8'), + '-w', + '-Ibuild_lib:lib/shared:test', + ENV['RUBY_DEBUG'] + ].compact.join(' ') require 'hoe' Hoe.plugin :gemcutter - Hoe.add_include_dirs('build_lib') hoe = Hoe.spec("jruby-openssl") do |p| - load File.dirname(__FILE__) + "/lib/jopenssl/version.rb" + load File.dirname(__FILE__) + "/lib/shared/jopenssl/version.rb" p.version = Jopenssl::Version::VERSION p.rubyforge_name = "jruby-extras" p.url = "http://jruby-extras.rubyforge.org/jruby-openssl" @@ -67,6 +73,8 @@ begin p.extra_deps << ['bouncy-castle-java', '>= 1.5.0146.1'] end hoe.spec.dependencies.delete_if { |dep| dep.name == "hoe" } + # Either lib/1.8 or lib/1.9 is added to $LOAD_PATH dynamically. + hoe.spec.require_paths = ['lib/shared'] task :gemspec do File.open("#{hoe.name}.gemspec", "w") {|f| f << hoe.spec.to_ruby } diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index b872599..97d91ce 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -4,30 +4,30 @@ Gem::Specification.new do |s| s.name = %q{jruby-openssl} s.version = "0.7.5.dev" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Ola Bini and JRuby contributors"] - s.date = %q{2011-04-28} + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.authors = [%q{Ola Bini and JRuby contributors}] + s.date = %q{2011-10-13} s.description = %q{JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library.} s.email = %q{ola.bini@gmail.com} - s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/jopenssl.jar", "lib/openssl.rb", "lib/openssl/dummy.rb", "lib/openssl/dummyssl.rb", "lib/openssl/config.rb", "lib/openssl/cipher.rb", "lib/openssl/ssl.rb", "lib/openssl/bn.rb", "lib/openssl/x509.rb", "lib/openssl/digest.rb", "lib/openssl/buffering.rb", "lib/openssl/pkcs7.rb", "lib/jopenssl/version.rb", "test/test_imaps.rb", "test/test_all.rb", "test/test_integration.rb", "test/ut_eof.rb", "test/test_java.rb", "test/test_openssl.rb", "test/test_pkey.rb", "test/test_cipher.rb", "test/cert_with_ec_pk.cer", "test/test_pkcs7.rb", "test/test_x509store.rb", "test/test_certificate.rb", "test/test_parse_certificate.rb", "test/test_ssl.rb", "test/openssl/test_x509name.rb", "test/openssl/test_ns_spki.rb", "test/openssl/test_x509cert.rb", "test/openssl/ssl_server.rb", "test/openssl/test_pair.rb", "test/openssl/test_ec.rb", "test/openssl/test_config.rb", "test/openssl/utils.rb", "test/openssl/test_x509req.rb", "test/openssl/test_cipher.rb", "test/openssl/test_digest.rb", "test/openssl/test_x509ext.rb", "test/openssl/test_asn1.rb", "test/openssl/test_pkcs7.rb", "test/openssl/test_x509store.rb", "test/openssl/test_pkey_rsa.rb", "test/openssl/test_ssl.rb", "test/openssl/test_x509crl.rb", "test/openssl/test_hmac.rb", "test/ref/compile.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/fixture/cacert.pem", "test/fixture/ca-bundle.crt", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/localhost_keypair.pem", "test/fixture/verisign_c3.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/keypair.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/sslserver.pem", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/ca_path/verisign.pem", "test/fixture/ca_path/72fa7371.0", "test/java/pkcs7_mime_enveloped.message", "test/java/pkcs7_mime_signed.message", "test/java/test_java_pkcs7.rb", "test/java/test_java_bio.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_mime.rb", "test/java/test_java_attribute.rb", "test/java/test_java_smime.rb"] + s.extra_rdoc_files = [%q{History.txt}, %q{Manifest.txt}, %q{README.txt}, %q{License.txt}] + s.files = [%q{Rakefile}, %q{History.txt}, %q{Manifest.txt}, %q{README.txt}, %q{License.txt}, %q{lib/shared/jopenssl.jar}, %q{lib/1.8/openssl.rb}, %q{lib/1.8/openssl/config.rb}, %q{lib/1.8/openssl/ssl-internal.rb}, %q{lib/1.8/openssl/cipher.rb}, %q{lib/1.8/openssl/ssl.rb}, %q{lib/1.8/openssl/bn.rb}, %q{lib/1.8/openssl/x509.rb}, %q{lib/1.8/openssl/digest.rb}, %q{lib/1.8/openssl/buffering.rb}, %q{lib/1.8/openssl/pkcs7.rb}, %q{lib/1.8/openssl/x509-internal.rb}, %q{lib/1.9/openssl.rb}, %q{lib/1.9/openssl/config.rb}, %q{lib/1.9/openssl/cipher.rb}, %q{lib/1.9/openssl/ssl.rb}, %q{lib/1.9/openssl/bn.rb}, %q{lib/1.9/openssl/x509.rb}, %q{lib/1.9/openssl/digest.rb}, %q{lib/1.9/openssl/buffering.rb}, %q{lib/shared/openssl.rb}, %q{lib/shared/openssl/dummy.rb}, %q{lib/shared/openssl/dummyssl.rb}, %q{lib/shared/openssl/ssl.rb}, %q{lib/shared/openssl/x509.rb}, %q{lib/shared/jopenssl/version.rb}, %q{test/test_imaps.rb}, %q{test/test_all.rb}, %q{test/test_integration.rb}, %q{test/ut_eof.rb}, %q{test/test_pkey_dsa.rb}, %q{test/test_java.rb}, %q{test/test_openssl.rb}, %q{test/test_cipher.rb}, %q{test/cert_with_ec_pk.cer}, %q{test/test_pkcs7.rb}, %q{test/test_x509store.rb}, %q{test/test_certificate.rb}, %q{test/test_parse_certificate.rb}, %q{test/test_pkey_rsa.rb}, %q{test/test_ssl.rb}, %q{test/openssl/test_x509name.rb}, %q{test/openssl/test_ns_spki.rb}, %q{test/openssl/test_x509cert.rb}, %q{test/openssl/ssl_server.rb}, %q{test/openssl/test_pair.rb}, %q{test/openssl/test_ec.rb}, %q{test/openssl/test_config.rb}, %q{test/openssl/utils.rb}, %q{test/openssl/test_x509req.rb}, %q{test/openssl/test_cipher.rb}, %q{test/openssl/test_digest.rb}, %q{test/openssl/test_x509ext.rb}, %q{test/openssl/test_asn1.rb}, %q{test/openssl/test_pkcs7.rb}, %q{test/openssl/test_x509store.rb}, %q{test/openssl/test_pkey_rsa.rb}, %q{test/openssl/test_ssl.rb}, %q{test/openssl/test_x509crl.rb}, %q{test/openssl/test_hmac.rb}, %q{test/ref/compile.rb}, %q{test/ref/a.out}, %q{test/ref/pkcs1}, %q{test/ref/pkcs1.c}, %q{test/fixture/cacert.pem}, %q{test/fixture/ca-bundle.crt}, %q{test/fixture/common.pem}, %q{test/fixture/key_then_cert.pem}, %q{test/fixture/verisign.pem}, %q{test/fixture/cert_localhost.pem}, %q{test/fixture/localhost_keypair.pem}, %q{test/fixture/verisign_c3.pem}, %q{test/fixture/selfcert.pem}, %q{test/fixture/ids_in_subject_rdn_set.pem}, %q{test/fixture/max.pem}, %q{test/fixture/keypair.pem}, %q{test/fixture/purpose/cacert.pem}, %q{test/fixture/purpose/b70a5bc1.0}, %q{test/fixture/purpose/sslclient.pem}, %q{test/fixture/purpose/sslserver.pem}, %q{test/fixture/purpose/sslclient/sslclient.pem}, %q{test/fixture/purpose/sslclient/csr.pem}, %q{test/fixture/purpose/sslclient/keypair.pem}, %q{test/fixture/purpose/ca/cacert.pem}, %q{test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234}, %q{test/fixture/purpose/ca/ca_config.rb}, %q{test/fixture/purpose/ca/serial}, %q{test/fixture/purpose/ca/newcerts/2_cert.pem}, %q{test/fixture/purpose/ca/newcerts/3_cert.pem}, %q{test/fixture/purpose/ca/private/cakeypair.pem}, %q{test/fixture/purpose/scripts/gen_cert.rb}, %q{test/fixture/purpose/scripts/init_ca.rb}, %q{test/fixture/purpose/scripts/gen_csr.rb}, %q{test/fixture/purpose/sslserver/sslserver.pem}, %q{test/fixture/purpose/sslserver/csr.pem}, %q{test/fixture/purpose/sslserver/keypair.pem}, %q{test/fixture/imaps/cacert.pem}, %q{test/fixture/imaps/server.crt}, %q{test/fixture/imaps/server.key}, %q{test/fixture/ca_path/verisign.pem}, %q{test/fixture/ca_path/72fa7371.0}, %q{test/java/pkcs7_mime_enveloped.message}, %q{test/java/pkcs7_mime_signed.message}, %q{test/java/test_java_pkcs7.rb}, %q{test/java/test_java_bio.rb}, %q{test/java/pkcs7_multipart_signed.message}, %q{test/java/test_java_mime.rb}, %q{test/java/test_java_attribute.rb}, %q{test/java/test_java_smime.rb}, %q{.gemtest}] s.homepage = %q{http://jruby-extras.rubyforge.org/jruby-openssl} - s.rdoc_options = ["--main", "README.txt"] - s.require_paths = ["lib"] + s.rdoc_options = [%q{--main}, %q{README.txt}] + s.require_paths = [%q{lib/shared}] s.rubyforge_project = %q{jruby-extras} - s.rubygems_version = %q{1.5.1} + s.rubygems_version = %q{1.8.9} s.summary = %q{OpenSSL add-on for JRuby} - s.test_files = ["test/test_all.rb"] + s.test_files = [%q{test/test_all.rb}] if s.respond_to? :specification_version then s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 0"]) + s.add_runtime_dependency(%q, [">= 1.5.0146.1"]) else - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 1.5.0146.1"]) end else - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 1.5.0146.1"]) end end diff --git a/lib/openssl.rb b/lib/1.8/openssl.rb similarity index 83% rename from lib/openssl.rb rename to lib/1.8/openssl.rb index 8f62544..d95bba7 100644 --- a/lib/openssl.rb +++ b/lib/1.8/openssl.rb @@ -14,10 +14,6 @@ $Id: openssl.rb 12496 2007-06-08 15:02:04Z technorama $ =end -unless defined? JRUBY_VERSION - warn 'Loading jruby-openssl in a non-JRuby interpreter' -end - # TODO: remove this chunk after 1.4 support is dropped require 'digest' unless defined?(::Digest::Class) @@ -62,19 +58,10 @@ def length end # end of compat chunk. -begin - require 'bouncy-castle-java' -rescue LoadError - # runs under restricted mode. -end -require 'jopenssl' - - require 'openssl/bn' require 'openssl/cipher' require 'openssl/config' require 'openssl/digest' require 'openssl/pkcs7' -require 'openssl/ssl' -require 'openssl/x509' - +require 'openssl/ssl-internal' +require 'openssl/x509-internal' diff --git a/lib/openssl/bn.rb b/lib/1.8/openssl/bn.rb similarity index 86% rename from lib/openssl/bn.rb rename to lib/1.8/openssl/bn.rb index cf44a09..d269425 100644 --- a/lib/openssl/bn.rb +++ b/lib/1.8/openssl/bn.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: bn.rb 11708 2007-02-12 23:01:19Z shyouhei $ + $Id: bn.rb 31657 2011-05-20 22:25:35Z shyouhei $ =end ## @@ -29,7 +29,7 @@ class BN # class Integer def to_bn - OpenSSL::BN::new(self) + OpenSSL::BN::new(self.to_s(16), 16) end end # Integer diff --git a/lib/openssl/buffering.rb b/lib/1.8/openssl/buffering.rb similarity index 97% rename from lib/openssl/buffering.rb rename to lib/1.8/openssl/buffering.rb index 42c047c..bad5766 100644 --- a/lib/openssl/buffering.rb +++ b/lib/1.8/openssl/buffering.rb @@ -11,9 +11,10 @@ (See the file 'LICENCE'.) = Version - $Id: buffering.rb 13706 2007-10-15 08:29:08Z usa $ + $Id: buffering.rb 28004 2010-05-24 23:58:49Z shyouhei $ =end +module OpenSSL module Buffering include Enumerable attr_accessor :sync @@ -237,3 +238,4 @@ def close sysclose end end +end diff --git a/lib/openssl/cipher.rb b/lib/1.8/openssl/cipher.rb similarity index 100% rename from lib/openssl/cipher.rb rename to lib/1.8/openssl/cipher.rb diff --git a/lib/openssl/config.rb b/lib/1.8/openssl/config.rb similarity index 99% rename from lib/openssl/config.rb rename to lib/1.8/openssl/config.rb index 9fc42c6..21c98b7 100644 --- a/lib/openssl/config.rb +++ b/lib/1.8/openssl/config.rb @@ -284,7 +284,7 @@ def to_s def each @data.each do |section, hash| hash.each do |key, value| - yield [section, key, value] + yield(section, key, value) end end end diff --git a/lib/openssl/digest.rb b/lib/1.8/openssl/digest.rb similarity index 93% rename from lib/openssl/digest.rb rename to lib/1.8/openssl/digest.rb index e64b0cf..27bc250 100644 --- a/lib/openssl/digest.rb +++ b/lib/1.8/openssl/digest.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: digest.rb 15600 2008-02-25 08:48:57Z technorama $ + $Id: digest.rb 28004 2010-05-24 23:58:49Z shyouhei $ =end ## @@ -40,7 +40,7 @@ def self.digest(name, data) super(name, data.first) } } - singleton = (class < 3 + raise ExtensionError, "unexpected array form" if ary.size > 3 create_ext(ary[0], ary[1], ary[2]) end @@ -38,12 +36,12 @@ def create_ext_from_string(str) # "oid = critical, value" value.strip! create_ext(oid, value) end - + def create_ext_from_hash(hash) create_ext(hash["oid"], hash["value"], hash["critical"]) end end - + class Extension def to_s # "oid = critical, value" str = self.oid @@ -51,7 +49,7 @@ def to_s # "oid = critical, value" str << "critical, " if self.critical? str << self.value.gsub(/\n/, ", ") end - + def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} end @@ -82,7 +80,8 @@ module RFC2253DN def expand_pair(str) return nil unless str - return str.gsub(Pair){|pair| + return str.gsub(Pair){ + pair = $& case pair.size when 2 then pair[1,1] when 3 then Integer("0x#{pair[1,2]}").chr @@ -93,7 +92,7 @@ def expand_pair(str) def expand_hexstring(str) return nil unless str - der = str.gsub(HexPair){|hex| Integer("0x#{hex}").chr } + der = str.gsub(HexPair){$&.to_i(16).chr } a1 = OpenSSL::ASN1.decode(der) return a1.value, a1.tag end diff --git a/lib/1.8/openssl/x509.rb b/lib/1.8/openssl/x509.rb new file mode 100644 index 0000000..3f17f5a --- /dev/null +++ b/lib/1.8/openssl/x509.rb @@ -0,0 +1 @@ +require 'openssl' diff --git a/lib/jopenssl/version.rb b/lib/shared/jopenssl/version.rb similarity index 100% rename from lib/jopenssl/version.rb rename to lib/shared/jopenssl/version.rb diff --git a/lib/shared/openssl.rb b/lib/shared/openssl.rb new file mode 100644 index 0000000..08b691b --- /dev/null +++ b/lib/shared/openssl.rb @@ -0,0 +1,18 @@ +unless defined? JRUBY_VERSION + warn 'Loading jruby-openssl in a non-JRuby interpreter' +end + +begin + require 'bouncy-castle-java' +rescue LoadError + # runs under restricted mode. +end +require 'jopenssl' + +if RUBY_VERSION >= '1.9.0' + $LOAD_PATH.unshift(File.expand_path('../../1.9', __FILE__)) + load(File.expand_path('../../1.9/openssl.rb', __FILE__)) +else + $LOAD_PATH.unshift(File.expand_path('../../1.8', __FILE__)) + load(File.expand_path('../../1.8/openssl.rb', __FILE__)) +end diff --git a/lib/openssl/dummy.rb b/lib/shared/openssl/dummy.rb similarity index 100% rename from lib/openssl/dummy.rb rename to lib/shared/openssl/dummy.rb diff --git a/lib/openssl/dummyssl.rb b/lib/shared/openssl/dummyssl.rb similarity index 100% rename from lib/openssl/dummyssl.rb rename to lib/shared/openssl/dummyssl.rb diff --git a/lib/shared/openssl/ssl.rb b/lib/shared/openssl/ssl.rb new file mode 100644 index 0000000..3f17f5a --- /dev/null +++ b/lib/shared/openssl/ssl.rb @@ -0,0 +1 @@ +require 'openssl' diff --git a/lib/shared/openssl/x509.rb b/lib/shared/openssl/x509.rb new file mode 100644 index 0000000..3f17f5a --- /dev/null +++ b/lib/shared/openssl/x509.rb @@ -0,0 +1 @@ +require 'openssl' diff --git a/test/openssl/ssl_server.rb b/test/1.8/ssl_server.rb similarity index 100% rename from test/openssl/ssl_server.rb rename to test/1.8/ssl_server.rb diff --git a/test/openssl/test_asn1.rb b/test/1.8/test_asn1.rb similarity index 96% rename from test/openssl/test_asn1.rb rename to test/1.8/test_asn1.rb index f196bc4..d9dd4ec 100644 --- a/test/openssl/test_asn1.rb +++ b/test/1.8/test_asn1.rb @@ -194,4 +194,18 @@ def test_decode cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der) assert_equal(cululated_sig, sig_val.value) end + + def test_encode_boolean + encode_decode_test(OpenSSL::ASN1::Boolean, [true, false]) + end + + def test_encode_integer + encode_decode_test(OpenSSL::ASN1::Integer, [72, -127, -128, 128, -1, 0, 1, -(2**12345), 2**12345]) + end + + def encode_decode_test(type, values) + values.each do |v| + assert_equal(v, OpenSSL::ASN1.decode(type.new(v).to_der).value) + end + end end if defined?(OpenSSL) diff --git a/test/openssl/test_cipher.rb b/test/1.8/test_cipher.rb similarity index 100% rename from test/openssl/test_cipher.rb rename to test/1.8/test_cipher.rb diff --git a/test/openssl/test_config.rb b/test/1.8/test_config.rb similarity index 100% rename from test/openssl/test_config.rb rename to test/1.8/test_config.rb diff --git a/test/openssl/test_digest.rb b/test/1.8/test_digest.rb similarity index 100% rename from test/openssl/test_digest.rb rename to test/1.8/test_digest.rb diff --git a/test/openssl/test_ec.rb b/test/1.8/test_ec.rb similarity index 100% rename from test/openssl/test_ec.rb rename to test/1.8/test_ec.rb diff --git a/test/openssl/test_hmac.rb b/test/1.8/test_hmac.rb similarity index 100% rename from test/openssl/test_hmac.rb rename to test/1.8/test_hmac.rb diff --git a/test/openssl/test_ns_spki.rb b/test/1.8/test_ns_spki.rb similarity index 100% rename from test/openssl/test_ns_spki.rb rename to test/1.8/test_ns_spki.rb diff --git a/test/openssl/test_pair.rb b/test/1.8/test_pair.rb similarity index 100% rename from test/openssl/test_pair.rb rename to test/1.8/test_pair.rb diff --git a/test/openssl/test_pkcs7.rb b/test/1.8/test_pkcs7.rb similarity index 100% rename from test/openssl/test_pkcs7.rb rename to test/1.8/test_pkcs7.rb diff --git a/test/openssl/test_pkey_rsa.rb b/test/1.8/test_pkey_rsa.rb similarity index 100% rename from test/openssl/test_pkey_rsa.rb rename to test/1.8/test_pkey_rsa.rb diff --git a/test/openssl/test_ssl.rb b/test/1.8/test_ssl.rb similarity index 100% rename from test/openssl/test_ssl.rb rename to test/1.8/test_ssl.rb diff --git a/test/openssl/test_x509cert.rb b/test/1.8/test_x509cert.rb similarity index 100% rename from test/openssl/test_x509cert.rb rename to test/1.8/test_x509cert.rb diff --git a/test/openssl/test_x509crl.rb b/test/1.8/test_x509crl.rb similarity index 100% rename from test/openssl/test_x509crl.rb rename to test/1.8/test_x509crl.rb diff --git a/test/openssl/test_x509ext.rb b/test/1.8/test_x509ext.rb similarity index 100% rename from test/openssl/test_x509ext.rb rename to test/1.8/test_x509ext.rb diff --git a/test/openssl/test_x509name.rb b/test/1.8/test_x509name.rb similarity index 100% rename from test/openssl/test_x509name.rb rename to test/1.8/test_x509name.rb diff --git a/test/openssl/test_x509req.rb b/test/1.8/test_x509req.rb similarity index 100% rename from test/openssl/test_x509req.rb rename to test/1.8/test_x509req.rb diff --git a/test/openssl/test_x509store.rb b/test/1.8/test_x509store.rb similarity index 100% rename from test/openssl/test_x509store.rb rename to test/1.8/test_x509store.rb diff --git a/test/openssl/utils.rb b/test/1.8/utils.rb similarity index 100% rename from test/openssl/utils.rb rename to test/1.8/utils.rb diff --git a/test/test_openssl.rb b/test/test_openssl.rb index 1d15cc7..08be4a7 100644 --- a/test/test_openssl.rb +++ b/test/test_openssl.rb @@ -1,4 +1,4 @@ -files = File.join(File.dirname(__FILE__), 'openssl', 'test_*.rb') +files = File.join(File.dirname(__FILE__), (RUBY_VERSION >= '1.9.0' ? '1.9' : '1.8'), 'test_*.rb') Dir.glob(files).sort.each do |tc| require tc end diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 4d72396..96db4e3 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -3,7 +3,7 @@ require 'webrick/https' require 'net/https' require 'logger' -require File.join(File.dirname(__FILE__), "openssl/utils.rb") +require File.join(File.dirname(__FILE__), "1.8/utils.rb") class TestSSL < Test::Unit::TestCase From d0b2668b543e9b44306ab5f41f46557b88d552c4 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 13 Oct 2011 17:39:31 +0900 Subject: [PATCH 12/66] Import 1.9.3 lib and test To run 1.9 testcase; jruby --1.9 -S rake test instead of; jruby --1.8 -S rake test 1.9 support has not completed yet. Test result: 366 tests, 1757 assertions, 22 failures, 78 errors, 0 skips --- lib/1.9/openssl.rb | 22 ++ lib/1.9/openssl/bn.rb | 35 ++ lib/1.9/openssl/buffering.rb | 448 +++++++++++++++++++++++ lib/1.9/openssl/cipher.rb | 65 ++++ lib/1.9/openssl/config.rb | 313 ++++++++++++++++ lib/1.9/openssl/digest.rb | 72 ++++ lib/1.9/openssl/ssl-internal.rb | 177 ++++++++++ lib/1.9/openssl/ssl.rb | 2 + lib/1.9/openssl/x509-internal.rb | 158 +++++++++ lib/1.9/openssl/x509.rb | 2 + test/1.9/ssl_server.rb | 81 +++++ test/1.9/test_asn1.rb | 589 +++++++++++++++++++++++++++++++ test/1.9/test_bn.rb | 23 ++ test/1.9/test_buffering.rb | 88 +++++ test/1.9/test_cipher.rb | 105 ++++++ test/1.9/test_config.rb | 288 +++++++++++++++ test/1.9/test_digest.rb | 118 +++++++ test/1.9/test_engine.rb | 15 + test/1.9/test_hmac.rb | 32 ++ test/1.9/test_ns_spki.rb | 50 +++ test/1.9/test_ocsp.rb | 47 +++ test/1.9/test_pair.rb | 250 +++++++++++++ test/1.9/test_pkcs12.rb | 209 +++++++++++ test/1.9/test_pkcs7.rb | 151 ++++++++ test/1.9/test_pkey_dh.rb | 72 ++++ test/1.9/test_pkey_dsa.rb | 224 ++++++++++++ test/1.9/test_pkey_ec.rb | 182 ++++++++++ test/1.9/test_pkey_rsa.rb | 244 +++++++++++++ test/1.9/test_ssl.rb | 399 +++++++++++++++++++++ test/1.9/test_ssl_session.rb | 327 +++++++++++++++++ test/1.9/test_x509cert.rb | 217 ++++++++++++ test/1.9/test_x509crl.rb | 221 ++++++++++++ test/1.9/test_x509ext.rb | 69 ++++ test/1.9/test_x509name.rb | 296 ++++++++++++++++ test/1.9/test_x509req.rb | 150 ++++++++ test/1.9/test_x509store.rb | 229 ++++++++++++ test/1.9/utils.rb | 313 ++++++++++++++++ test/ruby/envutil.rb | 208 +++++++++++ test/ruby/ut_eof.rb | 128 +++++++ 39 files changed, 6619 insertions(+) create mode 100644 lib/1.9/openssl.rb create mode 100644 lib/1.9/openssl/bn.rb create mode 100644 lib/1.9/openssl/buffering.rb create mode 100644 lib/1.9/openssl/cipher.rb create mode 100644 lib/1.9/openssl/config.rb create mode 100644 lib/1.9/openssl/digest.rb create mode 100644 lib/1.9/openssl/ssl-internal.rb create mode 100644 lib/1.9/openssl/ssl.rb create mode 100644 lib/1.9/openssl/x509-internal.rb create mode 100644 lib/1.9/openssl/x509.rb create mode 100644 test/1.9/ssl_server.rb create mode 100644 test/1.9/test_asn1.rb create mode 100644 test/1.9/test_bn.rb create mode 100644 test/1.9/test_buffering.rb create mode 100644 test/1.9/test_cipher.rb create mode 100644 test/1.9/test_config.rb create mode 100644 test/1.9/test_digest.rb create mode 100644 test/1.9/test_engine.rb create mode 100644 test/1.9/test_hmac.rb create mode 100644 test/1.9/test_ns_spki.rb create mode 100644 test/1.9/test_ocsp.rb create mode 100644 test/1.9/test_pair.rb create mode 100644 test/1.9/test_pkcs12.rb create mode 100644 test/1.9/test_pkcs7.rb create mode 100644 test/1.9/test_pkey_dh.rb create mode 100644 test/1.9/test_pkey_dsa.rb create mode 100644 test/1.9/test_pkey_ec.rb create mode 100644 test/1.9/test_pkey_rsa.rb create mode 100644 test/1.9/test_ssl.rb create mode 100644 test/1.9/test_ssl_session.rb create mode 100644 test/1.9/test_x509cert.rb create mode 100644 test/1.9/test_x509crl.rb create mode 100644 test/1.9/test_x509ext.rb create mode 100644 test/1.9/test_x509name.rb create mode 100644 test/1.9/test_x509req.rb create mode 100644 test/1.9/test_x509store.rb create mode 100644 test/1.9/utils.rb create mode 100644 test/ruby/envutil.rb create mode 100644 test/ruby/ut_eof.rb diff --git a/lib/1.9/openssl.rb b/lib/1.9/openssl.rb new file mode 100644 index 0000000..3efdd1e --- /dev/null +++ b/lib/1.9/openssl.rb @@ -0,0 +1,22 @@ +=begin += $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions + += Info + 'OpenSSL for Ruby 2' project + Copyright (C) 2002 Michal Rokos + All rights reserved. + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + += Version + $Id$ +=end + +require 'openssl/bn' +require 'openssl/cipher' +require 'openssl/config' +require 'openssl/digest' +require 'openssl/ssl-internal' +require 'openssl/x509-internal' diff --git a/lib/1.9/openssl/bn.rb b/lib/1.9/openssl/bn.rb new file mode 100644 index 0000000..a527a10 --- /dev/null +++ b/lib/1.9/openssl/bn.rb @@ -0,0 +1,35 @@ +#-- +# +# $RCSfile$ +# +# = Ruby-space definitions that completes C-space funcs for BN +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos +# All rights reserved. +# +# = Licence +# This program is licenced under the same licence as Ruby. +# (See the file 'LICENCE'.) +# +# = Version +# $Id: bn.rb 33067 2011-08-25 00:52:10Z drbrain $ +# +#++ + +module OpenSSL + class BN + include Comparable + end # BN +end # OpenSSL + +## +# Add double dispatch to Integer +# +class Integer + def to_bn + OpenSSL::BN::new(self.to_s(16), 16) + end +end # Integer + diff --git a/lib/1.9/openssl/buffering.rb b/lib/1.9/openssl/buffering.rb new file mode 100644 index 0000000..e2f3235 --- /dev/null +++ b/lib/1.9/openssl/buffering.rb @@ -0,0 +1,448 @@ +=begin += $RCSfile$ -- Buffering mix-in module. + += Info + 'OpenSSL for Ruby 2' project + Copyright (C) 2001 GOTOU YUUZOU + All rights reserved. + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + += Version + $Id: buffering.rb 32012 2011-06-11 14:07:42Z nahi $ +=end + +## +# OpenSSL IO buffering mix-in module. +# +# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO. + +module OpenSSL::Buffering + include Enumerable + + ## + # The "sync mode" of the SSLSocket. + # + # See IO#sync for full details. + + attr_accessor :sync + + ## + # Default size to read from or write to the SSLSocket for buffer operations. + + BLOCK_SIZE = 1024*16 + + def initialize(*args) + @eof = false + @rbuffer = "" + @sync = @io.sync + end + + # + # for reading. + # + private + + ## + # Fills the buffer from the underlying SSLSocket + + def fill_rbuff + begin + @rbuffer << self.sysread(BLOCK_SIZE) + rescue Errno::EAGAIN + retry + rescue EOFError + @eof = true + end + end + + ## + # Consumes +size+ bytes from the buffer + + def consume_rbuff(size=nil) + if @rbuffer.empty? + nil + else + size = @rbuffer.size unless size + ret = @rbuffer[0, size] + @rbuffer[0, size] = "" + ret + end + end + + public + + ## + # Reads +size+ bytes from the stream. If +buf+ is provided it must + # reference a string which will receive the data. + # + # See IO#read for full details. + + def read(size=nil, buf=nil) + if size == 0 + if buf + buf.clear + return buf + else + return "" + end + end + until @eof + break if size && size <= @rbuffer.size + fill_rbuff + end + ret = consume_rbuff(size) || "" + if buf + buf.replace(ret) + ret = buf + end + (size && ret.empty?) ? nil : ret + end + + ## + # Reads at most +maxlen+ bytes from the stream. If +buf+ is provided it + # must reference a string which will receive the data. + # + # See IO#readpartial for full details. + + def readpartial(maxlen, buf=nil) + if maxlen == 0 + if buf + buf.clear + return buf + else + return "" + end + end + if @rbuffer.empty? + begin + return sysread(maxlen, buf) + rescue Errno::EAGAIN + retry + end + end + ret = consume_rbuff(maxlen) + if buf + buf.replace(ret) + ret = buf + end + raise EOFError if ret.empty? + ret + end + + ## + # Reads at most +maxlen+ bytes in the non-blocking manner. + # + # When no data can be read without blocking it raises + # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. + # + # IO::WaitReadable means SSL needs to read internally so read_nonblock + # should be called again when the underlying IO is readable. + # + # IO::WaitWritable means SSL needs to write internally so read_nonblock + # should be called again after the underlying IO is writable. + # + # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows: + # + # # emulates blocking read (readpartial). + # begin + # result = ssl.read_nonblock(maxlen) + # rescue IO::WaitReadable + # IO.select([io]) + # retry + # rescue IO::WaitWritable + # IO.select(nil, [io]) + # retry + # end + # + # Note that one reason that read_nonblock writes to the underlying IO is + # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for + # more details. http://www.openssl.org/support/faq.html + + def read_nonblock(maxlen, buf=nil) + if maxlen == 0 + if buf + buf.clear + return buf + else + return "" + end + end + if @rbuffer.empty? + return sysread_nonblock(maxlen, buf) + end + ret = consume_rbuff(maxlen) + if buf + buf.replace(ret) + ret = buf + end + raise EOFError if ret.empty? + ret + end + + ## + # Reads the next "line+ from the stream. Lines are separated by +eol+. If + # +limit+ is provided the result will not be longer than the given number of + # bytes. + # + # +eol+ may be a String or Regexp. + # + # Unlike IO#gets the line read will not be assigned to +$_+. + # + # Unlike IO#gets the separator must be provided if a limit is provided. + + def gets(eol=$/, limit=nil) + idx = @rbuffer.index(eol) + until @eof + break if idx + fill_rbuff + idx = @rbuffer.index(eol) + end + if eol.is_a?(Regexp) + size = idx ? idx+$&.size : nil + else + size = idx ? idx+eol.size : nil + end + if limit and limit >= 0 + size = [size, limit].min + end + consume_rbuff(size) + end + + ## + # Executes the block for every line in the stream where lines are separated + # by +eol+. + # + # See also #gets + + def each(eol=$/) + while line = self.gets(eol) + yield line + end + end + alias each_line each + + ## + # Reads lines from the stream which are separated by +eol+. + # + # See also #gets + + def readlines(eol=$/) + ary = [] + while line = self.gets(eol) + ary << line + end + ary + end + + ## + # Reads a line from the stream which is separated by +eol+. + # + # Raises EOFError if at end of file. + + def readline(eol=$/) + raise EOFError if eof? + gets(eol) + end + + ## + # Reads one character from the stream. Returns nil if called at end of + # file. + + def getc + read(1) + end + + ## + # Calls the given block once for each byte in the stream. + + def each_byte # :yields: byte + while c = getc + yield(c.ord) + end + end + + ## + # Reads a one-character string from the stream. Raises an EOFError at end + # of file. + + def readchar + raise EOFError if eof? + getc + end + + ## + # Pushes character +c+ back onto the stream such that a subsequent buffered + # character read will return it. + # + # Unlike IO#getc multiple bytes may be pushed back onto the stream. + # + # Has no effect on unbuffered reads (such as #sysread). + + def ungetc(c) + @rbuffer[0,0] = c.chr + end + + ## + # Returns true if the stream is at file which means there is no more data to + # be read. + + def eof? + fill_rbuff if !@eof && @rbuffer.empty? + @eof && @rbuffer.empty? + end + alias eof eof? + + # + # for writing. + # + private + + ## + # Writes +s+ to the buffer. When the buffer is full or #sync is true the + # buffer is flushed to the underlying socket. + + def do_write(s) + @wbuffer = "" unless defined? @wbuffer + @wbuffer << s + @sync ||= false + if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) + remain = idx ? idx + $/.size : @wbuffer.length + nwritten = 0 + while remain > 0 + str = @wbuffer[nwritten,remain] + begin + nwrote = syswrite(str) + rescue Errno::EAGAIN + retry + end + remain -= nwrote + nwritten += nwrote + end + @wbuffer[0,nwritten] = "" + end + end + + public + + ## + # Writes +s+ to the stream. If the argument is not a string it will be + # converted using String#to_s. Returns the number of bytes written. + + def write(s) + do_write(s) + s.length + end + + ## + # Writes +str+ in the non-blocking manner. + # + # If there is buffered data, it is flushed first. This may block. + # + # write_nonblock returns number of bytes written to the SSL connection. + # + # When no data can be written without blocking it raises + # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. + # + # IO::WaitReadable means SSL needs to read internally so write_nonblock + # should be called again after the underlying IO is readable. + # + # IO::WaitWritable means SSL needs to write internally so write_nonblock + # should be called again after underlying IO is writable. + # + # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows. + # + # # emulates blocking write. + # begin + # result = ssl.write_nonblock(str) + # rescue IO::WaitReadable + # IO.select([io]) + # retry + # rescue IO::WaitWritable + # IO.select(nil, [io]) + # retry + # end + # + # Note that one reason that write_nonblock reads from the underlying IO + # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ + # for more details. http://www.openssl.org/support/faq.html + + def write_nonblock(s) + flush + syswrite_nonblock(s) + end + + ## + # Writes +s+ to the stream. +s+ will be converted to a String using + # String#to_s. + + def << (s) + do_write(s) + self + end + + ## + # Writes +args+ to the stream along with a record separator. + # + # See IO#puts for full details. + + def puts(*args) + s = "" + if args.empty? + s << "\n" + end + args.each{|arg| + s << arg.to_s + if $/ && /\n\z/ !~ s + s << "\n" + end + } + do_write(s) + nil + end + + ## + # Writes +args+ to the stream. + # + # See IO#print for full details. + + def print(*args) + s = "" + args.each{ |arg| s << arg.to_s } + do_write(s) + nil + end + + ## + # Formats and writes to the stream converting parameters under control of + # the format string. + # + # See Kernel#sprintf for format string details. + + def printf(s, *args) + do_write(s % args) + nil + end + + ## + # Flushes buffered data to the SSLSocket. + + def flush + osync = @sync + @sync = true + do_write "" + return self + ensure + @sync = osync + end + + ## + # Closes the SSLSocket and flushes any unwritten data. + + def close + flush rescue nil + sysclose + end +end diff --git a/lib/1.9/openssl/cipher.rb b/lib/1.9/openssl/cipher.rb new file mode 100644 index 0000000..f365477 --- /dev/null +++ b/lib/1.9/openssl/cipher.rb @@ -0,0 +1,65 @@ +#-- +# +# $RCSfile$ +# +# = Ruby-space predefined Cipher subclasses +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos +# All rights reserved. +# +# = Licence +# This program is licenced under the same licence as Ruby. +# (See the file 'LICENCE'.) +# +# = Version +# $Id: cipher.rb 33067 2011-08-25 00:52:10Z drbrain $ +# +#++ + +module OpenSSL + class Cipher + %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| + klass = Class.new(Cipher){ + define_method(:initialize){|*args| + cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } + super(cipher_name) + } + } + const_set(name, klass) + } + + %w(128 192 256).each{|keylen| + klass = Class.new(Cipher){ + define_method(:initialize){|mode| + mode ||= "CBC" + cipher_name = "AES-#{keylen}-#{mode}" + super(cipher_name) + } + } + const_set("AES#{keylen}", klass) + } + + # Generate, set, and return a random key. + # You must call cipher.encrypt or cipher.decrypt before calling this method. + def random_key + str = OpenSSL::Random.random_bytes(self.key_len) + self.key = str + return str + end + + # Generate, set, and return a random iv. + # You must call cipher.encrypt or cipher.decrypt before calling this method. + def random_iv + str = OpenSSL::Random.random_bytes(self.iv_len) + self.iv = str + return str + end + + # This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future. + class Cipher < Cipher + # add warning + end + end # Cipher +end # OpenSSL diff --git a/lib/1.9/openssl/config.rb b/lib/1.9/openssl/config.rb new file mode 100644 index 0000000..24a54c9 --- /dev/null +++ b/lib/1.9/openssl/config.rb @@ -0,0 +1,313 @@ +=begin += Ruby-space definitions that completes C-space funcs for Config + += Info + Copyright (C) 2010 Hiroshi Nakamura + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + +=end + +require 'stringio' + +module OpenSSL + class Config + include Enumerable + + class << self + def parse(str) + c = new() + parse_config(StringIO.new(str)).each do |section, hash| + c[section] = hash + end + c + end + + alias load new + + def parse_config(io) + begin + parse_config_lines(io) + rescue ConfigError => e + e.message.replace("error in line #{io.lineno}: " + e.message) + raise + end + end + + def get_key_string(data, section, key) # :nodoc: + if v = data[section] && data[section][key] + return v + elsif section == 'ENV' + if v = ENV[key] + return v + end + end + if v = data['default'] && data['default'][key] + return v + end + end + + private + + def parse_config_lines(io) + section = 'default' + data = {section => {}} + while definition = get_definition(io) + definition = clear_comments(definition) + next if definition.empty? + if definition[0] == ?[ + if /\[([^\]]*)\]/ =~ definition + section = $1.strip + data[section] ||= {} + else + raise ConfigError, "missing close square bracket" + end + else + if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition + if $2 + section = $1 + key = $2 + else + key = $1 + end + value = unescape_value(data, section, $3) + (data[section] ||= {})[key] = value.strip + else + raise ConfigError, "missing equal sign" + end + end + end + data + end + + # escape with backslash + QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ + # escape with backslash and doubled dq + QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ + # escaped char map + ESCAPE_MAP = { + "r" => "\r", + "n" => "\n", + "b" => "\b", + "t" => "\t", + } + + def unescape_value(data, section, value) + scanned = [] + while m = value.match(/['"\\$]/) + scanned << m.pre_match + c = m[0] + value = m.post_match + case c + when "'" + if m = value.match(QUOTE_REGEXP_SQ) + scanned << m[1].gsub(/\\(.)/, '\\1') + value = m.post_match + else + break + end + when '"' + if m = value.match(QUOTE_REGEXP_DQ) + scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') + value = m.post_match + else + break + end + when "\\" + c = value.slice!(0, 1) + scanned << (ESCAPE_MAP[c] || c) + when "$" + ref, value = extract_reference(value) + refsec = section + if ref.index('::') + refsec, ref = ref.split('::', 2) + end + if v = get_key_string(data, refsec, ref) + scanned << v + else + raise ConfigError, "variable has no value" + end + else + raise 'must not reaced' + end + end + scanned << value + scanned.join + end + + def extract_reference(value) + rest = '' + if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) + value = m[1] || m[2] + rest = m.post_match + elsif [?(, ?{].include?(value[0]) + raise ConfigError, "no close brace" + end + if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) + return m[0], m.post_match + rest + else + raise + end + end + + def clear_comments(line) + # FCOMMENT + if m = line.match(/\A([\t\n\f ]*);.*\z/) + return m[1] + end + # COMMENT + scanned = [] + while m = line.match(/[#'"\\]/) + scanned << m.pre_match + c = m[0] + line = m.post_match + case c + when '#' + line = nil + break + when "'", '"' + regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ + scanned << c + if m = line.match(regexp) + scanned << m[0] + line = m.post_match + else + scanned << line + line = nil + break + end + when "\\" + scanned << c + scanned << line.slice!(0, 1) + else + raise 'must not reaced' + end + end + scanned << line + scanned.join + end + + def get_definition(io) + if line = get_line(io) + while /[^\\]\\\z/ =~ line + if extra = get_line(io) + line += extra + else + break + end + end + return line.strip + end + end + + def get_line(io) + if line = io.gets + line.gsub(/[\r\n]*/, '') + end + end + end + + def initialize(filename = nil) + @data = {} + if filename + File.open(filename.to_s) do |file| + Config.parse_config(file).each do |section, hash| + self[section] = hash + end + end + end + end + + def get_value(section, key) + if section.nil? + raise TypeError.new('nil not allowed') + end + section = 'default' if section.empty? + get_key_string(section, key) + end + + def value(arg1, arg2 = nil) + warn('Config#value is deprecated; use Config#get_value') + if arg2.nil? + section, key = 'default', arg1 + else + section, key = arg1, arg2 + end + section ||= 'default' + section = 'default' if section.empty? + get_key_string(section, key) + end + + def add_value(section, key, value) + check_modify + (@data[section] ||= {})[key] = value + end + + def [](section) + @data[section] || {} + end + + def section(name) + warn('Config#section is deprecated; use Config#[]') + @data[name] || {} + end + + def []=(section, pairs) + check_modify + @data[section] ||= {} + pairs.each do |key, value| + self.add_value(section, key, value) + end + end + + def sections + @data.keys + end + + def to_s + ary = [] + @data.keys.sort.each do |section| + ary << "[ #{section} ]\n" + @data[section].keys.each do |key| + ary << "#{key}=#{@data[section][key]}\n" + end + ary << "\n" + end + ary.join + end + + def each + @data.each do |section, hash| + hash.each do |key, value| + yield [section, key, value] + end + end + end + + def inspect + "#<#{self.class.name} sections=#{sections.inspect}>" + end + + protected + + def data + @data + end + + private + + def initialize_copy(other) + @data = other.data.dup + end + + def check_modify + raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? + end + + def get_key_string(section, key) + Config.get_key_string(@data, section, key) + end + end +end diff --git a/lib/1.9/openssl/digest.rb b/lib/1.9/openssl/digest.rb new file mode 100644 index 0000000..09bd858 --- /dev/null +++ b/lib/1.9/openssl/digest.rb @@ -0,0 +1,72 @@ +#-- +# +# $RCSfile$ +# +# = Ruby-space predefined Digest subclasses +# +# = Info +# 'OpenSSL for Ruby 2' project +# Copyright (C) 2002 Michal Rokos +# All rights reserved. +# +# = Licence +# This program is licenced under the same licence as Ruby. +# (See the file 'LICENCE'.) +# +# = Version +# $Id: digest.rb 33067 2011-08-25 00:52:10Z drbrain $ +# +#++ + +module OpenSSL + class Digest + + alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) + if OPENSSL_VERSION_NUMBER > 0x00908000 + alg += %w(SHA224 SHA256 SHA384 SHA512) + end + + # Return the +data+ hash computed with +name+ Digest. +name+ is either the + # long name or short name of a supported digest algorithm. + # + # === Examples + # + # OpenSSL::Digest.digest("SHA256, "abc") + # + # which is equivalent to: + # + # OpenSSL::Digest::SHA256.digest("abc") + + def self.digest(name, data) + super(data, name) + end + + alg.each{|name| + klass = Class.new(Digest){ + define_method(:initialize){|*data| + if data.length > 1 + raise ArgumentError, + "wrong number of arguments (#{data.length} for 1)" + end + super(name, data.first) + } + } + singleton = (class << klass; self; end) + singleton.class_eval{ + define_method(:digest){|data| Digest.digest(name, data) } + define_method(:hexdigest){|data| Digest.hexdigest(name, data) } + } + const_set(name, klass) + } + + # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. + class Digest < Digest + def initialize(*args) + # add warning + super(*args) + end + end + + end # Digest +end # OpenSSL + diff --git a/lib/1.9/openssl/ssl-internal.rb b/lib/1.9/openssl/ssl-internal.rb new file mode 100644 index 0000000..9c0320c --- /dev/null +++ b/lib/1.9/openssl/ssl-internal.rb @@ -0,0 +1,177 @@ +=begin += $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL + += Info + 'OpenSSL for Ruby 2' project + Copyright (C) 2001 GOTOU YUUZOU + All rights reserved. + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + += Version + $Id: ssl-internal.rb 29189 2010-09-06 01:53:00Z nahi $ +=end + +require "openssl/buffering" +require "fcntl" + +module OpenSSL + module SSL + class SSLContext + DEFAULT_PARAMS = { + :ssl_version => "SSLv23", + :verify_mode => OpenSSL::SSL::VERIFY_PEER, + :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", + :options => OpenSSL::SSL::OP_ALL, + } + + DEFAULT_CERT_STORE = OpenSSL::X509::Store.new + DEFAULT_CERT_STORE.set_default_paths + if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) + DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + end + + def set_params(params={}) + params = DEFAULT_PARAMS.merge(params) + params.each{|name, value| self.__send__("#{name}=", value) } + if self.verify_mode != OpenSSL::SSL::VERIFY_NONE + unless self.ca_file or self.ca_path or self.cert_store + self.cert_store = DEFAULT_CERT_STORE + end + end + return params + end + end + + module SocketForwarder + def addr + to_io.addr + end + + def peeraddr + to_io.peeraddr + end + + def setsockopt(level, optname, optval) + to_io.setsockopt(level, optname, optval) + end + + def getsockopt(level, optname) + to_io.getsockopt(level, optname) + end + + def fcntl(*args) + to_io.fcntl(*args) + end + + def closed? + to_io.closed? + end + + def do_not_reverse_lookup=(flag) + to_io.do_not_reverse_lookup = flag + end + end + + module Nonblock + def initialize(*args) + flag = File::NONBLOCK + flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) + @io.fcntl(Fcntl::F_SETFL, flag) + super + end + end + + def verify_certificate_identity(cert, hostname) + should_verify_common_name = true + cert.extensions.each{|ext| + next if ext.oid != "subjectAltName" + ext.value.split(/,\s+/).each{|general_name| + if /\ADNS:(.*)/ =~ general_name + should_verify_common_name = false + reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") + return true if /\A#{reg}\z/i =~ hostname + elsif /\AIP Address:(.*)/ =~ general_name + should_verify_common_name = false + return true if $1 == hostname + end + } + } + if should_verify_common_name + cert.subject.to_a.each{|oid, value| + if oid == "CN" + reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") + return true if /\A#{reg}\z/i =~ hostname + end + } + end + return false + end + module_function :verify_certificate_identity + + class SSLSocket + include Buffering + include SocketForwarder + include Nonblock + + def post_connection_check(hostname) + unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) + raise SSLError, "hostname does not match the server certificate" + end + return true + end + + def session + SSL::Session.new(self) + rescue SSL::Session::SessionError + nil + end + end + + class SSLServer + include SocketForwarder + attr_accessor :start_immediately + + def initialize(svr, ctx) + @svr = svr + @ctx = ctx + unless ctx.session_id_context + session_id = OpenSSL::Digest::MD5.hexdigest($0) + @ctx.session_id_context = session_id + end + @start_immediately = true + end + + def to_io + @svr + end + + def listen(backlog=5) + @svr.listen(backlog) + end + + def shutdown(how=Socket::SHUT_RDWR) + @svr.shutdown(how) + end + + def accept + sock = @svr.accept + begin + ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) + ssl.sync_close = true + ssl.accept if @start_immediately + ssl + rescue SSLError => ex + sock.close + raise ex + end + end + + def close + @svr.close + end + end + end +end diff --git a/lib/1.9/openssl/ssl.rb b/lib/1.9/openssl/ssl.rb new file mode 100644 index 0000000..15f42d6 --- /dev/null +++ b/lib/1.9/openssl/ssl.rb @@ -0,0 +1,2 @@ +warn 'deprecated openssl/ssl use: require "openssl" instead of "openssl/ssl"' +require 'openssl' diff --git a/lib/1.9/openssl/x509-internal.rb b/lib/1.9/openssl/x509-internal.rb new file mode 100644 index 0000000..d92d5d9 --- /dev/null +++ b/lib/1.9/openssl/x509-internal.rb @@ -0,0 +1,158 @@ +=begin += $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses + += Info + 'OpenSSL for Ruby 2' project + Copyright (C) 2002 Michal Rokos + All rights reserved. + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + += Version + $Id: x509-internal.rb 32663 2011-07-25 04:51:26Z nahi $ +=end + +module OpenSSL + module X509 + class ExtensionFactory + def create_extension(*arg) + if arg.size > 1 + create_ext(*arg) + else + send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) + end + end + + def create_ext_from_array(ary) + raise ExtensionError, "unexpected array form" if ary.size > 3 + create_ext(ary[0], ary[1], ary[2]) + end + + def create_ext_from_string(str) # "oid = critical, value" + oid, value = str.split(/=/, 2) + oid.strip! + value.strip! + create_ext(oid, value) + end + + def create_ext_from_hash(hash) + create_ext(hash["oid"], hash["value"], hash["critical"]) + end + end + + class Extension + def to_s # "oid = critical, value" + str = self.oid + str << " = " + str << "critical, " if self.critical? + str << self.value.gsub(/\n/, ", ") + end + + def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} + {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} + end + + def to_a + [ self.oid, self.value, self.critical? ] + end + end + + class Name + module RFC2253DN + Special = ',=+<>#;' + HexChar = /[0-9a-fA-F]/ + HexPair = /#{HexChar}#{HexChar}/ + HexString = /#{HexPair}+/ + Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ + StringChar = /[^#{Special}\\"]/ + QuoteChar = /[^\\"]/ + AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ + AttributeValue = / + (?!["#])((?:#{StringChar}|#{Pair})*)| + \#(#{HexString})| + "((?:#{QuoteChar}|#{Pair})*)" + /x + TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ + + module_function + + def expand_pair(str) + return nil unless str + return str.gsub(Pair){ + pair = $& + case pair.size + when 2 then pair[1,1] + when 3 then Integer("0x#{pair[1,2]}").chr + else raise OpenSSL::X509::NameError, "invalid pair: #{str}" + end + } + end + + def expand_hexstring(str) + return nil unless str + der = str.gsub(HexPair){$&.to_i(16).chr } + a1 = OpenSSL::ASN1.decode(der) + return a1.value, a1.tag + end + + def expand_value(str1, str2, str3) + value = expand_pair(str1) + value, tag = expand_hexstring(str2) unless value + value = expand_pair(str3) unless value + return value, tag + end + + def scan(dn) + str = dn + ary = [] + while true + if md = TypeAndValue.match(str) + remain = md.post_match + type = md[1] + value, tag = expand_value(md[2], md[3], md[4]) rescue nil + if value + type_and_value = [type, value] + type_and_value.push(tag) if tag + ary.unshift(type_and_value) + if remain.length > 2 && remain[0] == ?, + str = remain[1..-1] + next + elsif remain.length > 2 && remain[0] == ?+ + raise OpenSSL::X509::NameError, + "multi-valued RDN is not supported: #{dn}" + elsif remain.empty? + break + end + end + end + msg_dn = dn[0, dn.length - str.length] + " =>" + str + raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" + end + return ary + end + end + + class << self + def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE) + ary = OpenSSL::X509::Name::RFC2253DN.scan(str) + self.new(ary, template) + end + + def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE) + ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) } + self.new(ary, template) + end + + alias parse parse_openssl + end + end + + class StoreContext + def cleanup + warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE + end + end + end +end diff --git a/lib/1.9/openssl/x509.rb b/lib/1.9/openssl/x509.rb new file mode 100644 index 0000000..f1777cd --- /dev/null +++ b/lib/1.9/openssl/x509.rb @@ -0,0 +1,2 @@ +warn 'deprecated openssl/x509 use: require "openssl" instead of "openssl/x509"' +require 'openssl' diff --git a/test/1.9/ssl_server.rb b/test/1.9/ssl_server.rb new file mode 100644 index 0000000..d3ad55d --- /dev/null +++ b/test/1.9/ssl_server.rb @@ -0,0 +1,81 @@ +require "socket" +require "thread" +require "openssl" +require File.join(File.dirname(__FILE__), "utils.rb") + +def get_pem(io=$stdin) + buf = "" + while line = io.gets + if /^-----BEGIN / =~ line + buf << line + break + end + end + while line = io.gets + buf << line + if /^-----END / =~ line + break + end + end + return buf +end + +def make_key(pem) + begin + return OpenSSL::PKey::RSA.new(pem) + rescue + return OpenSSL::PKey::DSA.new(pem) + end +end + +ca_cert = OpenSSL::X509::Certificate.new(get_pem) +ssl_cert = OpenSSL::X509::Certificate.new(get_pem) +ssl_key = make_key(get_pem) +port = Integer(ARGV.shift) +verify_mode = Integer(ARGV.shift) +start_immediately = (/yes/ =~ ARGV.shift) + +store = OpenSSL::X509::Store.new +store.add_cert(ca_cert) +store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT +ctx = OpenSSL::SSL::SSLContext.new +ctx.cert_store = store +#ctx.extra_chain_cert = [ ca_cert ] +ctx.cert = ssl_cert +ctx.key = ssl_key +ctx.verify_mode = verify_mode + +Socket.do_not_reverse_lookup = true +tcps = nil +100.times{|i| + begin + tcps = TCPServer.new("0.0.0.0", port+i) + port = port + i + break + rescue Errno::EADDRINUSE + next + end +} +ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) +ssls.start_immediately = start_immediately + +$stdout.sync = true +$stdout.puts Process.pid +$stdout.puts port + +loop do + ssl = ssls.accept rescue next + Thread.start{ + q = Queue.new + th = Thread.start{ ssl.write(q.shift) while true } + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.accept + next + end + q.push(line) + end + th.kill if q.empty? + ssl.close + } +end diff --git a/test/1.9/test_asn1.rb b/test/1.9/test_asn1.rb new file mode 100644 index 0000000..0932476 --- /dev/null +++ b/test/1.9/test_asn1.rb @@ -0,0 +1,589 @@ +require_relative 'utils' + +class OpenSSL::TestASN1 < Test::Unit::TestCase + def test_decode + subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") + key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + now = Time.at(Time.now.to_i) # suppress usec + s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf + exts = [ + ["basicConstraints","CA:TRUE,pathlen:1",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ] + dgst = OpenSSL::Digest::SHA1.new + cert = OpenSSL::TestUtils.issue_cert( + subj, key, s, now, now+3600, exts, nil, nil, dgst) + + + asn1 = OpenSSL::ASN1.decode(cert) + assert_equal(OpenSSL::ASN1::Sequence, asn1.class) + assert_equal(3, asn1.value.size) + tbs_cert, sig_alg, sig_val = *asn1.value + + assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class) + assert_equal(8, tbs_cert.value.size) + + version = tbs_cert.value[0] + assert_equal(:CONTEXT_SPECIFIC, version.tag_class) + assert_equal(0, version.tag) + assert_equal(1, version.value.size) + assert_equal(OpenSSL::ASN1::Integer, version.value[0].class) + assert_equal(2, version.value[0].value) + + serial = tbs_cert.value[1] + assert_equal(OpenSSL::ASN1::Integer, serial.class) + assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value) + + sig = tbs_cert.value[2] + assert_equal(OpenSSL::ASN1::Sequence, sig.class) + assert_equal(2, sig.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class) + assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid) + assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) + + dn = tbs_cert.value[3] # issuer + assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) + assert_equal(OpenSSL::ASN1::Sequence, dn.class) + assert_equal(3, dn.value.size) + assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) + assert_equal(1, dn.value[0].value.size) + assert_equal(1, dn.value[1].value.size) + assert_equal(1, dn.value[2].value.size) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) + assert_equal(2, dn.value[0].value[0].value.size) + assert_equal(2, dn.value[1].value[0].value.size) + assert_equal(2, dn.value[2].value[0].value.size) + oid, value = *dn.value[0].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("org", value.value) + oid, value = *dn.value[1].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("ruby-lang", value.value) + oid, value = *dn.value[2].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("2.5.4.3", oid.oid) + assert_equal(OpenSSL::ASN1::UTF8String, value.class) + assert_equal("TestCA", value.value) + + validity = tbs_cert.value[4] + assert_equal(OpenSSL::ASN1::Sequence, validity.class) + assert_equal(2, validity.value.size) + assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class) + assert_equal(now, validity.value[0].value) + assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class) + assert_equal(now+3600, validity.value[1].value) + + dn = tbs_cert.value[5] # subject + assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash) + assert_equal(OpenSSL::ASN1::Sequence, dn.class) + assert_equal(3, dn.value.size) + assert_equal(OpenSSL::ASN1::Set, dn.value[0].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[1].class) + assert_equal(OpenSSL::ASN1::Set, dn.value[2].class) + assert_equal(1, dn.value[0].value.size) + assert_equal(1, dn.value[1].value.size) + assert_equal(1, dn.value[2].value.size) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class) + assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class) + assert_equal(2, dn.value[0].value[0].value.size) + assert_equal(2, dn.value[1].value[0].value.size) + assert_equal(2, dn.value[2].value[0].value.size) + oid, value = *dn.value[0].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("org", value.value) + oid, value = *dn.value[1].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("0.9.2342.19200300.100.1.25", oid.oid) + assert_equal(OpenSSL::ASN1::IA5String, value.class) + assert_equal("ruby-lang", value.value) + oid, value = *dn.value[2].value[0].value + assert_equal(OpenSSL::ASN1::ObjectId, oid.class) + assert_equal("2.5.4.3", oid.oid) + assert_equal(OpenSSL::ASN1::UTF8String, value.class) + assert_equal("TestCA", value.value) + + pkey = tbs_cert.value[6] + assert_equal(OpenSSL::ASN1::Sequence, pkey.class) + assert_equal(2, pkey.value.size) + assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class) + assert_equal(2, pkey.value[0].value.size) + assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) + assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) + assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class) + assert_equal(0, pkey.value[1].unused_bits) + spkey = OpenSSL::ASN1.decode(pkey.value[1].value) + assert_equal(OpenSSL::ASN1::Sequence, spkey.class) + assert_equal(2, spkey.value.size) + assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) + assert_equal(143085709396403084580358323862163416700436550432664688288860593156058579474547937626086626045206357324274536445865308750491138538454154232826011964045825759324933943290377903384882276841880081931690695505836279972214003660451338124170055999155993192881685495391496854691199517389593073052473319331505702779271, spkey.value[0].value) + assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) + assert_equal(65537, spkey.value[1].value) + + extensions = tbs_cert.value[7] + assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) + assert_equal(3, extensions.tag) + assert_equal(1, extensions.value.size) + assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class) + assert_equal(3, extensions.value[0].value.size) + + ext = extensions.value[0].value[0] # basicConstraints + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(3, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.19", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) + assert_equal(true, ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) + extv = OpenSSL::ASN1.decode(ext.value[2].value) + assert_equal(OpenSSL::ASN1::Sequence, extv.class) + assert_equal(2, extv.value.size) + assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class) + assert_equal(true, extv.value[0].value) + assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class) + assert_equal(1, extv.value[1].value) + + ext = extensions.value[0].value[1] # keyUsage + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(3, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.15", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class) + assert_equal(true, ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class) + extv = OpenSSL::ASN1.decode(ext.value[2].value) + assert_equal(OpenSSL::ASN1::BitString, extv.class) + str = "\000"; str[0] = 0b00000110.chr + assert_equal(str, extv.value) + + ext = extensions.value[0].value[2] # subjetKeyIdentifier + assert_equal(OpenSSL::ASN1::Sequence, ext.class) + assert_equal(2, ext.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) + assert_equal("2.5.29.14", ext.value[0].oid) + assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class) + extv = OpenSSL::ASN1.decode(ext.value[1].value) + assert_equal(OpenSSL::ASN1::OctetString, extv.class) + sha1 = OpenSSL::Digest::SHA1.new + sha1.update(pkey.value[1].value) + assert_equal(sha1.digest, extv.value) + + assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class) + assert_equal(2, sig_alg.value.size) + assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class) + assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid) + assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class) + + assert_equal(OpenSSL::ASN1::BitString, sig_val.class) + cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der) + assert_equal(cululated_sig, sig_val.value) + end + + def test_encode_boolean + encode_decode_test(OpenSSL::ASN1::Boolean, [true, false]) + end + + def test_encode_integer + encode_decode_test(OpenSSL::ASN1::Integer, [72, -127, -128, 128, -1, 0, 1, -(2**12345), 2**12345]) + end + + def encode_decode_test(type, values) + values.each do |v| + assert_equal(v, OpenSSL::ASN1.decode(type.new(v).to_der).value) + end + end + + def test_decode_pem #should fail gracefully (cf. [ruby-dev:44542]) + pem = <<-_EOS_ +-----BEGIN CERTIFICATE----- +MIIC8zCCAdugAwIBAgIBATANBgkqhkiG9w0BAQUFADA9MRMwEQYKCZImiZPyLGQB +GRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMQswCQYDVQQDDAJDQTAe +Fw0xMTA5MjUxMzQ4MjZaFw0xMTA5MjUxNDQ4MjZaMD0xEzARBgoJkiaJk/IsZAEZ +FgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5LWxhbmcxCzAJBgNVBAMMAkNBMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuV9ht9J7k4NBs38jOXvvTKY9 +gW8nLICSno5EETR1cuF7i4pNs9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enen +fzq/t/e/1IRW0wkJUJUFQign4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWm +qbjs07JbuS4QQGGXLc+Su96DkYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v6 +8JkRFIhdGlb6JL8fllf/A/blNwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX +9KZYcU00mOX+fdxOSnGqS/8JDRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wID +AQABMA0GCSqGSIb3DQEBBQUAA4IBAQAiAtrIr1pLX4GYN5klviWKb8HC9ICYuAFI +NfE3FwqzErEVXotuMe3yPVyB3Bv6rjYY/x5EtS5+WPTbHlvHZTkfcsnTpizcn4mW +dJ6dDRaFCHt1YKKjUxqBt9lvvrc3nReYZN/P+s1mrDhWzGf8iPZgf8sFUHgnaK7W +CXRVXmPFgCDRNpDDVQ0MQkr509yYfTH+dujNzqTCwSvkyZFyQ7Oe8Yj0VR6kquG3 +rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm +/93PnPG1IvPjYNd5VlV+sXSnaxQn974HRCsMv7jA8BD6IgSaX6WK +-----END CERTIFICATE----- + _EOS_ + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode(pem) } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode_all(pem) } + end + + def test_primitive_cannot_set_infinite_length + begin + prim = OpenSSL::ASN1::Integer.new(50) + assert_equal(false, prim.infinite_length) + prim.infinite_length = true + flunk('Could set infinite length on primitive value') + rescue NoMethodError => e + #ok + end + end + + def test_decode_all + expected = %w{ 02 01 01 02 01 02 02 01 03 } + raw = [expected.join('')].pack('H*') + ary = OpenSSL::ASN1.decode_all(raw) + assert_equal(3, ary.size) + ary.each_with_index do |asn1, i| + assert_universal(OpenSSL::ASN1::INTEGER, asn1) + assert_equal(i + 1, asn1.value) + end + end + + def test_create_inf_length_primitive + expected = %w{ 24 80 04 01 61 00 00 } + raw = [expected.join('')].pack('H*') + val = OpenSSL::ASN1::OctetString.new('a') + cons = OpenSSL::ASN1::Constructive.new([val, + OpenSSL::ASN1::EndOfContent.new], + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + cons.infinite_length = true + assert_equal(nil, cons.tagging) + assert_equal(raw, cons.to_der) + asn1 = OpenSSL::ASN1.decode(raw) + assert(asn1.infinite_length) + assert_equal(raw, asn1.to_der) + end + + def test_cons_without_inf_length_forbidden + assert_raise(OpenSSL::ASN1::ASN1Error) do + val = OpenSSL::ASN1::OctetString.new('a') + cons = OpenSSL::ASN1::Constructive.new([val], + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + cons.to_der + end + end + + def test_cons_without_array_forbidden + assert_raise(OpenSSL::ASN1::ASN1Error) do + val = OpenSSL::ASN1::OctetString.new('a') + cons = OpenSSL::ASN1::Constructive.new(val, + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + cons.infinite_length = true + cons.to_der + end + end + + def test_parse_empty_sequence + expected = %w{ A0 07 30 02 30 00 02 01 00 } + raw = [expected.join('')].pack('H*') + asn1 = OpenSSL::ASN1.decode(raw) + assert_equal(raw, asn1.to_der) + assert_equal(2, asn1.value.size) + seq = asn1.value[0] + assert_equal(1, seq.value.size) + inner_seq = seq.value[0] + assert_equal(0, inner_seq.value.size) + end + + def test_parse_tagged_0_infinite + expected = %w{ 30 80 02 01 01 80 01 02 00 00 } + raw = [expected.join('')].pack('H*') + asn1 = OpenSSL::ASN1.decode(raw) + assert_equal(3, asn1.value.size) + int = asn1.value[0] + assert_universal(OpenSSL::ASN1::INTEGER, int) + tagged = asn1.value[1] + assert_equal(0, tagged.tag) + assert_universal(OpenSSL::ASN1::EOC, asn1.value[2]) + assert_equal(raw, asn1.to_der) + end + + def test_seq_infinite_length + begin + content = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new ] + cons = OpenSSL::ASN1::Sequence.new(content) + cons.infinite_length = true + expected = %w{ 30 80 05 00 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_set_infinite_length + begin + content = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Set.new(content) + cons.infinite_length = true + expected = %w{ 31 80 05 00 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_octet_string_infinite_length + begin + octets = [ OpenSSL::ASN1::OctetString.new('aaa'), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new( + octets, + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + cons.infinite_length = true + expected = %w{ 24 80 04 03 61 61 61 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_prim_explicit_tagging + begin + oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) + expected = %w{ A0 03 04 01 61 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, oct_str.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_prim_explicit_tagging_tag_class + begin + oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) + oct_str2 = OpenSSL::ASN1::OctetString.new( + "a", + 0, + :EXPLICIT, + :CONTEXT_SPECIFIC) + assert_equal(oct_str.to_der, oct_str2.to_der) + end + end + + def test_prim_implicit_tagging + begin + int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) + expected = %w{ 80 01 01 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, int.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_prim_implicit_tagging_tag_class + begin + int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) + int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC); + assert_equal(int.to_der, int2.to_der) + end + end + + def test_cons_explicit_tagging + begin + content = [ OpenSSL::ASN1::PrintableString.new('abc') ] + seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) + expected = %w{ A2 07 30 05 13 03 61 62 63 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, seq.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_cons_explicit_tagging_inf_length + begin + content = [ OpenSSL::ASN1::PrintableString.new('abc') , + OpenSSL::ASN1::EndOfContent.new() ] + seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) + seq.infinite_length = true + expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, seq.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_cons_implicit_tagging + begin + content = [ OpenSSL::ASN1::Null.new(nil) ] + seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) + expected = %w{ A1 02 05 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, seq.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_cons_implicit_tagging_inf_length + begin + content = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new() ] + seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) + seq.infinite_length = true + expected = %w{ A1 80 05 00 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, seq.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_octet_string_infinite_length_explicit_tagging + begin + octets = [ OpenSSL::ASN1::OctetString.new('aaa'), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new( + octets, + 1, + :EXPLICIT) + cons.infinite_length = true + expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_octet_string_infinite_length_implicit_tagging + begin + octets = [ OpenSSL::ASN1::OctetString.new('aaa'), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new( + octets, + 0, + :IMPLICIT) + cons.infinite_length = true + expected = %w{ A0 80 04 03 61 61 61 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_recursive_octet_string_infinite_length + begin + octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"), + OpenSSL::ASN1::EndOfContent.new() ] + octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"), + OpenSSL::ASN1::EndOfContent.new() ] + container1 = OpenSSL::ASN1::Constructive.new( + octets_sub1, + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + container1.infinite_length = true + container2 = OpenSSL::ASN1::Constructive.new( + octets_sub2, + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + container2.infinite_length = true + octets3 = OpenSSL::ASN1::OctetString.new("\x03") + + octets = [ container1, container2, octets3, + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new( + octets, + OpenSSL::ASN1::OCTET_STRING, + nil, + :UNIVERSAL) + cons.infinite_length = true + expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_bit_string_infinite_length + begin + content = [ OpenSSL::ASN1::BitString.new("\x01"), + OpenSSL::ASN1::EndOfContent.new() ] + cons = OpenSSL::ASN1::Constructive.new( + content, + OpenSSL::ASN1::BIT_STRING, + nil, + :UNIVERSAL) + cons.infinite_length = true + expected = %w{ 23 80 03 02 00 01 00 00 } + raw = [expected.join('')].pack('H*') + assert_equal(raw, cons.to_der) + assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) + end + end + + def test_primitive_inf_length + assert_raises(OpenSSL::ASN1::ASN1Error) do + spec = %w{ 02 80 02 01 01 00 00 } + raw = [spec.join('')].pack('H*') + OpenSSL::ASN1.decode(raw) + OpenSSL::ASN1.decode_all(raw) + end + end + + def test_recursive_octet_string_parse + test = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } + raw = [test.join('')].pack('H*') + asn1 = OpenSSL::ASN1.decode(raw) + assert_equal(OpenSSL::ASN1::Constructive, asn1.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) + assert_equal(true, asn1.infinite_length) + assert_equal(4, asn1.value.size) + nested1 = asn1.value[0] + assert_equal(OpenSSL::ASN1::Constructive, nested1.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) + assert_equal(true, nested1.infinite_length) + assert_equal(2, nested1.value.size) + oct1 = nested1.value[0] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) + assert_equal(false, oct1.infinite_length) + assert_universal(OpenSSL::ASN1::EOC, nested1.value[1]) + assert_equal(false, nested1.value[1].infinite_length) + nested2 = asn1.value[1] + assert_equal(OpenSSL::ASN1::Constructive, nested2.class) + assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) + assert_equal(true, nested2.infinite_length) + assert_equal(2, nested2.value.size) + oct2 = nested2.value[0] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) + assert_equal(false, oct2.infinite_length) + assert_universal(OpenSSL::ASN1::EOC, nested2.value[1]) + assert_equal(false, nested2.value[1].infinite_length) + oct3 = asn1.value[2] + assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) + assert_equal(false, oct3.infinite_length) + assert_universal(OpenSSL::ASN1::EOC, asn1.value[3]) + assert_equal(false, asn1.value[3].infinite_length) + end + + private + + def assert_universal(tag, asn1) + assert_equal(tag, asn1.tag) + if asn1.respond_to?(:tagging) + assert_nil(asn1.tagging) + end + assert_equal(:UNIVERSAL, asn1.tag_class) + end + +end if defined?(OpenSSL) + diff --git a/test/1.9/test_bn.rb b/test/1.9/test_bn.rb new file mode 100644 index 0000000..7136de9 --- /dev/null +++ b/test/1.9/test_bn.rb @@ -0,0 +1,23 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestBN < Test::Unit::TestCase + def test_integer_to_bn + assert_equal(999.to_bn, OpenSSL::BN.new(999.to_s(16), 16)) + assert_equal((2 ** 107 - 1).to_bn, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16)) + end + + def test_prime_p + assert_equal(true, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16).prime?) + assert_equal(true, OpenSSL::BN.new((2 ** 127 - 1).to_s(16), 16).prime?(1)) + end + + def test_cmp_nil + bn = OpenSSL::BN.new('1') + assert_equal(false, bn == nil) + assert_equal(true, bn != nil) + end +end + +end diff --git a/test/1.9/test_buffering.rb b/test/1.9/test_buffering.rb new file mode 100644 index 0000000..1e21975 --- /dev/null +++ b/test/1.9/test_buffering.rb @@ -0,0 +1,88 @@ +require_relative 'utils' +require 'stringio' + +class OpenSSL::TestBuffering < Test::Unit::TestCase + + class IO + include OpenSSL::Buffering + + attr_accessor :sync + + def initialize + @io = "" + def @io.sync + true + end + + super + + @sync = false + end + + def string + @io + end + + def sysread(size) + str = @io.slice!(0, size) + raise EOFError if str.empty? + str + end + + def syswrite(str) + @io << str + str.size + end + end + + def setup + @io = IO.new + end + + def test_flush + @io.write 'a' + + refute @io.sync + assert_empty @io.string + + assert_equal @io, @io.flush + + refute @io.sync + assert_equal 'a', @io.string + end + + def test_flush_error + @io.write 'a' + + refute @io.sync + assert_empty @io.string + + def @io.syswrite *a + raise SystemCallError, 'fail' + end + + assert_raises SystemCallError do + @io.flush + end + + refute @io.sync, 'sync must not change' + end + + def test_getc + @io.syswrite('abc') + res = [] + assert_equal(?a, @io.getc) + assert_equal(?b, @io.getc) + assert_equal(?c, @io.getc) + end + + def test_each_byte + @io.syswrite('abc') + res = [] + @io.each_byte do |c| + res << c + end + assert_equal([97, 98, 99], res) + end + +end if defined?(OpenSSL) diff --git a/test/1.9/test_cipher.rb b/test/1.9/test_cipher.rb new file mode 100644 index 0000000..eb2f4fe --- /dev/null +++ b/test/1.9/test_cipher.rb @@ -0,0 +1,105 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestCipher < Test::Unit::TestCase + def setup + @c1 = OpenSSL::Cipher::Cipher.new("DES-EDE3-CBC") + @c2 = OpenSSL::Cipher::DES.new(:EDE3, "CBC") + @key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + @iv = "\0\0\0\0\0\0\0\0" + @hexkey = "0000000000000000000000000000000000000000000000" + @hexiv = "0000000000000000" + @data = "DATA" + end + + def teardown + @c1 = @c2 = nil + end + + def test_crypt + @c1.encrypt.pkcs5_keyivgen(@key, @iv) + @c2.encrypt.pkcs5_keyivgen(@key, @iv) + s1 = @c1.update(@data) + @c1.final + s2 = @c2.update(@data) + @c2.final + assert_equal(s1, s2, "encrypt") + + @c1.decrypt.pkcs5_keyivgen(@key, @iv) + @c2.decrypt.pkcs5_keyivgen(@key, @iv) + assert_equal(@data, @c1.update(s1)+@c1.final, "decrypt") + assert_equal(@data, @c2.update(s2)+@c2.final, "decrypt") + end + + def test_info + assert_equal("DES-EDE3-CBC", @c1.name, "name") + assert_equal("DES-EDE3-CBC", @c2.name, "name") + assert_kind_of(Fixnum, @c1.key_len, "key_len") + assert_kind_of(Fixnum, @c1.iv_len, "iv_len") + end + + def test_dup + assert_equal(@c1.name, @c1.dup.name, "dup") + assert_equal(@c1.name, @c1.clone.name, "clone") + @c1.encrypt + @c1.key = @key + @c1.iv = @iv + tmpc = @c1.dup + s1 = @c1.update(@data) + @c1.final + s2 = tmpc.update(@data) + tmpc.final + assert_equal(s1, s2, "encrypt dup") + end + + def test_reset + @c1.encrypt + @c1.key = @key + @c1.iv = @iv + s1 = @c1.update(@data) + @c1.final + @c1.reset + s2 = @c1.update(@data) + @c1.final + assert_equal(s1, s2, "encrypt reset") + end + + def test_empty_data + @c1.encrypt + assert_raise(ArgumentError){ @c1.update("") } + end + + def test_initialize + assert_raise(RuntimeError) {@c1.__send__(:initialize, "DES-EDE3-CBC")} + assert_raise(RuntimeError) {OpenSSL::Cipher.allocate.final} + end + + if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00907000 + def test_ciphers + OpenSSL::Cipher.ciphers.each{|name| + assert(OpenSSL::Cipher::Cipher.new(name).is_a?(OpenSSL::Cipher::Cipher)) + } + end + + def test_AES + pt = File.read(__FILE__) + %w(ECB CBC CFB OFB).each{|mode| + c1 = OpenSSL::Cipher::AES256.new(mode) + c1.encrypt + c1.pkcs5_keyivgen("passwd") + ct = c1.update(pt) + c1.final + + c2 = OpenSSL::Cipher::AES256.new(mode) + c2.decrypt + c2.pkcs5_keyivgen("passwd") + assert_equal(pt, c2.update(ct) + c2.final) + } + end + + def test_AES_crush + 500.times do + assert_nothing_raised("[Bug #2768]") do + # it caused OpenSSL SEGV by uninitialized key + OpenSSL::Cipher::AES128.new("ECB").update "." * 17 + end + end + end + end +end + +end diff --git a/test/1.9/test_config.rb b/test/1.9/test_config.rb new file mode 100644 index 0000000..77f89b2 --- /dev/null +++ b/test/1.9/test_config.rb @@ -0,0 +1,288 @@ +require_relative 'utils' + +class OpenSSL::TestConfig < Test::Unit::TestCase + def setup + file = Tempfile.open("openssl.cnf") + file << <<__EOD__ +HOME = . +[ ca ] +default_ca = CA_default +[ CA_default ] +dir = ./demoCA +certs = ./certs +__EOD__ + file.close + @it = OpenSSL::Config.new(file.path) + end + + def test_constants + assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) + assert_nothing_raised do + OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE) + end + end + + def test_s_parse + c = OpenSSL::Config.parse('') + assert_equal("[ default ]\n\n", c.to_s) + c = OpenSSL::Config.parse(@it.to_s) + assert_equal(['CA_default', 'ca', 'default'], c.sections.sort) + end + + def test_s_parse_format + c = OpenSSL::Config.parse(<<__EOC__) + baz =qx\t # "baz = qx" + +foo::bar = baz # shortcut section::key format + default::bar = baz # ditto +a=\t \t # "a = ": trailing spaces are ignored + =b # " = b": empty key + =c # " = c": empty key (override the above line) + d= # "c = ": trailing comment is ignored + +sq = 'foo''b\\'ar' + dq ="foo""''\\"" + dq2 = foo""bar +esc=a\\r\\n\\b\\tb +foo\\bar = foo\\b\\\\ar +foo\\bar::foo\\bar = baz +[default1 default2]\t\t # space is allowed in section name + fo =b ar # space allowed in value +[emptysection] + [doller ] +foo=bar +bar = $(foo) +baz = 123$(default::bar)456${foo}798 +qux = ${baz} +quxx = $qux.$qux +__EOC__ + assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) + assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort) + assert_equal('c', c['default']['']) + assert_equal('', c['default']['a']) + assert_equal('qx', c['default']['baz']) + assert_equal('', c['default']['d']) + assert_equal('baz', c['default']['bar']) + assert_equal("foob'ar", c['default']['sq']) + assert_equal("foo''\"", c['default']['dq']) + assert_equal("foobar", c['default']['dq2']) + assert_equal("a\r\n\b\tb", c['default']['esc']) + assert_equal("foo\b\\ar", c['default']['foo\\bar']) + assert_equal('baz', c['foo']['bar']) + assert_equal('baz', c['foo\\bar']['foo\\bar']) + assert_equal('b ar', c['default1 default2']['fo']) + + # dolloer + assert_equal('bar', c['doller']['foo']) + assert_equal('bar', c['doller']['bar']) + assert_equal('123baz456bar798', c['doller']['baz']) + assert_equal('123baz456bar798', c['doller']['qux']) + assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx']) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("foo = $bar") + end + assert_equal("error in line 1: variable has no value", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("foo = $(bar") + end + assert_equal("error in line 1: no close brace", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse("f o =b ar # no space in key") + end + assert_equal("error in line 1: missing equal sign", excn.message) + + excn = assert_raise(OpenSSL::ConfigError) do + OpenSSL::Config.parse(<<__EOC__) +# comment 1 # comments + +# + # comment 2 +\t#comment 3 + [second ]\t +[third # section not terminated +__EOC__ + end + assert_equal("error in line 7: missing close square bracket", excn.message) + end + + def test_s_load + # alias of new + c = OpenSSL::Config.load + assert_equal("", c.to_s) + assert_equal([], c.sections) + # + file = Tempfile.open("openssl.cnf") + file.close + c = OpenSSL::Config.load(file.path) + assert_equal("[ default ]\n\n", c.to_s) + assert_equal(['default'], c.sections) + end + + def test_initialize + c = OpenSSL::Config.new + assert_equal("", c.to_s) + assert_equal([], c.sections) + end + + def test_initialize_with_empty_file + file = Tempfile.open("openssl.cnf") + file.close + c = OpenSSL::Config.new(file.path) + assert_equal("[ default ]\n\n", c.to_s) + assert_equal(['default'], c.sections) + end + + def test_initialize_with_example_file + assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) + end + + def test_get_value + assert_equal('CA_default', @it.get_value('ca', 'default_ca')) + assert_equal(nil, @it.get_value('ca', 'no such key')) + assert_equal(nil, @it.get_value('no such section', 'no such key')) + assert_equal('.', @it.get_value('', 'HOME')) + assert_raise(TypeError) do + @it.get_value(nil, 'HOME') # not allowed unlike Config#value + end + # fallback to 'default' ugly... + assert_equal('.', @it.get_value('unknown', 'HOME')) + end + + def test_get_value_ENV + key = ENV.keys.first + assert_not_nil(key) # make sure we have at least one ENV var. + assert_equal(ENV[key], @it.get_value('ENV', key)) + end + + def test_value + # supress deprecation warnings + OpenSSL::TestUtils.silent do + assert_equal('CA_default', @it.value('ca', 'default_ca')) + assert_equal(nil, @it.value('ca', 'no such key')) + assert_equal(nil, @it.value('no such section', 'no such key')) + assert_equal('.', @it.value('', 'HOME')) + assert_equal('.', @it.value(nil, 'HOME')) + assert_equal('.', @it.value('HOME')) + # fallback to 'default' ugly... + assert_equal('.', @it.value('unknown', 'HOME')) + end + end + + def test_value_ENV + OpenSSL::TestUtils.silent do + key = ENV.keys.first + assert_not_nil(key) # make sure we have at least one ENV var. + assert_equal(ENV[key], @it.value('ENV', key)) + end + end + + def test_aref + assert_equal({'HOME' => '.'}, @it['default']) + assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default']) + assert_equal({}, @it['no_such_section']) + assert_equal({}, @it['']) + end + + def test_section + OpenSSL::TestUtils.silent do + assert_equal({'HOME' => '.'}, @it.section('default')) + assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) + assert_equal({}, @it.section('no_such_section')) + assert_equal({}, @it.section('')) + end + end + + def test_sections + assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) + @it['new_section'] = {'foo' => 'bar'} + assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) + @it['new_section'] = {} + assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) + end + + def test_add_value + c = OpenSSL::Config.new + assert_equal("", c.to_s) + # add key + c.add_value('default', 'foo', 'bar') + assert_equal("[ default ]\nfoo=bar\n\n", c.to_s) + # add another key + c.add_value('default', 'baz', 'qux') + assert_equal('bar', c['default']['foo']) + assert_equal('qux', c['default']['baz']) + # update the value + c.add_value('default', 'baz', 'quxxx') + assert_equal('bar', c['default']['foo']) + assert_equal('quxxx', c['default']['baz']) + # add section and key + c.add_value('section', 'foo', 'bar') + assert_equal('bar', c['default']['foo']) + assert_equal('quxxx', c['default']['baz']) + assert_equal('bar', c['section']['foo']) + end + + def test_aset + @it['foo'] = {'bar' => 'baz'} + assert_equal({'bar' => 'baz'}, @it['foo']) + @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'} + assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + + # OpenSSL::Config is add only for now. + @it['foo'] = {'foo' => 'foo'} + assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + # you cannot override or remove any section and key. + @it['foo'] = {} + assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) + end + + def test_each + # each returns [section, key, value] array. + ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] } + assert_equal(4, ary.size) + assert_equal('CA_default', ary[0][0]) + assert_equal('CA_default', ary[1][0]) + assert_equal(["ca", "default_ca", "CA_default"], ary[2]) + assert_equal(["default", "HOME", "."], ary[3]) + end + + def test_to_s + c = OpenSSL::Config.parse("[empty]\n") + assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s) + end + + def test_inspect + assert_match(/#/, @it.inspect) + end + + def test_freeze + c = OpenSSL::Config.new + c['foo'] = [['key', 'value']] + c.freeze + + bug = '[ruby-core:18377]' + # RuntimeError for 1.9, TypeError for 1.8 + e = assert_raise(TypeError, bug) do + c['foo'] = [['key', 'wrong']] + end + assert_match(/can't modify/, e.message, bug) + end + + def test_dup + assert(!@it.sections.empty?) + c = @it.dup + assert_equal(@it.sections.sort, c.sections.sort) + @it['newsection'] = {'a' => 'b'} + assert_not_equal(@it.sections.sort, c.sections.sort) + end + + def test_clone + assert(!@it.sections.empty?) + c = @it.clone + assert_equal(@it.sections.sort, c.sections.sort) + @it['newsection'] = {'a' => 'b'} + assert_not_equal(@it.sections.sort, c.sections.sort) + end +end if defined?(OpenSSL) diff --git a/test/1.9/test_digest.rb b/test/1.9/test_digest.rb new file mode 100644 index 0000000..81085d2 --- /dev/null +++ b/test/1.9/test_digest.rb @@ -0,0 +1,118 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestDigest < Test::Unit::TestCase + def setup + @d1 = OpenSSL::Digest::Digest::new("MD5") + @d2 = OpenSSL::Digest::MD5.new + @md = Digest::MD5.new + @data = "DATA" + end + + def teardown + @d1 = @d2 = @md = nil + end + + def test_digest + assert_equal(@md.digest, @d1.digest) + assert_equal(@md.hexdigest, @d1.hexdigest) + @d1 << @data + @d2 << @data + @md << @data + assert_equal(@md.digest, @d1.digest) + assert_equal(@md.hexdigest, @d1.hexdigest) + assert_equal(@d1.digest, @d2.digest) + assert_equal(@d1.hexdigest, @d2.hexdigest) + assert_equal(@md.digest, OpenSSL::Digest::MD5.digest(@data)) + assert_equal(@md.hexdigest, OpenSSL::Digest::MD5.hexdigest(@data)) + end + + def test_eql + assert(@d1 == @d2, "==") + d = @d1.clone + assert(d == @d1, "clone") + end + + def test_info + assert_equal("MD5", @d1.name, "name") + assert_equal("MD5", @d2.name, "name") + assert_equal(16, @d1.size, "size") + end + + def test_dup + @d1.update(@data) + assert_equal(@d1.name, @d1.dup.name, "dup") + assert_equal(@d1.name, @d1.clone.name, "clone") + assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") + end + + def test_reset + @d1.update(@data) + dig1 = @d1.digest + @d1.reset + @d1.update(@data) + dig2 = @d1.digest + assert_equal(dig1, dig2, "reset") + end + + def test_digest_constants + algs = %w(DSS1 MD4 MD5 RIPEMD160 SHA SHA1) + if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 + algs += %w(SHA224 SHA256 SHA384 SHA512) + end + algs.each do |alg| + assert_not_nil(OpenSSL::Digest.new(alg)) + klass = OpenSSL::Digest.const_get(alg) + assert_not_nil(klass.new) + end + end + + def test_digest_by_oid_and_name + check_digest(OpenSSL::ASN1::ObjectId.new("MD5")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA1")) + end + + if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 + def encode16(str) + str.unpack("H*").first + end + + def test_098_features + sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" + sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" + sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" + sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" + + assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) + assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) + assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) + assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) + + assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) + assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) + assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) + assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) + end + + def test_digest_by_oid_and_name_sha2 + check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) + check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) + end + end + + private + + def check_digest(oid) + d = OpenSSL::Digest.new(oid.sn) + assert_not_nil(d) + d = OpenSSL::Digest.new(oid.ln) + assert_not_nil(d) + d = OpenSSL::Digest.new(oid.oid) + assert_not_nil(d) + end +end + +end diff --git a/test/1.9/test_engine.rb b/test/1.9/test_engine.rb new file mode 100644 index 0000000..6d90e34 --- /dev/null +++ b/test/1.9/test_engine.rb @@ -0,0 +1,15 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestEngine < Test::Unit::TestCase + + def test_engines_free # [ruby-dev:44173] + OpenSSL::Engine.load + OpenSSL::Engine.engines + OpenSSL::Engine.engines + end + +end + +end diff --git a/test/1.9/test_hmac.rb b/test/1.9/test_hmac.rb new file mode 100644 index 0000000..ba158d2 --- /dev/null +++ b/test/1.9/test_hmac.rb @@ -0,0 +1,32 @@ +require_relative 'utils' + +class OpenSSL::TestHMAC < Test::Unit::TestCase + def setup + @digest = OpenSSL::Digest::MD5 + @key = "KEY" + @data = "DATA" + @h1 = OpenSSL::HMAC.new(@key, @digest.new) + @h2 = OpenSSL::HMAC.new(@key, "MD5") + end + + def teardown + end + + def test_hmac + @h1.update(@data) + @h2.update(@data) + assert_equal(@h1.digest, @h2.digest) + + assert_equal(OpenSSL::HMAC.digest(@digest.new, @key, @data), @h1.digest, "digest") + assert_equal(OpenSSL::HMAC.hexdigest(@digest.new, @key, @data), @h1.hexdigest, "hexdigest") + + assert_equal(OpenSSL::HMAC.digest("MD5", @key, @data), @h2.digest, "digest") + assert_equal(OpenSSL::HMAC.hexdigest("MD5", @key, @data), @h2.hexdigest, "hexdigest") + end + + def test_dup + @h1.update(@data) + h = @h1.dup + assert_equal(@h1.digest, h.digest, "dup digest") + end +end if defined?(OpenSSL) diff --git a/test/1.9/test_ns_spki.rb b/test/1.9/test_ns_spki.rb new file mode 100644 index 0000000..3bcf3e6 --- /dev/null +++ b/test/1.9/test_ns_spki.rb @@ -0,0 +1,50 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestNSSPI < Test::Unit::TestCase + def setup + # This request data is adopt from the specification of + # "Netscape Extensions for User Key Generation". + # -- http://wp.netscape.com/eng/security/comm4-keygen.html + @b64 = "MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" + @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" + @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" + @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" + @b64 << "i0//rgBvmco=" + end + + def test_build_data + key1 = OpenSSL::TestUtils::TEST_KEY_RSA1024 + key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + spki = OpenSSL::Netscape::SPKI.new + spki.challenge = "RandomString" + spki.public_key = key1.public_key + spki.sign(key1, OpenSSL::Digest::SHA1.new) + assert(spki.verify(spki.public_key)) + assert(spki.verify(key1.public_key)) + assert(!spki.verify(key2.public_key)) + + der = spki.to_der + spki = OpenSSL::Netscape::SPKI.new(der) + assert_equal("RandomString", spki.challenge) + assert_equal(key1.public_key.to_der, spki.public_key.to_der) + assert(spki.verify(spki.public_key)) + end + + def test_decode_data + spki = OpenSSL::Netscape::SPKI.new(@b64) + assert_equal(@b64, spki.to_pem) + assert_equal(@b64.unpack("m").first, spki.to_der) + assert_equal("MozillaIsMyFriend", spki.challenge) + assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) + + spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) + assert_equal(@b64, spki.to_pem) + assert_equal(@b64.unpack("m").first, spki.to_der) + assert_equal("MozillaIsMyFriend", spki.challenge) + assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) + end +end + +end diff --git a/test/1.9/test_ocsp.rb b/test/1.9/test_ocsp.rb new file mode 100644 index 0000000..b42b57d --- /dev/null +++ b/test/1.9/test_ocsp.rb @@ -0,0 +1,47 @@ +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestOCSP < Test::Unit::TestCase + def setup + ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") + ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + ca_serial = 0xabcabcabcabc + + 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, [], nil, nil, dgst) + @cert = OpenSSL::TestUtils.issue_cert( + subj, @key, serial, now, now+3600, [], @ca_cert, nil, dgst) + end + + def test_new_certificate_id + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + assert_kind_of OpenSSL::OCSP::CertificateId, cid + assert_equal @cert.serial, cid.serial + end + + def test_new_certificate_id_with_digest + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) + assert_kind_of OpenSSL::OCSP::CertificateId, cid + assert_equal @cert.serial, cid.serial + end if defined?(OpenSSL::Digest::SHA256) + + def test_new_ocsp_request + 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, [@cert]) + assert_kind_of OpenSSL::OCSP::Request, request + # in current implementation not same instance of certificate id, but should contain same data + assert_equal cid.serial, request.certid.first.serial + end +end + +end diff --git a/test/1.9/test_pair.rb b/test/1.9/test_pair.rb new file mode 100644 index 0000000..940fa0c --- /dev/null +++ b/test/1.9/test_pair.rb @@ -0,0 +1,250 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +require 'socket' +require_relative '../ruby/ut_eof' + +module SSLPair + DHParam = OpenSSL::PKey::DH.new(128) + def server + host = "127.0.0.1" + port = 0 + ctx = OpenSSL::SSL::SSLContext.new() + ctx.ciphers = "ADH" + ctx.tmp_dh_callback = proc { DHParam } + tcps = TCPServer.new(host, port) + ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) + return ssls + end + + def client(port) + host = "127.0.0.1" + ctx = OpenSSL::SSL::SSLContext.new() + ctx.ciphers = "ADH" + s = TCPSocket.new(host, port) + ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) + ssl.connect + ssl.sync_close = true + ssl + end + + def ssl_pair + ssls = server + th = Thread.new { + ns = ssls.accept + ssls.close + ns + } + port = ssls.to_io.addr[1] + c = client(port) + s = th.value + if block_given? + begin + yield c, s + ensure + c.close unless c.closed? + s.close unless s.closed? + end + else + return c, s + end + ensure + if th && th.alive? + th.kill + th.join + end + end +end + +class OpenSSL::TestEOF1 < Test::Unit::TestCase + include TestEOF + include SSLPair + + def open_file(content) + s1, s2 = ssl_pair + Thread.new { s2 << content; s2.close } + yield s1 + end +end + +class OpenSSL::TestEOF2 < Test::Unit::TestCase + include TestEOF + include SSLPair + + def open_file(content) + s1, s2 = ssl_pair + Thread.new { s1 << content; s1.close } + yield s2 + end +end + +class OpenSSL::TestPair < Test::Unit::TestCase + include SSLPair + + def test_getc + ssl_pair {|s1, s2| + s1 << "a" + assert_equal(?a, s2.getc) + } + end + + def test_readpartial + ssl_pair {|s1, s2| + s2.write "a\nbcd" + assert_equal("a\n", s1.gets) + assert_equal("bcd", s1.readpartial(10)) + s2.write "efg" + assert_equal("efg", s1.readpartial(10)) + s2.close + assert_raise(EOFError) { s1.readpartial(10) } + assert_raise(EOFError) { s1.readpartial(10) } + assert_equal("", s1.readpartial(0)) + } + end + + def test_readall + ssl_pair {|s1, s2| + s2.close + assert_equal("", s1.read) + } + end + + def test_readline + ssl_pair {|s1, s2| + s2.close + assert_raise(EOFError) { s1.readline } + } + end + + def test_puts_meta + ssl_pair {|s1, s2| + begin + old = $/ + $/ = '*' + s1.puts 'a' + ensure + $/ = old + end + s1.close + assert_equal("a\n", s2.read) + } + end + + def test_puts_empty + ssl_pair {|s1, s2| + s1.puts + s1.close + assert_equal("\n", s2.read) + } + end + + def test_read_nonblock + ssl_pair {|s1, s2| + err = nil + assert_raise(OpenSSL::SSL::SSLError) { + begin + s2.read_nonblock(10) + ensure + err = $! + end + } + assert_kind_of(IO::WaitReadable, err) + s1.write "abc\ndef\n" + IO.select([s2]) + assert_equal("ab", s2.read_nonblock(2)) + assert_equal("c\n", s2.gets) + ret = nil + assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) } + assert_equal("def\n", ret) + } + end + + def test_write_nonblock + ssl_pair {|s1, s2| + n = 0 + begin + n += s1.write_nonblock("a" * 100000) + n += s1.write_nonblock("b" * 100000) + n += s1.write_nonblock("c" * 100000) + n += s1.write_nonblock("d" * 100000) + n += s1.write_nonblock("e" * 100000) + n += s1.write_nonblock("f" * 100000) + rescue IO::WaitWritable + end + s1.close + assert_equal(n, s2.read.length) + } + end + + def test_write_nonblock_with_buffered_data + ssl_pair {|s1, s2| + s1.write "foo" + s1.write_nonblock("bar") + s1.write "baz" + s1.close + assert_equal("foobarbaz", s2.read) + } + end + + def test_connect_accept_nonblock + host = "127.0.0.1" + port = 0 + ctx = OpenSSL::SSL::SSLContext.new() + ctx.ciphers = "ADH" + ctx.tmp_dh_callback = proc { DHParam } + serv = TCPServer.new(host, port) + + port = serv.connect_address.ip_port + + sock1 = TCPSocket.new(host, port) + sock2 = serv.accept + serv.close + + th = Thread.new { + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) + s2.sync_close = true + begin + sleep 0.2 + s2.accept_nonblock + rescue IO::WaitReadable + IO.select([s2]) + retry + rescue IO::WaitWritable + IO.select(nil, [s2]) + retry + end + s2 + } + + sleep 0.1 + ctx = OpenSSL::SSL::SSLContext.new() + ctx.ciphers = "ADH" + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) + begin + sleep 0.2 + s1.connect_nonblock + rescue IO::WaitReadable + IO.select([s1]) + retry + rescue IO::WaitWritable + IO.select(nil, [s1]) + retry + end + s1.sync_close = true + + s2 = th.value + + s1.print "a\ndef" + assert_equal("a\n", s2.gets) + ensure + s1.close if s1 && !s1.closed? + s2.close if s2 && !s2.closed? + serv.close if serv && !serv.closed? + sock1.close if sock1 && !sock1.closed? + sock2.close if sock2 && !sock2.closed? + end + +end + +end diff --git a/test/1.9/test_pkcs12.rb b/test/1.9/test_pkcs12.rb new file mode 100644 index 0000000..64e7530 --- /dev/null +++ b/test/1.9/test_pkcs12.rb @@ -0,0 +1,209 @@ +require_relative "utils" + +if defined?(OpenSSL) + +module OpenSSL + class TestPKCS12 < Test::Unit::TestCase + include OpenSSL::TestUtils + + def setup + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + + now = Time.now + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + + @cacert = issue_cert(ca, TEST_KEY_RSA2048, 1, now, now+3600, ca_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + + inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") + inter_ca_key = OpenSSL::PKey.read <<-_EOS_ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K +oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT +ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB +AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV +5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9 +iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC +G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5 +Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA +HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf +ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG +jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK +FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 +Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= +-----END RSA PRIVATE KEY----- + _EOS_ + + @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, now, now+3600, ca_exts, + @ca_cert, TEST_KEY_RSA2048, OpenSSL::Digest::SHA1.new) + + exts = [ + ["keyUsage","digitalSignature",true], + ["subjectKeyIdentifier","hash",false], + ] + ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") + @mycert = issue_cert(ee, TEST_KEY_RSA1024, 3, now, now+3600, exts, + @inter_cacert, inter_ca_key, OpenSSL::Digest::SHA1.new) + end + + def test_create + pkcs12 = OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert + ) + assert_equal @mycert, pkcs12.certificate + assert_equal TEST_KEY_RSA1024, pkcs12.key + assert_nil pkcs12.ca_certs + end + + def test_create_no_pass + pkcs12 = OpenSSL::PKCS12.create( + nil, + "hello", + TEST_KEY_RSA1024, + @mycert + ) + assert_equal @mycert, pkcs12.certificate + assert_equal TEST_KEY_RSA1024, pkcs12.key + assert_nil pkcs12.ca_certs + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der) + assert_cert @mycert, decoded.certificate + end + + def test_create_with_chain + chain = [@inter_cacert, @cacert] + + pkcs12 = OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + chain + ) + assert_equal chain, pkcs12.ca_certs + end + + def test_create_with_chain_decode + chain = [@cacert, @inter_cacert] + + passwd = "omg" + + pkcs12 = OpenSSL::PKCS12.create( + passwd, + "hello", + TEST_KEY_RSA1024, + @mycert, + chain + ) + + decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd) + assert_equal chain.size, decoded.ca_certs.size + assert_include_cert @cacert, decoded.ca_certs + assert_include_cert @inter_cacert, decoded.ca_certs + assert_cert @mycert, decoded.certificate + assert_equal TEST_KEY_RSA1024.to_der, decoded.key.to_der + end + + def test_create_with_bad_nid + assert_raises(ArgumentError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + [], + "foo" + ) + end + end + + def test_create_with_itr + OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + [], + nil, + nil, + 2048 + ) + + assert_raises(TypeError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + [], + nil, + nil, + "omg" + ) + end + end + + def test_create_with_mac_itr + OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + [], + nil, + nil, + nil, + 2048 + ) + + assert_raises(TypeError) do + OpenSSL::PKCS12.create( + "omg", + "hello", + TEST_KEY_RSA1024, + @mycert, + [], + nil, + nil, + nil, + "omg" + ) + end + end + + private + def assert_cert expected, actual + [ + :subject, + :issuer, + :serial, + :not_before, + :not_after, + ].each do |attribute| + assert_equal expected.send(attribute), actual.send(attribute) + end + assert_equal expected.to_der, actual.to_der + end + + def assert_include_cert cert, ary + der = cert.to_der + ary.each do |candidate| + if candidate.to_der == der + return true + end + end + false + end + + end +end + +end diff --git a/test/1.9/test_pkcs7.rb b/test/1.9/test_pkcs7.rb new file mode 100644 index 0000000..34c523a --- /dev/null +++ b/test/1.9/test_pkcs7.rb @@ -0,0 +1,151 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestPKCS7 < Test::Unit::TestCase + def setup + @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 + 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") + + now = Time.now + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + @ca_cert = issue_cert(ca, @rsa2048, 1, now, now+3600, ca_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + ee_exts = [ + ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], + ["authorityKeyIdentifier","keyid:always",false], + ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], + ] + @ee1_cert = issue_cert(ee1, @rsa1024, 2, now, now+1800, ee_exts, + @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + @ee2_cert = issue_cert(ee2, @rsa1024, 3, now, now+1800, ee_exts, + @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + end + + def issue_cert(*args) + OpenSSL::TestUtils.issue_cert(*args) + end + + def test_signed + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ca_certs = [@ca_cert] + + data = "aaaaa\r\nbbbbb\r\nccccc\r\n" + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + + # Normaly OpenSSL tries to translate the supplied content into canonical + # MIME format (e.g. a newline character is converted into CR+LF). + # If the content is a binary, PKCS7::BINARY flag should be used. + + data = "aaaaa\nbbbbb\nccccc\n" + flag = OpenSSL::PKCS7::BINARY + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + + # A signed-data which have multiple signatures can be created + # through the following steps. + # 1. create two signed-data + # 2. copy signerInfo and certificate from one to another + + tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) + tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) + tmp1.add_signer(tmp2.signers[0]) + tmp1.add_certificate(@ee2_cert) + + p7 = OpenSSL::PKCS7.new(tmp1.to_der) + certs = p7.certificates + signers = p7.signers + assert(p7.verify([], store)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(2, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + assert_equal(@ee2_cert.serial, signers[1].serial) + assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) + end + + def test_detached_sign + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ca_certs = [@ca_cert] + + data = "aaaaa\nbbbbb\nccccc\n" + flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED + tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + assert_nothing_raised do + OpenSSL::ASN1.decode(p7) + end + + certs = p7.certificates + signers = p7.signers + assert(!p7.verify([], store)) + assert(p7.verify([], store, data)) + assert_equal(data, p7.data) + assert_equal(2, certs.size) + assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) + assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) + assert_equal(1, signers.size) + assert_equal(@ee1_cert.serial, signers[0].serial) + assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) + end + + def test_enveloped + if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x0090704f + # PKCS7_encrypt() of OpenSSL-0.9.7d goes to SEGV. + # http://www.mail-archive.com/openssl-dev@openssl.org/msg17376.html + return + end + + certs = [@ee1_cert, @ee2_cert] + cipher = OpenSSL::Cipher::AES.new("128-CBC") + data = "aaaaa\nbbbbb\nccccc\n" + + tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) + p7 = OpenSSL::PKCS7.new(tmp.to_der) + recip = p7.recipients + assert_equal(:enveloped, p7.type) + assert_equal(2, recip.size) + + assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) + assert_equal(2, recip[0].serial) + assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) + + assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) + assert_equal(3, recip[1].serial) + assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) + end +end + +end diff --git a/test/1.9/test_pkey_dh.rb b/test/1.9/test_pkey_dh.rb new file mode 100644 index 0000000..bcba400 --- /dev/null +++ b/test/1.9/test_pkey_dh.rb @@ -0,0 +1,72 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestPKeyDH < Test::Unit::TestCase + def test_new + dh = OpenSSL::PKey::DH.new(256) + assert_key(dh) + end + + def test_to_der + dh = OpenSSL::PKey::DH.new(256) + der = dh.to_der + dh2 = OpenSSL::PKey::DH.new(der) + assert_equal_params(dh, dh2) + assert_no_key(dh2) + end + + def test_to_pem + dh = OpenSSL::PKey::DH.new(256) + pem = dh.to_pem + dh2 = OpenSSL::PKey::DH.new(pem) + assert_equal_params(dh, dh2) + assert_no_key(dh2) + end + + def test_public_key + dh = OpenSSL::PKey::DH.new(256) + public_key = dh.public_key + assert_no_key(public_key) #implies public_key.public? is false! + assert_equal(dh.to_der, public_key.to_der) + assert_equal(dh.to_pem, public_key.to_pem) + end + + def test_generate_key + dh = OpenSSL::TestUtils::TEST_KEY_DH512.public_key # creates a copy + assert_no_key(dh) + dh.generate_key! + assert_key(dh) + end + + def test_key_exchange + dh = OpenSSL::TestUtils::TEST_KEY_DH512 + dh2 = dh.public_key + dh.generate_key! + dh2.generate_key! + assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) + end + + private + + def assert_equal_params(dh1, dh2) + assert_equal(dh1.g, dh2.g) + assert_equal(dh1.p, dh2.p) + end + + def assert_no_key(dh) + assert_equal(false, dh.public?) + assert_equal(false, dh.private?) + assert_equal(nil, dh.pub_key) + assert_equal(nil, dh.priv_key) + end + + def assert_key(dh) + assert(dh.public?) + assert(dh.private?) + assert(dh.pub_key) + assert(dh.priv_key) + end +end + +end diff --git a/test/1.9/test_pkey_dsa.rb b/test/1.9/test_pkey_dsa.rb new file mode 100644 index 0000000..e498e3c --- /dev/null +++ b/test/1.9/test_pkey_dsa.rb @@ -0,0 +1,224 @@ +require_relative 'utils' +require 'base64' + +if defined?(OpenSSL) + +class OpenSSL::TestPKeyDSA < Test::Unit::TestCase + def test_private + key = OpenSSL::PKey::DSA.new(256) + assert(key.private?) + key2 = OpenSSL::PKey::DSA.new(key.to_der) + assert(key2.private?) + key3 = key.public_key + assert(!key3.private?) + key4 = OpenSSL::PKey::DSA.new(key3.to_der) + assert(!key4.private?) + end + + def test_new + key = OpenSSL::PKey::DSA.new 256 + pem = key.public_key.to_pem + OpenSSL::PKey::DSA.new pem + assert_equal([], OpenSSL.errors) + end + + def test_sys_sign_verify + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + data = 'Sign me!' + digest = OpenSSL::Digest::SHA1.digest(data) + sig = key.syssign(digest) + assert(key.sysverify(digest, sig)) + end + + def test_sign_verify + check_sign_verify(OpenSSL::Digest::DSS1.new) + end + +if (OpenSSL::OPENSSL_VERSION_NUMBER > 0x10000000) + def test_sign_verify_sha1 + check_sign_verify(OpenSSL::Digest::SHA1.new) + end + + def test_sign_verify_sha256 + check_sign_verify(OpenSSL::Digest::SHA256.new) + end +end + + def test_digest_state_irrelevant_verify + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + digest1 = OpenSSL::Digest::DSS1.new + digest2 = OpenSSL::Digest::DSS1.new + data = 'Sign me!' + sig = key.sign(digest1, data) + digest1.reset + digest1 << 'Change state of digest1' + assert(key.verify(digest1, sig, data)) + assert(key.verify(digest2, sig, data)) + end + + def test_read_DSA_PUBKEY + p = 7188211954100152441468596248707152960171255279130004340103875772401008316444412091945435731597638374542374929457672178957081124632837356913990200866056699 + q = 957032439192465935099784319494405376402293318491 + g = 122928973717064636255205666162891733518376475981809749897454444301389338825906076467196186192907631719698166056821519884939865041993585844526937010746285 + y = 1235756183583465414789073313502727057075641172514181938731172021825149551960029708596057102104063395063907739571546165975727369183495540798749742124846271 + algo = OpenSSL::ASN1::ObjectId.new('DSA') + params = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(p), + OpenSSL::ASN1::Integer.new(q), + OpenSSL::ASN1::Integer.new(g)]) + algo_id = OpenSSL::ASN1::Sequence.new ([algo, params]) + pub_key = OpenSSL::ASN1::Integer.new(y) + seq = OpenSSL::ASN1::Sequence.new([algo_id, OpenSSL::ASN1::BitString.new(pub_key.to_der)]) + key = OpenSSL::PKey::DSA.new(seq.to_der) + assert(key.public?) + assert(!key.private?) + assert_equal(p, key.p) + assert_equal(q, key.q) + assert_equal(g, key.g) + assert_equal(y, key.pub_key) + assert_equal(nil, key.priv_key) + assert_equal([], OpenSSL.errors) + end + + def test_read_DSAPublicKey_pem + p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699 + q = 979494906553787301107832405790107343409973851677 + g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845 + y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695 + pem = <<-EOF +-----BEGIN DSA PUBLIC KEY----- +MIHfAkEAyJSJ+g+P/knVcgDwwTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4 +VUC/phySExY0PdcqItkR/xYAYNMbNwJBAOoV57X0FxKO/PrNa/MkoWzkCKV/hzhE +p0zbFdsicw+hIjJ7S6Sd/FlDlo89HQZ2FuvWJ6wGLM1j00r39+F2qbMCFQCrkhIX +SG+is37hz1IaBeEudjB2HQJAR0AloavBvtsng8obsjLb7EKnB+pSeHr/BdIQ3VH7 +fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== +-----END DSA PUBLIC KEY----- + EOF + key = OpenSSL::PKey::DSA.new(pem) + assert(key.public?) + assert(!key.private?) + assert_equal(p, key.p) + assert_equal(q, key.q) + assert_equal(g, key.g) + assert_equal(y, key.pub_key) + assert_equal(nil, key.priv_key) + assert_equal([], OpenSSL.errors) + end + + def test_read_DSA_PUBKEY_pem + p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699 + q = 979494906553787301107832405790107343409973851677 + g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845 + y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695 + pem = <<-EOF +-----BEGIN PUBLIC KEY----- +MIHxMIGoBgcqhkjOOAQBMIGcAkEA6hXntfQXEo78+s1r8yShbOQIpX+HOESnTNsV +2yJzD6EiMntLpJ38WUOWjz0dBnYW69YnrAYszWPTSvf34XapswIVAKuSEhdIb6Kz +fuHPUhoF4S52MHYdAkBHQCWhq8G+2yeDyhuyMtvsQqcH6lJ4ev8F0hDdUft9Ys6q +qTMV5GtgwPNSmXfpeS1jpirwQliVb2kIyYFU3L91A0QAAkEAyJSJ+g+P/knVcgDw +wTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4VUC/phySExY0PdcqItkR/xYA +YNMbNw== +-----END PUBLIC KEY----- + EOF + key = OpenSSL::PKey::DSA.new(pem) + assert(key.public?) + assert(!key.private?) + assert_equal(p, key.p) + assert_equal(q, key.q) + assert_equal(g, key.g) + assert_equal(y, key.pub_key) + assert_equal(nil, key.priv_key) + assert_equal([], OpenSSL.errors) + end + + def test_export_format_is_DSA_PUBKEY_pem + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + pem = key.public_key.to_pem + pem.gsub!(/^-+(\w|\s)+-+$/, "") # eliminate --------BEGIN...------- + asn1 = OpenSSL::ASN1.decode(Base64.decode64(pem)) + assert_equal(OpenSSL::ASN1::SEQUENCE, asn1.tag) + assert_equal(2, asn1.value.size) + seq = asn1.value + assert_equal(OpenSSL::ASN1::SEQUENCE, seq[0].tag) + assert_equal(2, seq[0].value.size) + algo_id = seq[0].value + assert_equal(OpenSSL::ASN1::OBJECT, algo_id[0].tag) + assert_equal('DSA', algo_id[0].value) + assert_equal(OpenSSL::ASN1::SEQUENCE, algo_id[1].tag) + assert_equal(3, algo_id[1].value.size) + params = algo_id[1].value + assert_equal(OpenSSL::ASN1::INTEGER, params[0].tag) + assert_equal(key.p, params[0].value) + assert_equal(OpenSSL::ASN1::INTEGER, params[1].tag) + assert_equal(key.q, params[1].value) + assert_equal(OpenSSL::ASN1::INTEGER, params[2].tag) + assert_equal(key.g, params[2].value) + assert_equal(OpenSSL::ASN1::BIT_STRING, seq[1].tag) + assert_equal(0, seq[1].unused_bits) + pub_key = OpenSSL::ASN1.decode(seq[1].value) + assert_equal(OpenSSL::ASN1::INTEGER, pub_key.tag) + assert_equal(key.pub_key, pub_key.value) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_der + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + der = key.to_der + key2 = OpenSSL::PKey.read(der) + assert(key2.private?) + assert_equal(der, key2.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + pem = key.to_pem + key2 = OpenSSL::PKey.read(pem) + assert(key2.private?) + assert_equal(pem, key2.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_der + key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key + der = key.to_der + key2 = OpenSSL::PKey.read(der) + assert(!key2.private?) + assert_equal(der, key2.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_pem + key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key + pem = key.to_pem + key2 = OpenSSL::PKey.read(pem) + assert(!key2.private?) + assert_equal(pem, key2.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem_pw + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + pem = key.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') + #callback form for password + key2 = OpenSSL::PKey.read(pem) do + 'secret' + end + assert(key2.private?) + # pass password directly + key2 = OpenSSL::PKey.read(pem, 'secret') + assert(key2.private?) + #omit pem equality check, will be different due to cipher iv + assert_equal([], OpenSSL.errors) + end + + private + + def check_sign_verify(digest) + key = OpenSSL::TestUtils::TEST_KEY_DSA256 + data = 'Sign me!' + sig = key.sign(digest, data) + assert(key.verify(digest, sig, data)) + end +end + +end diff --git a/test/1.9/test_pkey_ec.rb b/test/1.9/test_pkey_ec.rb new file mode 100644 index 0000000..e63f617 --- /dev/null +++ b/test/1.9/test_pkey_ec.rb @@ -0,0 +1,182 @@ +require_relative 'utils' + +if defined?(OpenSSL::PKey::EC) + +class OpenSSL::TestEC < Test::Unit::TestCase + def setup + @data1 = 'foo' + @data2 = 'bar' * 1000 # data too long for DSA sig + + @group1 = OpenSSL::PKey::EC::Group.new('secp112r1') + @group2 = OpenSSL::PKey::EC::Group.new('sect163k1') + @group3 = OpenSSL::PKey::EC::Group.new('prime256v1') + + @key1 = OpenSSL::PKey::EC.new + @key1.group = @group1 + @key1.generate_key + + @key2 = OpenSSL::PKey::EC.new(@group2.curve_name) + @key2.generate_key + + @key3 = OpenSSL::PKey::EC.new(@group3) + @key3.generate_key + + @groups = [@group1, @group2, @group3] + @keys = [@key1, @key2, @key3] + end + + def compare_keys(k1, k2) + assert_equal(k1.to_pem, k2.to_pem) + end + + def test_curve_names + @groups.each_with_index do |group, idx| + key = @keys[idx] + assert_equal(group.curve_name, key.group.curve_name) + end + end + + def test_check_key + for key in @keys + assert_equal(key.check_key, true) + assert_equal(key.private_key?, true) + assert_equal(key.public_key?, true) + end + end + + def test_encoding + for group in @groups + for meth in [:to_der, :to_pem] + txt = group.send(meth) + gr = OpenSSL::PKey::EC::Group.new(txt) + assert_equal(txt, gr.send(meth)) + + assert_equal(group.generator.to_bn, gr.generator.to_bn) + assert_equal(group.cofactor, gr.cofactor) + assert_equal(group.order, gr.order) + assert_equal(group.seed, gr.seed) + assert_equal(group.degree, gr.degree) + end + end + + for key in @keys + group = key.group + + for meth in [:to_der, :to_pem] + txt = key.send(meth) + assert_equal(txt, OpenSSL::PKey::EC.new(txt).send(meth)) + end + + bn = key.public_key.to_bn + assert_equal(bn, OpenSSL::PKey::EC::Point.new(group, bn).to_bn) + end + end + + def test_set_keys + for key in @keys + k = OpenSSL::PKey::EC.new + k.group = key.group + k.private_key = key.private_key + k.public_key = key.public_key + + compare_keys(key, k) + end + end + + def test_dsa_sign_verify + for key in @keys + sig = key.dsa_sign_asn1(@data1) + assert(key.dsa_verify_asn1(@data1, sig)) + end + end + + def test_dsa_sign_asn1_FIPS186_3 + for key in @keys + size = key.group.order.num_bits / 8 + 1 + dgst = (1..size).to_a.pack('C*') + begin + sig = key.dsa_sign_asn1(dgst) + # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m + assert(key.dsa_verify_asn1(dgst + "garbage", sig)) + rescue OpenSSL::PKey::ECError => e + # just an exception for longer dgst before openssl-0.9.8m + assert_equal('ECDSA_sign: data too large for key size', e.message) + # no need to do following tests + return + end + end + end + + def test_dh_compute_key + for key in @keys + k = OpenSSL::PKey::EC.new(key.group) + k.generate_key + + puba = key.public_key + pubb = k.public_key + a = key.dh_compute_key(pubb) + b = k.dh_compute_key(puba) + assert_equal(a, b) + end + end + + def test_read_private_key_der + ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 + der = ec.to_der + ec2 = OpenSSL::PKey.read(der) + assert(ec2.private_key?) + assert_equal(der, ec2.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem + ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 + pem = ec.to_pem + ec2 = OpenSSL::PKey.read(pem) + assert(ec2.private_key?) + assert_equal(pem, ec2.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_der + ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 + ec2 = OpenSSL::PKey::EC.new(ec.group) + ec2.public_key = ec.public_key + der = ec2.to_der + ec3 = OpenSSL::PKey.read(der) + assert(!ec3.private_key?) + assert_equal(der, ec3.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_pem + ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 + ec2 = OpenSSL::PKey::EC.new(ec.group) + ec2.public_key = ec.public_key + pem = ec2.to_pem + ec3 = OpenSSL::PKey.read(pem) + assert(!ec3.private_key?) + assert_equal(pem, ec3.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem_pw + ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 + pem = ec.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') + #callback form for password + ec2 = OpenSSL::PKey.read(pem) do + 'secret' + end + assert(ec2.private_key?) + # pass password directly + ec2 = OpenSSL::PKey.read(pem, 'secret') + assert(ec2.private_key?) + #omit pem equality check, will be different due to cipher iv + assert_equal([], OpenSSL.errors) + end + +# test Group: asn1_flag, point_conversion + +end + +end diff --git a/test/1.9/test_pkey_rsa.rb b/test/1.9/test_pkey_rsa.rb new file mode 100644 index 0000000..5ba1422 --- /dev/null +++ b/test/1.9/test_pkey_rsa.rb @@ -0,0 +1,244 @@ +require_relative 'utils' +require 'base64' + +if defined?(OpenSSL) + +class OpenSSL::TestPKeyRSA < Test::Unit::TestCase + def test_padding + key = OpenSSL::PKey::RSA.new(512, 3) + + # Need right size for raw mode + plain0 = "x" * (512/8) + cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) + plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) + assert_equal(plain0, plain1) + + # Need smaller size for pkcs1 mode + plain0 = "x" * (512/8 - 11) + cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) + plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) + assert_equal(plain0, plain1) + + cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default + plain1 = key.public_decrypt(cipherdef) + assert_equal(plain0, plain1) + assert_equal(cipher1, cipherdef) + + # Failure cases + assert_raise(ArgumentError){ key.private_encrypt() } + assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } + assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } + end + + def test_private + key = OpenSSL::PKey::RSA.new(512, 3) + assert(key.private?) + key2 = OpenSSL::PKey::RSA.new(key.to_der) + assert(key2.private?) + key3 = key.public_key + assert(!key3.private?) + key4 = OpenSSL::PKey::RSA.new(key3.to_der) + assert(!key4.private?) + end + + def test_new + key = OpenSSL::PKey::RSA.new 512 + pem = key.public_key.to_pem + OpenSSL::PKey::RSA.new pem + assert_equal([], OpenSSL.errors) + end + + def test_sign_verify + key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + digest = OpenSSL::Digest::SHA1.new + data = 'Sign me!' + sig = key.sign(digest, data) + assert(key.verify(digest, sig, data)) + end + + def test_digest_state_irrelevant_sign + key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + digest1 = OpenSSL::Digest::SHA1.new + digest2 = OpenSSL::Digest::SHA1.new + data = 'Sign me!' + digest1 << 'Change state of digest1' + sig1 = key.sign(digest1, data) + sig2 = key.sign(digest2, data) + assert_equal(sig1, sig2) + end + + def test_digest_state_irrelevant_verify + key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + digest1 = OpenSSL::Digest::SHA1.new + digest2 = OpenSSL::Digest::SHA1.new + data = 'Sign me!' + sig = key.sign(digest1, data) + digest1.reset + digest1 << 'Change state of digest1' + assert(key.verify(digest1, sig, data)) + assert(key.verify(digest2, sig, data)) + end + + def test_read_RSAPublicKey + modulus = 10664264882656732240315063514678024569492171560814833397008094754351396057398262071307709191731289492697968568138092052265293364132872019762410446076526351 + exponent = 65537 + seq = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(modulus), OpenSSL::ASN1::Integer.new(exponent)]) + key = OpenSSL::PKey::RSA.new(seq.to_der) + assert(key.public?) + assert(!key.private?) + assert_equal(modulus, key.n) + assert_equal(exponent, key.e) + assert_equal(nil, key.d) + assert_equal(nil, key.p) + assert_equal(nil, key.q) + assert_equal([], OpenSSL.errors) + end + + def test_read_RSA_PUBKEY + modulus = 10664264882656732240315063514678024569492171560814833397008094754351396057398262071307709191731289492697968568138092052265293364132872019762410446076526351 + exponent = 65537 + algo = OpenSSL::ASN1::ObjectId.new('rsaEncryption') + null_params = OpenSSL::ASN1::Null.new(nil) + algo_id = OpenSSL::ASN1::Sequence.new ([algo, null_params]) + pub_key = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(modulus), OpenSSL::ASN1::Integer.new(exponent)]) + seq = OpenSSL::ASN1::Sequence.new([algo_id, OpenSSL::ASN1::BitString.new(pub_key.to_der)]) + key = OpenSSL::PKey::RSA.new(seq.to_der) + assert(key.public?) + assert(!key.private?) + assert_equal(modulus, key.n) + assert_equal(exponent, key.e) + assert_equal(nil, key.d) + assert_equal(nil, key.p) + assert_equal(nil, key.q) + assert_equal([], OpenSSL.errors) + end + + def test_read_RSAPublicKey_pem + modulus = 9416340886363418692990906464787534854462163316648195510702927337693641649864839352187127240942127674615733815606532506566068276485089353644309497938966061 + exponent = 65537 + pem = <<-EOF +-----BEGIN RSA PUBLIC KEY----- +MEgCQQCzyh2RIZK62E2PbTWqUljD+K23XR9AGBKNtXjal6WD2yRGcLqzPJLNCa60 +AudJR1JobbIbDJrQu6AXnWh5k/YtAgMBAAE= +-----END RSA PUBLIC KEY----- + EOF + key = OpenSSL::PKey::RSA.new(pem) + assert(key.public?) + assert(!key.private?) + assert_equal(modulus, key.n) + assert_equal(exponent, key.e) + assert_equal(nil, key.d) + assert_equal(nil, key.p) + assert_equal(nil, key.q) + assert_equal([], OpenSSL.errors) + end + + def test_read_RSA_PUBKEY_pem + modulus = 9416340886363418692990906464787534854462163316648195510702927337693641649864839352187127240942127674615733815606532506566068276485089353644309497938966061 + exponent = 65537 + pem = <<-EOF +-----BEGIN PUBLIC KEY----- +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALPKHZEhkrrYTY9tNapSWMP4rbdd +H0AYEo21eNqXpYPbJEZwurM8ks0JrrQC50lHUmhtshsMmtC7oBedaHmT9i0C +AwEAAQ== +-----END PUBLIC KEY----- + EOF + key = OpenSSL::PKey::RSA.new(pem) + assert(key.public?) + assert(!key.private?) + assert_equal(modulus, key.n) + assert_equal(exponent, key.e) + assert_equal(nil, key.d) + assert_equal(nil, key.p) + assert_equal(nil, key.q) + assert_equal([], OpenSSL.errors) + end + + def test_export_format_is_RSA_PUBKEY + key = OpenSSL::PKey::RSA.new(512) + asn1 = OpenSSL::ASN1.decode(key.public_key.to_der) + check_PUBKEY(asn1, key) + end + + def test_export_format_is_RSA_PUBKEY_pem + key = OpenSSL::PKey::RSA.new(512) + pem = key.public_key.to_pem + pem.gsub!(/^-+(\w|\s)+-+$/, "") # eliminate --------BEGIN...------- + asn1 = OpenSSL::ASN1.decode(Base64.decode64(pem)) + check_PUBKEY(asn1, key) + end + + def test_read_private_key_der + der = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_der + key = OpenSSL::PKey.read(der) + assert(key.private?) + assert_equal(der, key.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem + pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem + key = OpenSSL::PKey.read(pem) + assert(key.private?) + assert_equal(pem, key.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_der + der = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_der + key = OpenSSL::PKey.read(der) + assert(!key.private?) + assert_equal(der, key.to_der) + assert_equal([], OpenSSL.errors) + end + + def test_read_public_key_pem + pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_pem + key = OpenSSL::PKey.read(pem) + assert(!key.private?) + assert_equal(pem, key.to_pem) + assert_equal([], OpenSSL.errors) + end + + def test_read_private_key_pem_pw + pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') + #callback form for password + key = OpenSSL::PKey.read(pem) do + 'secret' + end + assert(key.private?) + # pass password directly + key = OpenSSL::PKey.read(pem, 'secret') + assert(key.private?) + #omit pem equality check, will be different due to cipher iv + assert_equal([], OpenSSL.errors) + end + + private + + def check_PUBKEY(asn1, key) + assert_equal(OpenSSL::ASN1::SEQUENCE, asn1.tag) + assert_equal(2, asn1.value.size) + seq = asn1.value + assert_equal(OpenSSL::ASN1::SEQUENCE, seq[0].tag) + assert_equal(2, seq[0].value.size) + algo_id = seq[0].value + assert_equal(OpenSSL::ASN1::OBJECT, algo_id[0].tag) + assert_equal('rsaEncryption', algo_id[0].value) + assert_equal(OpenSSL::ASN1::NULL, algo_id[1].tag) + assert_equal(nil, algo_id[1].value) + assert_equal(OpenSSL::ASN1::BIT_STRING, seq[1].tag) + assert_equal(0, seq[1].unused_bits) + pub_key = OpenSSL::ASN1.decode(seq[1].value) + assert_equal(OpenSSL::ASN1::SEQUENCE, pub_key.tag) + assert_equal(2, pub_key.value.size) + assert_equal(OpenSSL::ASN1::INTEGER, pub_key.value[0].tag) + assert_equal(key.n, pub_key.value[0].value) + assert_equal(OpenSSL::ASN1::INTEGER, pub_key.value[1].tag) + assert_equal(key.e, pub_key.value[1].value) + assert_equal([], OpenSSL.errors) + end + +end + +end diff --git a/test/1.9/test_ssl.rb b/test/1.9/test_ssl.rb new file mode 100644 index 0000000..a081931 --- /dev/null +++ b/test/1.9/test_ssl.rb @@ -0,0 +1,399 @@ +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestSSL < OpenSSL::SSLTestCase + def test_ctx_setup + ctx = OpenSSL::SSL::SSLContext.new + assert_equal(ctx.setup, true) + assert_equal(ctx.setup, nil) + end + + def test_ctx_setup_no_compression + ctx = OpenSSL::SSL::SSLContext.new + ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_COMPRESSION + assert_equal(ctx.setup, true) + assert_equal(ctx.setup, nil) + assert_equal(OpenSSL::SSL::OP_NO_COMPRESSION, + ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION) + end if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) + + def test_not_started_session + skip "non socket argument of SSLSocket.new is not supported on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM + open(__FILE__) do |f| + assert_nil OpenSSL::SSL::SSLSocket.new(f).cert + end + end + + def test_ssl_read_nonblock + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + assert_raise(IO::WaitReadable) { ssl.read_nonblock(100) } + ssl.write("abc\n") + IO.select [ssl] + assert_equal('a', ssl.read_nonblock(1)) + assert_equal("bc\n", ssl.read_nonblock(100)) + assert_raise(IO::WaitReadable) { ssl.read_nonblock(100) } + } + end + + def test_connect_and_close + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + assert(ssl.connect) + ssl.close + assert(!sock.closed?) + sock.close + + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true # !! + assert(ssl.connect) + ssl.close + assert(sock.closed?) + } + end + + def test_read_and_write + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + + # syswrite and sysread + ITERATIONS.times{|i| + str = "x" * 100 + "\n" + ssl.syswrite(str) + assert_equal(str, ssl.sysread(str.size)) + + str = "x" * i * 100 + "\n" + buf = "" + ssl.syswrite(str) + assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id) + assert_equal(str, buf) + } + + # puts and gets + ITERATIONS.times{ + str = "x" * 100 + "\n" + ssl.puts(str) + assert_equal(str, ssl.gets) + + str = "x" * 100 + ssl.puts(str) + assert_equal(str, ssl.gets("\n", 100)) + assert_equal("\n", ssl.gets) + } + + # read and write + ITERATIONS.times{|i| + str = "x" * 100 + "\n" + ssl.write(str) + assert_equal(str, ssl.read(str.size)) + + str = "x" * i * 100 + "\n" + buf = "" + ssl.write(str) + assert_equal(buf.object_id, ssl.read(str.size, buf).object_id) + assert_equal(str, buf) + } + + ssl.close + } + end + + def test_client_auth + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(PORT, vflag, true){|server, port| + assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET){ + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.key = @cli_key + ctx.cert = @cli_cert + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + ssl.puts("foo") + assert_equal("foo\n", ssl.gets) + ssl.close + + called = nil + ctx = OpenSSL::SSL::SSLContext.new + ctx.client_cert_cb = Proc.new{ |sslconn| + called = true + [@cli_cert, @cli_key] + } + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + assert(called) + ssl.puts("foo") + assert_equal("foo\n", ssl.gets) + ssl.close + } + end + + def test_client_ca + ctx_proc = Proc.new do |ctx| + ctx.client_ca = [@ca_cert] + end + + vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + start_server(PORT, vflag, true, :ctx_proc => ctx_proc){|server, port| + ctx = OpenSSL::SSL::SSLContext.new + client_ca_from_server = nil + ctx.client_cert_cb = Proc.new do |sslconn| + client_ca_from_server = sslconn.client_ca + [@cli_cert, @cli_key] + end + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + assert_equal([@ca], client_ca_from_server) + ssl.close + } + end + + def test_starttls + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + str = "x" * 1000 + "\n" + + OpenSSL::TestUtils.silent do + ITERATIONS.times{ + ssl.puts(str) + assert_equal(str, ssl.gets) + } + starttls(ssl) + end + + ITERATIONS.times{ + ssl.puts(str) + assert_equal(str, ssl.gets) + } + + ssl.close + } + end + + def test_parallel + GC.start + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + ssls = [] + 10.times{ + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + ssl.sync_close = true + ssls << ssl + } + str = "x" * 1000 + "\n" + ITERATIONS.times{ + ssls.each{|ssl| + ssl.puts(str) + assert_equal(str, ssl.gets) + } + } + ssls.each{|ssl| ssl.close } + } + end + + def test_verify_result + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } + assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) + + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params( + :verify_callback => Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_OK + true + end + ) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.connect + assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) + + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params( + :verify_callback => Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION + false + end + ) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } + assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) + } + end + + def test_exception_in_verify_callback_is_ignored + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params( + :verify_callback => Proc.new do |preverify_ok, store_ctx| + store_ctx.error = OpenSSL::X509::V_OK + raise RuntimeError + end + ) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + OpenSSL::TestUtils.silent do + # SSLError, not RuntimeError + assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } + end + assert_equal(OpenSSL::X509::V_ERR_CERT_REJECTED, ssl.verify_result) + ssl.close + } + end + + def test_sslctx_set_params + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + assert_equal(OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode) + assert_equal(OpenSSL::SSL::OP_ALL, ctx.options) + ciphers = ctx.ciphers + ciphers_versions = ciphers.collect{|_, v, _, _| v } + ciphers_names = ciphers.collect{|v, _, _, _| v } + assert(ciphers_names.all?{|v| /ADH/ !~ v }) + assert(ciphers_versions.all?{|v| /SSLv2/ !~ v }) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } + assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) + } + end + + def test_post_connection_check + sslerr = OpenSSL::SSL::SSLError + + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} + assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} + assert(ssl.post_connection_check("localhost")) + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + + cert = ssl.peer_cert + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + + now = Time.now + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:localhost.localdomain",false], + ["subjectAltName","IP:127.0.0.1",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert(ssl.post_connection_check("localhost.localdomain")) + assert(ssl.post_connection_check("127.0.0.1")) + assert_raise(sslerr){ssl.post_connection_check("localhost")} + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + + cert = ssl.peer_cert + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + + now = Time.now + exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ["subjectAltName","DNS:*.localdomain",false], + ] + @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + assert(ssl.post_connection_check("localhost.localdomain")) + assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} + assert_raise(sslerr){ssl.post_connection_check("localhost")} + assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} + cert = ssl.peer_cert + assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) + assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) + } + end + + def test_tlsext_hostname + return unless OpenSSL::SSL::SSLSocket.instance_methods.include?(:hostname) + + ctx_proc = Proc.new do |ctx, ssl| + foo_ctx = ctx.dup + + ctx.servername_cb = Proc.new do |ssl2, hostname| + case hostname + when 'foo.example.com' + foo_ctx + when 'bar.example.com' + nil + else + raise "unknown hostname #{hostname.inspect}" + end + end + end + + server_proc = Proc.new do |ctx, ssl| + readwrite_loop(ctx, ssl) + end + + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + 2.times do |i| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + if defined?(OpenSSL::SSL::OP_NO_TICKET) + # disable RFC4507 support + ctx.options = OpenSSL::SSL::OP_NO_TICKET + end + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.hostname = (i & 1 == 0) ? 'foo.example.com' : 'bar.example.com' + ssl.connect + + str = "x" * 100 + "\n" + ssl.puts(str) + assert_equal(str, ssl.gets) + + ssl.close + end + end + end +end + +end diff --git a/test/1.9/test_ssl_session.rb b/test/1.9/test_ssl_session.rb new file mode 100644 index 0000000..12c6152 --- /dev/null +++ b/test/1.9/test_ssl_session.rb @@ -0,0 +1,327 @@ +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase + def test_session + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new("TLSv1") + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + session = ssl.session + assert(session == OpenSSL::SSL::Session.new(session.to_pem)) + assert(session == OpenSSL::SSL::Session.new(ssl)) + assert_equal(300, session.timeout) + session.timeout = 5 + assert_equal(5, session.timeout) + assert_not_nil(session.time) + # SSL_SESSION_time keeps long value so we can't keep nsec fragment. + session.time = t1 = Time.now.to_i + assert_equal(Time.at(t1), session.time) + if session.respond_to?(:id) + assert_not_nil(session.id) + end + pem = session.to_pem + assert_match(/\A-----BEGIN SSL SESSION PARAMETERS-----/, pem) + assert_match(/-----END SSL SESSION PARAMETERS-----\Z/, pem) + pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') + assert_equal(session.to_der, pem.unpack('m*')[0]) + assert_not_nil(session.to_text) + ssl.close + end + end + + DUMMY_SESSION = <<__EOS__ +-----BEGIN SSL SESSION PARAMETERS----- +MIIDzQIBAQICAwEEAgA5BCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad +MQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy +NNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB +BQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 +LWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1 +MVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt +bGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs +k4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z +D9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO +BgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d +8fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1 +ek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU +zIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2 +sOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO +gF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr +KkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP +/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V +jismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh +8uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y +j+RBGfCFrrQbBdnkFI/ztgM= +-----END SSL SESSION PARAMETERS----- +__EOS__ + + DUMMY_SESSION_NO_EXT = <<-__EOS__ +-----BEGIN SSL SESSION PARAMETERS----- +MIIDCAIBAQICAwAEAgA5BCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+ +lAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53 +hPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B +AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi +eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3 +MTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 +LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB +7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ +GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw +DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr +tDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3 +q9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz +FCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR +KYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4 +L6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr +a3EqpAIEAKUDAgET +-----END SSL SESSION PARAMETERS----- +__EOS__ + + + def test_session_time + sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) + sess.time = (now = Time.now) + assert_equal(now.to_i, sess.time.to_i) + sess.time = 1 + assert_equal(1, sess.time.to_i) + sess.time = 1.2345 + assert_equal(1, sess.time.to_i) + # Can OpenSSL handle t>2038y correctly? Version? + sess.time = 2**31 - 1 + assert_equal(2**31 - 1, sess.time.to_i) + end + + def test_session_timeout + sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) + assert_raise(TypeError) do + sess.timeout = (now = Time.now) + end + sess.timeout = 1 + assert_equal(1, sess.timeout.to_i) + sess.timeout = 1.2345 + assert_equal(1, sess.timeout.to_i) + sess.timeout = 2**31 - 1 + assert_equal(2**31 - 1, sess.timeout.to_i) + end + + def test_session_exts_read + assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) + end if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x009080bf + + def test_client_session + last_session = nil + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + 2.times do + sock = TCPSocket.new("127.0.0.1", port) + # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), + # when use default SSLContext. [ruby-dev:36167] + ctx = OpenSSL::SSL::SSLContext.new("TLSv1") + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.session = last_session if last_session + ssl.connect + + session = ssl.session + if last_session + assert(ssl.session_reused?) + + if session.respond_to?(:id) + assert_equal(session.id, last_session.id) + end + assert_equal(session.to_pem, last_session.to_pem) + assert_equal(session.to_der, last_session.to_der) + # Older version of OpenSSL may not be consistent. Look up which versions later. + assert_equal(session.to_text, last_session.to_text) + else + assert(!ssl.session_reused?) + end + last_session = session + + str = "x" * 100 + "\n" + ssl.puts(str) + assert_equal(str, ssl.gets) + + ssl.close + end + end + end + + def test_server_session + connections = 0 + saved_session = nil + + ctx_proc = Proc.new do |ctx, ssl| +# add test for session callbacks here + end + + server_proc = Proc.new do |ctx, ssl| + session = ssl.session + stats = ctx.session_cache_stats + + case connections + when 0 + assert_equal(stats[:cache_num], 1) + assert_equal(stats[:cache_hits], 0) + assert_equal(stats[:cache_misses], 0) + assert(!ssl.session_reused?) + when 1 + assert_equal(stats[:cache_num], 1) + assert_equal(stats[:cache_hits], 1) + assert_equal(stats[:cache_misses], 0) + assert(ssl.session_reused?) + ctx.session_remove(session) + saved_session = session + when 2 + assert_equal(stats[:cache_num], 1) + assert_equal(stats[:cache_hits], 1) + assert_equal(stats[:cache_misses], 1) + assert(!ssl.session_reused?) + ctx.session_add(saved_session) + when 3 + assert_equal(stats[:cache_num], 2) + assert_equal(stats[:cache_hits], 2) + assert_equal(stats[:cache_misses], 1) + assert(ssl.session_reused?) + ctx.flush_sessions(Time.now + 5000) + when 4 + assert_equal(stats[:cache_num], 1) + assert_equal(stats[:cache_hits], 2) + assert_equal(stats[:cache_misses], 2) + assert(!ssl.session_reused?) + ctx.session_add(saved_session) + end + connections += 1 + + readwrite_loop(ctx, ssl) + end + + first_session = nil + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + 10.times do |i| + sock = TCPSocket.new("127.0.0.1", port) + ctx = OpenSSL::SSL::SSLContext.new + if defined?(OpenSSL::SSL::OP_NO_TICKET) + # disable RFC4507 support + ctx.options = OpenSSL::SSL::OP_NO_TICKET + end + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.session = first_session if first_session + ssl.connect + + session = ssl.session + if first_session + case i + when 1; assert(ssl.session_reused?) + when 2; assert(!ssl.session_reused?) + when 3; assert(ssl.session_reused?) + when 4; assert(!ssl.session_reused?) + when 5..10; assert(ssl.session_reused?) + end + end + first_session ||= session + + str = "x" * 100 + "\n" + ssl.puts(str) + assert_equal(str, ssl.gets) + + ssl.close + end + end + end + + def test_ctx_client_session_cb + called = {} + ctx = OpenSSL::SSL::SSLContext.new("SSLv3") + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT + + ctx.session_new_cb = lambda { |ary| + sock, sess = ary + called[:new] = [sock, sess] + } + + ctx.session_remove_cb = lambda { |ary| + ctx, sess = ary + called[:remove] = [ctx, sess] + # any resulting value is OK (ignored) + } + + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) + ssl.sync_close = true + ssl.connect + assert_equal(1, ctx.session_cache_stats[:cache_num]) + assert_equal(1, ctx.session_cache_stats[:connect_good]) + assert_equal([ssl, ssl.session], called[:new]) + assert(ctx.session_remove(ssl.session)) + assert(!ctx.session_remove(ssl.session)) + assert_equal([ctx, ssl.session], called[:remove]) + ssl.close + end + end + + def test_ctx_server_session_cb + called = {} + + ctx_proc = Proc.new { |ctx, ssl| + ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER + last_server_session = nil + + # get_cb is called whenever a client proposed to resume a session but + # the session could not be found in the internal session cache. + ctx.session_get_cb = lambda { |ary| + sess, data = ary + if last_server_session + called[:get2] = [sess, data] + last_server_session + else + called[:get1] = [sess, data] + last_server_session = sess + nil + end + } + + ctx.session_new_cb = lambda { |ary| + sock, sess = ary + called[:new] = [sock, sess] + # SSL server doesn't cache sessions so get_cb is called next time. + ctx.session_remove(sess) + } + + ctx.session_remove_cb = lambda { |ary| + ctx, sess = ary + called[:remove] = [ctx, sess] + } + } + + server_proc = Proc.new { |c, ssl| + session = ssl.session + stats = c.session_cache_stats + readwrite_loop(c, ssl) + } + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| + last_client_session = nil + 3.times do + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new("SSLv3")) + ssl.sync_close = true + ssl.session = last_client_session if last_client_session + ssl.connect + last_client_session = ssl.session + ssl.close + Thread.pass # try to ensure server calls callbacks + assert(called.delete(:new)) + assert(called.delete(:remove)) + end + end + assert(called[:get1]) + assert(called[:get2]) + end +end + +end diff --git a/test/1.9/test_x509cert.rb b/test/1.9/test_x509cert.rb new file mode 100644 index 0000000..8b8c51c --- /dev/null +++ b/test/1.9/test_x509cert.rb @@ -0,0 +1,217 @@ +require_relative "utils" + +if defined?(OpenSSL) + +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, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_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, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_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, certificate_error_returns_false { cert.verify(@rsa1024) }) + assert_equal(false, certificate_error_returns_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)) + + begin + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.subject = @ee1 + assert_equal(false, cert.verify(@rsa2048)) + rescue OpenSSL::X509::CertificateError + end + + assert_raise(OpenSSL::X509::CertificateError){ + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::MD5.new) + } + end + + def test_dsig_algorithm_mismatch + assert_raise(OpenSSL::X509::CertificateError) do + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + end + assert_raise(OpenSSL::X509::CertificateError) do + cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::MD5.new) + end + end + + def test_dsa_with_sha2 + begin + cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA256.new) + assert_equal("dsa_with_SHA256", cert.signature_algorithm) + rescue OpenSSL::X509::CertificateError + # dsa_with_sha2 not supported. skip following test. + return + end + # TODO: need more tests for dsa + sha2 + + # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) + cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal("dsaWithSHA1", cert.signature_algorithm) + end if defined?(OpenSSL::Digest::SHA256) + + def test_check_private_key + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + assert_equal(true, cert.check_private_key(@rsa2048)) + end + + private + + def certificate_error_returns_false + yield + rescue OpenSSL::X509::CertificateError + false + end +end + +end diff --git a/test/1.9/test_x509crl.rb b/test/1.9/test_x509crl.rb new file mode 100644 index 0000000..56508e0 --- /dev/null +++ b/test/1.9/test_x509crl.rb @@ -0,0 +1,221 @@ +require_relative "utils" + +if defined?(OpenSSL) + +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(cert.issuer.to_der, crl.issuer.to_der) + 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(cert.issuer.to_der, crl.issuer.to_der) + 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_error_returns_false { crl.verify(@dsa256) }) + assert_equal(false, crl_error_returns_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_error_returns_false { crl.verify(@rsa1024) }) + assert_equal(false, crl_error_returns_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 + + private + + def crl_error_returns_false + yield + rescue OpenSSL::X509::CRLError + false + end +end + +end diff --git a/test/1.9/test_x509ext.rb b/test/1.9/test_x509ext.rb new file mode 100644 index 0000000..89b45c7 --- /dev/null +++ b/test/1.9/test_x509ext.rb @@ -0,0 +1,69 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestX509Extension < Test::Unit::TestCase + def setup + @basic_constraints_value = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Boolean(true), # CA + OpenSSL::ASN1::Integer(2) # pathlen + ]) + @basic_constraints = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("basicConstraints"), + OpenSSL::ASN1::Boolean(true), + OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der), + ]) + end + + def teardown + end + + def test_new + ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + assert_equal("basicConstraints", ext.oid) + assert_equal(true, ext.critical?) + assert_equal("CA:TRUE, pathlen:2", ext.value) + + ext = OpenSSL::X509::Extension.new("2.5.29.19", + @basic_constraints_value.to_der, true) + assert_equal(@basic_constraints.to_der, ext.to_der) + end + + def test_create_by_factory + ef = OpenSSL::X509::ExtensionFactory.new + + bc = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + assert_equal(@basic_constraints.to_der, bc.to_der) + + bc = ef.create_extension("basicConstraints", "CA:TRUE, pathlen:2", true) + assert_equal(@basic_constraints.to_der, bc.to_der) + + begin + ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_) + [crlDistPts] + URI.1 = http://www.example.com/crl + URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + _end_of_cnf_ + rescue NotImplementedError + return + end + + cdp = ef.create_extension("crlDistributionPoints", "@crlDistPts") + assert_equal(false, cdp.critical?) + assert_equal("crlDistributionPoints", cdp.oid) + assert_match(%{URI:http://www\.example\.com/crl}, cdp.value) + assert_match( + %r{URI:ldap://ldap\.example\.com/cn=ca\?certificateRevocationList;binary}, + cdp.value) + + cdp = ef.create_extension("crlDistributionPoints", "critical, @crlDistPts") + assert_equal(true, cdp.critical?) + assert_equal("crlDistributionPoints", cdp.oid) + assert_match(%{URI:http://www.example.com/crl}, cdp.value) + assert_match( + %r{URI:ldap://ldap.example.com/cn=ca\?certificateRevocationList;binary}, + cdp.value) + end +end + +end diff --git a/test/1.9/test_x509name.rb b/test/1.9/test_x509name.rb new file mode 100644 index 0000000..cf5a8b0 --- /dev/null +++ b/test/1.9/test_x509name.rb @@ -0,0 +1,296 @@ +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestX509Name < Test::Unit::TestCase + OpenSSL::ASN1::ObjectId.register( + "1.2.840.113549.1.9.1", "emailAddress", "emailAddress") + OpenSSL::ASN1::ObjectId.register( + "2.5.4.5", "serialNumber", "serialNumber") + + 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(dn2) + 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(dn2, @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_s_parse_rfc2253 + scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan) + + assert_equal([["C", "JP"]], scanner.call("C=JP")) + assert_equal([ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ], + scanner.call( + "emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,"+ + "DC=ruby-lang,DC=org") + ) + + u8 = OpenSSL::ASN1::UTF8STRING + assert_equal([ + ["DC", "org"], + ["DC", "ruby-lang"], + ["O", ",=+<>#;"], + ["O", ",=+<>#;"], + ["OU", ""], + ["OU", ""], + ["L", "aaa=\"bbb, ccc\""], + ["L", "aaa=\"bbb, ccc\""], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], + ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["2.5.4.3", "GOTOU, Yuuzou"], + ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], + ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], + ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ], + scanner.call( + "emailAddress=gotoyuzo@ruby-lang.org," + + "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + + 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + + 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + + '2.5.4.3=GOTOU\,\20Yuuzou,' + + '2.5.4.3=GOTOU\, Yuuzou,' + + '2.5.4.3="GOTOU, Yuuzou",' + + '2.5.4.3="GOTOU\, Yuuzou",' + + "CN=#0C0CE5BE8CE897A4E8A395E894B5," + + 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + + "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + + "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + + 'L=aaa\=\"bbb\, ccc\",' + + 'L="aaa=\"bbb, ccc\"",' + + 'OU=,' + + 'OU="",' + + 'O=\,\=\+\<\>\#\;,' + + 'O=",=+<>#;",' + + "DC=ruby-lang," + + "DC=org") + ) + + [ + "DC=org+DC=jp", + "DC=org,DC=ruby-lang+DC=rubyist,DC=www" + ].each{|dn| + ex = scanner.call(dn) rescue $! + dn_r = Regexp.escape(dn) + assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) + } + + [ + ["DC=org,DC=exapmle,CN", "CN"], + ["DC=org,DC=example,", ""], + ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], + ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], + ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], + ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], + ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], + ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], + ].each{|dn, msg| + ex = scanner.call(dn) rescue $! + assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) + } + + dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" + name = OpenSSL::X509::Name.parse_rfc2253(dn) + assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) + 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]) + 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 + + def test_equals2 + n1 = OpenSSL::X509::Name.parse 'CN=a' + n2 = OpenSSL::X509::Name.parse 'CN=a' + + assert_equal n1, n2 + end + + def test_spaceship + n1 = OpenSSL::X509::Name.parse 'CN=a' + n2 = OpenSSL::X509::Name.parse 'CN=b' + + assert_equal -1, n1 <=> n2 + end + + def name_hash(name) + # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of + # X509Name for X509_NAME_hash. + name.respond_to?(:hash_old) ? name.hash_old : name.hash + end + + def test_hash + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + d = Digest::MD5.digest(name.to_der) + expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 + assert_equal(expected, name_hash(name)) + # + dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org" + name = OpenSSL::X509::Name.parse(dn) + d = Digest::MD5.digest(name.to_der) + expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 + assert_equal(expected, name_hash(name)) + end +end + +end diff --git a/test/1.9/test_x509req.rb b/test/1.9/test_x509req.rb new file mode 100644 index 0000000..882a1d7 --- /dev/null +++ b/test/1.9/test_x509req.rb @@ -0,0 +1,150 @@ +require_relative "utils" + +if defined?(OpenSSL) + +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, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_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, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_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, request_error_returns_false { req.verify(@rsa1024) }) + assert_equal(false, request_error_returns_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)) + + begin + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) + assert_equal(true, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) + req.version = 1 + assert_equal(false, req.verify(@rsa1024)) + rescue OpenSSL::X509::RequestError + end + + assert_raise(OpenSSL::X509::RequestError){ + issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } + end + + private + + def request_error_returns_false + yield + rescue OpenSSL::X509::RequestError + false + end +end + +end diff --git a/test/1.9/test_x509store.rb b/test/1.9/test_x509store.rb new file mode 100644 index 0000000..ff820c1 --- /dev/null +++ b/test/1.9/test_x509store.rb @@ -0,0 +1,229 @@ +require_relative "utils" + +if defined?(OpenSSL) + +class OpenSSL::TestX509Store < 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 + @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") + @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") + @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 test_nosegv_on_cleanup + cert = OpenSSL::X509::Certificate.new + store = OpenSSL::X509::Store.new + ctx = OpenSSL::X509::StoreContext.new(store, cert, []) + ctx.cleanup + ctx.verify + end + + def issue_cert(*args) + OpenSSL::TestUtils.issue_cert(*args) + end + + def issue_crl(*args) + OpenSSL::TestUtils.issue_crl(*args) + end + + def test_verify + now = Time.at(Time.now.to_i) + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, ca_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + ca2_cert = issue_cert(@ca2, @rsa1024, 2, now, now+1800, ca_exts, + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + ee1_cert = issue_cert(@ee1, @dsa256, 10, now, now+1800, ee_exts, + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + ee2_cert = issue_cert(@ee2, @dsa512, 20, now, now+1800, ee_exts, + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + ee3_cert = issue_cert(@ee2, @dsa512, 30, now-100, now-1, ee_exts, + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + ee4_cert = issue_cert(@ee2, @dsa512, 40, now+1000, now+2000, ee_exts, + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [2, now, 1], ] + crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [20, now, 1], ] + crl2 = issue_crl(revoke_info, 1, now, now+1800, [], + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + revoke_info = [] + crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], + ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) + + assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed + assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, ee1_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, ee2_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, ee3_cert.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, crl1.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, crl1_2.verify(ca1_cert.public_key)) # issued by ca1 + assert_equal(true, crl2.verify(ca2_cert.public_key)) # issued by ca2 + assert_equal(true, crl2_2.verify(ca2_cert.public_key)) # issued by ca2 + + store = OpenSSL::X509::Store.new + assert_equal(false, store.verify(ca1_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + assert_equal(false, store.verify(ca2_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + store.add_cert(ca1_cert) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + assert_equal("ok", store.error_string) + chain = store.chain + assert_equal(2, chain.size) + assert_equal(@ca2.to_der, chain[0].subject.to_der) + assert_equal(@ca1.to_der, chain[1].subject.to_der) + + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + assert_equal(false, store.verify(ca2_cert)) + assert_not_equal(OpenSSL::X509::V_OK, store.error) + + store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN + assert_equal(true, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + + store.add_cert(ca2_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + assert_equal(true, store.verify(ee1_cert)) + assert_equal(true, store.verify(ee2_cert)) + assert_equal(OpenSSL::X509::V_OK, store.error) + assert_equal("ok", store.error_string) + chain = store.chain + assert_equal(3, chain.size) + assert_equal(@ee2.to_der, chain[0].subject.to_der) + assert_equal(@ca2.to_der, chain[1].subject.to_der) + assert_equal(@ca1.to_der, chain[2].subject.to_der) + assert_equal(false, store.verify(ee3_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_match(/expire/i, store.error_string) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + assert_match(/not yet valid/i, store.error_string) + + store = OpenSSL::X509::Store.new + store.add_cert(ca1_cert) + store.add_cert(ca2_cert) + store.time = now + 1500 + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee4_cert)) + store.time = now + 1900 + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + store.time = now + 4000 + assert_equal(false, store.verify(ee1_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee4_cert)) + assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) + + # the underlying X509 struct caches the result of the last + # verification for signature and not-before. so the following code + # rebuilds new objects to avoid site effect. + store.time = Time.now - 4000 + assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert))) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert))) + assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) + + return unless defined?(OpenSSL::X509::V_FLAG_CRL_CHECK) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK + store.add_cert(ca1_cert) + store.add_crl(crl1) # revoke no cert + store.add_crl(crl2) # revoke ee2_cert + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee1_cert, [ca2_cert])) + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK + store.add_cert(ca1_cert) + store.add_crl(crl1_2) # revoke ca2_cert + store.add_crl(crl2) # revoke ee2_cert + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(true, store.verify(ee1_cert, [ca2_cert]), + "This test is expected to be success with OpenSSL 0.9.7c or later.") + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store.flags = + OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + assert_equal(true, store.verify(ca1_cert)) + assert_equal(false, store.verify(ca2_cert)) + assert_equal(false, store.verify(ee1_cert, [ca2_cert])) + assert_equal(false, store.verify(ee2_cert, [ca2_cert])) + + store = OpenSSL::X509::Store.new + store.purpose = OpenSSL::X509::PURPOSE_ANY + store.flags = + OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL + store.add_cert(ca1_cert) + store.add_cert(ca2_cert) + store.add_crl(crl1) + store.add_crl(crl2_2) # issued by ca2 but expired. + assert_equal(true, store.verify(ca1_cert)) + assert_equal(true, store.verify(ca2_cert)) + assert_equal(false, store.verify(ee1_cert)) + assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error) + assert_equal(false, store.verify(ee2_cert)) + end + + def test_set_errors + now = Time.now + ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, [], + nil, nil, OpenSSL::Digest::SHA1.new) + store = OpenSSL::X509::Store.new + store.add_cert(ca1_cert) + assert_raise(OpenSSL::X509::StoreError){ + store.add_cert(ca1_cert) # add same certificate twice + } + + revoke_info = [] + crl1 = issue_crl(revoke_info, 1, now, now+1800, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + revoke_info = [ [2, now, 1], ] + crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], + ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) + store.add_crl(crl1) + if /0\.9\.8.*-rhel/ =~ OpenSSL::OPENSSL_VERSION + # RedHat is distributing a patched version of OpenSSL that allows + # multiple CRL for a key (multi-crl.patch) + assert_nothing_raised do + store.add_crl(crl2) # add CRL issued by same CA twice. + end + else + assert_raise(OpenSSL::X509::StoreError){ + store.add_crl(crl2) # add CRL issued by same CA twice. + } + end + end +end + +end diff --git a/test/1.9/utils.rb b/test/1.9/utils.rb new file mode 100644 index 0000000..c4c0a0c --- /dev/null +++ b/test/1.9/utils.rb @@ -0,0 +1,313 @@ +begin + require "openssl" +rescue LoadError +end +require "test/unit" +require "digest/md5" +require 'tempfile' +require "rbconfig" +require "socket" +require_relative '../ruby/envutil' + +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_ + +if defined?(OpenSSL::PKey::EC) + + TEST_KEY_EC_P256V1 = OpenSSL::PKey::EC.new <<-_end_of_pem_ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 +AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt +CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== +-----END EC PRIVATE KEY----- + _end_of_pem_ + +end + + TEST_KEY_DH512 = OpenSSL::PKey::DH.new <<-_end_of_pem_ +-----BEGIN DH PARAMETERS----- +MEYCQQDmWXGPqk76sKw/edIOdhAQD4XzjJ+AR/PTk2qzaGs+u4oND2yU5D2NN4wr +aPgwHyJBiK1/ebK3tYcrSKrOoRyrAgEC +-----END DH PARAMETERS----- + _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.issuer = issuer.subject + crl.version = 1 + crl.last_update = lastup + crl.next_update = nextup + revoke_info.each{|rserial, time, reason_code| + revoked = OpenSSL::X509::Revoked.new + revoked.serial = rserial + 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 + + def silent + begin + back, $VERBOSE = $VERBOSE, nil + yield + ensure + $VERBOSE = back + end + end + + class OpenSSL::SSLTestCase < Test::Unit::TestCase + RUBY = EnvUtil.rubybin + SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb") + PORT = 20443 + ITERATIONS = ($0 == __FILE__) ? 100 : 10 + + def setup + @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256 + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + now = Time.at(Time.now.to_i) + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + @ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) + @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + @server = nil + end + + def teardown + end + + def issue_cert(*arg) + OpenSSL::TestUtils.issue_cert(*arg) + end + + def issue_crl(*arg) + OpenSSL::TestUtils.issue_crl(*arg) + end + + def readwrite_loop(ctx, ssl) + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.accept + next + end + ssl.write(line) + end + rescue OpenSSL::SSL::SSLError + rescue IOError + ensure + ssl.close rescue nil + end + + def server_loop(ctx, ssls, server_proc) + loop do + ssl = nil + begin + ssl = ssls.accept + rescue OpenSSL::SSL::SSLError + retry + end + + Thread.start do + Thread.current.abort_on_exception = true + server_proc.call(ctx, ssl) + end + end + rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK + end + + DHParam = OpenSSL::PKey::DH.new(128) + def start_server(port0, verify_mode, start_immediately, args = {}, &block) + ctx_proc = args[:ctx_proc] + server_proc = args[:server_proc] + server_proc ||= method(:readwrite_loop) + + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert_store = store + #ctx.extra_chain_cert = [ ca_cert ] + ctx.cert = @svr_cert + ctx.key = @svr_key + ctx.tmp_dh_callback = proc { DHParam } + ctx.verify_mode = verify_mode + ctx_proc.call(ctx) if ctx_proc + + Socket.do_not_reverse_lookup = true + tcps = nil + port = port0 + begin + tcps = TCPServer.new("127.0.0.1", port) + rescue Errno::EADDRINUSE + port += 1 + retry + end + + ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) + ssls.start_immediately = start_immediately + + begin + server = Thread.new do + Thread.current.abort_on_exception = true + server_loop(ctx, ssls, server_proc) + end + + $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, $$, port) if $DEBUG + + block.call(server, port.to_i) + ensure + begin + begin + tcps.shutdown + rescue Errno::ENOTCONN + # when `Errno::ENOTCONN: Socket is not connected' on some platforms, + # call #close instead of #shutdown. + tcps.close + tcps = nil + end if (tcps) + if (server) + server.join(5) + if server.alive? + server.kill + server.join + flunk("TCPServer was closed and SSLServer is still alive") unless $! + end + end + ensure + tcps.close if (tcps) + end + end + end + + def starttls(ssl) + ssl.puts("STARTTLS") + sleep 1 # When this line is eliminated, process on Cygwin blocks + # forever at ssl.connect. But I don't know why it does. + ssl.connect + end + end + +end if defined?(OpenSSL) diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb new file mode 100644 index 0000000..4a8451a --- /dev/null +++ b/test/ruby/envutil.rb @@ -0,0 +1,208 @@ +require "open3" +require "timeout" + +module EnvUtil + def rubybin + unless ENV["RUBYOPT"] + + end + if ruby = ENV["RUBY"] + return ruby + end + ruby = "ruby" + rubyexe = ruby+".exe" + 3.times do + if File.exist? ruby and File.executable? ruby and !File.directory? ruby + return File.expand_path(ruby) + end + if File.exist? rubyexe and File.executable? rubyexe + return File.expand_path(rubyexe) + end + ruby = File.join("..", ruby) + end + if defined?(RbConfig.ruby) + RbConfig.ruby + else + "ruby" + end + end + module_function :rubybin + + LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" + + def invoke_ruby(args, stdin_data="", capture_stdout=false, capture_stderr=false, opt={}) + in_c, in_p = IO.pipe + out_p, out_c = IO.pipe if capture_stdout + err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout + opt = opt.dup + opt[:in] = in_c + opt[:out] = out_c if capture_stdout + opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr + if enc = opt.delete(:encoding) + out_p.set_encoding(enc) if out_p + err_p.set_encoding(enc) if err_p + end + c = "C" + child_env = {} + LANG_ENVS.each {|lc| child_env[lc] = c} + if Array === args and Hash === args.first + child_env.update(args.shift) + end + args = [args] if args.kind_of?(String) + pid = spawn(child_env, EnvUtil.rubybin, *args, opt) + in_c.close + out_c.close if capture_stdout + err_c.close if capture_stderr && capture_stderr != :merge_to_stdout + if block_given? + return yield in_p, out_p, err_p + else + th_stdout = Thread.new { out_p.read } if capture_stdout + th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout + in_p.write stdin_data.to_str + in_p.close + timeout = opt.fetch(:timeout, 10) + if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) + stdout = th_stdout.value if capture_stdout + stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout + else + raise Timeout::Error + end + out_p.close if capture_stdout + err_p.close if capture_stderr && capture_stderr != :merge_to_stdout + Process.wait pid + status = $? + return stdout, stderr, status + end + ensure + [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| + io.close if io && !io.closed? + end + [th_stdout, th_stderr].each do |th| + (th.kill; th.join) if th + end + end + module_function :invoke_ruby + + alias rubyexec invoke_ruby + class << self + alias rubyexec invoke_ruby + end + + def verbose_warning + class << (stderr = "") + alias write << + end + stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true + yield stderr + ensure + stderr, $stderr, $VERBOSE = $stderr, stderr, verbose + return stderr + end + module_function :verbose_warning + + def suppress_warning + verbose, $VERBOSE = $VERBOSE, nil + yield + ensure + $VERBOSE = verbose + end + module_function :suppress_warning + + def under_gc_stress + stress, GC.stress = GC.stress, true + yield + ensure + GC.stress = stress + end + module_function :under_gc_stress +end + +module Test + module Unit + module Assertions + public + def assert_normal_exit(testsrc, message = '', opt = {}) + if opt.include?(:child_env) + opt = opt.dup + child_env = [opt.delete(:child_env)] || [] + else + child_env = [] + end + out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt) + pid = status.pid + faildesc = proc do + signo = status.termsig + signame = Signal.list.invert[signo] + sigdesc = "signal #{signo}" + if signame + sigdesc = "SIG#{signame} (#{sigdesc})" + end + if status.coredump? + sigdesc << " (core dumped)" + end + full_message = '' + if !message.empty? + full_message << message << "\n" + end + full_message << "pid #{pid} killed by #{sigdesc}" + if !out.empty? + out << "\n" if /\n\z/ !~ out + full_message << "\n#{out.gsub(/^/, '| ')}" + end + full_message + end + assert !status.signaled?, faildesc + end + + def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, opt={}) + stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt) + if block_given? + yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }) + else + if test_stdout.is_a?(Regexp) + assert_match(test_stdout, stdout, message) + else + assert_equal(test_stdout, stdout.lines.map {|l| l.chomp }, message) + end + if test_stderr.is_a?(Regexp) + assert_match(test_stderr, stderr, message) + else + assert_equal(test_stderr, stderr.lines.map {|l| l.chomp }, message) + end + status + end + end + + def assert_ruby_status(args, test_stdin="", message=nil, opt={}) + _, _, status = EnvUtil.invoke_ruby(args, test_stdin, false, false, opt) + m = message ? "#{message} (#{status.inspect})" : "ruby exit status is not success: #{status.inspect}" + assert(status.success?, m) + end + + def assert_warn(msg) + stderr = EnvUtil.verbose_warning { yield } + assert(msg === stderr, "warning message #{stderr.inspect} is expected to match #{msg.inspect}") + end + + end + end +end + +begin + require 'rbconfig' +rescue LoadError +else + module RbConfig + @ruby = EnvUtil.rubybin + class << self + undef ruby if method_defined?(:ruby) + attr_reader :ruby + end + dir = File.dirname(ruby) + name = File.basename(ruby, CONFIG['EXEEXT']) + CONFIG['bindir'] = dir + CONFIG['ruby_install_name'] = name + CONFIG['RUBY_INSTALL_NAME'] = name + Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap) + end +end diff --git a/test/ruby/ut_eof.rb b/test/ruby/ut_eof.rb new file mode 100644 index 0000000..b7219dd --- /dev/null +++ b/test/ruby/ut_eof.rb @@ -0,0 +1,128 @@ +require 'test/unit' + +module TestEOF + def test_eof_0 + open_file("") {|f| + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("") {|f| + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("") {|f| + s = "x" + assert_equal("", f.read(nil, s)) + assert_equal("", s) + } + open_file("") {|f| + s = "x" + assert_nil(f.read(10, s)) + assert_equal("", s) + } + end + + def test_eof_0_rw + return unless respond_to? :open_file_rw + open_file_rw("") {|f| + assert_equal("", f.read) + assert_equal("", f.read) + assert_equal(0, f.syswrite("")) + assert_equal("", f.read) + } + end + + def test_eof_1 + open_file("a") {|f| + assert_equal("", f.read(0)) + assert_equal("a", f.read(1)) + assert_equal("" , f.read(0)) + assert_equal("" , f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + assert_equal("a", f.read(1)) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_nil(f.read(1)) + assert_equal("", f.read) + assert_nil(f.read(1)) + } + open_file("a") {|f| + assert_equal("a", f.read(2)) + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file("a") {|f| + assert_equal("a", f.read) + assert_equal("", f.read(0)) + } + open_file("a") {|f| + s = "x" + assert_equal("a", f.read(nil, s)) + assert_equal("a", s) + } + open_file("a") {|f| + s = "x" + assert_equal("a", f.read(10, s)) + assert_equal("a", s) + } + end + + def test_eof_2 + open_file("") {|f| + assert_equal("", f.read) + assert(f.eof?) + } + end + + def test_eof_3 + open_file("") {|f| + assert(f.eof?) + } + end + + module Seek + def open_file_seek(content, pos) + open_file(content) do |f| + f.seek(pos) + yield f + end + end + + def test_eof_0_seek + open_file_seek("", 10) {|f| + assert_equal(10, f.pos) + assert_equal("", f.read(0)) + assert_equal("", f.read) + assert_equal("", f.read(0)) + assert_equal("", f.read) + } + end + + def test_eof_1_seek + open_file_seek("a", 10) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + open_file_seek("a", 1) {|f| + assert_equal("", f.read) + assert_equal("", f.read) + } + end + end +end From 38d00c7cd7fef4dc177aeca7ca6335b58570f087 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Fri, 14 Oct 2011 15:16:29 +0900 Subject: [PATCH 13/66] Reduce test warnings Use proper version of test/{1.8 or 1.9}/utils.rb --- test/test_ssl.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 96db4e3..da797c2 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -3,7 +3,7 @@ require 'webrick/https' require 'net/https' require 'logger' -require File.join(File.dirname(__FILE__), "1.8/utils.rb") +require File.join(File.dirname(__FILE__), (RUBY_VERSION >= '1.9.0' ? '1.9' : '1.8'), "utils.rb") class TestSSL < Test::Unit::TestCase From a5fc39b83f14ae7f9d0e477053b122835bfd20b1 Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 13 Sep 2011 22:49:15 -0400 Subject: [PATCH 14/66] Add empty method signatures to missing methods. --- src/java/org/jruby/ext/openssl/SSLSocket.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java index 6351ff7..23554f4 100644 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/java/org/jruby/ext/openssl/SSLSocket.java @@ -190,6 +190,11 @@ public IRubyObject connect(ThreadContext context) { return this; } + @JRubyMethod + public IRubyObject connect_nonblock(ThreadContext context) { + throw new UnsupportedOperationException(); + } + @JRubyMethod public IRubyObject accept(ThreadContext context) { Ruby runtime = context.getRuntime(); @@ -229,6 +234,11 @@ public IRubyObject accept(ThreadContext context) { return this; } + @JRubyMethod + public IRubyObject accept_nonblock(ThreadContext context) { + throw new UnsupportedOperationException(); + } + @JRubyMethod public IRubyObject verify_result() { if (engine == null) { @@ -535,6 +545,11 @@ public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { } } + @JRubyMethod(rest = true, required = 1, optional = 1) + public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject[] args) { + throw new UnsupportedOperationException(); + } + @JRubyMethod public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { Ruby runtime = context.getRuntime(); @@ -557,6 +572,11 @@ public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { } } + @JRubyMethod + public IRubyObject syswrite_nonblock(ThreadContext context) { + throw new UnsupportedOperationException(); + } + private void checkClosed() { if (!getSocketChannel().isOpen()) { throw getRuntime().newIOError("closed stream"); @@ -660,6 +680,16 @@ public IRubyObject pending() { System.err.println("WARNING: unimplemented method called: SSLSocket#pending"); return getRuntime().getNil(); } + + @JRubyMethod + public IRubyObject session_reused_p() { + throw new UnsupportedOperationException(); + } + + @JRubyMethod + public synchronized IRubyObject session_set(IRubyObject aSession) { + throw new UnsupportedOperationException(); + } private SocketChannel getSocketChannel() { return (SocketChannel) io.getChannel(); From 69fa61c87d5d4b016aea602828b783f801eb0674 Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Wed, 14 Sep 2011 11:53:49 -0400 Subject: [PATCH 15/66] Implement sysread_nonblock and syswrite_nonblock. --- src/java/org/jruby/ext/openssl/SSLSocket.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java index 23554f4..931f450 100644 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/java/org/jruby/ext/openssl/SSLSocket.java @@ -50,6 +50,7 @@ import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyClass; +import org.jruby.RubyException; import org.jruby.RubyIO; import org.jruby.RubyModule; import org.jruby.RubyNumeric; @@ -497,8 +498,7 @@ private void doShutdown() throws IOException { flushData(); } - @JRubyMethod(rest = true, required = 1, optional = 1) - public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { + private IRubyObject do_sysread(ThreadContext context, IRubyObject[] args, boolean nonBlock) { Ruby runtime = context.getRuntime(); int len = RubyNumeric.fix2int(args[0]); RubyString str = null; @@ -518,8 +518,15 @@ public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { try { // So we need to make sure to only block when there is no data left to process - if(engine == null || !(peerAppData.hasRemaining() || peerNetData.position() > 0)) { - waitSelect(SelectionKey.OP_READ); + if (engine == null || !(peerAppData.hasRemaining() || peerNetData.position() > 0)) { + if (nonBlock) { + RaiseException re = newSSLError(runtime, "read would raise"); + IRubyObject waitReadable = runtime.getIO().getConstant("WaitReadable"); + re.getException().extend(new IRubyObject[] {waitReadable}); + throw re; + } else { + waitSelect(SelectionKey.OP_READ); + } } ByteBuffer dst = ByteBuffer.allocate(len); @@ -545,17 +552,28 @@ public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { } } + @JRubyMethod(rest = true, required = 1, optional = 1) + public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { + return do_sysread(context, args, false); + } + @JRubyMethod(rest = true, required = 1, optional = 1) public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject[] args) { - throw new UnsupportedOperationException(); + return do_sysread(context, args, true); } - @JRubyMethod - public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { + private IRubyObject do_syswrite(ThreadContext context, IRubyObject arg, boolean nonBlock) { Ruby runtime = context.getRuntime(); try { checkClosed(); - waitSelect(SelectionKey.OP_WRITE); + if (nonBlock) { + RaiseException re = newSSLError(runtime, "write would raise"); + IRubyObject waitWritable = runtime.getIO().getConstant("WaitWritable"); + re.getException().extend(new IRubyObject[] {waitWritable}); + throw re; + } else { + waitSelect(SelectionKey.OP_WRITE); + } byte[] bls = arg.convertToString().getBytes(); ByteBuffer b1 = ByteBuffer.wrap(bls); int written; @@ -573,8 +591,13 @@ public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { } @JRubyMethod - public IRubyObject syswrite_nonblock(ThreadContext context) { - throw new UnsupportedOperationException(); + public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { + return do_syswrite(context, arg, false); + } + + @JRubyMethod + public IRubyObject syswrite_nonblock(ThreadContext context, IRubyObject arg) { + return do_syswrite(context, arg, true); } private void checkClosed() { From cd9e9706974cf248d99813d49bc03ee0f2b913bd Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Fri, 16 Sep 2011 15:51:51 -0400 Subject: [PATCH 16/66] Return nil if engine is null or getLocalCertificates returns null. --- src/java/org/jruby/ext/openssl/SSLSocket.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java index 931f450..3a7d7fe 100644 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/java/org/jruby/ext/openssl/SSLSocket.java @@ -641,12 +641,16 @@ public IRubyObject sysclose() { public IRubyObject cert() { try { Certificate[] cert = engine.getSession().getLocalCertificates(); - if (cert.length > 0) { + + if (cert != null && cert.length > 0) { return X509Cert.wrap(getRuntime(), cert[0]); } } catch (CertificateEncodingException ex) { throw X509Cert.newCertificateError(getRuntime(), ex); - } + } catch (NullPointerException ex) { + return getRuntime().getNil(); + } + return getRuntime().getNil(); } From bd9ec62ae3ff4a5d681df7b4866520f9767fc30b Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 14 Dec 2011 13:47:18 +0900 Subject: [PATCH 17/66] JRUBY-6270: wrong keyUsage check for SSL server We only allow digitalSignature && keyEncipherment keyUsage for SSL server in contrast to OpenSSL allows digitalSignature || keyEncipherment. Follow OpenSSL. --- .../jruby/ext/openssl/x509store/Purpose.java | 3 ++- test/fixture/purpose/ca/newcerts/4_cert.pem | 19 +++++++++++++++++++ .../purpose/sslserver_no_dsig_in_keyUsage.pem | 19 +++++++++++++++++++ test/test_x509store.rb | 8 ++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/fixture/purpose/ca/newcerts/4_cert.pem create mode 100644 test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem diff --git a/src/java/org/jruby/ext/openssl/x509store/Purpose.java b/src/java/org/jruby/ext/openssl/x509store/Purpose.java index dee6794..2370da4 100644 --- a/src/java/org/jruby/ext/openssl/x509store/Purpose.java +++ b/src/java/org/jruby/ext/openssl/x509store/Purpose.java @@ -357,7 +357,8 @@ public int call(Object _xp, Object _x, Object _ca) throws Exception { // when the cert has nsCertType, it must include NS_SSL_SERVER return 0; } - if(x.getKeyUsage() != null && (!x.getKeyUsage()[0] || !x.getKeyUsage()[2])) { + /* Now as for keyUsage: we'll at least need to sign OR encipher */ + if(x.getKeyUsage() != null && !(x.getKeyUsage()[0] || x.getKeyUsage()[2])) { return 0; } return 1; diff --git a/test/fixture/purpose/ca/newcerts/4_cert.pem b/test/fixture/purpose/ca/newcerts/4_cert.pem new file mode 100644 index 0000000..6961c84 --- /dev/null +++ b/test/fixture/purpose/ca/newcerts/4_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa +MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 +MQswCQYDVQQDDAJDQTAeFw0xMTEyMTQwNDQxNTNaFw0yOTEyMDkwNDQxNTNaMD0x +CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzESMBAGA1UE +AwwJc3Nsc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgYsazavfR +a72yK4qfnIjOrDT9Uv2ToL4swbE86PXY5N+YvUig3fVmNJo72rT5JlAODs+MtJJU +aJ8HsczlGdrhjTWyT/0fyoY/rC4mi5UFASBCbaoaviDPgbhI6ehBY6d5vEYQOW79 +fL95KIa+OyGzUNYy+EkSxJmvt/8EJYtqIwIDAQABo4GFMIGCMAwGA1UdEwEB/wQC +MAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm +aWNhdGUwHQYDVR0OBBYEFJsUyGU/R4muSKVIeckJElcBNbipMAsGA1UdDwQEAwIF +IDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEArdmTvG5H +elHkiHWp/yFdiIrbUHfDsAmB1jN7Zhte9yWzUuaVKR6GS6FzL4zU6dgAA3UNroVK +MuyeL5Cejsck2+HgOvAtwTJFjP4c8YwdlYuycvMkk5EbaByY1h59ZvV1J+GxmoDA +uO3iTqGrKwrFDK59yuxhdn1yyGTwYTBAdvllfSmTmfnbOkV/faF8gpRvrenx3lLK +eAVhBCzAw2cblXKJEvly+wzAXykS6jagtrnHm5ilt2R5zPzS1wNJlzBq4laI+pZU +timqb2wMA9TLd4FCKqK4HwiUKyAR7eknxtdskQ0/2DBAiOoh1Gl5hwnrDAlb73vA +DDOusxgmoBZS4w== +-----END CERTIFICATE----- diff --git a/test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem b/test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem new file mode 100644 index 0000000..6961c84 --- /dev/null +++ b/test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa +MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 +MQswCQYDVQQDDAJDQTAeFw0xMTEyMTQwNDQxNTNaFw0yOTEyMDkwNDQxNTNaMD0x +CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzESMBAGA1UE +AwwJc3Nsc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgYsazavfR +a72yK4qfnIjOrDT9Uv2ToL4swbE86PXY5N+YvUig3fVmNJo72rT5JlAODs+MtJJU +aJ8HsczlGdrhjTWyT/0fyoY/rC4mi5UFASBCbaoaviDPgbhI6ehBY6d5vEYQOW79 +fL95KIa+OyGzUNYy+EkSxJmvt/8EJYtqIwIDAQABo4GFMIGCMAwGA1UdEwEB/wQC +MAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm +aWNhdGUwHQYDVR0OBBYEFJsUyGU/R4muSKVIeckJElcBNbipMAsGA1UdDwQEAwIF +IDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEArdmTvG5H +elHkiHWp/yFdiIrbUHfDsAmB1jN7Zhte9yWzUuaVKR6GS6FzL4zU6dgAA3UNroVK +MuyeL5Cejsck2+HgOvAtwTJFjP4c8YwdlYuycvMkk5EbaByY1h59ZvV1J+GxmoDA +uO3iTqGrKwrFDK59yuxhdn1yyGTwYTBAdvllfSmTmfnbOkV/faF8gpRvrenx3lLK +eAVhBCzAw2cblXKJEvly+wzAXykS6jagtrnHm5ilt2R5zPzS1wNJlzBq4laI+pZU +timqb2wMA9TLd4FCKqK4HwiUKyAR7eknxtdskQ0/2DBAiOoh1Gl5hwnrDAlb73vA +DDOusxgmoBZS4w== +-----END CERTIFICATE----- diff --git a/test/test_x509store.rb b/test/test_x509store.rb index e421bbe..a6e7ecf 100644 --- a/test/test_x509store.rb +++ b/test/test_x509store.rb @@ -63,6 +63,14 @@ def test_purpose_ssl_server assert_equal(true, @store.verify(cert)) end + # keyUsage: no digitalSignature bit, keyEncipherment bit only. + def test_purpose_ssl_server_no_dsig_in_keyUsage + @store.add_file(path("fixture/purpose/cacert.pem")) + cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslserver_no_dsig_in_keyUsage.pem"))) + @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER + assert_equal(true, @store.verify(cert)) + end + def test_add_file_multiple f = Tempfile.new("globalsign-root.pem") f << GLOBALSIGN_ROOT_CA From f85c4362ec04b97ecd75e703ccccfc122d9d4554 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 15 Dec 2011 13:51:26 +0900 Subject: [PATCH 18/66] Update gemspec You can generate it by 'rake gemspec' --- jruby-openssl.gemspec | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index b872599..fae6f04 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -4,30 +4,30 @@ Gem::Specification.new do |s| s.name = %q{jruby-openssl} s.version = "0.7.5.dev" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Ola Bini and JRuby contributors"] - s.date = %q{2011-04-28} + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.authors = [%q{Ola Bini and JRuby contributors}] + s.date = %q{2011-12-15} s.description = %q{JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library.} s.email = %q{ola.bini@gmail.com} - s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/jopenssl.jar", "lib/openssl.rb", "lib/openssl/dummy.rb", "lib/openssl/dummyssl.rb", "lib/openssl/config.rb", "lib/openssl/cipher.rb", "lib/openssl/ssl.rb", "lib/openssl/bn.rb", "lib/openssl/x509.rb", "lib/openssl/digest.rb", "lib/openssl/buffering.rb", "lib/openssl/pkcs7.rb", "lib/jopenssl/version.rb", "test/test_imaps.rb", "test/test_all.rb", "test/test_integration.rb", "test/ut_eof.rb", "test/test_java.rb", "test/test_openssl.rb", "test/test_pkey.rb", "test/test_cipher.rb", "test/cert_with_ec_pk.cer", "test/test_pkcs7.rb", "test/test_x509store.rb", "test/test_certificate.rb", "test/test_parse_certificate.rb", "test/test_ssl.rb", "test/openssl/test_x509name.rb", "test/openssl/test_ns_spki.rb", "test/openssl/test_x509cert.rb", "test/openssl/ssl_server.rb", "test/openssl/test_pair.rb", "test/openssl/test_ec.rb", "test/openssl/test_config.rb", "test/openssl/utils.rb", "test/openssl/test_x509req.rb", "test/openssl/test_cipher.rb", "test/openssl/test_digest.rb", "test/openssl/test_x509ext.rb", "test/openssl/test_asn1.rb", "test/openssl/test_pkcs7.rb", "test/openssl/test_x509store.rb", "test/openssl/test_pkey_rsa.rb", "test/openssl/test_ssl.rb", "test/openssl/test_x509crl.rb", "test/openssl/test_hmac.rb", "test/ref/compile.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/fixture/cacert.pem", "test/fixture/ca-bundle.crt", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/localhost_keypair.pem", "test/fixture/verisign_c3.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/keypair.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/sslserver.pem", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/ca_path/verisign.pem", "test/fixture/ca_path/72fa7371.0", "test/java/pkcs7_mime_enveloped.message", "test/java/pkcs7_mime_signed.message", "test/java/test_java_pkcs7.rb", "test/java/test_java_bio.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_mime.rb", "test/java/test_java_attribute.rb", "test/java/test_java_smime.rb"] + s.extra_rdoc_files = [%q{History.txt}, %q{Manifest.txt}, %q{README.txt}, %q{License.txt}] + s.files = [%q{Rakefile}, %q{History.txt}, %q{Manifest.txt}, %q{README.txt}, %q{License.txt}, %q{lib/jopenssl.jar}, %q{lib/openssl.rb}, %q{lib/openssl}, %q{lib/jopenssl}, %q{lib/openssl/bn.rb}, %q{lib/openssl/dummyssl.rb}, %q{lib/openssl/pkcs7.rb}, %q{lib/openssl/cipher.rb}, %q{lib/openssl/digest.rb}, %q{lib/openssl/ssl.rb}, %q{lib/openssl/buffering.rb}, %q{lib/openssl/x509.rb}, %q{lib/openssl/config.rb}, %q{lib/openssl/dummy.rb}, %q{lib/jopenssl/version.rb}, %q{test/ref}, %q{test/test_all.rb}, %q{test/test_pkey_dsa.rb}, %q{test/fixture}, %q{test/test_integration.rb}, %q{test/test_ssl.rb}, %q{test/test_parse_certificate.rb}, %q{test/test_openssl.rb}, %q{test/cert_with_ec_pk.cer}, %q{test/java}, %q{test/ut_eof.rb}, %q{test/test_x509store.rb}, %q{test/test_imaps.rb}, %q{test/test_certificate.rb}, %q{test/test_pkcs7.rb}, %q{test/test_cipher.rb}, %q{test/test_pkey_rsa.rb}, %q{test/openssl}, %q{test/test_java.rb}, %q{test/ref/a.out}, %q{test/ref/pkcs1}, %q{test/ref/pkcs1.c}, %q{test/ref/compile.rb}, %q{test/fixture/common.pem}, %q{test/fixture/ca_path}, %q{test/fixture/key_then_cert.pem}, %q{test/fixture/imaps}, %q{test/fixture/keypair.pem}, %q{test/fixture/cacert.pem}, %q{test/fixture/verisign.pem}, %q{test/fixture/purpose}, %q{test/fixture/cert_localhost.pem}, %q{test/fixture/selfcert.pem}, %q{test/fixture/max.pem}, %q{test/fixture/localhost_keypair.pem}, %q{test/fixture/ids_in_subject_rdn_set.pem}, %q{test/fixture/ca-bundle.crt}, %q{test/fixture/verisign_c3.pem}, %q{test/fixture/ca_path/72fa7371.0}, %q{test/fixture/ca_path/verisign.pem}, %q{test/fixture/imaps/cacert.pem}, %q{test/fixture/imaps/server.crt}, %q{test/fixture/imaps/server.key}, %q{test/fixture/purpose/ca}, %q{test/fixture/purpose/sslclient}, %q{test/fixture/purpose/scripts}, %q{test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem}, %q{test/fixture/purpose/cacert.pem}, %q{test/fixture/purpose/sslserver}, %q{test/fixture/purpose/sslserver.pem}, %q{test/fixture/purpose/sslclient.pem}, %q{test/fixture/purpose/b70a5bc1.0}, %q{test/fixture/purpose/ca/serial}, %q{test/fixture/purpose/ca/gen_cert.rb}, %q{test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234}, %q{test/fixture/purpose/ca/ca_config.rb}, %q{test/fixture/purpose/ca/cacert.pem}, %q{test/fixture/purpose/ca/private}, %q{test/fixture/purpose/ca/newcerts}, %q{test/fixture/purpose/ca/private/cakeypair.pem}, %q{test/fixture/purpose/ca/newcerts/4_cert.pem}, %q{test/fixture/purpose/ca/newcerts/3_cert.pem}, %q{test/fixture/purpose/ca/newcerts/2_cert.pem}, %q{test/fixture/purpose/sslclient/csr.pem}, %q{test/fixture/purpose/sslclient/keypair.pem}, %q{test/fixture/purpose/sslclient/sslclient.pem}, %q{test/fixture/purpose/scripts/gen_cert.rb}, %q{test/fixture/purpose/scripts/init_ca.rb}, %q{test/fixture/purpose/scripts/gen_csr.rb}, %q{test/fixture/purpose/sslserver/csr.pem}, %q{test/fixture/purpose/sslserver/keypair.pem}, %q{test/fixture/purpose/sslserver/sslserver.pem}, %q{test/java/pkcs7_mime_enveloped.message}, %q{test/java/test_java_attribute.rb}, %q{test/java/test_java_pkcs7.rb}, %q{test/java/test_java_mime.rb}, %q{test/java/pkcs7_mime_signed.message}, %q{test/java/test_java_smime.rb}, %q{test/java/pkcs7_multipart_signed.message}, %q{test/java/test_java_bio.rb}, %q{test/openssl/test_asn1.rb}, %q{test/openssl/ssl_server.rb}, %q{test/openssl/test_x509ext.rb}, %q{test/openssl/utils.rb}, %q{test/openssl/test_ssl.rb}, %q{test/openssl/test_ec.rb}, %q{test/openssl/test_ns_spki.rb}, %q{test/openssl/test_digest.rb}, %q{test/openssl/test_pair.rb}, %q{test/openssl/test_x509crl.rb}, %q{test/openssl/test_x509store.rb}, %q{test/openssl/test_pkcs7.rb}, %q{test/openssl/test_cipher.rb}, %q{test/openssl/test_pkey_rsa.rb}, %q{test/openssl/test_x509req.rb}, %q{test/openssl/test_x509name.rb}, %q{test/openssl/test_hmac.rb}, %q{test/openssl/test_x509cert.rb}, %q{test/openssl/test_config.rb}, %q{.gemtest}] s.homepage = %q{http://jruby-extras.rubyforge.org/jruby-openssl} - s.rdoc_options = ["--main", "README.txt"] - s.require_paths = ["lib"] + s.rdoc_options = [%q{--main}, %q{README.txt}] + s.require_paths = [%q{lib}] s.rubyforge_project = %q{jruby-extras} - s.rubygems_version = %q{1.5.1} + s.rubygems_version = %q{1.8.9} s.summary = %q{OpenSSL add-on for JRuby} - s.test_files = ["test/test_all.rb"] + s.test_files = [%q{test/test_all.rb}] if s.respond_to? :specification_version then s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 0"]) + s.add_runtime_dependency(%q, [">= 1.5.0146.1"]) else - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 1.5.0146.1"]) end else - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 1.5.0146.1"]) end end From bcc6d0831094ba3707bacd93f7cac87edf20ace2 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 15 Dec 2011 16:13:46 +0900 Subject: [PATCH 19/66] Test fixes for wrong expectation for read size These tests wrongly expects fixed size read to readpartial and sysread. CRuby should be fixed, too. --- test/fixture/purpose/ca/ca_config.rb | 2 +- test/fixture/purpose/ca/serial | 2 +- test/openssl/test_pair.rb | 12 +++++++-- test/openssl/test_ssl.rb | 37 +++++++++++++--------------- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/test/fixture/purpose/ca/ca_config.rb b/test/fixture/purpose/ca/ca_config.rb index faed4ae..378655e 100644 --- a/test/fixture/purpose/ca/ca_config.rb +++ b/test/fixture/purpose/ca/ca_config.rb @@ -11,7 +11,7 @@ class CAConfig CA_CERT_DAYS = 20 * 365 CA_RSA_KEY_LENGTH = 2048 - CERT_DAYS = 19 * 365 + CERT_DAYS = 18 * 365 CERT_KEY_LENGTH_MIN = 1024 CERT_KEY_LENGTH_MAX = 2048 CDP_LOCATION = nil diff --git a/test/fixture/purpose/ca/serial b/test/fixture/purpose/ca/serial index 9df46a8..5aa937e 100644 --- a/test/fixture/purpose/ca/serial +++ b/test/fixture/purpose/ca/serial @@ -1 +1 @@ -0004 \ No newline at end of file +0005 \ No newline at end of file diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index c4bb300..e13d63e 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -90,9 +90,17 @@ def test_readpartial ssl_pair {|s1, s2| s2.write "a\nbcd" assert_equal("a\n", s1.gets) - assert_equal("bcd", s1.readpartial(10)) + read = s1.readpartial(10) + assert_equal("bcd"[0, read.bytesize], read) + s1.read(read.bytesize - 3) # drop unread bytes + s2.write "efg" - assert_equal("efg", s1.readpartial(10)) + read = s1.readpartial(10) + assert_equal("efg"[0, read.bytesize], read) + rest = 3 - read.bytesize + while rest > 0 + rest -= s1.readpartial(rest).size + end s2.close assert_raise(EOFError) { s1.readpartial(10) } assert_raise(EOFError) { s1.readpartial(10) } diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 768fe00..efcc15e 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -200,19 +200,6 @@ def test_read_and_write assert_raise(ArgumentError) { ssl.sysread(-1) } - # syswrite and sysread - ITERATIONS.times{|i| - str = "x" * 100 + "\n" - ssl.syswrite(str) - assert_equal(str, ssl.sysread(str.size)) - - str = "x" * i * 100 + "\n" - buf = "" - ssl.syswrite(str) - assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id) - assert_equal(str, buf) - } - # puts and gets ITERATIONS.times{ str = "x" * 100 + "\n" @@ -237,6 +224,14 @@ def test_read_and_write } end + def sysread_size(ssl, size) + buf = '' + while buf.bytesize < size + buf += ssl.sysread(size - buf.bytesize) + end + buf + end + def test_sysread_chunks args = {} args[:server_proc] = proc { |ctx, ssl| @@ -257,11 +252,11 @@ def test_sysread_chunks ssl.sync_close = true ssl.connect ssl.syswrite("hello\n") - assert_equal("0" * 200, ssl.sysread(200)) - assert_equal("0" * 200, ssl.sysread(200)) - assert_equal("0" * 200, ssl.sysread(200)) - assert_equal("0" * 200, ssl.sysread(200)) - assert_equal("1" * 200, ssl.sysread(200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("1" * 200, sysread_size(ssl, 200)) ssl.close } end @@ -285,12 +280,14 @@ def test_sysread_buffer read = ssl.sysread(str.size, buf) assert(!read.empty?) assert_equal(buf.object_id, read.object_id) - assert_equal(str, buf) + assert_equal(str[0, buf.bytesize], buf) + sysread_size(ssl, str.bytesize - buf.bytesize) # drop unread bytes ssl.syswrite(str) read = ssl.sysread(str.size, nil) assert(!read.empty?) - assert_equal(str, read) + assert_equal(str[0, read.bytesize], read) + sysread_size(ssl, str.bytesize - read.bytesize) # drop unread bytes } ssl.close } From c59a6ee8b6436e20cf2a2b2838f3e2ec6a25f302 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 15 Dec 2011 16:31:11 +0900 Subject: [PATCH 20/66] JRUBY-6260: OpenSSL::ASN1::Integer#value incompatibility It should hold a OpenSSL::BN, not a Fixnum/Bignum. --- src/java/org/jruby/ext/openssl/ASN1.java | 2 +- test/openssl/test_asn1.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/org/jruby/ext/openssl/ASN1.java b/src/java/org/jruby/ext/openssl/ASN1.java index 87a4607..1c76541 100644 --- a/src/java/org/jruby/ext/openssl/ASN1.java +++ b/src/java/org/jruby/ext/openssl/ASN1.java @@ -535,7 +535,7 @@ private static IRubyObject decodeObj(RubyModule asnM,Object v) throws IOExceptio } else if(v instanceof DERNull) { return c.callMethod(tc,"new",asnM.getRuntime().getNil()); } else if(v instanceof DERInteger) { - return c.callMethod(tc,"new",RubyNumeric.str2inum(asnM.getRuntime(),asnM.getRuntime().newString(((DERInteger)v).getValue().toString()),10)); + return c.callMethod(tc, "new", BN.newBN(asnM.getRuntime(), ((DERInteger) v).getValue())); } else if(v instanceof DERUTCTime) { Date d = dateF.parse(((DERUTCTime)v).getAdjustedTime()); Calendar cal = Calendar.getInstance(); diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index f196bc4..14f07f5 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -35,6 +35,7 @@ def test_decode assert_equal(1, version.value.size) assert_equal(OpenSSL::ASN1::Integer, version.value[0].class) assert_equal(2, version.value[0].value) + assert_equal(OpenSSL::BN, version.value[0].value.class) serial = tbs_cert.value[1] assert_equal(OpenSSL::ASN1::Integer, serial.class) From 121b1758ff03be9f092813533c53eb821a4fd2e3 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 12:27:40 +0900 Subject: [PATCH 21/66] SSL server test utils update Stop SSL server with TCPServer#close, instead of TCPServer#shutdown as same as 1.8. JRuby does not behave as same as CRuby for stopping TCPSocket#accept by IPSocket#shutdown. --- test/1.9/utils.rb | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/test/1.9/utils.rb b/test/1.9/utils.rb index c4c0a0c..64fc6ed 100644 --- a/test/1.9/utils.rb +++ b/test/1.9/utils.rb @@ -279,25 +279,16 @@ def start_server(port0, verify_mode, start_immediately, args = {}, &block) block.call(server, port.to_i) ensure - begin - begin - tcps.shutdown - rescue Errno::ENOTCONN - # when `Errno::ENOTCONN: Socket is not connected' on some platforms, - # call #close instead of #shutdown. - tcps.close - tcps = nil - end if (tcps) - if (server) - server.join(5) - if server.alive? - server.kill - server.join - flunk("TCPServer was closed and SSLServer is still alive") unless $! - end + # TODO: as a workaround, stop TCPServer#accept by close, not by shutdown. + # JRuby's IO cannot handle shutdown correctly for now. + tcps.close if (tcps) + if (server) + server.join(5) + if server.alive? + server.kill + server.join + flunk("TCPServer was closed and SSLServer is still alive") unless $! end - ensure - tcps.close if (tcps) end end end From 25d7fbceaa96c9ab4d092d78cfb07a6a50df4cb6 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 12:31:53 +0900 Subject: [PATCH 22/66] Test fixes for wrong expectation for read size Apply the fix for 1.8 at bcc6d083 as well as for 1.9. These tests wrongly expects fixed size read to readpartial and sysread. CRuby should be fixed, too. --- test/1.9/test_pair.rb | 11 ++++-- test/1.9/test_ssl.rb | 82 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/test/1.9/test_pair.rb b/test/1.9/test_pair.rb index 940fa0c..1214f14 100644 --- a/test/1.9/test_pair.rb +++ b/test/1.9/test_pair.rb @@ -93,9 +93,16 @@ def test_readpartial ssl_pair {|s1, s2| s2.write "a\nbcd" assert_equal("a\n", s1.gets) - assert_equal("bcd", s1.readpartial(10)) + read = s1.readpartial(10) + assert_equal("bcd"[0, read.bytesize], read) + s1.read(read.bytesize - 3) # drop unread bytes s2.write "efg" - assert_equal("efg", s1.readpartial(10)) + read = s1.readpartial(10) + assert_equal("efg"[0, read.bytesize], read) + rest = 3 - read.bytesize + while rest > 0 + rest -= s1.readpartial(rest).size + end s2.close assert_raise(EOFError) { s1.readpartial(10) } assert_raise(EOFError) { s1.readpartial(10) } diff --git a/test/1.9/test_ssl.rb b/test/1.9/test_ssl.rb index a081931..59c4316 100644 --- a/test/1.9/test_ssl.rb +++ b/test/1.9/test_ssl.rb @@ -65,19 +65,6 @@ def test_read_and_write ssl.sync_close = true ssl.connect - # syswrite and sysread - ITERATIONS.times{|i| - str = "x" * 100 + "\n" - ssl.syswrite(str) - assert_equal(str, ssl.sysread(str.size)) - - str = "x" * i * 100 + "\n" - buf = "" - ssl.syswrite(str) - assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id) - assert_equal(str, buf) - } - # puts and gets ITERATIONS.times{ str = "x" * 100 + "\n" @@ -107,6 +94,75 @@ def test_read_and_write } end + def sysread_size(ssl, size) + buf = '' + while buf.bytesize < size + buf += ssl.sysread(size - buf.bytesize) + end + buf + end + + def test_sysread_chunks + args = {} + args[:server_proc] = proc { |ctx, ssl| + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.accept + next + end + ssl.write("0" * 800) + ssl.write("1" * 200) + ssl.close + break + end + } + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, args){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + ssl.syswrite("hello\n") + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("0" * 200, sysread_size(ssl, 200)) + assert_equal("1" * 200, sysread_size(ssl, 200)) + ssl.close + } + end + + def test_sysread_buffer + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + ITERATIONS.times{|i| + # the given buffer is cleared before concatenating. + # NB: SSLSocket#readpartial depends sysread. + str = "x" * i * 100 + "\n" + ssl.syswrite(str) + buf = "asdf" + assert_equal(buf.object_id, ssl.sysread(0, buf).object_id) + assert_equal("", buf) + + buf = "asdf" + read = ssl.sysread(str.size, buf) + assert(!read.empty?) + assert_equal(buf.object_id, read.object_id) + assert_equal(str[0, buf.bytesize], buf) + sysread_size(ssl, str.bytesize - buf.bytesize) # drop unread bytes + + ssl.syswrite(str) + read = ssl.sysread(str.size, nil) + assert(!read.empty?) + assert_equal(str[0, read.bytesize], read) + sysread_size(ssl, str.bytesize - read.bytesize) # drop unread bytes + } + ssl.close + } + end + def test_client_auth vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT start_server(PORT, vflag, true){|server, port| From db1ded9b978c08c2e5eb5484e645bfa0d9466b52 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 12:32:57 +0900 Subject: [PATCH 23/66] Avoid catching NullPointerException Check if engine is null (session not started) for SSLSocket#{cert, peer_cert, peer_cert_chain}. --- src/java/org/jruby/ext/openssl/SSLSocket.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java index 3a7d7fe..f86643c 100644 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/java/org/jruby/ext/openssl/SSLSocket.java @@ -639,23 +639,25 @@ public IRubyObject sysclose() { @JRubyMethod public IRubyObject cert() { + if (engine == null) { + return getRuntime().getNil(); + } try { Certificate[] cert = engine.getSession().getLocalCertificates(); - if (cert != null && cert.length > 0) { return X509Cert.wrap(getRuntime(), cert[0]); } } catch (CertificateEncodingException ex) { throw X509Cert.newCertificateError(getRuntime(), ex); - } catch (NullPointerException ex) { - return getRuntime().getNil(); - } - + } return getRuntime().getNil(); } @JRubyMethod - public IRubyObject peer_cert() { + public IRubyObject peer_cert() { + if (engine == null) { + return getRuntime().getNil(); + } try { Certificate[] cert = engine.getSession().getPeerCertificates(); if (cert.length > 0) { @@ -673,11 +675,13 @@ public IRubyObject peer_cert() { @JRubyMethod public IRubyObject peer_cert_chain() { + if (engine == null) { + return getRuntime().getNil(); + } try { javax.security.cert.Certificate[] certs = engine.getSession().getPeerCertificateChain(); - RubyArray arr = getRuntime().newArray(certs.length); - for(int i = 0 ; i < certs.length; i++ ) { + for (int i = 0; i < certs.length; i++) { arr.add(X509Cert.wrap(getRuntime(), certs[i])); } return arr; From 687242abf5ba1aedd0b775d4d51080cbdc454ce8 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 13:59:38 +0900 Subject: [PATCH 24/66] Run test_ssl_session.rb if Session is defined Not yet implemented in JRuby. JRUBY-4371 --- test/1.9/test_ssl_session.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/1.9/test_ssl_session.rb b/test/1.9/test_ssl_session.rb index 12c6152..e6855d5 100644 --- a/test/1.9/test_ssl_session.rb +++ b/test/1.9/test_ssl_session.rb @@ -1,6 +1,6 @@ require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL) && defined?(OpenSSL::SSL::Session) class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase def test_session From b828b1699caa97b41df1dc14cfe2163cb45560fc Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 14:16:06 +0900 Subject: [PATCH 25/66] require correct bcprov jar Running test_java.rb standalone fails. --- test/test_java.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_java.rb b/test/test_java.rb index f29f4b8..eceec11 100644 --- a/test/test_java.rb +++ b/test/test_java.rb @@ -6,7 +6,7 @@ if defined?(JRUBY_VERSION) require "java" $CLASSPATH << 'pkg/classes' - $CLASSPATH << 'build_lib/bcprov-jdk15-144.jar' + $CLASSPATH << Dir["build_lib/bcprov-*"].first module PKCS7Test module ASN1 From 7b4a84401ca068ce4d4f1c9901620a8552cbb206 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 14:21:35 +0900 Subject: [PATCH 26/66] Do not depend on PKCS7::PKCS7 existence It's deprecated module hierarchy. --- src/java/org/jruby/ext/openssl/PKCS7.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/PKCS7.java b/src/java/org/jruby/ext/openssl/PKCS7.java index 14919bc..c5dc2b0 100644 --- a/src/java/org/jruby/ext/openssl/PKCS7.java +++ b/src/java/org/jruby/ext/openssl/PKCS7.java @@ -156,7 +156,7 @@ public static IRubyObject read_smime(IRubyObject klass, IRubyObject arg) { throw newPKCS7Error(klass.getRuntime(), null); } IRubyObject data = out[0] != null ? membio2str(klass.getRuntime(), out[0]) : klass.getRuntime().getNil(); - PKCS7 ret = wrap(Utils.getClassFromPath(klass.getRuntime(), "OpenSSL::PKCS7::PKCS7"), pkcs7); + PKCS7 ret = wrap(Utils.getClassFromPath(klass.getRuntime(), "OpenSSL::PKCS7"), pkcs7); ret.setData(data); return ret; } @@ -199,7 +199,7 @@ public static IRubyObject sign(IRubyObject recv, IRubyObject[] args) { try { org.jruby.ext.openssl.impl.PKCS7 p7 = org.jruby.ext.openssl.impl.PKCS7.sign(x509, pkey, x509s, in, flg); - PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7::PKCS7"), p7); + PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7"), p7); ret.setData(data); return ret; } catch (PKCS7Exception pkcs7e) { @@ -237,7 +237,7 @@ public static IRubyObject encrypt(IRubyObject recv, IRubyObject[] args) { List x509s = x509_ary2sk(certs); try { org.jruby.ext.openssl.impl.PKCS7 p7 = org.jruby.ext.openssl.impl.PKCS7.encrypt(x509s, in, ciph, flg); - PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7::PKCS7"), p7); + PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7"), p7); ret.setData(data); return ret; } catch (PKCS7Exception pkcs7e) { From e1b49fa9ff6b43b02cb043300987182f3fe5e9c4 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 14:37:14 +0900 Subject: [PATCH 27/66] Test update for 1.8/1.9 dual mode --- test/test_pkey_rsa.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index 5498426..87c37b3 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -3,13 +3,13 @@ class TestPKeyRSA < Test::Unit::TestCase def test_has_correct_methods - pkey_methods = OpenSSL::PKey::PKey.instance_methods(false).sort - ["initialize"] - assert_equal ["sign", "verify"], pkey_methods + pkey_methods = OpenSSL::PKey::PKey.instance_methods(false).sort.map(&:intern) - [:initialize] + assert_equal [:sign, :verify], pkey_methods - rsa_methods = OpenSSL::PKey::RSA.instance_methods(false).sort - ["initialize"] - assert_equal ["d", "d=", "dmp1", "dmp1=", "dmq1", "dmq1=", "e", "e=", "export", "iqmp", "iqmp=", "n", "n=", "p", "p=", "params", "private?", "private_decrypt", "private_encrypt", "public?", "public_decrypt", "public_encrypt", "public_key", "q", "q=", "to_der", "to_pem", "to_s", "to_text"], rsa_methods + rsa_methods = OpenSSL::PKey::RSA.instance_methods(false).sort.map(&:intern) - [:initialize] + assert_equal [:d, :d=, :dmp1, :dmp1=, :dmq1, :dmq1=, :e, :e=, :export, :iqmp, :iqmp=, :n, :n=, :p, :p=, :params, :private?, :private_decrypt, :private_encrypt, :public?, :public_decrypt, :public_encrypt, :public_key, :q, :q=, :to_der, :to_pem, :to_s, :to_text], rsa_methods - assert_equal ["generate"], OpenSSL::PKey::RSA.methods(false) + assert_equal [:generate], OpenSSL::PKey::RSA.methods(false).map(&:intern) end #iqmp == coefficient From d995fdfc873bffd58db885ec5f5c9b6fbba92bba Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 14:40:09 +0900 Subject: [PATCH 28/66] Add TODO for 1.9 support --- TODO-1_9-support.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 TODO-1_9-support.txt diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt new file mode 100644 index 0000000..a8e656a --- /dev/null +++ b/TODO-1_9-support.txt @@ -0,0 +1,17 @@ +TODO for 1.9 support + +* Debug test failures + * 1F for test_pkey_rsa.rb + * 23F57E for test_openssl.rb + * 100% CPU for test_ssl.rb + * 100% CPU for test_integration.rb + +* Implement some methods of SSLSocket + * sysread_nonblock + * syswrite_nonblock + +* Fixes needed for JRuby + * Implement BasicSocket#connect_address for test_pair.rb + * Stop Socket#accept by Socket#shutdown, not by Socket#close + +* Implement SSL::Session From 49d28bfb97e600e9ca9ab6fc7afc6de631332f9c Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 18:00:04 +0900 Subject: [PATCH 29/66] Ignore engine test --- test/1.9/test_engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/1.9/test_engine.rb b/test/1.9/test_engine.rb index 6d90e34..97c5381 100644 --- a/test/1.9/test_engine.rb +++ b/test/1.9/test_engine.rb @@ -1,6 +1,6 @@ require_relative 'utils' -if defined?(OpenSSL) +if defined?(OpenSSL) && defined?(OpenSSL::Engine) class OpenSSL::TestEngine < Test::Unit::TestCase From f4370d1ed4eeb2999099ee6f021fc16ddfabd856 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 26 Dec 2011 22:48:42 +0900 Subject: [PATCH 30/66] Clear inherited verify_callback if not specified --- src/java/org/jruby/ext/openssl/SSLContext.java | 8 ++++++++ src/java/org/jruby/ext/openssl/X509Name.java | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/org/jruby/ext/openssl/SSLContext.java b/src/java/org/jruby/ext/openssl/SSLContext.java index 3e36790..9d0b52e 100644 --- a/src/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/java/org/jruby/ext/openssl/SSLContext.java @@ -237,6 +237,8 @@ public IRubyObject setup() { value = getInstanceVariable("@verify_callback"); if (value != null && !value.isNil()) { internalCtx.store.setExtraData(1, value); + } else { + internalCtx.store.setExtraData(1, null); } value = getInstanceVariable("@timeout"); @@ -247,6 +249,8 @@ public IRubyObject setup() { value = getInstanceVariable("@verify_depth"); if (value != null && !value.isNil()) { internalCtx.store.setDepth(RubyNumeric.fix2int(value)); + } else { + internalCtx.store.setDepth(-1); } /* TODO: should be implemented for SSLSession @@ -723,6 +727,10 @@ private void verifyChain(StoreContext storeCtx) throws CertificateException { throw new CertificateException("certificate verify failed"); } } catch (Exception e) { + ctx.setLastVerifyResultInternal(storeCtx.error); + if (storeCtx.error == X509Utils.V_OK) { + ctx.setLastVerifyResultInternal(X509Utils.V_ERR_CERT_REJECTED); + } throw new CertificateException("certificate verify failed", e); } } diff --git a/src/java/org/jruby/ext/openssl/X509Name.java b/src/java/org/jruby/ext/openssl/X509Name.java index 2b2d30e..03a6e6c 100644 --- a/src/java/org/jruby/ext/openssl/X509Name.java +++ b/src/java/org/jruby/ext/openssl/X509Name.java @@ -341,7 +341,7 @@ public IRubyObject cmp(IRubyObject other) { if(eql_p(other).isTrue()) { return RubyFixnum.zero(getRuntime()); } - + // TODO: huh? return RubyFixnum.one(getRuntime()); } From 19580086d931aac56fc33ab3dddb06462e39fd44 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 27 Dec 2011 00:57:10 +0900 Subject: [PATCH 31/66] Make 'rake test' work. --- Rakefile | 2 +- TODO-1_9-support.txt | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Rakefile b/Rakefile index 54d69ab..bd37b90 100644 --- a/Rakefile +++ b/Rakefile @@ -54,7 +54,7 @@ begin ENV['RUBY_FLAGS'] ||= [ (RUBY_VERSION >= '1.9.0' ? '--1.9' : '--1.8'), '-w', - '-Ibuild_lib:lib/shared:test', + '-Ibuild_lib:lib/shared:lib:test', ENV['RUBY_DEBUG'] ].compact.join(' ') require 'hoe' diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt index a8e656a..557df60 100644 --- a/TODO-1_9-support.txt +++ b/TODO-1_9-support.txt @@ -1,14 +1,38 @@ TODO for 1.9 support * Debug test failures - * 1F for test_pkey_rsa.rb - * 23F57E for test_openssl.rb + * 23F57E for test/test_openssl.rb + * 2F0E test/1.9/test_ssl.rb + * 0F3E test/1.9/test_pair.rb + * 2F0E test/1.9/test_x509name.rb + * 2F1E test/1.9/test_cipher.rb + * 11F11E test/1.9/test_asn1.rb + * 1F11E test/1.9/test_pkey_dsa.rb + * 1F11E test/1.9/test_pkey_rsa.rb + * 0F7E test/1.9/test_pkcs12.rb + * 0F4E test/1.9/test_pkey_dh.rb + * 0F1E test/1.9/test_digest.rb + * 1F0E test/1.9/test_x509ext.rb + * 1F0E test/1.9/test_config.rb + * 0F3E test/1.9/test_ocsp.rb + * 100% CPU for test_ssl.rb * 100% CPU for test_integration.rb -* Implement some methods of SSLSocket - * sysread_nonblock - * syswrite_nonblock +* Implement some mehotds properly + * OpenSSL::ASN1::ObjectId.new for SHA-2 ids such as SHA224 + * X509Name#cmp + * Cipher#pkcs5_keyivgen + * AES encryption without a key specified + * ASN.1 handling + +* Implement some methods + * PKey.read + * PKey::DH#public_key + * SSLSocket#sysread_nonblock + * SSLSocket#syswrite_nonblock + * OCSP + * config file * Fixes needed for JRuby * Implement BasicSocket#connect_address for test_pair.rb From 0ce9c50ff7737516ffe55bc1c9ed0a66689933f3 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 27 Dec 2011 01:00:11 +0900 Subject: [PATCH 32/66] Update gemspec --- jruby-openssl.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 84c3a34..0978d46 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2011-12-25" + s.date = "2011-12-26" s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] s.rubyforge_project = "jruby-extras" - s.rubygems_version = "1.8.12" + s.rubygems_version = "1.8.13" s.summary = "OpenSSL add-on for JRuby" s.test_files = ["test/test_all.rb"] From 050d2cc9ce2bcd9c9c7759bd12d956143be1adc8 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 27 Dec 2011 18:08:23 +0900 Subject: [PATCH 33/66] Cipher bug fixes for 1.9 test suite * check uninitialized Cipher to avoid NPE * check re-initialization --- TODO-1_9-support.txt | 10 +++------- src/java/org/jruby/ext/openssl/Cipher.java | 22 ++++++++++++++++++---- test/1.9/test_cipher.rb | 4 +++- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt index 557df60..e0c6e63 100644 --- a/TODO-1_9-support.txt +++ b/TODO-1_9-support.txt @@ -2,10 +2,6 @@ TODO for 1.9 support * Debug test failures * 23F57E for test/test_openssl.rb - * 2F0E test/1.9/test_ssl.rb - * 0F3E test/1.9/test_pair.rb - * 2F0E test/1.9/test_x509name.rb - * 2F1E test/1.9/test_cipher.rb * 11F11E test/1.9/test_asn1.rb * 1F11E test/1.9/test_pkey_dsa.rb * 1F11E test/1.9/test_pkey_rsa.rb @@ -15,9 +11,7 @@ TODO for 1.9 support * 1F0E test/1.9/test_x509ext.rb * 1F0E test/1.9/test_config.rb * 0F3E test/1.9/test_ocsp.rb - - * 100% CPU for test_ssl.rb - * 100% CPU for test_integration.rb + * 2F0E test/1.9/test_x509name.rb * Implement some mehotds properly * OpenSSL::ASN1::ObjectId.new for SHA-2 ids such as SHA224 @@ -33,9 +27,11 @@ TODO for 1.9 support * SSLSocket#syswrite_nonblock * OCSP * config file + * SSLSession#client_ca can we get CertificateRequest* in ServerHello? * Fixes needed for JRuby * Implement BasicSocket#connect_address for test_pair.rb * Stop Socket#accept by Socket#shutdown, not by Socket#close + * busy loop for SSLSocket#read_nonblock (and revert net/protocol.rb) * Implement SSL::Session diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java index 2e25c2c..828f71e 100644 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ b/src/java/org/jruby/ext/openssl/Cipher.java @@ -352,6 +352,9 @@ public IRubyObject initialize(IRubyObject str) { if (!CipherModule.isSupportedCipher(name)) { throw newCipherError(getRuntime(), String.format("unsupported cipher algorithm (%s)", name)); } + if (ciph != null) { + throw getRuntime().newRuntimeError("Cipher already inititalized!"); + } String[] values = Algorithm.osslToJsse(name, padding); cryptoBase = values[0]; cryptoVersion = values[1]; @@ -489,6 +492,7 @@ public IRubyObject set_iv(IRubyObject iv) { @JRubyMethod public IRubyObject block_size() { + checkInitialized(); if (isStreamCipher()) { // getBlockSize() returns 0 for stream cipher in JCE. OpenSSL returns 1 for RC4. return getRuntime().newFixnum(1); @@ -552,6 +556,7 @@ public IRubyObject decrypt(IRubyObject[] args) { @JRubyMethod public IRubyObject reset() { + checkInitialized(); if (!isStreamCipher()) { this.realIV = orgIV; doInitialize(); @@ -616,10 +621,11 @@ private void doInitialize() { System.out.println("*** doInitialize"); dumpVars(); } - ciphInited = true; + checkInitialized(); + if (key == null) { + throw newCipherError(getRuntime(), "key not specified"); + } try { - assert (key.length * 8 == keyLen) || (key.length == keyLen) : "Key wrong length"; - assert (this.realIV.length * 8 == ivLen) || (this.realIV.length == ivLen) : "IV wrong length"; if (!"ECB".equalsIgnoreCase(cryptoMode)) { if (this.realIV == null) { this.realIV = new byte[ivLen]; @@ -642,6 +648,7 @@ private void doInitialize() { } throw newCipherError(getRuntime(), e.getMessage()); } + ciphInited = true; } private byte[] lastIv = null; @@ -650,7 +657,7 @@ public IRubyObject update(IRubyObject data) { if (DEBUG) { System.out.println("*** update [" + data + "]"); } - + checkInitialized(); byte[] val = data.convertToString().getBytes(); if (val.length == 0) { throw getRuntime().newArgumentError("data must not be empty"); @@ -700,6 +707,7 @@ public IRubyObject update_deprecated(IRubyObject data) { @JRubyMethod(name = "final") public IRubyObject _final() { + checkInitialized(); if (!ciphInited) { doInitialize(); } @@ -768,6 +776,12 @@ int getGenerateKeyLen() { return (generateKeyLen == -1) ? keyLen : generateKeyLen; } + private void checkInitialized() { + if (ciph == null) { + throw getRuntime().newRuntimeError("Cipher not inititalized!"); + } + } + private boolean isStreamCipher() { return ciph.getBlockSize() == 0; } diff --git a/test/1.9/test_cipher.rb b/test/1.9/test_cipher.rb index eb2f4fe..4a23f1b 100644 --- a/test/1.9/test_cipher.rb +++ b/test/1.9/test_cipher.rb @@ -76,6 +76,7 @@ def test_ciphers } end + # This test fails without unlimited US_export.policy def test_AES pt = File.read(__FILE__) %w(ECB CBC CFB OFB).each{|mode| @@ -91,7 +92,8 @@ def test_AES } end - def test_AES_crush + # In JRuby key must be provided first. (CipherError) + def NOT_test_AES_crush 500.times do assert_nothing_raised("[Bug #2768]") do # it caused OpenSSL SEGV by uninitialized key From b2769d1243fa30616f96ed5d74618ec7675b6442 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 27 Dec 2011 18:46:12 +0900 Subject: [PATCH 34/66] Update TODO for 1.9 test suite --- TODO-1_9-support.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt index e0c6e63..14507f7 100644 --- a/TODO-1_9-support.txt +++ b/TODO-1_9-support.txt @@ -16,8 +16,6 @@ TODO for 1.9 support * Implement some mehotds properly * OpenSSL::ASN1::ObjectId.new for SHA-2 ids such as SHA224 * X509Name#cmp - * Cipher#pkcs5_keyivgen - * AES encryption without a key specified * ASN.1 handling * Implement some methods @@ -27,11 +25,10 @@ TODO for 1.9 support * SSLSocket#syswrite_nonblock * OCSP * config file - * SSLSession#client_ca can we get CertificateRequest* in ServerHello? + * SSLSocket#client_ca - can we get CertificateRequest* in ServerHello? + * SSL::Session - can we? * Fixes needed for JRuby * Implement BasicSocket#connect_address for test_pair.rb * Stop Socket#accept by Socket#shutdown, not by Socket#close * busy loop for SSLSocket#read_nonblock (and revert net/protocol.rb) - -* Implement SSL::Session From d8f5711cf02eac787752a6a203cb1de39a618e42 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Thu, 29 Dec 2011 15:51:03 +0900 Subject: [PATCH 35/66] Implement OpenSSL.errors, debug, and debug= --- .../org/jruby/ext/openssl/OpenSSLReal.java | 36 +++++++ .../ext/openssl/x509store/X509Error.java | 100 ++++++++++++++++-- .../ext/openssl/x509store/X509Utils.java | 3 + 3 files changed, 128 insertions(+), 11 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/OpenSSLReal.java b/src/java/org/jruby/ext/openssl/OpenSSLReal.java index ac7c0f7..f5dfc2b 100644 --- a/src/java/org/jruby/ext/openssl/OpenSSLReal.java +++ b/src/java/org/jruby/ext/openssl/OpenSSLReal.java @@ -31,10 +31,19 @@ import java.security.MessageDigest; import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; +import java.util.ArrayList; +import java.util.List; + import javax.crypto.SecretKeyFactory; import org.jruby.Ruby; +import org.jruby.RubyArray; import org.jruby.RubyClass; import org.jruby.RubyModule; +import org.jruby.anno.JRubyMethod; +import org.jruby.anno.JRubyModule; +import org.jruby.ext.openssl.Cipher.CipherModule; +import org.jruby.ext.openssl.x509store.X509Error; +import org.jruby.runtime.builtin.IRubyObject; /** * @author Ola Bini @@ -98,6 +107,7 @@ public static void createOpenSSL(Ruby runtime) { RubyModule ossl = runtime.getOrCreateModule("OpenSSL"); RubyClass standardError = runtime.getClass("StandardError"); ossl.defineClassUnder("OpenSSLError", standardError, standardError.getAllocator()); + ossl.defineAnnotatedMethods(OpenSSLModule.class); // those are BC provider free (uses BC class but does not use BC provider) PKey.createPKey(runtime, ossl); @@ -137,6 +147,32 @@ public static void createOpenSSL(Ruby runtime) { ossl.setConstant("OPENSSL_VERSION", runtime.newString("jruby-ossl " + jopensslVersion)); ossl.setConstant("OPENSSL_VERSION_NUMBER", runtime.newFixnum(9469999)); + OpenSSLModule.setDebug(ossl, runtime.getFalse()); + } + + @JRubyModule(name = "OpenSSL") + public static class OpenSSLModule { + + @JRubyMethod(name = "errors", meta = true) + public static IRubyObject errors(IRubyObject recv) { + Ruby runtime = recv.getRuntime(); + RubyArray result = runtime.newArray(); + for (X509Error.ErrorException e : X509Error.getErrors()) { + result.add(runtime.newString(e.getMessage())); + } + return result; + } + + @JRubyMethod(name = "debug", meta = true) + public static IRubyObject getDebug(IRubyObject recv) { + return ((RubyModule) recv).getInstanceVariable("debug"); + } + + @JRubyMethod(name = "debug=", meta = true) + public static IRubyObject setDebug(IRubyObject recv, IRubyObject debug) { + ((RubyModule) recv).setInstanceVariable("debug", debug); + return debug; + } } public static javax.crypto.Cipher getCipherBC(final String algorithm) throws GeneralSecurityException { diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Error.java b/src/java/org/jruby/ext/openssl/x509store/X509Error.java index 6c5df63..63cb26d 100644 --- a/src/java/org/jruby/ext/openssl/x509store/X509Error.java +++ b/src/java/org/jruby/ext/openssl/x509store/X509Error.java @@ -41,30 +41,108 @@ public class X509Error { public static class ErrorException extends Exception { private static final long serialVersionUID = -3214495184277468063L; - + private int reason; + public ErrorException(int reason) { super(); this.reason = reason; } + public int getReason() { return reason; } + + @Override + public String getMessage() { + switch (reason) { + case X509Utils.X509_R_BAD_X509_FILETYPE: + return "bad x509 filetype"; + case X509Utils.X509_R_BASE64_DECODE_ERROR: + return "base64 decode error"; + case X509Utils.X509_R_CANT_CHECK_DH_KEY: + return "cant check dh key"; + case X509Utils.X509_R_CERT_ALREADY_IN_HASH_TABLE: + return "cert already in hash table"; + case X509Utils.X509_R_ERR_ASN1_LIB: + return "err asn1 lib"; + case X509Utils.X509_R_INVALID_DIRECTORY: + return "invalid directory"; + case X509Utils.X509_R_INVALID_FIELD_NAME: + return "invalid field name"; + case X509Utils.X509_R_INVALID_TRUST: + return "invalid trust"; + case X509Utils.X509_R_KEY_TYPE_MISMATCH: + return "key type mismatch"; + case X509Utils.X509_R_KEY_VALUES_MISMATCH: + return "key values mismatch"; + case X509Utils.X509_R_LOADING_CERT_DIR: + return "loading cert dir"; + case X509Utils.X509_R_LOADING_DEFAULTS: + return "loading defaults"; + case X509Utils.X509_R_METHOD_NOT_SUPPORTED: + return "method not supported"; + case X509Utils.X509_R_NO_CERT_SET_FOR_US_TO_VERIFY: + return "no cert set for us to verify"; + case X509Utils.X509_R_PUBLIC_KEY_DECODE_ERROR: + return "public key decode error"; + case X509Utils.X509_R_PUBLIC_KEY_ENCODE_ERROR: + return "public key encode error"; + case X509Utils.X509_R_SHOULD_RETRY: + return "should retry"; + case X509Utils.X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN: + return "unable to find parameters in chain"; + case X509Utils.X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY: + return "unable to get certs public key"; + case X509Utils.X509_R_UNKNOWN_KEY_TYPE: + return "unknown key type"; + case X509Utils.X509_R_UNKNOWN_NID: + return "unknown nid"; + case X509Utils.X509_R_UNKNOWN_PURPOSE_ID: + return "unknown purpose id"; + case X509Utils.X509_R_UNKNOWN_TRUST_ID: + return "unknown trust id"; + case X509Utils.X509_R_UNSUPPORTED_ALGORITHM: + return "unsupported algorithm"; + case X509Utils.X509_R_WRONG_LOOKUP_TYPE: + return "wrong lookup type"; + case X509Utils.X509_R_WRONG_TYPE: + return "wrong type"; + + default: + return "(unknown X509 error)"; + } + } } - public static synchronized void addError(int reason) { - List errs = errors.get(); - if(errs == null) { - errs = new ArrayList(); - errors.set(errs); + public static void addError(int reason) { + synchronized (errors) { + List errs = errors.get(); + if (errs == null) { + errs = new ArrayList(); + errors.set(errs); + } + errs.add(new ErrorException(reason)); } - errs.add(new ErrorException(reason)); } - public static synchronized void clearErrors() { - List errs = errors.get(); - if(errs != null) { - errs.clear(); + public static void clearErrors() { + synchronized (errors) { + List errs = errors.get(); + if (errs != null) { + errs.clear(); + } + } + } + + public static List getErrors() { + synchronized (errors) { + List errs = errors.get(); + if (errs == null) { + errs = new ArrayList(); + errors.set(errs); + } + return errs; } } }// Err diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/java/org/jruby/ext/openssl/x509store/X509Utils.java index e8d23d1..64a2cd3 100644 --- a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -395,6 +395,9 @@ public static int checkIfIssuedBy(X509AuxCertificate issuer, X509AuxCertificate public static final int X509_R_UNSUPPORTED_ALGORITHM = 111; public static final int X509_R_WRONG_LOOKUP_TYPE = 112; public static final int X509_R_WRONG_TYPE = 122; + public static final int X509_R_METHOD_NOT_SUPPORTED = 124; + public static final int X509_R_PUBLIC_KEY_DECODE_ERROR = 125; + public static final int X509_R_PUBLIC_KEY_ENCODE_ERROR = 126; public static final int X509_VP_FLAG_DEFAULT = 0x1; public static final int X509_VP_FLAG_OVERWRITE = 0x2; From 73bf55575635aa355859360fc18f053ee3665125 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Fri, 30 Dec 2011 09:52:11 +0900 Subject: [PATCH 36/66] Avoid re-initialize of Cipher by padding= --- src/java/org/jruby/ext/openssl/Cipher.java | 50 ++++++++++++---------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java index 828f71e..b9e91ce 100644 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ b/src/java/org/jruby/ext/openssl/Cipher.java @@ -355,27 +355,7 @@ public IRubyObject initialize(IRubyObject str) { if (ciph != null) { throw getRuntime().newRuntimeError("Cipher already inititalized!"); } - String[] values = Algorithm.osslToJsse(name, padding); - cryptoBase = values[0]; - cryptoVersion = values[1]; - cryptoMode = values[2]; - realName = values[3]; - padding_type = values[4]; - ciph = getCipher(); - - int[] lengths = Algorithm.osslKeyIvLength(name); - keyLen = lengths[0]; - ivLen = lengths[1]; - if ("DES".equalsIgnoreCase(cryptoBase)) { - generateKeyLen = keyLen / 8 * 7; - } - - // given 'rc4' must be 'RC4' here. OpenSSL checks it as a LN of object - // ID and set SN. We don't check 'name' is allowed as a LN in ASN.1 for - // the possibility of JCE specific algorithm so just do upperCase here - // for OpenSSL compatibility. - name = name.toUpperCase(); - + updateCipher(name, padding); return this; } @@ -564,6 +544,31 @@ public IRubyObject reset() { return this; } + private void updateCipher(String name, String padding) { + // given 'rc4' must be 'RC4' here. OpenSSL checks it as a LN of object + // ID and set SN. We don't check 'name' is allowed as a LN in ASN.1 for + // the possibility of JCE specific algorithm so just do upperCase here + // for OpenSSL compatibility. + this.name = name.toUpperCase(); + this.padding = padding; + + String[] values = Algorithm.osslToJsse(name, padding); + cryptoBase = values[0]; + cryptoVersion = values[1]; + cryptoMode = values[2]; + realName = values[3]; + padding_type = values[4]; + + int[] lengths = Algorithm.osslKeyIvLength(name); + keyLen = lengths[0]; + ivLen = lengths[1]; + if ("DES".equalsIgnoreCase(cryptoBase)) { + generateKeyLen = keyLen / 8 * 7; + } + + ciph = getCipher(); + } + javax.crypto.Cipher getCipher() { try { return javax.crypto.Cipher.getInstance(realName); @@ -747,8 +752,7 @@ public IRubyObject _final() { @JRubyMethod(name = "padding=") public IRubyObject set_padding(IRubyObject padding) { - this.padding = padding.toString(); - initialize(getRuntime().newString(name)); + updateCipher(name, padding.toString()); return padding; } From 73927d1a611891d67fb8bedbd12fe8f22a32d43b Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Sat, 31 Dec 2011 11:35:41 +0900 Subject: [PATCH 37/66] Make DH.new(DER) work as same as DH.new(PEM) With PEMInputOutput refactorings. --- TODO-1_9-support.txt | 15 +- src/java/org/jruby/ext/openssl/PKeyDH.java | 10 +- src/java/org/jruby/ext/openssl/impl/PKey.java | 45 +++ .../ext/openssl/x509store/PEMInputOutput.java | 260 +++++++----------- 4 files changed, 153 insertions(+), 177 deletions(-) diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt index 14507f7..4de291a 100644 --- a/TODO-1_9-support.txt +++ b/TODO-1_9-support.txt @@ -1,19 +1,7 @@ TODO for 1.9 support -* Debug test failures - * 23F57E for test/test_openssl.rb - * 11F11E test/1.9/test_asn1.rb - * 1F11E test/1.9/test_pkey_dsa.rb - * 1F11E test/1.9/test_pkey_rsa.rb - * 0F7E test/1.9/test_pkcs12.rb - * 0F4E test/1.9/test_pkey_dh.rb - * 0F1E test/1.9/test_digest.rb - * 1F0E test/1.9/test_x509ext.rb - * 1F0E test/1.9/test_config.rb - * 0F3E test/1.9/test_ocsp.rb - * 2F0E test/1.9/test_x509name.rb - * Implement some mehotds properly + * ASN1 (fix lots of failing tests) * OpenSSL::ASN1::ObjectId.new for SHA-2 ids such as SHA224 * X509Name#cmp * ASN.1 handling @@ -27,6 +15,7 @@ TODO for 1.9 support * config file * SSLSocket#client_ca - can we get CertificateRequest* in ServerHello? * SSL::Session - can we? + * @crlDisPts of tX509Extension * Fixes needed for JRuby * Implement BasicSocket#connect_address for test_pair.rb diff --git a/src/java/org/jruby/ext/openssl/PKeyDH.java b/src/java/org/jruby/ext/openssl/PKeyDH.java index 79a4b34..3587f51 100644 --- a/src/java/org/jruby/ext/openssl/PKeyDH.java +++ b/src/java/org/jruby/ext/openssl/PKeyDH.java @@ -131,17 +131,21 @@ public synchronized IRubyObject dh_initialize(IRubyObject[] args) { if (argc == 1 && arg0 instanceof RubyString) { try { DHParameterSpec spec = PEMInputOutput.readDHParameters(new StringReader(arg0.toString())); + if (spec == null) { + spec = org.jruby.ext.openssl.impl.PKey.readDHParameter(arg0.asString().getByteList().bytes()); + } + if (spec == null) { + throw runtime.newArgumentError("invalid DH PARAMETERS"); + } this.dh_p = spec.getP(); this.dh_g = spec.getG(); } catch (NoClassDefFoundError ncdfe) { throw newDHError(runtime, OpenSSLReal.bcExceptionMessage(ncdfe)); } catch (IOException e) { throw runtime.newIOErrorFromException(e); - } catch (InvalidParameterSpecException e) { - throw runtime.newArgumentError(e.getMessage()); } } else { - int bits = RubyNumeric.fix2int(args[0]); + int bits = RubyNumeric.fix2int(arg0); // g defaults to 2 int gval = argc == 2 ? RubyNumeric.fix2int(args[1]) : 2; BigInteger p; diff --git a/src/java/org/jruby/ext/openssl/impl/PKey.java b/src/java/org/jruby/ext/openssl/impl/PKey.java index 918f07a..017d5f9 100644 --- a/src/java/org/jruby/ext/openssl/impl/PKey.java +++ b/src/java/org/jruby/ext/openssl/impl/PKey.java @@ -27,6 +27,7 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.impl; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; @@ -41,10 +42,16 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.DSAPrivateKeySpec; import java.security.spec.DSAPublicKeySpec; +import java.security.spec.KeySpec; import java.security.spec.RSAPrivateCrtKeySpec; import java.security.spec.RSAPublicKeySpec; + +import javax.crypto.spec.DHParameterSpec; + import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERSequence; import org.jruby.util.ByteList; @@ -57,6 +64,35 @@ */ public class PKey { + public static KeyPair readPrivateKey(byte[] input, String type) throws IOException, GeneralSecurityException { + KeySpec pubSpec = null; + KeySpec privSpec = null; + ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(input).readObject(); + if (type.equals("RSA")) { + DERInteger mod = (DERInteger) seq.getObjectAt(1); + DERInteger pubExp = (DERInteger) seq.getObjectAt(2); + DERInteger privExp = (DERInteger) seq.getObjectAt(3); + DERInteger p1 = (DERInteger) seq.getObjectAt(4); + DERInteger p2 = (DERInteger) seq.getObjectAt(5); + DERInteger exp1 = (DERInteger) seq.getObjectAt(6); + DERInteger exp2 = (DERInteger) seq.getObjectAt(7); + DERInteger crtCoef = (DERInteger) seq.getObjectAt(8); + pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue()); + privSpec = new RSAPrivateCrtKeySpec(mod.getValue(), pubExp.getValue(), privExp.getValue(), p1.getValue(), p2.getValue(), exp1.getValue(), + exp2.getValue(), crtCoef.getValue()); + } else { // assume "DSA" for now. + DERInteger p = (DERInteger) seq.getObjectAt(1); + DERInteger q = (DERInteger) seq.getObjectAt(2); + DERInteger g = (DERInteger) seq.getObjectAt(3); + DERInteger y = (DERInteger) seq.getObjectAt(4); + DERInteger x = (DERInteger) seq.getObjectAt(5); + privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue()); + pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue()); + } + KeyFactory fact = KeyFactory.getInstance(type); + return new KeyPair(fact.generatePublic(pubSpec), fact.generatePrivate(privSpec)); + } + // d2i_RSAPrivateKey_bio public static PrivateKey readRSAPrivateKey(byte[] input) throws IOException, GeneralSecurityException { KeyFactory fact = KeyFactory.getInstance("RSA"); @@ -121,6 +157,15 @@ public static PublicKey readDSAPublicKey(byte[] input) throws IOException, Gener return null; } } + + // d2i_DHparams_bio + public static DHParameterSpec readDHParameter(byte[] input) throws IOException { + ASN1InputStream aIn = new ASN1InputStream(input); + ASN1Sequence seq = (ASN1Sequence) aIn.readObject(); + BigInteger p = ((DERInteger) seq.getObjectAt(0)).getValue(); + BigInteger g = ((DERInteger) seq.getObjectAt(1)).getValue(); + return new DHParameterSpec(p, g); + } public static byte[] toDerRSAKey(RSAPublicKey pubKey, RSAPrivateCrtKey privKey) throws IOException { ASN1EncodableVector v1 = new ASN1EncodableVector(); diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index b22f31d..19bb826 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -85,6 +85,8 @@ import org.bouncycastle.cms.CMSSignedData; import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -100,7 +102,10 @@ import java.security.spec.X509EncodedKeySpec; import java.util.StringTokenizer; +import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; @@ -289,20 +294,17 @@ public static KeyPair readPrivateKey(Reader in, char[] password) throws IOExcept } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8INF) != -1) { try { byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8INF); - ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); - ASN1InputStream aIn = new ASN1InputStream(bIn); - PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) aIn.readObject()); + PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(bytes).readObject()); String type = getPrivateKeyTypeFromObjectId(info.getAlgorithmId().getObjectId()); - return readPrivateKeySequence(info.getPrivateKey().getDEREncoded(), type); + return org.jruby.ext.openssl.impl.PKey.readPrivateKey(info.getPrivateKey().getDEREncoded(), type); } catch (Exception e) { throw new IOException("problem creating private key: " + e.toString()); } } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8) != -1) { try { byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8); - ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); - ASN1InputStream aIn = new ASN1InputStream(bIn); - org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo((ASN1Sequence) aIn.readObject()); + org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo( + (ASN1Sequence) new ASN1InputStream(bytes).readObject()); AlgorithmIdentifier algId = eIn.getEncryptionAlgorithm(); String algorithm = ASN1Registry.o2a(algId.getObjectId()); algorithm = (algorithm.split("-"))[0]; @@ -540,8 +542,7 @@ public static PKCS10CertificationRequestExt readX509Request(Reader in, char[] f) return null; } - public static DHParameterSpec readDHParameters(Reader _in) - throws IOException, InvalidParameterSpecException { + public static DHParameterSpec readDHParameters(Reader _in) throws IOException { BufferedReader in = makeBuffered(_in); String line; StringBuilder buf = new StringBuilder(); @@ -549,8 +550,7 @@ public static DHParameterSpec readDHParameters(Reader _in) if (line.indexOf(BEF_G + PEM_STRING_DHPARAMS) >= 0) { do { buf.append(line.trim()); - } while (line.indexOf(BEF_E + PEM_STRING_DHPARAMS) < 0 && - (line = in.readLine()) != null); + } while (line.indexOf(BEF_E + PEM_STRING_DHPARAMS) < 0 && (line = in.readLine()) != null); break; } } @@ -558,16 +558,12 @@ public static DHParameterSpec readDHParameters(Reader _in) if (m.find()) { try { byte[] decoded = Base64.decode(m.group(DH_PARAM_GROUP)); - ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(decoded)); - ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); - BigInteger p = ((DERInteger)seq.getObjectAt(0)).getValue(); - BigInteger g = ((DERInteger)seq.getObjectAt(1)).getValue(); - return new DHParameterSpec(p, g); - } catch (Exception e) {} + return org.jruby.ext.openssl.impl.PKey.readDHParameter(decoded); + } catch (Exception e) { + e.printStackTrace(System.err); + } } - // probably not exactly the intended use of this exception, but - // close enough for internal throw/catch - throw new InvalidParameterSpecException("invalid " + PEM_STRING_DHPARAMS); + return null; } private static byte[] getEncoded(java.security.Key key) { @@ -759,9 +755,7 @@ public static void writeX509Request(Writer _out, PKCS10CertificationRequestExt o public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, CipherSpec cipher, char[] passwd) throws IOException { BufferedWriter out = makeBuffered(_out); - ByteArrayInputStream bIn = new ByteArrayInputStream(getEncoded(obj)); - ASN1InputStream aIn = new ASN1InputStream(bIn); - PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) aIn.readObject()); + PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(getEncoded(obj)).readObject()); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ASN1OutputStream aOut = new ASN1OutputStream(bOut); @@ -903,9 +897,7 @@ private static byte[] readBytes(BufferedReader in, String endMarker) throws IOEx } private static RSAPublicKey readRSAPublicKey(BufferedReader in, String endMarker) throws IOException { - ByteArrayInputStream bAIS = new ByteArrayInputStream(readBytes(in,endMarker)); - ASN1InputStream ais = new ASN1InputStream(bAIS); - Object asnObject = ais.readObject(); + Object asnObject = new ASN1InputStream(readBytes(in, endMarker)).readObject(); ASN1Sequence sequence = (ASN1Sequence) asnObject; RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence); RSAPublicKeySpec keySpec = new RSAPublicKeySpec( @@ -924,32 +916,31 @@ private static RSAPublicKey readRSAPublicKey(BufferedReader in, String endMarker return null; } - private static PublicKey readPublicKey(BufferedReader in, String alg, String endMarker) throws IOException { - KeySpec keySpec = new X509EncodedKeySpec(readBytes(in,endMarker)); + private static PublicKey readPublicKey(byte[] input, String alg, String endMarker) throws IOException { + KeySpec keySpec = new X509EncodedKeySpec(input); try { KeyFactory keyFact = KeyFactory.getInstance(alg); PublicKey pubKey = keyFact.generatePublic(keySpec); return pubKey; - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { // ignore - } catch (InvalidKeySpecException e) { + } catch (InvalidKeySpecException e) { // ignore } return null; } + private static PublicKey readPublicKey(BufferedReader in, String alg, String endMarker) throws IOException { + return readPublicKey(readBytes(in, endMarker), alg, endMarker); + } + private static PublicKey readPublicKey(BufferedReader in, String endMarker) throws IOException { - KeySpec keySpec = new X509EncodedKeySpec(readBytes(in,endMarker)); - String[] algs = {"RSA","DSA"}; - for(int i=0;i Date: Sun, 1 Jan 2012 00:05:11 +0900 Subject: [PATCH 38/66] Implement PKey.read --- src/java/org/jruby/ext/openssl/PKey.java | 95 ++++++++++++++++++- src/java/org/jruby/ext/openssl/PKeyDSA.java | 26 ++++- src/java/org/jruby/ext/openssl/PKeyRSA.java | 16 +++- src/java/org/jruby/ext/openssl/impl/PKey.java | 42 +++++++- .../ext/openssl/x509store/PEMInputOutput.java | 14 ++- 5 files changed, 179 insertions(+), 14 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/PKey.java b/src/java/org/jruby/ext/openssl/PKey.java index 8813998..34c23a1 100644 --- a/src/java/org/jruby/ext/openssl/PKey.java +++ b/src/java/org/jruby/ext/openssl/PKey.java @@ -27,14 +27,24 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; +import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPublicKey; import org.jruby.Ruby; import org.jruby.RubyClass; @@ -43,7 +53,10 @@ import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; import org.jruby.exceptions.RaiseException; +import org.jruby.ext.openssl.x509store.PEMInputOutput; +import org.jruby.runtime.Arity; import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; /** @@ -54,6 +67,7 @@ public abstract class PKey extends RubyObject { public static void createPKey(Ruby runtime, RubyModule ossl) { RubyModule mPKey = ossl.defineModuleUnder("PKey"); + mPKey.defineAnnotatedMethods(PKeyModule.class); // PKey is abstract RubyClass cPKey = mPKey.defineClassUnder("PKey",runtime.getObject(),ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); RubyClass openSSLError = ossl.getClass("OpenSSLError"); @@ -70,6 +84,81 @@ public static RaiseException newPKeyError(Ruby runtime, String message) { return Utils.newError(runtime, "OpenSSL::PKey::PKeyError", message); } + public static class PKeyModule { + + @JRubyMethod(name = "read", meta = true, optional = 1) + public static IRubyObject read(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) { + Ruby runtime = ctx.runtime; + IRubyObject data; + char[] pass; + int argc = Arity.checkArgumentCount(runtime, args, 1, 2); + switch (argc) { + case 1: + data = args[0]; + pass = null; + break; + default: + data = args[0]; + pass = args[1].isNil() ? null : args[1].toString().toCharArray(); + } + byte[] input = OpenSSLImpl.readX509PEM(data); + KeyPair key = null; + // d2i_PrivateKey_bio + try { + key = org.jruby.ext.openssl.impl.PKey.readPrivateKey(input); + } catch (IOException ioe) { + // ignore + } catch (GeneralSecurityException gse) { + // ignore + } + // PEM_read_bio_PrivateKey + if (key == null) { + try { + key = PEMInputOutput.readPrivateKey(new InputStreamReader(new ByteArrayInputStream(input)), pass); + } catch (IOException ioe) { + // ignore + } + } + if (key != null) { + if (key.getPublic().getAlgorithm().equals("RSA")) { + return new PKeyRSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::RSA"), (RSAPrivateCrtKey) key.getPrivate(), + (RSAPublicKey) key.getPublic()); + } else if (key.getPublic().getAlgorithm().equals("DSA")) { + return new PKeyDSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::DSA"), (DSAPrivateKey) key.getPrivate(), + (DSAPublicKey) key.getPublic()); + } + } + + PublicKey pubKey = null; + // d2i_PUBKEY_bio + try { + pubKey = org.jruby.ext.openssl.impl.PKey.readPublicKey(input); + } catch (IOException ioe) { + // ignore + } catch (GeneralSecurityException gse) { + // ignore + } + // PEM_read_bio_PUBKEY + if (pubKey == null) { + try { + pubKey = PEMInputOutput.readPubKey(new InputStreamReader(new ByteArrayInputStream(input))); + } catch (IOException ioe) { + // ignore + } + } + + if (pubKey != null) { + if (pubKey.getAlgorithm().equals("RSA")) { + return new PKeyRSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::RSA"), (RSAPublicKey) pubKey); + } else if (key.getPublic().getAlgorithm().equals("DSA")) { + return new PKeyDSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::DSA"), (DSAPublicKey) pubKey); + } + } + + throw runtime.newArgumentError("Could not parse PKey"); + } + } + public PKey(Ruby runtime, RubyClass type) { super(runtime,type); } @@ -92,10 +181,10 @@ String getAlgorithm() { return "NONE"; } - // FIXME: any compelling reason for abstract method here? + // NetscapeSPKI uses it. public abstract IRubyObject to_der(); - @JRubyMethod + @JRubyMethod(name = "sign") public IRubyObject sign(IRubyObject digest, IRubyObject data) { if (!this.callMethod(getRuntime().getCurrentContext(), "private?").isTrue()) { throw getRuntime().newArgumentError("Private key is needed."); @@ -127,7 +216,7 @@ public IRubyObject sign(IRubyObject digest, IRubyObject data) { */ } - @JRubyMethod + @JRubyMethod(name = "verify") public IRubyObject verify(IRubyObject digest, IRubyObject sig, IRubyObject data) { if (!(digest instanceof Digest)) { throw newPKeyError(getRuntime(), "invalid digest"); diff --git a/src/java/org/jruby/ext/openssl/PKeyDSA.java b/src/java/org/jruby/ext/openssl/PKeyDSA.java index 69522f6..b1b19f9 100644 --- a/src/java/org/jruby/ext/openssl/PKeyDSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyDSA.java @@ -84,9 +84,19 @@ public static void createPKeyDSA(Ruby runtime, RubyModule mPKey) { public static RaiseException newDSAError(Ruby runtime, String message) { return Utils.newError(runtime, "OpenSSL::PKey::DSAError", message); } - + public PKeyDSA(Ruby runtime, RubyClass type) { - super(runtime,type); + super(runtime, type); + } + + public PKeyDSA(Ruby runtime, RubyClass type, DSAPrivateKey privKey, DSAPublicKey pubKey) { + super(runtime, type); + this.privKey = privKey; + this.pubKey = pubKey; + } + + public PKeyDSA(Ruby runtime, RubyClass type, DSAPublicKey pubKey) { + this(runtime, type, null, pubKey); } private DSAPrivateKey privKey; @@ -195,7 +205,7 @@ public IRubyObject initialize(IRubyObject[] args) { if (null == val) { // PEM_read_bio_DSA_PUBKEY try { - val = PEMInputOutput.readDSAPubKey(new StringReader(str.toString()), passwd); + val = PEMInputOutput.readDSAPubKey(new StringReader(str.toString())); } catch (NoClassDefFoundError e) { val = null; } catch (Exception e) { @@ -425,6 +435,16 @@ public synchronized IRubyObject get_pub_key() { } return getRuntime().getNil(); } + + @JRubyMethod(name="priv_key") + public synchronized IRubyObject get_priv_key() { + DSAPrivateKey key; + BigInteger param; + if ((key = this.privKey) != null) { + return BN.newBN(getRuntime(), key.getX()); + } + return getRuntime().getNil(); + } @JRubyMethod(name="pub_key=") public synchronized IRubyObject set_pub_key(IRubyObject pub_key) { diff --git a/src/java/org/jruby/ext/openssl/PKeyRSA.java b/src/java/org/jruby/ext/openssl/PKeyRSA.java index 49e145b..8c4afa7 100644 --- a/src/java/org/jruby/ext/openssl/PKeyRSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyRSA.java @@ -95,9 +95,19 @@ public static void createPKeyRSA(Ruby runtime, RubyModule mPKey) { public static RaiseException newRSAError(Ruby runtime, String message) { return Utils.newError(runtime, "OpenSSL::PKey::RSAError", message); } - + public PKeyRSA(Ruby runtime, RubyClass type) { - super(runtime,type); + super(runtime, type); + } + + public PKeyRSA(Ruby runtime, RubyClass type, RSAPrivateCrtKey privKey, RSAPublicKey pubKey) { + super(runtime, type); + this.privKey = privKey; + this.pubKey = pubKey; + } + + public PKeyRSA(Ruby runtime, RubyClass type, RSAPublicKey pubKey) { + this(runtime, type, null, pubKey); } private transient volatile RSAPrivateCrtKey privKey; @@ -221,7 +231,7 @@ public IRubyObject initialize(IRubyObject[] args, Block block) { if (null == val) { // PEM_read_bio_RSA_PUBKEY try { - val = PEMInputOutput.readRSAPubKey(new StringReader(str.toString()), passwd); + val = PEMInputOutput.readRSAPubKey(new StringReader(str.toString())); } catch (NoClassDefFoundError e) { val = null; } catch (Exception e) { diff --git a/src/java/org/jruby/ext/openssl/impl/PKey.java b/src/java/org/jruby/ext/openssl/impl/PKey.java index 017d5f9..02396ce 100644 --- a/src/java/org/jruby/ext/openssl/impl/PKey.java +++ b/src/java/org/jruby/ext/openssl/impl/PKey.java @@ -93,8 +93,44 @@ public static KeyPair readPrivateKey(byte[] input, String type) throws IOExcepti return new KeyPair(fact.generatePublic(pubSpec), fact.generatePrivate(privSpec)); } + // d2i_PrivateKey_bio + public static KeyPair readPrivateKey(byte[] input) throws IOException, GeneralSecurityException { + KeyPair key = null; + try { + key = readRSAPrivateKey(input); + } catch (Exception e) { + // ignore + } + if (key == null) { + try { + key = readDSAPrivateKey(input); + } catch (Exception e) { + // ignore + } + } + return key; + } + + // d2i_PUBKEY_bio + public static PublicKey readPublicKey(byte[] input) throws IOException, GeneralSecurityException { + PublicKey key = null; + try { + key = readRSAPublicKey(input); + } catch (Exception e) { + // ignore + } + if (key == null) { + try { + key = readDSAPublicKey(input); + } catch (Exception e) { + // ignore + } + } + return key; + } + // d2i_RSAPrivateKey_bio - public static PrivateKey readRSAPrivateKey(byte[] input) throws IOException, GeneralSecurityException { + public static KeyPair readRSAPrivateKey(byte[] input) throws IOException, GeneralSecurityException { KeyFactory fact = KeyFactory.getInstance("RSA"); DERSequence seq = (DERSequence) (new ASN1InputStream(input).readObject()); if (seq.size() == 9) { @@ -106,7 +142,9 @@ public static PrivateKey readRSAPrivateKey(byte[] input) throws IOException, Gen BigInteger primeep = ((DERInteger) seq.getObjectAt(6)).getValue(); BigInteger primeeq = ((DERInteger) seq.getObjectAt(7)).getValue(); BigInteger crtcoeff = ((DERInteger) seq.getObjectAt(8)).getValue(); - return fact.generatePrivate(new RSAPrivateCrtKeySpec(mod, pubexp, privexp, primep, primeq, primeep, primeeq, crtcoeff)); + PrivateKey priv = fact.generatePrivate(new RSAPrivateCrtKeySpec(mod, pubexp, privexp, primep, primeq, primeep, primeeq, crtcoeff)); + PublicKey pub = fact.generatePublic(new RSAPublicKeySpec(mod, pubexp)); + return new KeyPair(pub, priv); } else { return null; } diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index 19bb826..1e782a5 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -326,10 +326,19 @@ public static KeyPair readPrivateKey(Reader in, char[] password) throws IOExcept return null; } + // PEM_read_bio_PUBKEY + public static PublicKey readPubKey(Reader in) throws IOException { + PublicKey pubKey = readRSAPubKey(in); + if (pubKey == null) { + pubKey = readDSAPubKey(in); + } + return pubKey; + } + /* * c: PEM_read_bio_DSA_PUBKEY */ - public static DSAPublicKey readDSAPubKey(Reader in, char[] f) throws IOException { + public static DSAPublicKey readDSAPubKey(Reader in) throws IOException { BufferedReader _in = makeBuffered(in); String line; while ((line = _in.readLine()) != null) { @@ -384,7 +393,7 @@ public static KeyPair readDSAPrivateKey(Reader in, char[] f) throws IOException * reads an RSA public key encoded in an SubjectPublicKeyInfo RSA structure. * c: PEM_read_bio_RSA_PUBKEY */ - public static RSAPublicKey readRSAPubKey(Reader in, char[] f) throws IOException { + public static RSAPublicKey readRSAPubKey(Reader in) throws IOException { BufferedReader _in = makeBuffered(in); String line; while ((line = _in.readLine()) != null) { @@ -560,7 +569,6 @@ public static DHParameterSpec readDHParameters(Reader _in) throws IOException { byte[] decoded = Base64.decode(m.group(DH_PARAM_GROUP)); return org.jruby.ext.openssl.impl.PKey.readDHParameter(decoded); } catch (Exception e) { - e.printStackTrace(System.err); } } return null; From 9f3a2491e8af11f21d78a2673d1f8943e8a9df9f Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 17 Jan 2012 17:39:05 +0900 Subject: [PATCH 39/66] Follow JRuby's change to avoid NPE JRuby [master be4fc7941bff50f6c90210a1d9e9178ffc05adda] does not allow imClass to be null. --- src/java/org/jruby/ext/openssl/SSLContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/org/jruby/ext/openssl/SSLContext.java b/src/java/org/jruby/ext/openssl/SSLContext.java index 9d0b52e..afe65a5 100644 --- a/src/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/java/org/jruby/ext/openssl/SSLContext.java @@ -509,7 +509,8 @@ private long getOptions() { private X509Cert[] convertToX509Certs(IRubyObject value) { final ArrayList result = new ArrayList(); ThreadContext ctx = getRuntime().getCurrentContext(); - RuntimeHelpers.invoke(ctx, value, "each", CallBlock.newCallClosure(value, null, Arity.NO_ARGUMENTS, new BlockCallback() { + RubyClass klass = Utils.getClassFromPath(ctx.runtime, "OpenSSL::SSL::SSLContext"); + RuntimeHelpers.invoke(ctx, value, "each", CallBlock.newCallClosure(value, klass, Arity.NO_ARGUMENTS, new BlockCallback() { public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) { Utils.checkKind(getRuntime(), args[0], "OpenSSL::X509::Certificate"); From 625639a4acdd64e09bbb457dfdacefcad823609a Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 23 Jan 2012 11:42:29 +0900 Subject: [PATCH 40/66] Update History.txt for 0.7.5 --- History.txt | 58 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/History.txt b/History.txt index 4ffc8de..07a7e36 100644 --- a/History.txt +++ b/History.txt @@ -1,6 +1,21 @@ +== 0.7.5 + +This release improved 1.9 mode support with help of +Duncan Mak . Now jruby-ossl gem includes both 1.8 and 1.9 +libraries and part of features should work fine on 1.9 mode, too. + +- JRUBY-6270: Wrong keyUsage check for SSL server +- JRUBY-6260: OpenSSL::ASN1::Integer#value incompatibility +- JRUBY-6044: Improve Ecrypted RSA/DSA pem support +- JRUBY-5972: Allow to load/dump empty PKCS7 data +- JRUBY-5833: Fix X509Name handling; X509Name RDN can include multiple elements +- JRUBY-5362: Improved 1.9 support +- JRUBY-4992: Warn if loaded by non JRuby interpreter + == 0.7.4 -- JRUBY-5519: Avoid String encoding dependency in DER loading. PEM loading failed on JRuby 1.6.x. Fixed. +- JRUBY-5519: Avoid String encoding dependency in DER loading. PEM loading + failed on JRuby 1.6.x. Fixed. - JRUBY-5510: Add debug information to released jar - JRUBY-5478: Update bouncycastle jars to the latest version. (1.46) @@ -59,18 +74,22 @@ -- JRUBY-4342: Follow ruby-openssl of CRuby 1.8.7. -- JRUBY-4346: Sync tests with tests for ruby-openssl of CRuby 1.8.7. -- JRUBY-4444: OpenSSL crash running RubyGems tests --- JRUBY-4075: Net::SSH gives OpenSSL::Cipher::CipherError "No message available" +-- JRUBY-4075: Net::SSH gives OpenSSL::Cipher::CipherError "No message + available" -- JRUBY-4076: Net::SSH padding error using 3des-cbc on Solaris -- JRUBY-4541: jruby-openssl doesn't load on App Engine. -- JRUBY-4077: Net::SSH "all authorization methods failed" Solaris -> Solaris -- JRUBY-4535: Issues with the BouncyCastle provider -- JRUBY-4510: JRuby-OpenSSL crashes when JCE fails a initialise bcprov --- JRUBY-4343: Update BouncyCastle jar to upstream version; jdk14-139 -> jdk15-144 +-- JRUBY-4343: Update BouncyCastle jar to upstream version; jdk14-139 -> + jdk15-144 - Cipher issues --- JRUBY-4012: Initialization vector length handled differently than in MRI (longer IV sequence are trimmed to fit the required) +-- JRUBY-4012: Initialization vector length handled differently than in MRI + (longer IV sequence are trimmed to fit the required) -- JRUBY-4473: Implemented DSA key generation -- JRUBY-4472: Cipher does not support RC4 and CAST --- JRUBY-4577: InvalidParameterException 'Wrong keysize: must be equal to 112 or 168' for DES3 + SunJCE +-- JRUBY-4577: InvalidParameterException 'Wrong keysize: must be equal to 112 or + 168' for DES3 + SunJCE - SSL and X.509(PKIX) issues -- JRUBY-4384: TCP socket connection causes busy loop of SSL server -- JRUBY-4370: Implement SSLContext#ciphers @@ -80,16 +99,23 @@ -- JRUBY-4684: SSLContext#verify_depth is ignored -- JRUBY-4398: SSLContext#options does not affect to SSL sessions -- JRUBY-4360: Implement SSLSocket#verify_result and dependents --- JRUBY-3829: SSLSocket#read should clear given buffer before concatenating (ByteBuffer.java:328:in `allocate': java.lang.IllegalArgumentException when returning SOAP queries over a certain size) --- JRUBY-4686: SSLSocket can drop last chunk of data just before inbound channel close +-- JRUBY-3829: SSLSocket#read should clear given buffer before concatenating + (ByteBuffer.java:328:in `allocate': java.lang.IllegalArgumentException when + returning SOAP queries over a certain size) +-- JRUBY-4686: SSLSocket can drop last chunk of data just before inbound channel + close -- JRUBY-4369: X509Store#verify_callback is not called --- JRUBY-4409: OpenSSL::X509::Store#add_file corrupts when it includes certificates which have the same subject (problem with ruby-openid-apps-discovery (github jruby-openssl issue #2)) +-- JRUBY-4409: OpenSSL::X509::Store#add_file corrupts when it includes + certificates which have the same subject (problem with + ruby-openid-apps-discovery (github jruby-openssl issue #2)) -- JRUBY-4333: PKCS#8 formatted privkey read -- JRUBY-4454: Loading Key file as a Certificate causes NPE --- JRUBY-4455: calling X509::Certificate#sign for the Certificate initialized from PEM causes IllegalStateException +-- JRUBY-4455: calling X509::Certificate#sign for the Certificate initialized + from PEM causes IllegalStateException - PKCS#7 issues -- JRUBY-4379: PKCS7#sign failed for DES3 cipher algorithm --- JRUBY-4428: Allow to use DES-EDE3-CBC in PKCS#7 w/o the Policy Files (rake test doesn't finish on JDK5 w/o policy files update) +-- JRUBY-4428: Allow to use DES-EDE3-CBC in PKCS#7 w/o the Policy Files (rake + test doesn't finish on JDK5 w/o policy files update) - Misc -- JRUBY-4574: jruby-openssl deprecation warning cleanup -- JRUBY-4591: jruby-1.4 support @@ -132,21 +158,25 @@ == 0.5.1 -* Multiple fixes by Brice Figureau to get net/ssh working. Requires JRuby 1.3.1 to be 100% +* Multiple fixes by Brice Figureau to get net/ssh working. Requires JRuby 1.3.1 + to be 100% * Fix by Frederic Jean for a character-decoding issue for some certificates == 0.5 * Fixed JRUBY-3614: Unsupported HMAC algorithm (HMACSHA-256) -* Fixed JRUBY-3570: ActiveMerchant's AuthorizeNet Gateway throws OpenSSL Cert Validation Error, when there should be no error +* Fixed JRUBY-3570: ActiveMerchant's AuthorizeNet Gateway throws OpenSSL Cert + Validation Error, when there should be no error * Fixed JRUBY-3557 Class cast exception in PKeyRSA.java * Fixed JRUBY-3468 X.509 certificates: subjectKeyIdentifier corrupted -* Fixed JRUBY-3285 Unsupported HMAC algorithm (HMACSHA1) error when generating digest +* Fixed JRUBY-3285 Unsupported HMAC algorithm (HMACSHA1) error when generating + digest * Misc code cleanup == 0.2 -- Enable remaining tests; fix a nil string issue in SSLSocket.sysread (JRUBY-1888) +- Enable remaining tests; fix a nil string issue in SSLSocket.sysread + (JRUBY-1888) - Fix socket buffering issue by setting socket IO sync = true - Fix bad file descriptor issue caused by unnecessary close (JRUBY-2152) - Fix AES key length (JRUBY-2187) From 1b70c293f1250bfc4f25d561dbc1eb87ae21fdd1 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 23 Jan 2012 11:42:52 +0900 Subject: [PATCH 41/66] Version bump to 0.7.5 --- jruby-openssl.gemspec | 8 ++++---- lib/shared/jopenssl/version.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 0978d46..7619977 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,15 +2,15 @@ Gem::Specification.new do |s| s.name = "jruby-openssl" - s.version = "0.7.5.dev" + s.version = "0.7.5" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2011-12-26" + s.date = "2012-01-23" s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9", "lib/shared", "lib/jopenssl.jar", "lib/1.8", "lib/1.9/openssl.rb", "lib/1.9/openssl", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl", "lib/shared/jopenssl", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/1.9", "test/ref", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/fixture", "test/test_integration.rb", "test/ruby", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/java", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/1.8", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/ca_path", "test/fixture/key_then_cert.pem", "test/fixture/imaps", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/purpose", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] + s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9/openssl.rb", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/test_integration.rb", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] s.homepage = "http://jruby-extras.rubyforge.org/jruby-openssl" s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb index ea579b0..80d7540 100644 --- a/lib/shared/jopenssl/version.rb +++ b/lib/shared/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.5.dev" + VERSION = "0.7.5" end end From c7c0cfc520cd74ca1c20c640c20b70f6d3049b50 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 23 Jan 2012 11:48:37 +0900 Subject: [PATCH 42/66] Fixed typo of bug tracking number --- History.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 07a7e36..ab3a007 100644 --- a/History.txt +++ b/History.txt @@ -8,7 +8,7 @@ libraries and part of features should work fine on 1.9 mode, too. - JRUBY-6260: OpenSSL::ASN1::Integer#value incompatibility - JRUBY-6044: Improve Ecrypted RSA/DSA pem support - JRUBY-5972: Allow to load/dump empty PKCS7 data -- JRUBY-5833: Fix X509Name handling; X509Name RDN can include multiple elements +- JRUBY-5834: Fix X509Name handling; X509Name RDN can include multiple elements - JRUBY-5362: Improved 1.9 support - JRUBY-4992: Warn if loaded by non JRuby interpreter From df6b9e8e685eff3201342c4a2bc038a066f84f46 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 23 Jan 2012 12:02:06 +0900 Subject: [PATCH 43/66] Update Homepage URL for the next release --- README.txt | 2 +- Rakefile | 2 +- jruby-openssl.gemspec | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index c1a645e..9af9dd2 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,6 @@ = JRuby-OpenSSL -* http://jruby-extras.rubyforge.org/jruby-openssl +* https://github.com/jruby/jruby-ossl == DESCRIPTION: diff --git a/Rakefile b/Rakefile index bd37b90..b580ffc 100644 --- a/Rakefile +++ b/Rakefile @@ -63,7 +63,7 @@ begin load File.dirname(__FILE__) + "/lib/shared/jopenssl/version.rb" p.version = Jopenssl::Version::VERSION p.rubyforge_name = "jruby-extras" - p.url = "http://jruby-extras.rubyforge.org/jruby-openssl" + p.url = "https://github.com/jruby/jruby-ossl" p.author = "Ola Bini and JRuby contributors" p.email = "ola.bini@gmail.com" p.summary = "OpenSSL add-on for JRuby" diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 7619977..16c47f4 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -10,8 +10,8 @@ Gem::Specification.new do |s| s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9/openssl.rb", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/test_integration.rb", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/key_then_cert.pem", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] - s.homepage = "http://jruby-extras.rubyforge.org/jruby-openssl" + s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9", "lib/shared", "lib/1.8", "lib/1.9/openssl.rb", "lib/1.9/openssl", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl", "lib/shared/jopenssl", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/1.9", "test/ref", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/fixture", "test/test_integration.rb", "test/ruby", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/java", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/1.8", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/ca_path", "test/fixture/key_then_cert.pem", "test/fixture/imaps", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/purpose", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] + s.homepage = "https://github.com/jruby/jruby-ossl" s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] s.rubyforge_project = "jruby-extras" From 45a5bbc86ade1aedd038946e737dbdbf077537f4 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 14 Feb 2012 13:07:42 -0600 Subject: [PATCH 44/66] Fix JRUBY-6385 Tests failing with jruby-openssl installed * Fixed use of set/getInstanceVariable with non-ivar "debug" * Added -J-ea to test runs to avoid issues in future --- Rakefile | 1 + src/java/org/jruby/ext/openssl/OpenSSLReal.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index b580ffc..58ecec1 100644 --- a/Rakefile +++ b/Rakefile @@ -55,6 +55,7 @@ begin (RUBY_VERSION >= '1.9.0' ? '--1.9' : '--1.8'), '-w', '-Ibuild_lib:lib/shared:lib:test', + '-J-ea', ENV['RUBY_DEBUG'] ].compact.join(' ') require 'hoe' diff --git a/src/java/org/jruby/ext/openssl/OpenSSLReal.java b/src/java/org/jruby/ext/openssl/OpenSSLReal.java index f5dfc2b..6e09bd3 100644 --- a/src/java/org/jruby/ext/openssl/OpenSSLReal.java +++ b/src/java/org/jruby/ext/openssl/OpenSSLReal.java @@ -165,12 +165,12 @@ public static IRubyObject errors(IRubyObject recv) { @JRubyMethod(name = "debug", meta = true) public static IRubyObject getDebug(IRubyObject recv) { - return ((RubyModule) recv).getInstanceVariable("debug"); + return (IRubyObject)((RubyModule) recv).getInternalVariable("debug"); } @JRubyMethod(name = "debug=", meta = true) public static IRubyObject setDebug(IRubyObject recv, IRubyObject debug) { - ((RubyModule) recv).setInstanceVariable("debug", debug); + ((RubyModule) recv).setInternalVariable("debug", debug); return debug; } } From 1af2f3a16eaa1f5c6200cc166c3dbba66509f446 Mon Sep 17 00:00:00 2001 From: Jingwen Owen Ou Date: Tue, 14 Feb 2012 20:28:08 -0800 Subject: [PATCH 45/66] Add code to make PKCS12 work for simple case. --- lib/shared/openssl.rb | 2 ++ lib/shared/openssl/pkcs12.rb | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 lib/shared/openssl/pkcs12.rb diff --git a/lib/shared/openssl.rb b/lib/shared/openssl.rb index 08b691b..a3ab29f 100644 --- a/lib/shared/openssl.rb +++ b/lib/shared/openssl.rb @@ -16,3 +16,5 @@ $LOAD_PATH.unshift(File.expand_path('../../1.8', __FILE__)) load(File.expand_path('../../1.8/openssl.rb', __FILE__)) end + +require 'openssl/pkcs12' diff --git a/lib/shared/openssl/pkcs12.rb b/lib/shared/openssl/pkcs12.rb new file mode 100644 index 0000000..268aa10 --- /dev/null +++ b/lib/shared/openssl/pkcs12.rb @@ -0,0 +1,50 @@ +require 'java' + +module OpenSSL + class PKCS12 + java_import java.io.StringReader + java_import java.io.StringBufferInputStream + java_import java.security.cert.CertificateFactory + java_import java.security.KeyStore + java_import java.io.ByteArrayOutputStream + java_import org.bouncycastle.openssl.PEMReader + + java.security.Security.add_provider(org.bouncycastle.jce.provider.BouncyCastleProvider.new) + + def self.create(pass, name, key, cert) + pkcs12 = self.new(pass, name, key, cert) + pkcs12.generate + pkcs12 + end + + attr_reader :key, :certificate + + def initialize(pass, name, key, cert) + @pass = pass + @name = name + @key = key + @certificate = cert + end + + def generate + key_reader = StringReader.new(key.to_pem) + key_pair = PEMReader.new(key_reader).read_object + + cert_input_stream = StringBufferInputStream.new(certificate.to_pem) + certs = CertificateFactory.get_instance("X.509").generate_certificates(cert_input_stream) + + store = KeyStore.get_instance("PKCS12", "BC") + store.load(nil, nil) + store.set_key_entry(@name, key_pair.get_private, nil, certs.to_array(Java::java.security.cert.Certificate[certs.size].new)) + + pkcs12_output_stream = ByteArrayOutputStream.new + store.store(pkcs12_output_stream, @pass.to_java.to_char_array) + + @der = String.from_java_bytes(pkcs12_output_stream.to_byte_array) + end + + def to_der + @der + end + end +end From 387b18ba0c6ff3401264eb30f47e477eed0a7512 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 15 Feb 2012 16:38:21 +0900 Subject: [PATCH 46/66] Removed false assertion failure SSLEngine#handShakeStatus can be NOT_HANDSHAKING when the opposite side closes while unwrapping. Rewrite branches with switch to make the logic clear. --- src/java/org/jruby/ext/openssl/SSLSocket.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java index f86643c..291f935 100644 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ b/src/java/org/jruby/ext/openssl/SSLSocket.java @@ -322,15 +322,17 @@ private void doHandshake() throws IOException { while (true) { SSLEngineResult res; waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE); - if(hsStatus == SSLEngineResult.HandshakeStatus.FINISHED) { + switch (hsStatus) { + case FINISHED: if (initialHandshake) { finishInitialHandshake(); } return; - } else if(hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { + case NEED_TASK: doTasks(); - } else if(hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { - if(readAndUnwrap() == -1 && hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { + break; + case NEED_UNWRAP: + if (readAndUnwrap() == -1 && hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { throw new SSLHandshakeException("Socket closed"); } // during initialHandshake, calling readAndUnwrap that results UNDERFLOW @@ -339,18 +341,23 @@ private void doHandshake() throws IOException { if (initialHandshake && status == SSLEngineResult.Status.BUFFER_UNDERFLOW) { waitSelect(SelectionKey.OP_READ); } - } else if(hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { + break; + case NEED_WRAP: if (netData.hasRemaining()) { - while(flushData()) {} + while (flushData()) { + } } netData.clear(); res = engine.wrap(dummy, netData); hsStatus = res.getHandshakeStatus(); netData.flip(); flushData(); - } else { - assert false : "doHandshake() should never reach the NOT_HANDSHAKING state"; + break; + case NOT_HANDSHAKING: + // Opposite side could close while unwrapping. Handle this as same as FINISHED return; + default: + throw new IllegalStateException("Unknown handshaking status: " + hsStatus); } } } From 6b6bedda22e7052b9c2eea094b7fe6a3ec4d6aa4 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 15 Feb 2012 16:49:16 +0900 Subject: [PATCH 47/66] Updated build.xml for build target change --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 85b2466..67079b7 100644 --- a/build.xml +++ b/build.xml @@ -42,7 +42,7 @@ - + From 22be95ddba13bd79c5e4ed3110ab56f9b161828b Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 15 Feb 2012 16:51:43 +0900 Subject: [PATCH 48/66] Version bump to 0.7.6 --- jruby-openssl.gemspec | 8 ++++---- lib/shared/jopenssl/version.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 16c47f4..aff0371 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,20 +2,20 @@ Gem::Specification.new do |s| s.name = "jruby-openssl" - s.version = "0.7.5" + s.version = "0.7.6" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2012-01-23" + s.date = "2012-02-15" s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9", "lib/shared", "lib/1.8", "lib/1.9/openssl.rb", "lib/1.9/openssl", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl", "lib/shared/jopenssl", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/1.9", "test/ref", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/fixture", "test/test_integration.rb", "test/ruby", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/java", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/1.8", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/ca_path", "test/fixture/key_then_cert.pem", "test/fixture/imaps", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/purpose", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] + s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9", "lib/shared", "lib/1.8", "lib/1.9/openssl.rb", "lib/1.9/openssl", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl", "lib/shared/jopenssl", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/pkcs12.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/1.9", "test/ref", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/fixture", "test/test_integration.rb", "test/ruby", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/java", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/1.8", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/ca_path", "test/fixture/key_then_cert.pem", "test/fixture/imaps", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/purpose", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] s.homepage = "https://github.com/jruby/jruby-ossl" s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] s.rubyforge_project = "jruby-extras" - s.rubygems_version = "1.8.13" + s.rubygems_version = "1.8.15" s.summary = "OpenSSL add-on for JRuby" s.test_files = ["test/test_all.rb"] diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb index 80d7540..066af7d 100644 --- a/lib/shared/jopenssl/version.rb +++ b/lib/shared/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.5" + VERSION = "0.7.6" end end From 3e2ba307212a17c850677a35ff5e1d33f32bc426 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Wed, 15 Feb 2012 17:11:59 +0900 Subject: [PATCH 49/66] Add History for 0.7.6 --- History.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/History.txt b/History.txt index ab3a007..53009ef 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,10 @@ +== 0.7.6 + +This release includes initial implementation of PKCS12 by Owen Ou. + + - JRUBY-5066: Implement OpenSSL::PKCS12 (only for simple case) + - JRUBY-6385: Assertion failure with -J-ea + == 0.7.5 This release improved 1.9 mode support with help of From d88b4acab079ae302290ef0d2d2b7d6e180d61fc Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Sat, 14 Jan 2012 18:11:51 +0100 Subject: [PATCH 50/66] Fix PEM format parsing of CSR Signed-off-by: Charles Oliver Nutter --- src/java/org/jruby/ext/openssl/Request.java | 29 ++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/Request.java b/src/java/org/jruby/ext/openssl/Request.java index 9d350a1..746192b 100644 --- a/src/java/org/jruby/ext/openssl/Request.java +++ b/src/java/org/jruby/ext/openssl/Request.java @@ -138,15 +138,26 @@ public Object call() throws GeneralSecurityException { } ASN1Set in_attrs = req.getCertificationRequestInfo().getAttributes(); for(Enumeration enm = in_attrs.getObjects();enm.hasMoreElements();) { - DERSet obj = (DERSet)enm.nextElement(); - for(Enumeration enm2 = obj.getObjects();enm2.hasMoreElements();) { - DERSequence val = (DERSequence)enm2.nextElement(); - DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); - DERObject v1 = (DERObject)val.getObjectAt(1); - IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); - IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); - add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); - } + Object o = enm.nextElement(); + System.out.println("enm: " + o.getClass()); + if (o instanceof DERSequence) { + DERSequence val = (DERSequence)o; + DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); + DERObject v1 = (DERObject)val.getObjectAt(1); + IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); + IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); + add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); + } else { + DERSet obj = (DERSet)o; + for(Enumeration enm2 = obj.getObjects();enm2.hasMoreElements();) { + DERSequence val = (DERSequence)enm2.nextElement(); + DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); + DERObject v1 = (DERObject)val.getObjectAt(1); + IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); + IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); + add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); + } + } } this.valid = true; return this; From 5ba6e5239517f8a2f84d34bf8f177dc05e73c252 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 11:30:39 +0900 Subject: [PATCH 51/66] Version bump to 0.7.7.dev for development --- jruby-openssl.gemspec | 11 +++++++---- lib/shared/jopenssl/version.rb | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index aff0371..4adff10 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "jruby-openssl" - s.version = "0.7.6" + s.version = "0.7.7.dev" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2012-02-15" + s.date = "2012-04-30" s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] s.rubyforge_project = "jruby-extras" - s.rubygems_version = "1.8.15" + s.rubygems_version = "1.8.24" s.summary = "OpenSSL add-on for JRuby" s.test_files = ["test/test_all.rb"] @@ -24,10 +24,13 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q, [">= 1.5.0146.1"]) + s.add_development_dependency(%q, ["~> 3.10"]) else s.add_dependency(%q, [">= 1.5.0146.1"]) + s.add_dependency(%q, ["~> 3.10"]) end else s.add_dependency(%q, [">= 1.5.0146.1"]) + s.add_dependency(%q, ["~> 3.10"]) end end diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb index 066af7d..78bb52f 100644 --- a/lib/shared/jopenssl/version.rb +++ b/lib/shared/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.6" + VERSION = "0.7.7.dev" end end From 387ecc7c582e94e13882c5305685a5271a1b4e3a Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 11:31:23 +0900 Subject: [PATCH 52/66] Update tests to sync with CRuby ruby_1_9_3 --- test/1.9/test_pkcs7.rb | 5 +++ test/1.9/test_ssl.rb | 44 ++++++++++++++++++++++++ test/1.9/test_x509name.rb | 70 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/test/1.9/test_pkcs7.rb b/test/1.9/test_pkcs7.rb index 34c523a..b17cbda 100644 --- a/test/1.9/test_pkcs7.rb +++ b/test/1.9/test_pkcs7.rb @@ -146,6 +146,11 @@ def test_enveloped assert_equal(3, recip[1].serial) assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) end + + def test_graceful_parsing_failure #[ruby-core:43250] + contents = File.read(__FILE__) + assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } + end end end diff --git a/test/1.9/test_ssl.rb b/test/1.9/test_ssl.rb index 59c4316..0e47234 100644 --- a/test/1.9/test_ssl.rb +++ b/test/1.9/test_ssl.rb @@ -450,6 +450,50 @@ def test_tlsext_hostname end end end + + def test_multibyte_read_write + #German a umlaut + auml = [%w{ C3 A4 }.join('')].pack('H*') + auml.force_encoding(Encoding::UTF_8) + + [10, 1000, 100000].each {|i| + str = nil + num_written = nil + server_proc = Proc.new {|ctx, ssl| + cmp = ssl.read + raw_size = cmp.size + cmp.force_encoding(Encoding::UTF_8) + assert_equal(str, cmp) + assert_equal(num_written, raw_size) + ssl.close + } + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :server_proc => server_proc){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + str = auml * i + num_written = ssl.write(str) + ssl.close + } + } + end + + def test_unset_OP_ALL + ctx_proc = Proc.new { |ctx| + ctx.options = OpenSSL::SSL::OP_ALL & ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS + } + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc){|server, port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + ssl.puts('hello') + assert_equal("hello\n", ssl.gets) + ssl.close + } + end + end end diff --git a/test/1.9/test_x509name.rb b/test/1.9/test_x509name.rb index cf5a8b0..90c0992 100644 --- a/test/1.9/test_x509name.rb +++ b/test/1.9/test_x509name.rb @@ -100,6 +100,58 @@ def test_s_new assert_equal(name_from_der.to_der, name.to_der) end + def test_unrecognized_oid + dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.1", "Unknown OID 1"], + ["1.1.2.3.5.8.13.21.34", "Unknown OID 2"], + ["C", "US"], + ["postalCode", "60602"], + ["ST", "Illinois"], + ["L", "Chicago"], + #["street", "123 Fake St"], + ["O", "Some Company LLC"], + ["CN", "mydomain.com"] ] + + name = OpenSSL::X509::Name.new(dn) + ary = name.to_a + #assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/street=123 Fake St/O=Some Company LLC/CN=mydomain.com", name.to_s) + assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/O=Some Company LLC/CN=mydomain.com", name.to_s) + assert_equal("1.2.3.4.5.6.7.8.9.7.5.3.1", ary[0][0]) + assert_equal("1.1.2.3.5.8.13.21.34", ary[1][0]) + assert_equal("C", ary[2][0]) + assert_equal("postalCode", ary[3][0]) + assert_equal("ST", ary[4][0]) + assert_equal("L", ary[5][0]) + #assert_equal("street", ary[6][0]) + assert_equal("O", ary[6][0]) + assert_equal("CN", ary[7][0]) + assert_equal("Unknown OID 1", ary[0][1]) + assert_equal("Unknown OID 2", ary[1][1]) + assert_equal("US", ary[2][1]) + assert_equal("60602", ary[3][1]) + assert_equal("Illinois", ary[4][1]) + assert_equal("Chicago", ary[5][1]) + #assert_equal("123 Fake St", ary[6][1]) + assert_equal("Some Company LLC", ary[6][1]) + assert_equal("mydomain.com", ary[7][1]) + end + + def test_unrecognized_oid_parse_encode_equality + dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.2", "Unknown OID1"], + ["1.1.2.3.5.8.13.21.35", "Unknown OID2"], + ["C", "US"], + ["postalCode", "60602"], + ["ST", "Illinois"], + ["L", "Chicago"], + #["street", "123 Fake St"], + ["O", "Some Company LLC"], + ["CN", "mydomain.com"] ] + + name1 = OpenSSL::X509::Name.new(dn) + name2 = OpenSSL::X509::Name.parse(name1.to_s) + assert_equal(name1.to_s, name2.to_s) + assert_equal(name1.to_a, name2.to_a) + end + def test_s_parse dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" name = OpenSSL::X509::Name.parse(dn) @@ -258,6 +310,24 @@ def test_add_entry assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2]) end + def test_add_entry_street + return if OpenSSL::OPENSSL_VERSION_NUMBER < 0x009080df # 0.9.8m + # openssl/crypto/objects/obj_mac.h 1.83 + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "GOTOU Yuuzou"], + ["emailAddress", "gotoyuzo@ruby-lang.org"], + ["serialNumber", "123"], + ["street", "Namiki"], + ] + 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/street=Namiki", name.to_s) + assert_equal("Namiki", ary[5][1]) + end + def test_equals2 n1 = OpenSSL::X509::Name.parse 'CN=a' n2 = OpenSSL::X509::Name.parse 'CN=a' From 7a757e0e54599ea17b6cb59c16036fedd5cc3290 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 11:32:10 +0900 Subject: [PATCH 53/66] JRUBY-6515: sending UTF-8 data over SSL can hang with openssl Import upstream fix at http://bugs.ruby-lang.org/issues/5233 --- lib/1.9/openssl/buffering.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/1.9/openssl/buffering.rb b/lib/1.9/openssl/buffering.rb index e2f3235..51bc968 100644 --- a/lib/1.9/openssl/buffering.rb +++ b/lib/1.9/openssl/buffering.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: buffering.rb 32012 2011-06-11 14:07:42Z nahi $ + $Id$ =end ## @@ -307,6 +307,7 @@ def eof? def do_write(s) @wbuffer = "" unless defined? @wbuffer @wbuffer << s + @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) remain = idx ? idx + $/.size : @wbuffer.length @@ -333,7 +334,7 @@ def do_write(s) def write(s) do_write(s) - s.length + s.bytesize end ## From 2f134d402abdb97be8da5ebd17fe8bb436985842 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 12:33:39 +0900 Subject: [PATCH 54/66] JRUBY-6579: Avoid ClassCastException for public key loading --- src/java/org/jruby/ext/openssl/PKeyDSA.java | 10 ++++++++-- src/java/org/jruby/ext/openssl/PKeyRSA.java | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/PKeyDSA.java b/src/java/org/jruby/ext/openssl/PKeyDSA.java index b1b19f9..c6e5cb8 100644 --- a/src/java/org/jruby/ext/openssl/PKeyDSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyDSA.java @@ -251,8 +251,14 @@ public IRubyObject initialize(IRubyObject[] args) { } if (val instanceof KeyPair) { - privKey = (DSAPrivateKey) (((KeyPair) val).getPrivate()); - pubKey = (DSAPublicKey) (((KeyPair) val).getPublic()); + PrivateKey privateKey = ((KeyPair) val).getPrivate(); + PublicKey publicKey = ((KeyPair) val).getPublic(); + if (privateKey instanceof DSAPrivateKey) { + privKey = (DSAPrivateKey) privateKey; + pubKey = (DSAPublicKey) publicKey; + } else { + throw newDSAError(getRuntime(), "Neither PUB key nor PRIV key:"); + } } else if (val instanceof DSAPrivateKey) { privKey = (DSAPrivateKey) val; } else if (val instanceof DSAPublicKey) { diff --git a/src/java/org/jruby/ext/openssl/PKeyRSA.java b/src/java/org/jruby/ext/openssl/PKeyRSA.java index 8c4afa7..900782d 100644 --- a/src/java/org/jruby/ext/openssl/PKeyRSA.java +++ b/src/java/org/jruby/ext/openssl/PKeyRSA.java @@ -279,8 +279,14 @@ public IRubyObject initialize(IRubyObject[] args, Block block) { } if (val instanceof KeyPair) { - privKey = (RSAPrivateCrtKey) (((KeyPair) val).getPrivate()); - pubKey = (RSAPublicKey) (((KeyPair) val).getPublic()); + PrivateKey privateKey = ((KeyPair) val).getPrivate(); + PublicKey publicKey = ((KeyPair) val).getPublic(); + if (privateKey instanceof RSAPrivateCrtKey) { + privKey = (RSAPrivateCrtKey) privateKey; + pubKey = (RSAPublicKey) publicKey; + } else { + throw newRSAError(getRuntime(), "Neither PUB key nor PRIV key:"); + } } else if (val instanceof RSAPrivateCrtKey) { privKey = (RSAPrivateCrtKey) val; try { From 1e037faab0d79a07bf33397f9684ac07e66d9e29 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 12:40:15 +0900 Subject: [PATCH 55/66] Revert "Fix PEM format parsing of CSR" This reverts commit d88b4acab079ae302290ef0d2d2b7d6e180d61fc. The commit seems to include printf debugging. Please supply us a fix with test... --- src/java/org/jruby/ext/openssl/Request.java | 29 +++++++-------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/Request.java b/src/java/org/jruby/ext/openssl/Request.java index 746192b..9d350a1 100644 --- a/src/java/org/jruby/ext/openssl/Request.java +++ b/src/java/org/jruby/ext/openssl/Request.java @@ -138,26 +138,15 @@ public Object call() throws GeneralSecurityException { } ASN1Set in_attrs = req.getCertificationRequestInfo().getAttributes(); for(Enumeration enm = in_attrs.getObjects();enm.hasMoreElements();) { - Object o = enm.nextElement(); - System.out.println("enm: " + o.getClass()); - if (o instanceof DERSequence) { - DERSequence val = (DERSequence)o; - DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); - DERObject v1 = (DERObject)val.getObjectAt(1); - IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); - IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); - add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); - } else { - DERSet obj = (DERSet)o; - for(Enumeration enm2 = obj.getObjects();enm2.hasMoreElements();) { - DERSequence val = (DERSequence)enm2.nextElement(); - DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); - DERObject v1 = (DERObject)val.getObjectAt(1); - IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); - IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); - add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); - } - } + DERSet obj = (DERSet)enm.nextElement(); + for(Enumeration enm2 = obj.getObjects();enm2.hasMoreElements();) { + DERSequence val = (DERSequence)enm2.nextElement(); + DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); + DERObject v1 = (DERObject)val.getObjectAt(1); + IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); + IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); + add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); + } } this.valid = true; return this; From 6731933bb0cd4362d28e9797fb0b237ffbbf363c Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Mon, 30 Apr 2012 14:53:06 +0900 Subject: [PATCH 56/66] JRUBY-4326: Confusing (and late) OpenSSL error message Notice the JCE restriction to users when InvalidKeyException is raised. This exception also thrown when IV length or key length is wrong but those length should be checked before initialization. --- src/java/org/jruby/ext/openssl/Cipher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java index b9e91ce..0ccd3d1 100644 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ b/src/java/org/jruby/ext/openssl/Cipher.java @@ -647,6 +647,8 @@ private void doInitialize() { } else { this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(realName.split("/")[0], this.key)); } + } catch (java.security.InvalidKeyException ike) { + throw newCipherError(getRuntime(), ike.getMessage() + ": possibly you need to install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for your JRE"); } catch (Exception e) { if (DEBUG) { e.printStackTrace(); From ebf5545f302f185f89a9e059f2b77aca0a8c1159 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Sun, 13 May 2012 14:09:33 +0900 Subject: [PATCH 57/66] JRUBY-6622: Support loading encrypted RSA key with PBES2 Yet another BouncyCastle dependency. Root cause is because we depend on BC for ASN.1. --- .../ext/openssl/x509store/PEMInputOutput.java | 99 ++++++++++++++++--- test/test_pkey_rsa.rb | 31 ++++++ 2 files changed, 119 insertions(+), 11 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index 1e782a5..2f62905 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -28,6 +28,10 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.x509store; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.io.BufferedWriter; @@ -56,9 +60,11 @@ import org.jruby.ext.openssl.OpenSSLReal; import org.jruby.ext.openssl.PKCS10CertificationRequestExt; +import org.jruby.ext.openssl.SimpleSecretKey; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Sequence; @@ -71,15 +77,30 @@ import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.pkcs.EncryptionScheme; +import org.bouncycastle.asn1.pkcs.PBES2Parameters; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.pkcs.RC2CBCParameter; import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure; import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.engines.DESedeEngine; +import org.bouncycastle.crypto.engines.RC2Engine; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.cms.CMSSignedData; @@ -97,6 +118,7 @@ import java.security.spec.DSAPublicKeySpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPrivateCrtKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -306,17 +328,12 @@ public static KeyPair readPrivateKey(Reader in, char[] password) throws IOExcept org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo( (ASN1Sequence) new ASN1InputStream(bytes).readObject()); AlgorithmIdentifier algId = eIn.getEncryptionAlgorithm(); - String algorithm = ASN1Registry.o2a(algId.getObjectId()); - algorithm = (algorithm.split("-"))[0]; - PKCS12PBEParams pbeParams = new PKCS12PBEParams((ASN1Sequence) algId.getParameters()); - SecretKeyFactory fact = OpenSSLReal.getSecretKeyFactoryBC(algorithm); // need to use BC for PKCS12PBEParams. - PBEKeySpec pbeSpec = new PBEKeySpec(password); - SecretKey key = fact.generateSecret(pbeSpec); - PBEParameterSpec defParams = new PBEParameterSpec(pbeParams.getIV(), pbeParams.getIterations().intValue()); - Cipher cipher = OpenSSLReal.getCipherBC(algorithm); // need to use BC for PBEParameterSpec. - cipher.init(Cipher.UNWRAP_MODE, key, defParams); - // wrappedKeyAlgorithm is unknown ("") - PrivateKey privKey = (PrivateKey) cipher.unwrap(eIn.getEncryptedData(), "", Cipher.PRIVATE_KEY); + PrivateKey privKey; + if (algId.getAlgorithm().toString().equals("1.2.840.113549.1.5.13")) { // PBES2 + privKey = derivePrivateKeyPBES2(eIn, algId, password); + } else { + privKey = derivePrivateKeyPBES1(eIn, algId, password); + } return new KeyPair(null, privKey); } catch (Exception e) { throw new IOException("problem creating private key: " + e.toString()); @@ -326,6 +343,66 @@ public static KeyPair readPrivateKey(Reader in, char[] password) throws IOExcept return null; } + private static PrivateKey derivePrivateKeyPBES1(org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password) + throws GeneralSecurityException { + PKCS12PBEParams pkcs12Params = new PKCS12PBEParams((ASN1Sequence) algId.getParameters()); + PBEParameterSpec pbeParams = new PBEParameterSpec(pkcs12Params.getIV(), pkcs12Params.getIterations().intValue()); + + String algorithm = ASN1Registry.o2a(algId.getAlgorithm()); + algorithm = (algorithm.split("-"))[0]; + Cipher cipher = OpenSSLReal.getCipherBC(algorithm); // need to use BC for PBEParameterSpec. + + SecretKeyFactory fact = OpenSSLReal.getSecretKeyFactoryBC(algorithm); // need to use BC for PKCS12PBEParams. + SecretKey key = fact.generateSecret(new PBEKeySpec(password)); + + cipher.init(Cipher.UNWRAP_MODE, key, pbeParams); + // wrappedKeyAlgorithm is unknown ("") + return (PrivateKey) cipher.unwrap(eIn.getEncryptedData(), "", Cipher.PRIVATE_KEY); + } + + private static PrivateKey derivePrivateKeyPBES2(org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password) + throws GeneralSecurityException, InvalidCipherTextException { + PBES2Parameters pbeParams = new PBES2Parameters((ASN1Sequence) algId.getParameters()); + CipherParameters cipherParams = extractPBES2CipherParams(password, pbeParams); + + EncryptionScheme scheme = pbeParams.getEncryptionScheme(); + BufferedBlockCipher cipher; + if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) { + RC2CBCParameter rc2Params = new RC2CBCParameter((ASN1Sequence) scheme.getObject()); + byte[] iv = rc2Params.getIV(); + CipherParameters param = new ParametersWithIV(cipherParams, iv); + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine())); + cipher.init(false, param); + } else { + byte[] iv = ((ASN1OctetString) scheme.getObject()).getOctets(); + CipherParameters param = new ParametersWithIV(cipherParams, iv); + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine())); + cipher.init(false, param); + } + + byte[] data = eIn.getEncryptedData(); + byte[] out = new byte[cipher.getOutputSize(data.length)]; + int len = cipher.processBytes(data, 0, data.length, out, 0); + len += cipher.doFinal(out, len); + byte[] pkcs8 = new byte[len]; + System.arraycopy(out, 0, pkcs8, 0, len); + KeyFactory fact = KeyFactory.getInstance("RSA"); // It seems to work for both RSA and DSA. + return fact.generatePrivate(new PKCS8EncodedKeySpec(pkcs8)); + } + + private static CipherParameters extractPBES2CipherParams(char[] password, PBES2Parameters pbeParams) { + PBKDF2Params pbkdfParams = PBKDF2Params.getInstance(pbeParams.getKeyDerivationFunc().getParameters()); + int keySize = 192; + if (pbkdfParams.getKeyLength() != null) { + keySize = pbkdfParams.getKeyLength().intValue() * 8; + } + int iterationCount = pbkdfParams.getIterationCount().intValue(); + byte[] salt = pbkdfParams.getSalt(); + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, iterationCount); + return generator.generateDerivedParameters(keySize); + } + // PEM_read_bio_PUBKEY public static PublicKey readPubKey(Reader in) throws IOException { PublicKey pubKey = readRSAPubKey(in); diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index 87c37b3..708c5e9 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -103,6 +103,37 @@ def test_load_pkey_rsa_enc end end + # JRUBY-6622 + def test_load_pkey_rsa_enc_pbes2 + # password is 'password' + pem = <<__EOP__ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIaYgszaX31yECAggA +MBQGCCqGSIb3DQMHBAij3LmXGCmB8wSCAoDcLnAeXiBugFmwXd3wrvznlKvwHkP2 +76lIrTiwDRZOLuaKHdBgNQDJ3NP+UPGdM7YEyNqdfdbN/3cLd0qfzeobuU+c/lGI +aE5pAwlWm5lK9boTsJnCqaDFEgJz2khZF+7RqYQVSG7MTM9SnIRNScLKjhTk7AaF +PD2qSnMVtixw/VfwdzhUknuwP2monLY8Ip/l9abicmBp9HGQ+0WA/nKQLQ/egWG0 +S6rrXsH91exaxL7gcZL8jF+Ub7VDt4Hvx1RB/3r12k7AQGsK+TyIrKQFUllSnSq/ +eFwBqpLSKWYyGJZlkJzW5MTHyeXqpTvav6T7e2mKZ4GG/a8THoWxLLrKeODFFoWn +LQNOQZ2Axa15E0TdeSkaumsOWPJm5DgFxf/1cRNxhJqYdX68QjWXeNS2SXPZBwlx +HCaAYo6OoCHZQ7O/3MpiT3rUAk30fbSa09VSvrenYi5s5lPieKFt3QZI44uGvi9j +MXyN4fkjzzXasE0xZzf6bQLS6aM+ucyQ8CMv0oAgAndoeKu10Ha4KmdT5dZf3LHj +BUXZDYp3Q5UF6ePyxKBdAqJf4PNKl4+VehYJ4eQ6CIQiSxSuWv9T+2b90PyDuRkz +sB1XZpeDD6dhQuU9GjdwCTyatITcm97ZkbdZEoQiDpiWQB4parTvKLKbD4AbP/+E +08btPFgXNocFUjLb5lB4Y/6RqaQxY7VoaFOPOfPpWPXF26X9Y5y3y+ymXdYFpkhp +wGBGScH+dutQWHoRV1TWUjv9a7CuzUxCX2Hrjooz1BtOnG8CoPA7K43+kvire5jN +529p6u+FtUZPUWLm5L5WHBUECEtJGw3ImjosX1HtoM/rW34XDmMHuN0u +-----END ENCRYPTED PRIVATE KEY----- +__EOP__ + assert_nothing_raised do + pkey = OpenSSL::PKey::RSA.new(pem, 'password') + pkey2 = OpenSSL::PKey::RSA.new(pkey.to_pem) + assert_equal(pkey.n, pkey2.n) + assert_equal(pkey.e, pkey2.e) + assert_equal(pkey.d, pkey2.d) + end + end + # jruby-openssl/0.6 causes NPE def test_generate_pkey_rsa_empty assert_nothing_raised do From bc3cbf29e0cd8d558a23c9d1e2739c6a59e88daf Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Sun, 13 May 2012 14:20:15 +0900 Subject: [PATCH 58/66] Remove unused imports introduced by ebf5545f --- .../ext/openssl/x509store/PEMInputOutput.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index 2f62905..fad29a8 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -28,10 +28,6 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.x509store; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.io.BufferedWriter; @@ -51,7 +47,6 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPrivateCrtKey; -import java.security.spec.InvalidParameterSpecException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -60,7 +55,6 @@ import org.jruby.ext.openssl.OpenSSLReal; import org.jruby.ext.openssl.PKCS10CertificationRequestExt; -import org.jruby.ext.openssl.SimpleSecretKey; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; @@ -85,17 +79,13 @@ import org.bouncycastle.asn1.pkcs.RC2CBCParameter; import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure; import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; -import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.RC2Engine; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; @@ -106,28 +96,19 @@ import org.bouncycastle.cms.CMSSignedData; import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.CertificateFactory; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.StringTokenizer; -import javax.crypto.BadPaddingException; import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; From 747d6ef1b22364425d69942150c1e6e8e0d2cf18 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 22 May 2012 07:11:47 +0900 Subject: [PATCH 59/66] Version bump to 0.7.7 --- Rakefile | 2 +- jruby-openssl.gemspec | 8 ++++---- lib/shared/jopenssl/version.rb | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Rakefile b/Rakefile index 58ecec1..8bc40be 100644 --- a/Rakefile +++ b/Rakefile @@ -64,7 +64,7 @@ begin load File.dirname(__FILE__) + "/lib/shared/jopenssl/version.rb" p.version = Jopenssl::Version::VERSION p.rubyforge_name = "jruby-extras" - p.url = "https://github.com/jruby/jruby-ossl" + p.urls = ["https://github.com/jruby/jruby-ossl"] p.author = "Ola Bini and JRuby contributors" p.email = "ola.bini@gmail.com" p.summary = "OpenSSL add-on for JRuby" diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec index 4adff10..70652e7 100644 --- a/jruby-openssl.gemspec +++ b/jruby-openssl.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "jruby-openssl" - s.version = "0.7.7.dev" + s.version = "0.7.7" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2012-04-30" + s.date = "2012-05-21" s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." s.email = "ola.bini@gmail.com" s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.txt"] s.require_paths = ["lib/shared"] s.rubyforge_project = "jruby-extras" - s.rubygems_version = "1.8.24" + s.rubygems_version = "1.8.15" s.summary = "OpenSSL add-on for JRuby" s.test_files = ["test/test_all.rb"] diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb index 78bb52f..5f58ff8 100644 --- a/lib/shared/jopenssl/version.rb +++ b/lib/shared/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.7.dev" + VERSION = "0.7.7" end end From d4c3751a596928dafed9b48bb8c16c0cbcaa8158 Mon Sep 17 00:00:00 2001 From: Hiroshi Nakamura Date: Tue, 22 May 2012 07:18:07 +0900 Subject: [PATCH 60/66] Add changes in 0.7.7 --- History.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/History.txt b/History.txt index 53009ef..8962405 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,13 @@ +== 0.7.7 + +This release includes bug fixes. + + - JRUBY-6622: Support loading encrypted RSA key with PBES2 + - JRUBY-4326: Confusing (and late) OpenSSL error message + - JRUBY-6579: Avoid ClassCastException for public key loading + - JRUBY-6515: sending UTF-8 data over SSL can hang with openssl + - Update tests to sync with CRuby ruby_1_9_3 + == 0.7.6 This release includes initial implementation of PKCS12 by Owen Ou. From 94df0d04c795b987c1ee18b5475cffcfb7e928ae Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 26 Oct 2012 22:47:05 -0500 Subject: [PATCH 61/66] Update jruby-ossl gem from JRuby proper. --- lib/1.8/openssl/bn.rb | 2 +- lib/1.8/openssl/buffering.rb | 2 +- lib/1.8/openssl/cipher.rb | 2 +- lib/1.8/openssl/digest.rb | 2 +- lib/1.8/openssl/dummy.rb | 33 +++ lib/1.8/openssl/dummyssl.rb | 14 ++ lib/1.9/openssl/bn.rb | 2 +- lib/1.9/openssl/cipher.rb | 2 +- lib/1.9/openssl/digest.rb | 2 +- lib/1.9/openssl/ssl-internal.rb | 2 +- lib/1.9/openssl/x509-internal.rb | 2 +- lib/shared/openssl.rb | 10 +- src/java/JopensslService.java | 41 ---- src/java/org/jruby/ext/openssl/ASN1.java | 11 +- src/java/org/jruby/ext/openssl/Cipher.java | 8 + src/java/org/jruby/ext/openssl/Digest.java | 6 +- src/java/org/jruby/ext/openssl/HMAC.java | 6 + .../org/jruby/ext/openssl/NetscapeSPKI.java | 1 + .../org/jruby/ext/openssl/OSSLLibrary.java | 14 ++ .../PKCS10CertificationRequestExt.java | 1 + src/java/org/jruby/ext/openssl/PKCS7.java | 74 +++++- src/java/org/jruby/ext/openssl/PKey.java | 7 +- src/java/org/jruby/ext/openssl/Request.java | 18 +- .../org/jruby/ext/openssl/SSLContext.java | 18 +- src/java/org/jruby/ext/openssl/SSLSocket.java | 222 +++++++++++------- src/java/org/jruby/ext/openssl/X509CRL.java | 4 +- src/java/org/jruby/ext/openssl/X509Cert.java | 5 +- src/java/org/jruby/ext/openssl/X509Name.java | 1 + src/java/org/jruby/ext/openssl/X509Store.java | 13 +- .../jruby/ext/openssl/impl/ASN1Registry.java | 1 + .../jruby/ext/openssl/impl/EncContent.java | 13 +- .../org/jruby/ext/openssl/impl/PKCS7.java | 40 ++-- .../org/jruby/ext/openssl/impl/RecipInfo.java | 1 + .../ext/openssl/impl/SignerInfoWithPkey.java | 1 + .../jruby/ext/openssl/x509store/Lookup.java | 40 +++- .../org/jruby/ext/openssl/x509store/Name.java | 1 + .../ext/openssl/x509store/PEMInputOutput.java | 7 +- .../jruby/ext/openssl/x509store/Store.java | 4 +- .../ext/openssl/x509store/X509Object.java | 1 + .../ext/openssl/x509store/X509Utils.java | 10 +- 40 files changed, 419 insertions(+), 225 deletions(-) create mode 100644 lib/1.8/openssl/dummy.rb create mode 100644 lib/1.8/openssl/dummyssl.rb delete mode 100644 src/java/JopensslService.java create mode 100644 src/java/org/jruby/ext/openssl/OSSLLibrary.java diff --git a/lib/1.8/openssl/bn.rb b/lib/1.8/openssl/bn.rb index d269425..624c137 100644 --- a/lib/1.8/openssl/bn.rb +++ b/lib/1.8/openssl/bn.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: bn.rb 31657 2011-05-20 22:25:35Z shyouhei $ + $Id$ =end ## diff --git a/lib/1.8/openssl/buffering.rb b/lib/1.8/openssl/buffering.rb index bad5766..c83b92b 100644 --- a/lib/1.8/openssl/buffering.rb +++ b/lib/1.8/openssl/buffering.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: buffering.rb 28004 2010-05-24 23:58:49Z shyouhei $ + $Id$ =end module OpenSSL diff --git a/lib/1.8/openssl/cipher.rb b/lib/1.8/openssl/cipher.rb index 5fbfcd4..290e9c1 100644 --- a/lib/1.8/openssl/cipher.rb +++ b/lib/1.8/openssl/cipher.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: cipher.rb 12496 2007-06-08 15:02:04Z technorama $ + $Id$ =end ## diff --git a/lib/1.8/openssl/digest.rb b/lib/1.8/openssl/digest.rb index 27bc250..e603c41 100644 --- a/lib/1.8/openssl/digest.rb +++ b/lib/1.8/openssl/digest.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: digest.rb 28004 2010-05-24 23:58:49Z shyouhei $ + $Id$ =end ## diff --git a/lib/1.8/openssl/dummy.rb b/lib/1.8/openssl/dummy.rb new file mode 100644 index 0000000..af84c03 --- /dev/null +++ b/lib/1.8/openssl/dummy.rb @@ -0,0 +1,33 @@ +warn "OpenSSL ASN1/PKey/X509/Netscape/PKCS7 implementation unavailable" +warn "gem install bouncy-castle-java for full support." +module OpenSSL + module ASN1 + class ASN1Error < OpenSSLError; end + class ASN1Data; end + class Primitive; end + class Constructive; end + end + module X509 + class Name; end + class Certificate; end + class Extension; end + class CRL; end + class Revoked; end + class Store + def set_default_paths; end + end + class Request; end + class Attribute; end + end + module Netscape + class SPKI; end + end + class PKCS7 + # this definition causes TypeError "superclass mismatch for class PKCS7" + # MRI also crashes following definition; + # class Foo; class Foo < Foo; end; end + # class Foo; class Foo < Foo; end; end + # + # class PKCS7 < PKCS7; end + end +end diff --git a/lib/1.8/openssl/dummyssl.rb b/lib/1.8/openssl/dummyssl.rb new file mode 100644 index 0000000..6a1d617 --- /dev/null +++ b/lib/1.8/openssl/dummyssl.rb @@ -0,0 +1,14 @@ +warn "Warning: OpenSSL SSL implementation unavailable" +warn "You must run on JDK 1.5 (Java 5) or higher to use SSL" +module OpenSSL + module SSL + class SSLError < OpenSSLError; end + class SSLContext; end + class SSLSocket; end + VERIFY_NONE = 0 + VERIFY_PEER = 1 + VERIFY_FAIL_IF_NO_PEER_CERT = 2 + VERIFY_CLIENT_ONCE = 4 + OP_ALL = 0x00000FFF + end +end diff --git a/lib/1.9/openssl/bn.rb b/lib/1.9/openssl/bn.rb index a527a10..b2fca16 100644 --- a/lib/1.9/openssl/bn.rb +++ b/lib/1.9/openssl/bn.rb @@ -14,7 +14,7 @@ # (See the file 'LICENCE'.) # # = Version -# $Id: bn.rb 33067 2011-08-25 00:52:10Z drbrain $ +# $Id$ # #++ diff --git a/lib/1.9/openssl/cipher.rb b/lib/1.9/openssl/cipher.rb index f365477..eb146fb 100644 --- a/lib/1.9/openssl/cipher.rb +++ b/lib/1.9/openssl/cipher.rb @@ -14,7 +14,7 @@ # (See the file 'LICENCE'.) # # = Version -# $Id: cipher.rb 33067 2011-08-25 00:52:10Z drbrain $ +# $Id$ # #++ diff --git a/lib/1.9/openssl/digest.rb b/lib/1.9/openssl/digest.rb index 09bd858..b470071 100644 --- a/lib/1.9/openssl/digest.rb +++ b/lib/1.9/openssl/digest.rb @@ -14,7 +14,7 @@ # (See the file 'LICENCE'.) # # = Version -# $Id: digest.rb 33067 2011-08-25 00:52:10Z drbrain $ +# $Id$ # #++ diff --git a/lib/1.9/openssl/ssl-internal.rb b/lib/1.9/openssl/ssl-internal.rb index 9c0320c..c70b5b8 100644 --- a/lib/1.9/openssl/ssl-internal.rb +++ b/lib/1.9/openssl/ssl-internal.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: ssl-internal.rb 29189 2010-09-06 01:53:00Z nahi $ + $Id$ =end require "openssl/buffering" diff --git a/lib/1.9/openssl/x509-internal.rb b/lib/1.9/openssl/x509-internal.rb index d92d5d9..47e3a6f 100644 --- a/lib/1.9/openssl/x509-internal.rb +++ b/lib/1.9/openssl/x509-internal.rb @@ -11,7 +11,7 @@ (See the file 'LICENCE'.) = Version - $Id: x509-internal.rb 32663 2011-07-25 04:51:26Z nahi $ + $Id$ =end module OpenSSL diff --git a/lib/shared/openssl.rb b/lib/shared/openssl.rb index a3ab29f..b0cab18 100644 --- a/lib/shared/openssl.rb +++ b/lib/shared/openssl.rb @@ -2,13 +2,19 @@ warn 'Loading jruby-openssl in a non-JRuby interpreter' end +# Load bouncy-castle gem if available begin require 'bouncy-castle-java' rescue LoadError - # runs under restricted mode. + # runs under restricted mode or uses builtin BC end -require 'jopenssl' +# Load extension +require 'jruby' +require 'jopenssl.jar' +org.jruby.ext.openssl.OSSLLibrary.new.load(JRuby.runtime, false) + +# Add version-appropriate library path to LOAD_PATH if RUBY_VERSION >= '1.9.0' $LOAD_PATH.unshift(File.expand_path('../../1.9', __FILE__)) load(File.expand_path('../../1.9/openssl.rb', __FILE__)) diff --git a/src/java/JopensslService.java b/src/java/JopensslService.java deleted file mode 100644 index 2bda6ed..0000000 --- a/src/java/JopensslService.java +++ /dev/null @@ -1,41 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ - -import java.io.IOException; - -import org.jruby.Ruby; -import org.jruby.runtime.load.BasicLibraryService; - -import org.jruby.ext.openssl.OpenSSLReal; - -public class JopensslService implements BasicLibraryService { - public boolean basicLoad(final Ruby runtime) throws IOException { - OpenSSLReal.createOpenSSL(runtime); - return true; - } -} diff --git a/src/java/org/jruby/ext/openssl/ASN1.java b/src/java/org/jruby/ext/openssl/ASN1.java index 1c76541..f1a7a5e 100644 --- a/src/java/org/jruby/ext/openssl/ASN1.java +++ b/src/java/org/jruby/ext/openssl/ASN1.java @@ -78,6 +78,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class ASN1 { private static Map> SYM_TO_OID = new IdentityHashMap>(); private static Map> OID_TO_SYM = new IdentityHashMap>(); @@ -275,16 +276,18 @@ public static void createASN1(Ruby runtime, RubyModule ossl) { } RubyClass cASN1Data = mASN1.defineClassUnder("ASN1Data",runtime.getObject(), ASN1Data.ALLOCATOR); - cASN1Data.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newString("value"),runtime.newString("tag"),runtime.newString("tag_class")}); + cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "value"); + cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "tag"); + cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "tag_class"); cASN1Data.defineAnnotatedMethods(ASN1Data.class); RubyClass cASN1Primitive = mASN1.defineClassUnder("Primitive",cASN1Data, ASN1Primitive.ALLOCATOR); - cASN1Primitive.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newString("tagging")}); + cASN1Primitive.addReadWriteAttribute(runtime.getCurrentContext(), "tagging"); cASN1Primitive.defineAnnotatedMethods(ASN1Primitive.class); RubyClass cASN1Constructive = mASN1.defineClassUnder("Constructive",cASN1Data,ASN1Constructive.ALLOCATOR); cASN1Constructive.includeModule(runtime.getModule("Enumerable")); - cASN1Constructive.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newString("tagging")}); + cASN1Constructive.addReadWriteAttribute(runtime.getCurrentContext(), "tagging"); cASN1Constructive.defineAnnotatedMethods(ASN1Constructive.class); mASN1.defineClassUnder("Boolean",cASN1Primitive,cASN1Primitive.getAllocator()); @@ -315,7 +318,7 @@ public static void createASN1(Ruby runtime, RubyModule ossl) { cASN1ObjectId.defineAnnotatedMethods(ObjectId.class); - cASN1BitString.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newSymbol("unused_bits")}); + cASN1BitString.addReadWriteAttribute(runtime.getCurrentContext(), "unused_bits"); } diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java index 0ccd3d1..dafe964 100644 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ b/src/java/org/jruby/ext/openssl/Cipher.java @@ -169,6 +169,14 @@ public static String jsseToOssl(String inName, int keyLen) { return cryptoBase + "-" + cryptoVersion + "-" + cryptoMode; } + public static String getAlgorithmBase(javax.crypto.Cipher cipher) { + String algoBase = cipher.getAlgorithm(); + if (algoBase.indexOf('/') != -1) { + algoBase = algoBase.split("/")[0]; + } + return algoBase; + } + public static String[] osslToJsse(String inName) { // assume PKCS5Padding return osslToJsse(inName, null); diff --git a/src/java/org/jruby/ext/openssl/Digest.java b/src/java/org/jruby/ext/openssl/Digest.java index a36337f..4e53d51 100644 --- a/src/java/org/jruby/ext/openssl/Digest.java +++ b/src/java/org/jruby/ext/openssl/Digest.java @@ -56,8 +56,8 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) { public static void createDigest(Ruby runtime, RubyModule mOSSL) { runtime.getLoadService().require("digest"); - RubyModule mDigest = runtime.fastGetModule("Digest"); - RubyClass cDigestClass = mDigest.fastGetClass("Class"); + RubyModule mDigest = runtime.getModule("Digest"); + RubyClass cDigestClass = mDigest.getClass("Class"); RubyClass cDigest = mOSSL.defineClassUnder("Digest", cDigestClass, DIGEST_ALLOCATOR); cDigest.defineAnnotatedMethods(Digest.class); RubyClass openSSLError = mOSSL.getClass("OpenSSLError"); @@ -146,7 +146,7 @@ public IRubyObject initialize_copy(IRubyObject obj) { @JRubyMethod(name={"update","<<"}) public IRubyObject update(IRubyObject obj) { ByteList bytes = obj.convertToString().getByteList(); - algo.update(bytes.bytes, bytes.begin, bytes.realSize); + algo.update(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize()); return this; } diff --git a/src/java/org/jruby/ext/openssl/HMAC.java b/src/java/org/jruby/ext/openssl/HMAC.java index d2b5e62..5bb63dc 100644 --- a/src/java/org/jruby/ext/openssl/HMAC.java +++ b/src/java/org/jruby/ext/openssl/HMAC.java @@ -156,6 +156,12 @@ public IRubyObject digest() { return RubyString.newString(getRuntime(), mac.doFinal(ByteList.plain(data))); } + @JRubyMethod + public IRubyObject reset() { + data.setLength(0); + return this; + } + @JRubyMethod(name={"hexdigest","inspect","to_s"}) public IRubyObject hexdigest() { mac.reset(); diff --git a/src/java/org/jruby/ext/openssl/NetscapeSPKI.java b/src/java/org/jruby/ext/openssl/NetscapeSPKI.java index 59692c7..7c88d22 100644 --- a/src/java/org/jruby/ext/openssl/NetscapeSPKI.java +++ b/src/java/org/jruby/ext/openssl/NetscapeSPKI.java @@ -52,6 +52,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class NetscapeSPKI extends RubyObject { private static final long serialVersionUID = 3211242351810109432L; diff --git a/src/java/org/jruby/ext/openssl/OSSLLibrary.java b/src/java/org/jruby/ext/openssl/OSSLLibrary.java new file mode 100644 index 0000000..a1846bc --- /dev/null +++ b/src/java/org/jruby/ext/openssl/OSSLLibrary.java @@ -0,0 +1,14 @@ +package org.jruby.ext.openssl; + +import org.jruby.Ruby; +import org.jruby.ext.nkf.RubyNKF; +import org.jruby.ext.openssl.OpenSSLReal; +import org.jruby.runtime.load.Library; + +import java.io.IOException; + +public class OSSLLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + OpenSSLReal.createOpenSSL(runtime); + } +} \ No newline at end of file diff --git a/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java b/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java index 58575f6..b1c6d66 100644 --- a/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java +++ b/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java @@ -52,6 +52,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class PKCS10CertificationRequestExt extends PKCS10CertificationRequest { public PKCS10CertificationRequestExt(byte[] bytes) { super(bytes); diff --git a/src/java/org/jruby/ext/openssl/PKCS7.java b/src/java/org/jruby/ext/openssl/PKCS7.java index c5dc2b0..5cff125 100644 --- a/src/java/org/jruby/ext/openssl/PKCS7.java +++ b/src/java/org/jruby/ext/openssl/PKCS7.java @@ -27,7 +27,6 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl; - import java.io.IOException; import java.io.StringWriter; import java.security.GeneralSecurityException; @@ -38,9 +37,6 @@ import java.util.HashSet; import java.util.List; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERSequence; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyBignum; @@ -86,7 +82,8 @@ public static void createPKCS7(Ruby runtime, RubyModule mOSSL) { RubyClass cPKCS7 = mOSSL.defineClassUnder("PKCS7",runtime.getObject(),PKCS7_ALLOCATOR); RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); cPKCS7.defineClassUnder("PKCS7Error",openSSLError,openSSLError.getAllocator()); - cPKCS7.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newSymbol("data"),runtime.newSymbol("error_string")}); + cPKCS7.addReadWriteAttribute(runtime.getCurrentContext(), "data"); + cPKCS7.addReadWriteAttribute(runtime.getCurrentContext(), "error_string"); cPKCS7.defineAnnotatedMethods(PKCS7.class); cPKCS7.defineAnnotatedMethods(ModuleMethods.class); @@ -116,7 +113,7 @@ public static BIO obj2bio(IRubyObject obj) { } else { RubyString str = obj.convertToString(); ByteList bl = str.getByteList(); - return BIO.memBuf(bl.bytes, bl.begin, bl.realSize); + return BIO.memBuf(bl.getUnsafeBytes(), bl.getBegin(), bl.getRealSize()); } } @@ -299,8 +296,29 @@ public IRubyObject initialize_copy(IRubyObject obj) { @JRubyMethod(name="type=") public IRubyObject set_type(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#type="); - return getRuntime().getNil(); + int typeId = ASN1Registry.NID_undef; + + String type = obj.convertToString().asJavaString(); + + if ("signed".equals(type)) { + typeId = ASN1Registry.NID_pkcs7_signed; + } else if ("data".equals(type)) { + typeId = ASN1Registry.NID_pkcs7_data; + } else if ("signedAndEnveloped".equals(type)) { + typeId = ASN1Registry.NID_pkcs7_signedAndEnveloped; + } else if ("enveloped".equals(type)) { + typeId = ASN1Registry.NID_pkcs7_enveloped; + } else if ("encrypted".equals(type)) { + typeId = ASN1Registry.NID_pkcs7_encrypted; + } + + try { + p7.setType(typeId); + } catch (PKCS7Exception pkcs7e) { + throw newPKCS7Exception(getRuntime(), pkcs7e); + } + + return obj; } @JRubyMethod(name="type") @@ -478,8 +496,44 @@ public IRubyObject crls() { @JRubyMethod(name={"add_data", "data="}) public IRubyObject add_data(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#add_data"); - return getRuntime().getNil(); + if (p7.isSigned()) { + try { + p7.contentNew(ASN1Registry.NID_pkcs7_data); + } catch (PKCS7Exception pkcs7e) { + throw newPKCS7Exception(getRuntime(), pkcs7e); + } + } + + BIO in = obj2bio(obj); + BIO out = null; + try { + out = p7.dataInit(null); + } catch (PKCS7Exception pkcs7e) { + throw newPKCS7Exception(getRuntime(), pkcs7e); + } + byte[] buf = new byte[4096]; + for(;;) { + try { + int i = in.read(buf, 0, buf.length); + if(i <= 0) { + break; + } + if(out != null) { + out.write(buf, 0, i); + } + } catch(IOException e) { + throw getRuntime().newIOErrorFromException(e); + } + } + + try { + p7.dataFinal(out); + } catch (PKCS7Exception pkcs7e) { + throw newPKCS7Exception(getRuntime(), pkcs7e); + } + setData(getRuntime().getNil()); + + return obj; } @JRubyMethod(rest=true) diff --git a/src/java/org/jruby/ext/openssl/PKey.java b/src/java/org/jruby/ext/openssl/PKey.java index 34c23a1..fd8945f 100644 --- a/src/java/org/jruby/ext/openssl/PKey.java +++ b/src/java/org/jruby/ext/openssl/PKey.java @@ -86,13 +86,12 @@ public static RaiseException newPKeyError(Ruby runtime, String message) { public static class PKeyModule { - @JRubyMethod(name = "read", meta = true, optional = 1) + @JRubyMethod(name = "read", meta = true, required = 1, optional = 1) public static IRubyObject read(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) { Ruby runtime = ctx.runtime; IRubyObject data; char[] pass; - int argc = Arity.checkArgumentCount(runtime, args, 1, 2); - switch (argc) { + switch (args.length) { case 1: data = args[0]; pass = null; @@ -165,7 +164,7 @@ public PKey(Ruby runtime, RubyClass type) { @Override @JRubyMethod - public IRubyObject initialize() { + public IRubyObject initialize(ThreadContext context) { return this; } diff --git a/src/java/org/jruby/ext/openssl/Request.java b/src/java/org/jruby/ext/openssl/Request.java index 9d350a1..381f89d 100644 --- a/src/java/org/jruby/ext/openssl/Request.java +++ b/src/java/org/jruby/ext/openssl/Request.java @@ -60,6 +60,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class Request extends RubyObject { private static final long serialVersionUID = -5551557929791764918L; @@ -136,17 +137,16 @@ public Object call() throws GeneralSecurityException { Object t = getRuntime().newFixnum(ASN1.idForClass(internal.getObjectAt(1).getClass())); ((X509Name)subject).addEntry(oid,v,t); } + // Attributes ::= SET OF Attribute ASN1Set in_attrs = req.getCertificationRequestInfo().getAttributes(); for(Enumeration enm = in_attrs.getObjects();enm.hasMoreElements();) { - DERSet obj = (DERSet)enm.nextElement(); - for(Enumeration enm2 = obj.getObjects();enm2.hasMoreElements();) { - DERSequence val = (DERSequence)enm2.nextElement(); - DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); - DERObject v1 = (DERObject)val.getObjectAt(1); - IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); - IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); - add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); - } + // Attribute ::= SEQUENCE { type, values SET SIZE(1..MAX) } + DERSequence val = (DERSequence)enm.nextElement(); + DERObjectIdentifier v0 = (DERObjectIdentifier)val.getObjectAt(0); + DERObject v1 = (DERObject)val.getObjectAt(1); + IRubyObject a1 = getRuntime().newString(ASN1.getSymLookup(getRuntime()).get(v0)); + IRubyObject a2 = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), RubyString.newString(getRuntime(), v1.getDEREncoded())); + add_attribute(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Attribute", new IRubyObject[] { a1, a2 })); } this.valid = true; return this; diff --git a/src/java/org/jruby/ext/openssl/SSLContext.java b/src/java/org/jruby/ext/openssl/SSLContext.java index afe65a5..c6c1e97 100644 --- a/src/java/org/jruby/ext/openssl/SSLContext.java +++ b/src/java/org/jruby/ext/openssl/SSLContext.java @@ -45,6 +45,7 @@ import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.RubyString; +import org.jruby.RubySymbol; import org.jruby.anno.JRubyMethod; import org.jruby.common.IRubyWarnings.ID; import org.jruby.exceptions.RaiseException; @@ -67,6 +68,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class SSLContext extends RubyObject { private static final long serialVersionUID = -6203496135962974777L; @@ -123,7 +125,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) { public static void createSSLContext(Ruby runtime, RubyModule mSSL) { RubyClass cSSLContext = mSSL.defineClassUnder("SSLContext",runtime.getObject(),SSLCONTEXT_ALLOCATOR); for(int i=0;i= 1) { Set keySet = selector.selectedKeys(); if (keySet.iterator().next() == key) { - return; + return true; } } - } catch (IOException ioe) { - throw runtime.newRuntimeError("Error with selector: " + ioe.getMessage()); + + return false; + } catch (InterruptedException ie) { + return false; } finally { // Note: I don't like ignoring these exceptions, but it's // unclear how likely they are to happen or what damage we @@ -318,10 +356,36 @@ private void waitSelect(int operations) throws IOException { } } - private void doHandshake() throws IOException { + private void readWouldBlock() { + Ruby runtime = getRuntime(); + RaiseException eagain = newSSLError(runtime, "read would block"); + eagain.getException().extend(new IRubyObject[]{runtime.getIO().getConstant("WaitReadable")}); + throw eagain; + } + + private void writeWouldBlock() { + Ruby runtime = getRuntime(); + RaiseException eagain = newSSLError(runtime, "write would block"); + eagain.getException().extend(new IRubyObject[]{runtime.getIO().getConstant("WaitWritable")}); + throw eagain; + } + + private void doHandshake(boolean blocking) throws IOException { while (true) { SSLEngineResult res; - waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + boolean ready = waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE, blocking); + + // if not blocking, raise EAGAIN + if (!blocking && !ready) { + Ruby runtime = getRuntime(); + + throw runtime.is1_9() ? + runtime.newErrnoEAGAINWritableError("Resource temporarily unavailable") : + runtime.newErrnoEAGAINError("Resource temporarily unavailable"); + } + + // otherwise, proceed as before + switch (hsStatus) { case FINISHED: if (initialHandshake) { @@ -332,14 +396,14 @@ private void doHandshake() throws IOException { doTasks(); break; case NEED_UNWRAP: - if (readAndUnwrap() == -1 && hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { + if (readAndUnwrap(blocking) == -1 && hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { throw new SSLHandshakeException("Socket closed"); } // during initialHandshake, calling readAndUnwrap that results UNDERFLOW // does not mean writable. we explicitly wait for readable channel to avoid // busy loop. if (initialHandshake && status == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - waitSelect(SelectionKey.OP_READ); + waitSelect(SelectionKey.OP_READ, blocking); } break; case NEED_WRAP: @@ -416,7 +480,7 @@ public int write(ByteBuffer src) throws SSLException, IOException { return res.bytesConsumed(); } - public int read(ByteBuffer dst) throws IOException { + public int read(ByteBuffer dst, boolean blocking) throws IOException { if(initialHandshake) { return 0; } @@ -424,10 +488,10 @@ public int read(ByteBuffer dst) throws IOException { return -1; } if (!peerAppData.hasRemaining()) { - int appBytesProduced = readAndUnwrap(); + int appBytesProduced = readAndUnwrap(blocking); if (appBytesProduced == -1 || appBytesProduced == 0) { return appBytesProduced; - } + } } int limit = Math.min(peerAppData.remaining(), dst.remaining()); peerAppData.get(dst.array(), dst.arrayOffset(), limit); @@ -435,7 +499,7 @@ public int read(ByteBuffer dst) throws IOException { return limit; } - private int readAndUnwrap() throws IOException { + private int readAndUnwrap(boolean blocking) throws IOException { int bytesRead = getSocketChannel().read(peerNetData); if (bytesRead == -1) { if (!peerNetData.hasRemaining() || (status == SSLEngineResult.Status.BUFFER_UNDERFLOW)) { @@ -477,7 +541,7 @@ private int readAndUnwrap() throws IOException { if(!initialHandshake && (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK || hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP || hsStatus == SSLEngineResult.HandshakeStatus.FINISHED)) { - doHandshake(); + doHandshake(blocking); } return peerAppData.remaining(); } @@ -506,7 +570,7 @@ private void doShutdown() throws IOException { } private IRubyObject do_sysread(ThreadContext context, IRubyObject[] args, boolean nonBlock) { - Ruby runtime = context.getRuntime(); + Ruby runtime = context.runtime; int len = RubyNumeric.fix2int(args[0]); RubyString str = null; @@ -526,14 +590,7 @@ private IRubyObject do_sysread(ThreadContext context, IRubyObject[] args, boolea try { // So we need to make sure to only block when there is no data left to process if (engine == null || !(peerAppData.hasRemaining() || peerNetData.position() > 0)) { - if (nonBlock) { - RaiseException re = newSSLError(runtime, "read would raise"); - IRubyObject waitReadable = runtime.getIO().getConstant("WaitReadable"); - re.getException().extend(new IRubyObject[] {waitReadable}); - throw re; - } else { - waitSelect(SelectionKey.OP_READ); - } + waitSelect(SelectionKey.OP_READ, !nonBlock); } ByteBuffer dst = ByteBuffer.allocate(len); @@ -543,7 +600,7 @@ private IRubyObject do_sysread(ThreadContext context, IRubyObject[] args, boolea if (engine == null) { rr = getSocketChannel().read(dst); } else { - rr = read(dst); + rr = read(dst, !nonBlock); } if (rr == -1) { throw getRuntime().newEOFError(); @@ -570,19 +627,14 @@ public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject[] args) { } private IRubyObject do_syswrite(ThreadContext context, IRubyObject arg, boolean nonBlock) { - Ruby runtime = context.getRuntime(); + Ruby runtime = context.runtime; try { checkClosed(); - if (nonBlock) { - RaiseException re = newSSLError(runtime, "write would raise"); - IRubyObject waitWritable = runtime.getIO().getConstant("WaitWritable"); - re.getException().extend(new IRubyObject[] {waitWritable}); - throw re; - } else { - waitSelect(SelectionKey.OP_WRITE); - } - byte[] bls = arg.convertToString().getBytes(); - ByteBuffer b1 = ByteBuffer.wrap(bls); + + waitSelect(SelectionKey.OP_WRITE, !nonBlock); + + ByteList bls = arg.convertToString().getByteList(); + ByteBuffer b1 = ByteBuffer.wrap(bls.getUnsafeBytes(), bls.getBegin(), bls.getRealSize()); int written; if(engine == null) { written = writeToChannel(b1); diff --git a/src/java/org/jruby/ext/openssl/X509CRL.java b/src/java/org/jruby/ext/openssl/X509CRL.java index f2b9fad..7ecfba5 100644 --- a/src/java/org/jruby/ext/openssl/X509CRL.java +++ b/src/java/org/jruby/ext/openssl/X509CRL.java @@ -50,7 +50,6 @@ import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.x509.X509V2CRLGenerator; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyClass; @@ -69,6 +68,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class X509CRL extends RubyObject { private static final long serialVersionUID = -2463300006179688577L; @@ -97,7 +97,7 @@ public static void createX509CRL(Ruby runtime, RubyModule mX509) { private boolean changed = true; - private X509V2CRLGenerator generator = new X509V2CRLGenerator(); + private org.bouncycastle.x509.X509V2CRLGenerator generator = new org.bouncycastle.x509.X509V2CRLGenerator(); private java.security.cert.X509CRL crl; private DERObject crl_v; diff --git a/src/java/org/jruby/ext/openssl/X509Cert.java b/src/java/org/jruby/ext/openssl/X509Cert.java index 40ec6bf..5a92b88 100644 --- a/src/java/org/jruby/ext/openssl/X509Cert.java +++ b/src/java/org/jruby/ext/openssl/X509Cert.java @@ -76,6 +76,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class X509Cert extends RubyObject { private static final long serialVersionUID = 5626619026058595493L; @@ -139,7 +140,7 @@ public static IRubyObject wrap(Ruby runtime, javax.security.cert.Certificate c) @JRubyMethod(name="initialize", optional = 1, frame=true) public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block unusedBlock) { - Ruby runtime = context.getRuntime(); + Ruby runtime = context.runtime; extensions = new ArrayList(); if(args.length == 0) { return this; @@ -401,7 +402,7 @@ private void lazyInitializePublicKey() { @JRubyMethod public IRubyObject sign(ThreadContext context, final IRubyObject key, IRubyObject digest) { - Ruby runtime = context.getRuntime(); + Ruby runtime = context.runtime; // Have to obey some artificial constraints of the OpenSSL implementation. Stupid. String keyAlg = ((PKey)key).getAlgorithm(); diff --git a/src/java/org/jruby/ext/openssl/X509Name.java b/src/java/org/jruby/ext/openssl/X509Name.java index 03a6e6c..058d845 100644 --- a/src/java/org/jruby/ext/openssl/X509Name.java +++ b/src/java/org/jruby/ext/openssl/X509Name.java @@ -65,6 +65,7 @@ /** * @author Ola Bini */ +@SuppressWarnings("deprecation") public class X509Name extends RubyObject { private static final long serialVersionUID = -226196051911335103L; diff --git a/src/java/org/jruby/ext/openssl/X509Store.java b/src/java/org/jruby/ext/openssl/X509Store.java index 0cff008..cee58cc 100644 --- a/src/java/org/jruby/ext/openssl/X509Store.java +++ b/src/java/org/jruby/ext/openssl/X509Store.java @@ -61,9 +61,10 @@ public static void createX509Store(Ruby runtime, RubyModule mX509) { RubyClass cX509Store = mX509.defineClassUnder("Store",runtime.getObject(),X509STORE_ALLOCATOR); RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); mX509.defineClassUnder("StoreError",openSSLError,openSSLError.getAllocator()); - cX509Store.attr_accessor(runtime.getCurrentContext(), new IRubyObject[]{runtime.newSymbol("verify_callback"),runtime.newSymbol("error"), - runtime.newSymbol("error_string"),runtime.newSymbol("chain")}); - + cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "verify_callback"); + cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "error"); + cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "error_string"); + cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "chain"); cX509Store.defineAnnotatedMethods(X509Store.class); X509StoreCtx.createX509StoreCtx(runtime, mX509); @@ -155,11 +156,7 @@ public IRubyObject add_file(IRubyObject arg) { @JRubyMethod public IRubyObject set_default_paths() { try { - RubyHash env = (RubyHash)getRuntime().getObject().fastGetConstant("ENV"); - String file = (String)env.get(getRuntime().newString(X509Utils.getDefaultCertificateFileEnvironment())); - store.loadLocations(file, null); - String path = (String)env.get(getRuntime().newString(X509Utils.getDefaultCertificateDirectoryEnvironment())); - store.loadLocations(null, path); + store.setDefaultPaths(); } catch(Exception e) { raise("setting default path failed: " + e.getMessage()); diff --git a/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java b/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java index e489d00..95e4485 100644 --- a/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java +++ b/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java @@ -35,6 +35,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class ASN1Registry { @SuppressWarnings("unchecked") private static Map SYM_TO_OID = new HashMap(org.bouncycastle.asn1.x509.X509Name.DefaultLookUp); diff --git a/src/java/org/jruby/ext/openssl/impl/EncContent.java b/src/java/org/jruby/ext/openssl/impl/EncContent.java index a2d8a03..dfa7767 100644 --- a/src/java/org/jruby/ext/openssl/impl/EncContent.java +++ b/src/java/org/jruby/ext/openssl/impl/EncContent.java @@ -27,20 +27,24 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ext.openssl.impl; +import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DEREncodable; import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.jruby.util.ByteList; /** PKCS7_ENC_CONTENT * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class EncContent { /** * Describe contentType here. @@ -157,7 +161,14 @@ public static EncContent fromASN1(DEREncodable content) { ec.setAlgorithm(AlgorithmIdentifier.getInstance(sequence.getObjectAt(1))); if(sequence.size() > 2 && sequence.getObjectAt(2) instanceof DERTaggedObject && ((DERTaggedObject)(sequence.getObjectAt(2))).getTagNo() == 0) { DEREncodable ee = ((DERTaggedObject)(sequence.getObjectAt(2))).getObject(); - if(ee instanceof ASN1Sequence) { + if(ee instanceof ASN1Sequence && ((ASN1Sequence)ee).size() > 0) { + ByteList combinedOctets = new ByteList(); + Enumeration enm = ((ASN1Sequence)ee).getObjects(); + while (enm.hasMoreElements()) { + byte[] octets = ((ASN1OctetString)enm.nextElement()).getOctets(); + combinedOctets.append(octets); + } + ec.setEncData(new DEROctetString(combinedOctets.bytes())); } else { ec.setEncData((ASN1OctetString)ee); } diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7.java b/src/java/org/jruby/ext/openssl/impl/PKCS7.java index 82132fe..559a993 100644 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7.java +++ b/src/java/org/jruby/ext/openssl/impl/PKCS7.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.math.BigInteger; -import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; @@ -65,7 +64,6 @@ import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.X509Name; -import org.jruby.ext.openssl.OpenSSLReal; import org.jruby.ext.openssl.x509store.Name; import org.jruby.ext.openssl.x509store.Store; import org.jruby.ext.openssl.x509store.StoreContext; @@ -78,6 +76,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class PKCS7 { // OpenSSL behavior: PKCS#7 ObjectId for "ITU-T" + "0" private static final String EMPTY_PKCS7_OID = "0.0"; @@ -127,7 +126,7 @@ public static PKCS7 fromASN1(DEREncodable obj) throws PKCS7Exception { // OpenSSL behavior p7.setType(ASN1Registry.NID_undef); } else { - int nid = ASN1Registry.obj2nid(contentType); + Integer nid = ASN1Registry.obj2nid(contentType); DEREncodable content = size == 1 ? (DEREncodable) null : ((ASN1Sequence) obj).getObjectAt(1); @@ -243,7 +242,7 @@ public void signatureVerify(BIO bio, SignerInfoWithPkey si, X509AuxCertificate x throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_WRONG_PKCS7_TYPE); } - int md_type = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId()); + int md_type = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId()).intValue(); BIO btmp = bio; MessageDigest mdc = null; @@ -678,7 +677,7 @@ public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) thro dataBody = getSignedAndEnveloped().getEncData().getEncData().getOctets(); encAlg = getSignedAndEnveloped().getEncData().getAlgorithm(); try { - evpCipher = getCipher(encAlg.getObjectId()); + evpCipher = EVP.getCipher(encAlg.getAlgorithm()); } catch(Exception e) { e.printStackTrace(System.err); throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e); @@ -689,7 +688,7 @@ public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) thro dataBody = getEnveloped().getEncData().getEncData().getOctets(); encAlg = getEnveloped().getEncData().getAlgorithm(); try { - evpCipher = getCipher(encAlg.getObjectId()); + evpCipher = EVP.getCipher(encAlg.getAlgorithm()); } catch(Exception e) { e.printStackTrace(System.err); throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e); @@ -703,7 +702,7 @@ public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) thro if(mdSk != null) { for(AlgorithmIdentifier xa : mdSk) { try { - MessageDigest evpMd = EVP.getDigest(xa.getObjectId()); + MessageDigest evpMd = EVP.getDigest(xa.getAlgorithm()); btmp = BIO.mdFilter(evpMd); if(out == null) { out = btmp; @@ -771,20 +770,21 @@ public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) thro DEREncodable params = encAlg.getParameters(); try { + String algo = org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(evpCipher); if(params != null && params instanceof ASN1OctetString) { - if (evpCipher.getAlgorithm().startsWith("RC2")) { + if (algo.startsWith("RC2")) { // J9's IBMJCE needs this exceptional RC2 support. // Giving IvParameterSpec throws 'Illegal parameter' on IBMJCE. - SecretKeySpec sks = new SecretKeySpec(tmp, evpCipher.getAlgorithm()); + SecretKeySpec sks = new SecretKeySpec(tmp, algo); RC2ParameterSpec s = new RC2ParameterSpec(tmp.length * 8, ((ASN1OctetString) params).getOctets()); evpCipher.init(Cipher.DECRYPT_MODE, sks, s); } else { - SecretKeySpec sks = new SecretKeySpec(tmp, evpCipher.getAlgorithm()); + SecretKeySpec sks = new SecretKeySpec(tmp, algo); IvParameterSpec iv = new IvParameterSpec(((ASN1OctetString) params).getOctets()); evpCipher.init(Cipher.DECRYPT_MODE, sks, iv); } } else { - evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, evpCipher.getAlgorithm())); + evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, algo)); } } catch(Exception e) { e.printStackTrace(System.err); @@ -814,17 +814,6 @@ public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) thro return out; } - // Without Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files, - // getting Cipher object via OID(1.2.840.113549.3.7 - DES-EDE3-CBC) causes 'Illegal Key Length' - // exception. To avoid this, we get Cipher object via algo name(DESede/cbc/PKCS5Padding). - private static Cipher getCipher(DERObjectIdentifier oid) throws GeneralSecurityException { - // check DES-EDE3-CBC - if (oid.getId().equals("1.2.840.113549.3.7")) { - return OpenSSLReal.getCipherBC("DESede/cbc/PKCS5Padding"); - } - return EVP.getCipher(oid); - } - /** c: PKCS7_dataInit * */ @@ -935,7 +924,12 @@ public BIO dataInit(BIO bio) throws PKCS7Exception { bio.setMemEofReturn(0); } } - out.push(bio); + + if (out != null) { + out.push(bio); + } else { + out = bio; + } bio = null; return out; } diff --git a/src/java/org/jruby/ext/openssl/impl/RecipInfo.java b/src/java/org/jruby/ext/openssl/impl/RecipInfo.java index 71617f9..008c833 100644 --- a/src/java/org/jruby/ext/openssl/impl/RecipInfo.java +++ b/src/java/org/jruby/ext/openssl/impl/RecipInfo.java @@ -47,6 +47,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class RecipInfo { private int version; private IssuerAndSerialNumber issuerAndSerial; diff --git a/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java b/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java index 38c5f01..5ddc594 100644 --- a/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java +++ b/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java @@ -61,6 +61,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class SignerInfoWithPkey extends ASN1Encodable { private DERInteger version; private IssuerAndSerialNumber issuerAndSerialNumber; diff --git a/src/java/org/jruby/ext/openssl/x509store/Lookup.java b/src/java/org/jruby/ext/openssl/x509store/Lookup.java index c7240f0..d66a499 100644 --- a/src/java/org/jruby/ext/openssl/x509store/Lookup.java +++ b/src/java/org/jruby/ext/openssl/x509store/Lookup.java @@ -46,12 +46,17 @@ import java.util.Iterator; import java.util.List; import org.jruby.Ruby; +import org.jruby.RubyHash; import org.jruby.util.io.ChannelDescriptor; import org.jruby.util.io.ChannelStream; import org.jruby.util.io.FileExistsException; import org.jruby.util.io.InvalidValueException; import org.jruby.util.io.ModeFlags; +import java.security.KeyStore; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; + /** * X509_LOOKUP * @@ -264,6 +269,31 @@ public int loadCertificateOrCRLFile(String file, int type) throws Exception { return count; } + public int loadDefaultJavaCACertsFile() throws Exception { + int count = 0; + String certsFile = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar); + FileInputStream fin = new FileInputStream(certsFile); + try { + KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + // we pass a null password, as the cacerts file isn't password protected + keystore.load(fin, null); + PKIXParameters params = new PKIXParameters(keystore); + for(TrustAnchor trustAnchor : params.getTrustAnchors()) { + X509Certificate certificate = trustAnchor.getTrustedCert(); + store.addCertificate(certificate); + count++; + } + } finally { + if (fin != null) { + try { + fin.close(); + } catch (Exception ignored) { + } + } + } + return count; + } + private InputStream wrapJRubyNormalizedInputStream(String file) throws IOException { Ruby runtime = Ruby.getGlobalRuntime(); try { @@ -398,13 +428,14 @@ public int call(Object _ctx, Object _cmd, Object _argp, Object _argl, Object _re case X509Utils.X509_L_FILE_LOAD: if (argl == X509Utils.X509_FILETYPE_DEFAULT) { try { - file = System.getenv(X509Utils.getDefaultCertificateFileEnvironment()); + RubyHash env = (RubyHash)Ruby.getGlobalRuntime().getObject().getConstant("ENV"); + file = (String)env.get(Ruby.getGlobalRuntime().newString(X509Utils.getDefaultCertificateFileEnvironment())); } catch (Error error) { } if (file != null) { ok = ctx.loadCertificateOrCRLFile(file, X509Utils.X509_FILETYPE_PEM) != 0 ? 1 : 0; } else { - ok = (ctx.loadCertificateOrCRLFile(X509Utils.getDefaultCertificateFile(), X509Utils.X509_FILETYPE_PEM) != 0) ? 1 : 0; + ok = (ctx.loadDefaultJavaCACertsFile() != 0) ? 1: 0; } if (ok == 0) { X509Error.addError(X509Utils.X509_R_LOADING_DEFAULTS); @@ -475,7 +506,8 @@ public int call(Object _ctx, Object _cmd, Object _argp, Object _argl, Object _re case X509Utils.X509_L_ADD_DIR: if(argl == X509Utils.X509_FILETYPE_DEFAULT) { try { - dir = System.getenv(X509Utils.getDefaultCertificateDirectoryEnvironment()); + RubyHash env = (RubyHash)Ruby.getGlobalRuntime().getObject().getConstant("ENV"); + dir = (String)env.get(Ruby.getGlobalRuntime().newString(X509Utils.getDefaultCertificateDirectoryEnvironment())); } catch (Error error) { } if(null != dir) { @@ -555,7 +587,7 @@ public int call(Object _xl, Object _type, Object _name, Object _ret) throws Exce int tp = iter.next(); int k = 0; for(;;) { - b.append(String.format("%s/%08x.%s%d", cdir, h, postfix, k)); + b.append(String.format("%s%s%08x.%s%d", cdir, File.separator, h, postfix, k)); k++; if(!(new File(b.toString()).exists())) { break; diff --git a/src/java/org/jruby/ext/openssl/x509store/Name.java b/src/java/org/jruby/ext/openssl/x509store/Name.java index 71a945d..dada079 100644 --- a/src/java/org/jruby/ext/openssl/x509store/Name.java +++ b/src/java/org/jruby/ext/openssl/x509store/Name.java @@ -40,6 +40,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class Name { public X509Name name; diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java index fad29a8..c0d0c24 100644 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java @@ -126,6 +126,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public class PEMInputOutput { public static final String BEF = "-----"; public static final String AFT = "-----"; @@ -878,10 +879,6 @@ private static void writePemPlain(BufferedWriter out, String pemHeader, byte[] e private static void writePemEncrypted(BufferedWriter out, String pemHeader, byte[] encoding, CipherSpec cipher, char[] passwd) throws IOException { Cipher c = cipher.getCipher(); - String algoBase = c.getAlgorithm(); - if (algoBase.indexOf('/') != -1) { - algoBase = algoBase.split("/")[0]; - } byte[] iv = new byte[c.getBlockSize()]; random.nextBytes(iv); byte[] salt = new byte[8]; @@ -889,7 +886,7 @@ private static void writePemEncrypted(BufferedWriter out, String pemHeader, byte OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits()); - SecretKey secretKey = new SecretKeySpec(param.getKey(), algoBase); + SecretKey secretKey = new SecretKeySpec(param.getKey(), org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(c)); byte[] encData = null; try { c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); diff --git a/src/java/org/jruby/ext/openssl/x509store/Store.java b/src/java/org/jruby/ext/openssl/x509store/Store.java index 6ebb3c6..b8a29f8 100644 --- a/src/java/org/jruby/ext/openssl/x509store/Store.java +++ b/src/java/org/jruby/ext/openssl/x509store/Store.java @@ -325,9 +325,7 @@ public int loadLocations(String file, String path) throws Exception { /** * c: X509_STORE_set_default_paths - * not used for now: invoking this method causes refering System.getenv("SSL_CERT_DIR") etc. - * We need to get the dir via evaluating "ENV['SSL_CERT_DIR']" instead of it. - */ + */ public int setDefaultPaths() throws Exception { Lookup lookup; diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Object.java b/src/java/org/jruby/ext/openssl/x509store/X509Object.java index b7f35db..61a6a1b 100644 --- a/src/java/org/jruby/ext/openssl/x509store/X509Object.java +++ b/src/java/org/jruby/ext/openssl/x509store/X509Object.java @@ -34,6 +34,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public abstract class X509Object implements Comparable { /** * c: X509_OBJECT_idx_by_subject diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/java/org/jruby/ext/openssl/x509store/X509Utils.java index 64a2cd3..63b8f3c 100644 --- a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ b/src/java/org/jruby/ext/openssl/x509store/X509Utils.java @@ -39,7 +39,6 @@ import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.asn1.x509.X509Name; /** * Contains most of the functionality that beings with X509 in @@ -47,6 +46,7 @@ * * @author Ola Bini */ +@SuppressWarnings("deprecation") public abstract class X509Utils { private X509Utils() {} @@ -240,14 +240,14 @@ public static int checkIfIssuedBy(X509AuxCertificate issuer, X509AuxCertificate } if(sakid.getAuthorityCertIssuer() != null) { GeneralName[] gens = sakid.getAuthorityCertIssuer().getNames(); - X509Name nm = null; + org.bouncycastle.asn1.x509.X509Name nm = null; for(int i=0;i Date: Fri, 26 Oct 2012 22:50:38 -0500 Subject: [PATCH 62/66] Add a gem-specific file to allow loading OpenSSL from gem. --- lib/shared/jruby-openssl.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/shared/jruby-openssl.rb diff --git a/lib/shared/jruby-openssl.rb b/lib/shared/jruby-openssl.rb new file mode 100644 index 0000000..b0cab18 --- /dev/null +++ b/lib/shared/jruby-openssl.rb @@ -0,0 +1,26 @@ +unless defined? JRUBY_VERSION + warn 'Loading jruby-openssl in a non-JRuby interpreter' +end + +# Load bouncy-castle gem if available +begin + require 'bouncy-castle-java' +rescue LoadError + # runs under restricted mode or uses builtin BC +end + +# Load extension +require 'jruby' +require 'jopenssl.jar' +org.jruby.ext.openssl.OSSLLibrary.new.load(JRuby.runtime, false) + +# Add version-appropriate library path to LOAD_PATH +if RUBY_VERSION >= '1.9.0' + $LOAD_PATH.unshift(File.expand_path('../../1.9', __FILE__)) + load(File.expand_path('../../1.9/openssl.rb', __FILE__)) +else + $LOAD_PATH.unshift(File.expand_path('../../1.8', __FILE__)) + load(File.expand_path('../../1.8/openssl.rb', __FILE__)) +end + +require 'openssl/pkcs12' From 6cdad5ec9ab5911568e67302471f27d9061179a3 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 26 Oct 2012 22:51:13 -0500 Subject: [PATCH 63/66] Update .gitignore for new layout. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b15e2c9..c54fb83 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,6 @@ pkg Manifest.txt build.properties nbproject/private -lib/jopenssl.jar +lib/shared/jopenssl.jar *.orig *.rej From f94c31f0845ea2f5b26795d04edf4e3f22efc4cc Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 26 Oct 2012 22:55:00 -0500 Subject: [PATCH 64/66] Update version to 0.8.0.pre1 --- lib/shared/jopenssl/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb index 5f58ff8..beadba2 100644 --- a/lib/shared/jopenssl/version.rb +++ b/lib/shared/jopenssl/version.rb @@ -1,5 +1,5 @@ module Jopenssl module Version - VERSION = "0.7.7" + VERSION = "0.8.0.pre1" end end From 9417c3a016ebc5155329062061a0e725512879b6 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sat, 27 Oct 2012 01:06:34 -0500 Subject: [PATCH 65/66] Wipe out jruby-ossl repository. --- History.txt | 218 - License.txt | 30 - README.md | 3 + README.txt | 13 - Rakefile | 88 - TODO-1_9-support.txt | 23 - build.properties.SAMPLE | 7 - build.xml | 60 - build_lib/bcmail-jdk15-146.jar | Bin 487135 -> 0 bytes build_lib/bcprov-jdk15-146.jar | Bin 1815677 -> 0 bytes build_lib/bouncy-castle-java.rb | 3 - build_lib/mocha/COPYING.rdoc | 3 - build_lib/mocha/MIT-LICENSE.rdoc | 7 - build_lib/mocha/README.rdoc | 39 - build_lib/mocha/RELEASE.rdoc | 318 - build_lib/mocha/Rakefile | 216 - build_lib/mocha/examples/misc.rb | 43 - build_lib/mocha/examples/mocha.rb | 25 - build_lib/mocha/examples/stubba.rb | 64 - build_lib/mocha/lib/mocha.rb | 4 - .../mocha/lib/mocha/any_instance_method.rb | 59 - build_lib/mocha/lib/mocha/api.rb | 173 - .../mocha/lib/mocha/argument_iterator.rb | 21 - build_lib/mocha/lib/mocha/backtrace_filter.rb | 17 - build_lib/mocha/lib/mocha/cardinality.rb | 95 - build_lib/mocha/lib/mocha/central.rb | 33 - .../lib/mocha/change_state_side_effect.rb | 19 - build_lib/mocha/lib/mocha/class_method.rb | 91 - build_lib/mocha/lib/mocha/configuration.rb | 79 - build_lib/mocha/lib/mocha/deprecation.rb | 22 - build_lib/mocha/lib/mocha/exception_raiser.rb | 17 - build_lib/mocha/lib/mocha/expectation.rb | 479 -- .../mocha/lib/mocha/expectation_error.rb | 15 - build_lib/mocha/lib/mocha/expectation_list.rb | 50 - .../lib/mocha/in_state_ordering_constraint.rb | 19 - build_lib/mocha/lib/mocha/inspect.rb | 67 - build_lib/mocha/lib/mocha/instance_method.rb | 16 - build_lib/mocha/lib/mocha/integration.rb | 38 - .../mocha/lib/mocha/integration/mini_test.rb | 46 - .../mini_test/assertion_counter.rb | 23 - .../mini_test/exception_translation.rb | 20 - .../mocha/integration/mini_test/version_13.rb | 44 - .../integration/mini_test/version_140.rb | 45 - .../integration/mini_test/version_141.rb | 56 - .../mini_test/version_142_and_above.rb | 56 - .../mocha/lib/mocha/integration/test_unit.rb | 55 - .../test_unit/assertion_counter.rb | 23 - .../integration/test_unit/gem_version_200.rb | 52 - .../test_unit/gem_version_201_to_202.rb | 52 - .../test_unit/gem_version_203_to_209.rb | 52 - .../test_unit/ruby_version_185_and_below.rb | 51 - .../test_unit/ruby_version_186_and_above.rb | 53 - build_lib/mocha/lib/mocha/is_a.rb | 9 - build_lib/mocha/lib/mocha/logger.rb | 15 - build_lib/mocha/lib/mocha/metaclass.rb | 13 - build_lib/mocha/lib/mocha/method_matcher.rb | 21 - build_lib/mocha/lib/mocha/mock.rb | 200 - build_lib/mocha/lib/mocha/mockery.rb | 181 - build_lib/mocha/lib/mocha/module_method.rb | 16 - build_lib/mocha/lib/mocha/multiple_yields.rb | 20 - build_lib/mocha/lib/mocha/names.rb | 53 - build_lib/mocha/lib/mocha/no_yields.rb | 11 - build_lib/mocha/lib/mocha/object.rb | 220 - build_lib/mocha/lib/mocha/options.rb | 1 - .../mocha/lib/mocha/parameter_matchers.rb | 27 - .../lib/mocha/parameter_matchers/all_of.rb | 42 - .../lib/mocha/parameter_matchers/any_of.rb | 47 - .../parameter_matchers/any_parameters.rb | 40 - .../lib/mocha/parameter_matchers/anything.rb | 33 - .../lib/mocha/parameter_matchers/base.rb | 63 - .../lib/mocha/parameter_matchers/equals.rb | 42 - .../mocha/parameter_matchers/has_entries.rb | 45 - .../lib/mocha/parameter_matchers/has_entry.rb | 57 - .../lib/mocha/parameter_matchers/has_key.rb | 43 - .../lib/mocha/parameter_matchers/has_value.rb | 43 - .../lib/mocha/parameter_matchers/includes.rb | 41 - .../mocha/parameter_matchers/instance_of.rb | 42 - .../lib/mocha/parameter_matchers/is_a.rb | 42 - .../lib/mocha/parameter_matchers/kind_of.rb | 42 - .../mocha/lib/mocha/parameter_matchers/not.rb | 42 - .../lib/mocha/parameter_matchers/object.rb | 15 - .../mocha/parameter_matchers/optionally.rb | 55 - .../parameter_matchers/regexp_matches.rb | 44 - .../mocha/parameter_matchers/responds_with.rb | 43 - .../parameter_matchers/yaml_equivalent.rb | 43 - .../mocha/lib/mocha/parameters_matcher.rb | 37 - .../mocha/lib/mocha/pretty_parameters.rb | 28 - build_lib/mocha/lib/mocha/return_values.rb | 31 - build_lib/mocha/lib/mocha/sequence.rb | 42 - .../mocha/lib/mocha/single_return_value.rb | 17 - build_lib/mocha/lib/mocha/single_yield.rb | 18 - build_lib/mocha/lib/mocha/standalone.rb | 1 - build_lib/mocha/lib/mocha/state_machine.rb | 91 - build_lib/mocha/lib/mocha/stubbing_error.rb | 16 - .../mocha/lib/mocha/unexpected_invocation.rb | 18 - build_lib/mocha/lib/mocha/yield_parameters.rb | 31 - build_lib/mocha/lib/mocha_standalone.rb | 2 - build_lib/mocha/lib/stubba.rb | 4 - .../test/acceptance/acceptance_test_helper.rb | 38 - build_lib/mocha/test/acceptance/api_test.rb | 139 - .../mocha/test/acceptance/bug_18914_test.rb | 43 - .../mocha/test/acceptance/bug_21465_test.rb | 34 - .../mocha/test/acceptance/bug_21563_test.rb | 25 - .../test/acceptance/exception_rescue_test.rb | 58 - .../expected_invocation_count_test.rb | 196 - .../test/acceptance/failure_messages_test.rb | 64 - .../mocha/test/acceptance/minitest_test.rb | 157 - .../test/acceptance/mocha_example_test.rb | 98 - .../test/acceptance/mocha_test_result_test.rb | 84 - build_lib/mocha/test/acceptance/mock_test.rb | 100 - .../mock_with_initializer_block_test.rb | 51 - .../mocked_methods_dispatch_test.rb | 78 - .../acceptance/optional_parameters_test.rb | 70 - .../test/acceptance/parameter_matcher_test.rb | 246 - .../test/acceptance/partial_mocks_test.rb | 47 - .../test/acceptance/return_value_test.rb | 52 - .../mocha/test/acceptance/sequence_test.rb | 186 - .../mocha/test/acceptance/states_test.rb | 70 - .../stub_any_instance_method_test.rb | 198 - .../test/acceptance/stub_class_method_test.rb | 206 - .../test/acceptance/stub_everything_test.rb | 56 - .../acceptance/stub_instance_method_test.rb | 206 - .../acceptance/stub_module_method_test.rb | 163 - build_lib/mocha/test/acceptance/stub_test.rb | 52 - .../test/acceptance/stubba_example_test.rb | 102 - .../mocha/test/acceptance/stubba_test.rb | 15 - .../acceptance/stubba_test_result_test.rb | 66 - .../stubbing_error_backtrace_test.rb | 64 - .../stubbing_method_unnecessarily_test.rb | 65 - ...g_non_existent_any_instance_method_test.rb | 130 - ...stubbing_non_existent_class_method_test.rb | 157 - ...bbing_non_existent_instance_method_test.rb | 147 - ...ing_non_public_any_instance_method_test.rb | 130 - .../stubbing_non_public_class_method_test.rb | 163 - ...tubbing_non_public_instance_method_test.rb | 143 - .../stubbing_on_non_mock_object_test.rb | 64 - .../mocha/test/acceptance/unstubbing_test.rb | 122 - build_lib/mocha/test/deprecation_disabler.rb | 15 - build_lib/mocha/test/execution_point.rb | 36 - build_lib/mocha/test/method_definer.rb | 24 - build_lib/mocha/test/mini_test_result.rb | 74 - build_lib/mocha/test/simple_counter.rb | 13 - build_lib/mocha/test/test_helper.rb | 17 - build_lib/mocha/test/test_runner.rb | 47 - .../test/unit/any_instance_method_test.rb | 126 - .../mocha/test/unit/array_inspect_test.rb | 16 - .../mocha/test/unit/backtrace_filter_test.rb | 19 - build_lib/mocha/test/unit/cardinality_test.rb | 56 - build_lib/mocha/test/unit/central_test.rb | 91 - .../unit/change_state_side_effect_test.rb | 41 - .../mocha/test/unit/class_method_test.rb | 237 - .../mocha/test/unit/configuration_test.rb | 38 - .../mocha/test/unit/date_time_inspect_test.rb | 21 - .../mocha/test/unit/exception_raiser_test.rb | 42 - .../mocha/test/unit/expectation_list_test.rb | 57 - build_lib/mocha/test/unit/expectation_test.rb | 480 -- .../mocha/test/unit/hash_inspect_test.rb | 16 - .../unit/in_state_ordering_constraint_test.rb | 43 - build_lib/mocha/test/unit/metaclass_test.rb | 22 - .../mocha/test/unit/method_matcher_test.rb | 23 - build_lib/mocha/test/unit/mock_test.rb | 302 - build_lib/mocha/test/unit/mockery_test.rb | 149 - .../mocha/test/unit/multiple_yields_test.rb | 18 - build_lib/mocha/test/unit/no_yields_test.rb | 18 - .../mocha/test/unit/object_inspect_test.rb | 38 - build_lib/mocha/test/unit/object_test.rb | 82 - .../unit/parameter_matchers/all_of_test.rb | 26 - .../unit/parameter_matchers/any_of_test.rb | 26 - .../unit/parameter_matchers/anything_test.rb | 21 - .../unit/parameter_matchers/equals_test.rb | 25 - .../parameter_matchers/has_entries_test.rb | 51 - .../unit/parameter_matchers/has_entry_test.rb | 82 - .../unit/parameter_matchers/has_key_test.rb | 55 - .../unit/parameter_matchers/has_value_test.rb | 57 - .../unit/parameter_matchers/includes_test.rb | 44 - .../parameter_matchers/instance_of_test.rb | 25 - .../test/unit/parameter_matchers/is_a_test.rb | 25 - .../unit/parameter_matchers/kind_of_test.rb | 25 - .../test/unit/parameter_matchers/not_test.rb | 26 - .../parameter_matchers/regexp_matches_test.rb | 46 - .../parameter_matchers/responds_with_test.rb | 25 - .../unit/parameter_matchers/stub_matcher.rb | 27 - .../yaml_equivalent_test.rb | 25 - .../test/unit/parameters_matcher_test.rb | 121 - .../mocha/test/unit/return_values_test.rb | 63 - build_lib/mocha/test/unit/sequence_test.rb | 104 - .../test/unit/single_return_value_test.rb | 14 - .../mocha/test/unit/single_yield_test.rb | 18 - .../mocha/test/unit/state_machine_test.rb | 98 - .../mocha/test/unit/string_inspect_test.rb | 11 - .../mocha/test/unit/yield_parameters_test.rb | 93 - jruby-openssl.gemspec | 36 - lib/1.8/openssl.rb | 67 - lib/1.8/openssl/bn.rb | 35 - lib/1.8/openssl/buffering.rb | 241 - lib/1.8/openssl/cipher.rb | 65 - lib/1.8/openssl/config.rb | 316 - lib/1.8/openssl/digest.rb | 61 - lib/1.8/openssl/dummy.rb | 33 - lib/1.8/openssl/dummyssl.rb | 14 - lib/1.8/openssl/pkcs7.rb | 25 - lib/1.8/openssl/ssl-internal.rb | 179 - lib/1.8/openssl/ssl.rb | 1 - lib/1.8/openssl/x509-internal.rb | 153 - lib/1.8/openssl/x509.rb | 1 - lib/1.9/openssl.rb | 22 - lib/1.9/openssl/bn.rb | 35 - lib/1.9/openssl/buffering.rb | 449 -- lib/1.9/openssl/cipher.rb | 65 - lib/1.9/openssl/config.rb | 313 - lib/1.9/openssl/digest.rb | 72 - lib/1.9/openssl/ssl-internal.rb | 177 - lib/1.9/openssl/ssl.rb | 2 - lib/1.9/openssl/x509-internal.rb | 158 - lib/1.9/openssl/x509.rb | 2 - lib/shared/jopenssl/version.rb | 5 - lib/shared/jruby-openssl.rb | 26 - lib/shared/openssl.rb | 26 - lib/shared/openssl/dummy.rb | 33 - lib/shared/openssl/dummyssl.rb | 14 - lib/shared/openssl/pkcs12.rb | 50 - lib/shared/openssl/ssl.rb | 1 - lib/shared/openssl/x509.rb | 1 - nbproject/genfiles.properties | 5 - nbproject/jdk.xml | 157 - nbproject/nbjdk.properties | 1 - nbproject/nbjdk.xml | 16 - nbproject/project.xml | 117 - src/java/org/jruby/ext/openssl/ASN1.java | 938 --- src/java/org/jruby/ext/openssl/Attribute.java | 133 - src/java/org/jruby/ext/openssl/BN.java | 766 --- .../ext/openssl/BouncyCastlePEMHandler.java | 69 - src/java/org/jruby/ext/openssl/Cipher.java | 806 --- .../org/jruby/ext/openssl/CipherStrings.java | 1856 ------ src/java/org/jruby/ext/openssl/Config.java | 49 - .../jruby/ext/openssl/DefaultPEMHandler.java | 44 - src/java/org/jruby/ext/openssl/Digest.java | 191 - src/java/org/jruby/ext/openssl/HMAC.java | 184 - .../org/jruby/ext/openssl/NetscapeSPKI.java | 253 - .../org/jruby/ext/openssl/OSSLLibrary.java | 14 - .../org/jruby/ext/openssl/OpenSSLImpl.java | 357 -- .../org/jruby/ext/openssl/OpenSSLReal.java | 214 - .../org/jruby/ext/openssl/PEMHandler.java | 40 - .../PKCS10CertificationRequestExt.java | 159 - src/java/org/jruby/ext/openssl/PKCS7.java | 759 --- src/java/org/jruby/ext/openssl/PKey.java | 264 - src/java/org/jruby/ext/openssl/PKeyDH.java | 398 -- src/java/org/jruby/ext/openssl/PKeyDSA.java | 502 -- src/java/org/jruby/ext/openssl/PKeyRSA.java | 769 --- src/java/org/jruby/ext/openssl/Random.java | 103 - src/java/org/jruby/ext/openssl/Request.java | 328 -- src/java/org/jruby/ext/openssl/SSL.java | 94 - .../org/jruby/ext/openssl/SSLContext.java | 747 --- src/java/org/jruby/ext/openssl/SSLSocket.java | 787 --- .../jruby/ext/openssl/SimpleSecretKey.java | 53 - src/java/org/jruby/ext/openssl/Utils.java | 98 - src/java/org/jruby/ext/openssl/X509.java | 108 - src/java/org/jruby/ext/openssl/X509CRL.java | 462 -- src/java/org/jruby/ext/openssl/X509Cert.java | 536 -- .../org/jruby/ext/openssl/X509Extensions.java | 786 --- src/java/org/jruby/ext/openssl/X509Name.java | 421 -- .../org/jruby/ext/openssl/X509Revoked.java | 113 - src/java/org/jruby/ext/openssl/X509Store.java | 240 - .../org/jruby/ext/openssl/X509StoreCtx.java | 228 - .../jruby/ext/openssl/impl/ASN1Registry.java | 5152 ----------------- .../org/jruby/ext/openssl/impl/Attribute.java | 88 - src/java/org/jruby/ext/openssl/impl/BIO.java | 345 -- .../org/jruby/ext/openssl/impl/BIOFilter.java | 38 - .../org/jruby/ext/openssl/impl/Base64.java | 2066 ------- .../ext/openssl/impl/Base64BIOFilter.java | 74 - .../ext/openssl/impl/CipherBIOFilter.java | 158 - .../jruby/ext/openssl/impl/CipherSpec.java | 78 - .../org/jruby/ext/openssl/impl/Digest.java | 126 - src/java/org/jruby/ext/openssl/impl/EVP.java | 147 - .../jruby/ext/openssl/impl/EncContent.java | 188 - .../org/jruby/ext/openssl/impl/Encrypt.java | 77 - .../org/jruby/ext/openssl/impl/Envelope.java | 167 - .../ext/openssl/impl/IssuerAndSerial.java | 35 - .../org/jruby/ext/openssl/impl/MemBIO.java | 117 - .../openssl/impl/MessageDigestBIOFilter.java | 76 - src/java/org/jruby/ext/openssl/impl/Mime.java | 244 - .../jruby/ext/openssl/impl/MimeHeader.java | 113 - .../org/jruby/ext/openssl/impl/MimeParam.java | 80 - .../impl/NotVerifiedPKCS7Exception.java | 40 - .../jruby/ext/openssl/impl/NullSinkBIO.java | 52 - .../org/jruby/ext/openssl/impl/PKCS7.java | 1277 ---- .../org/jruby/ext/openssl/impl/PKCS7Data.java | 166 - .../jruby/ext/openssl/impl/PKCS7DataData.java | 92 - .../ext/openssl/impl/PKCS7DataDigest.java | 64 - .../ext/openssl/impl/PKCS7DataEncrypted.java | 61 - .../ext/openssl/impl/PKCS7DataEnveloped.java | 89 - .../ext/openssl/impl/PKCS7DataSigned.java | 134 - .../impl/PKCS7DataSignedAndEnveloped.java | 97 - .../ext/openssl/impl/PKCS7Exception.java | 70 - src/java/org/jruby/ext/openssl/impl/PKey.java | 257 - .../org/jruby/ext/openssl/impl/RecipInfo.java | 245 - .../org/jruby/ext/openssl/impl/SMIME.java | 280 - .../jruby/ext/openssl/impl/SignEnvelope.java | 200 - .../org/jruby/ext/openssl/impl/Signed.java | 364 -- .../ext/openssl/impl/SignerInfoWithPkey.java | 365 -- .../ext/openssl/impl/TypeDiscriminating.java | 34 - .../org/jruby/ext/openssl/x509store/CRL.java | 59 - .../ext/openssl/x509store/Certificate.java | 57 - .../openssl/x509store/CertificateFile.java | 46 - .../openssl/x509store/CertificateHashDir.java | 46 - .../ext/openssl/x509store/Function0.java | 43 - .../ext/openssl/x509store/Function1.java | 43 - .../ext/openssl/x509store/Function2.java | 43 - .../ext/openssl/x509store/Function3.java | 43 - .../ext/openssl/x509store/Function4.java | 43 - .../ext/openssl/x509store/Function5.java | 43 - .../jruby/ext/openssl/x509store/Lookup.java | 624 -- .../ext/openssl/x509store/LookupMethod.java | 84 - .../org/jruby/ext/openssl/x509store/Name.java | 86 - .../ext/openssl/x509store/PEMInputOutput.java | 1275 ---- .../org/jruby/ext/openssl/x509store/PKey.java | 41 - .../ext/openssl/x509store/PolicyTree.java | 36 - .../jruby/ext/openssl/x509store/Purpose.java | 476 -- .../jruby/ext/openssl/x509store/Store.java | 375 -- .../ext/openssl/x509store/StoreContext.java | 1400 ----- .../jruby/ext/openssl/x509store/Trust.java | 279 - .../openssl/x509store/VerifyParameter.java | 324 -- .../jruby/ext/openssl/x509store/X509Aux.java | 43 - .../openssl/x509store/X509AuxCertificate.java | 170 - .../ext/openssl/x509store/X509Error.java | 148 - .../ext/openssl/x509store/X509Object.java | 89 - .../ext/openssl/x509store/X509Utils.java | 536 -- test/1.8/ssl_server.rb | 99 - test/1.8/test_asn1.rb | 212 - test/1.8/test_cipher.rb | 193 - test/1.8/test_config.rb | 290 - test/1.8/test_digest.rb | 88 - test/1.8/test_ec.rb | 128 - test/1.8/test_hmac.rb | 46 - test/1.8/test_ns_spki.rb | 59 - test/1.8/test_pair.rb | 149 - test/1.8/test_pkcs7.rb | 489 -- test/1.8/test_pkey_rsa.rb | 49 - test/1.8/test_ssl.rb | 1032 ---- test/1.8/test_x509cert.rb | 277 - test/1.8/test_x509crl.rb | 253 - test/1.8/test_x509ext.rb | 99 - test/1.8/test_x509name.rb | 290 - test/1.8/test_x509req.rb | 195 - test/1.8/test_x509store.rb | 246 - test/1.8/utils.rb | 144 - test/1.9/ssl_server.rb | 81 - test/1.9/test_asn1.rb | 589 -- test/1.9/test_bn.rb | 23 - test/1.9/test_buffering.rb | 88 - test/1.9/test_cipher.rb | 107 - test/1.9/test_config.rb | 288 - test/1.9/test_digest.rb | 118 - test/1.9/test_engine.rb | 15 - test/1.9/test_hmac.rb | 32 - test/1.9/test_ns_spki.rb | 50 - test/1.9/test_ocsp.rb | 47 - test/1.9/test_pair.rb | 257 - test/1.9/test_pkcs12.rb | 209 - test/1.9/test_pkcs7.rb | 156 - test/1.9/test_pkey_dh.rb | 72 - test/1.9/test_pkey_dsa.rb | 224 - test/1.9/test_pkey_ec.rb | 182 - test/1.9/test_pkey_rsa.rb | 244 - test/1.9/test_ssl.rb | 499 -- test/1.9/test_ssl_session.rb | 327 -- test/1.9/test_x509cert.rb | 217 - test/1.9/test_x509crl.rb | 221 - test/1.9/test_x509ext.rb | 69 - test/1.9/test_x509name.rb | 366 -- test/1.9/test_x509req.rb | 150 - test/1.9/test_x509store.rb | 229 - test/1.9/utils.rb | 304 - test/cert_with_ec_pk.cer | 27 - test/fixture/ca-bundle.crt | 2794 --------- test/fixture/ca_path/72fa7371.0 | 1 - test/fixture/ca_path/verisign.pem | 19 - test/fixture/cacert.pem | 23 - test/fixture/cert_localhost.pem | 19 - test/fixture/common.pem | 48 - test/fixture/ids_in_subject_rdn_set.pem | 31 - test/fixture/imaps/cacert.pem | 60 - test/fixture/imaps/server.crt | 61 - test/fixture/imaps/server.key | 15 - test/fixture/key_then_cert.pem | 34 - test/fixture/keypair.pem | 27 - test/fixture/localhost_keypair.pem | 18 - test/fixture/max.pem | 29 - test/fixture/purpose/b70a5bc1.0 | 1 - .../purpose/ca/PASSWD_OF_CA_KEY_IS_1234 | 0 test/fixture/purpose/ca/ca_config.rb | 37 - test/fixture/purpose/ca/cacert.pem | 24 - test/fixture/purpose/ca/newcerts/2_cert.pem | 19 - test/fixture/purpose/ca/newcerts/3_cert.pem | 19 - test/fixture/purpose/ca/newcerts/4_cert.pem | 19 - test/fixture/purpose/ca/private/cakeypair.pem | 30 - test/fixture/purpose/ca/serial | 1 - test/fixture/purpose/cacert.pem | 24 - test/fixture/purpose/scripts/gen_cert.rb | 127 - test/fixture/purpose/scripts/gen_csr.rb | 50 - test/fixture/purpose/scripts/init_ca.rb | 66 - test/fixture/purpose/sslclient.pem | 19 - test/fixture/purpose/sslclient/csr.pem | 10 - test/fixture/purpose/sslclient/keypair.pem | 15 - test/fixture/purpose/sslclient/sslclient.pem | 19 - test/fixture/purpose/sslserver.pem | 19 - test/fixture/purpose/sslserver/csr.pem | 10 - test/fixture/purpose/sslserver/keypair.pem | 15 - test/fixture/purpose/sslserver/sslserver.pem | 19 - .../purpose/sslserver_no_dsig_in_keyUsage.pem | 19 - test/fixture/selfcert.pem | 23 - test/fixture/verisign.pem | 19 - test/fixture/verisign_c3.pem | 14 - test/java/pkcs7_mime_enveloped.message | 19 - test/java/pkcs7_mime_signed.message | 30 - test/java/pkcs7_multipart_signed.message | 45 - test/java/test_java_attribute.rb | 25 - test/java/test_java_bio.rb | 42 - test/java/test_java_mime.rb | 173 - test/java/test_java_pkcs7.rb | 772 --- test/java/test_java_smime.rb | 177 - test/ref/a.out | 0 test/ref/compile.rb | 8 - test/ref/pkcs1 | Bin 12720 -> 0 bytes test/ref/pkcs1.c | 21 - test/ruby/envutil.rb | 208 - test/ruby/ut_eof.rb | 128 - test/test_all.rb | 1 - test/test_certificate.rb | 132 - test/test_cipher.rb | 197 - test/test_imaps.rb | 107 - test/test_integration.rb | 144 - test/test_java.rb | 98 - test/test_openssl.rb | 4 - test/test_parse_certificate.rb | 27 - test/test_pkcs7.rb | 56 - test/test_pkey_dsa.rb | 180 - test/test_pkey_rsa.rb | 329 -- test/test_ssl.rb | 97 - test/test_x509store.rb | 168 - test/ut_eof.rb | 128 - 441 files changed, 3 insertions(+), 65658 deletions(-) delete mode 100644 History.txt delete mode 100644 License.txt create mode 100644 README.md delete mode 100644 README.txt delete mode 100644 Rakefile delete mode 100644 TODO-1_9-support.txt delete mode 100644 build.properties.SAMPLE delete mode 100644 build.xml delete mode 100644 build_lib/bcmail-jdk15-146.jar delete mode 100644 build_lib/bcprov-jdk15-146.jar delete mode 100644 build_lib/bouncy-castle-java.rb delete mode 100644 build_lib/mocha/COPYING.rdoc delete mode 100644 build_lib/mocha/MIT-LICENSE.rdoc delete mode 100644 build_lib/mocha/README.rdoc delete mode 100644 build_lib/mocha/RELEASE.rdoc delete mode 100644 build_lib/mocha/Rakefile delete mode 100644 build_lib/mocha/examples/misc.rb delete mode 100644 build_lib/mocha/examples/mocha.rb delete mode 100644 build_lib/mocha/examples/stubba.rb delete mode 100644 build_lib/mocha/lib/mocha.rb delete mode 100644 build_lib/mocha/lib/mocha/any_instance_method.rb delete mode 100644 build_lib/mocha/lib/mocha/api.rb delete mode 100644 build_lib/mocha/lib/mocha/argument_iterator.rb delete mode 100644 build_lib/mocha/lib/mocha/backtrace_filter.rb delete mode 100644 build_lib/mocha/lib/mocha/cardinality.rb delete mode 100644 build_lib/mocha/lib/mocha/central.rb delete mode 100644 build_lib/mocha/lib/mocha/change_state_side_effect.rb delete mode 100644 build_lib/mocha/lib/mocha/class_method.rb delete mode 100644 build_lib/mocha/lib/mocha/configuration.rb delete mode 100644 build_lib/mocha/lib/mocha/deprecation.rb delete mode 100644 build_lib/mocha/lib/mocha/exception_raiser.rb delete mode 100644 build_lib/mocha/lib/mocha/expectation.rb delete mode 100644 build_lib/mocha/lib/mocha/expectation_error.rb delete mode 100644 build_lib/mocha/lib/mocha/expectation_list.rb delete mode 100644 build_lib/mocha/lib/mocha/in_state_ordering_constraint.rb delete mode 100644 build_lib/mocha/lib/mocha/inspect.rb delete mode 100644 build_lib/mocha/lib/mocha/instance_method.rb delete mode 100644 build_lib/mocha/lib/mocha/integration.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/assertion_counter.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/exception_translation.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/version_13.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/version_140.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/version_141.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/mini_test/version_142_and_above.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/assertion_counter.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/gem_version_200.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/gem_version_201_to_202.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/gem_version_203_to_209.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb delete mode 100644 build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb delete mode 100644 build_lib/mocha/lib/mocha/is_a.rb delete mode 100644 build_lib/mocha/lib/mocha/logger.rb delete mode 100644 build_lib/mocha/lib/mocha/metaclass.rb delete mode 100644 build_lib/mocha/lib/mocha/method_matcher.rb delete mode 100644 build_lib/mocha/lib/mocha/mock.rb delete mode 100644 build_lib/mocha/lib/mocha/mockery.rb delete mode 100644 build_lib/mocha/lib/mocha/module_method.rb delete mode 100644 build_lib/mocha/lib/mocha/multiple_yields.rb delete mode 100644 build_lib/mocha/lib/mocha/names.rb delete mode 100644 build_lib/mocha/lib/mocha/no_yields.rb delete mode 100644 build_lib/mocha/lib/mocha/object.rb delete mode 100644 build_lib/mocha/lib/mocha/options.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/all_of.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/any_of.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/any_parameters.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/anything.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/base.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/equals.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/has_entries.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/has_entry.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/has_key.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/has_value.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/includes.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/instance_of.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/is_a.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/kind_of.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/not.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/object.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/optionally.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/regexp_matches.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/responds_with.rb delete mode 100644 build_lib/mocha/lib/mocha/parameter_matchers/yaml_equivalent.rb delete mode 100644 build_lib/mocha/lib/mocha/parameters_matcher.rb delete mode 100644 build_lib/mocha/lib/mocha/pretty_parameters.rb delete mode 100644 build_lib/mocha/lib/mocha/return_values.rb delete mode 100644 build_lib/mocha/lib/mocha/sequence.rb delete mode 100644 build_lib/mocha/lib/mocha/single_return_value.rb delete mode 100644 build_lib/mocha/lib/mocha/single_yield.rb delete mode 100644 build_lib/mocha/lib/mocha/standalone.rb delete mode 100644 build_lib/mocha/lib/mocha/state_machine.rb delete mode 100644 build_lib/mocha/lib/mocha/stubbing_error.rb delete mode 100644 build_lib/mocha/lib/mocha/unexpected_invocation.rb delete mode 100644 build_lib/mocha/lib/mocha/yield_parameters.rb delete mode 100644 build_lib/mocha/lib/mocha_standalone.rb delete mode 100644 build_lib/mocha/lib/stubba.rb delete mode 100644 build_lib/mocha/test/acceptance/acceptance_test_helper.rb delete mode 100644 build_lib/mocha/test/acceptance/api_test.rb delete mode 100644 build_lib/mocha/test/acceptance/bug_18914_test.rb delete mode 100644 build_lib/mocha/test/acceptance/bug_21465_test.rb delete mode 100644 build_lib/mocha/test/acceptance/bug_21563_test.rb delete mode 100644 build_lib/mocha/test/acceptance/exception_rescue_test.rb delete mode 100644 build_lib/mocha/test/acceptance/expected_invocation_count_test.rb delete mode 100644 build_lib/mocha/test/acceptance/failure_messages_test.rb delete mode 100644 build_lib/mocha/test/acceptance/minitest_test.rb delete mode 100644 build_lib/mocha/test/acceptance/mocha_example_test.rb delete mode 100644 build_lib/mocha/test/acceptance/mocha_test_result_test.rb delete mode 100644 build_lib/mocha/test/acceptance/mock_test.rb delete mode 100644 build_lib/mocha/test/acceptance/mock_with_initializer_block_test.rb delete mode 100644 build_lib/mocha/test/acceptance/mocked_methods_dispatch_test.rb delete mode 100644 build_lib/mocha/test/acceptance/optional_parameters_test.rb delete mode 100644 build_lib/mocha/test/acceptance/parameter_matcher_test.rb delete mode 100644 build_lib/mocha/test/acceptance/partial_mocks_test.rb delete mode 100644 build_lib/mocha/test/acceptance/return_value_test.rb delete mode 100644 build_lib/mocha/test/acceptance/sequence_test.rb delete mode 100644 build_lib/mocha/test/acceptance/states_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_any_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_class_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_everything_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_module_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stub_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubba_example_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubba_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubba_test_result_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_error_backtrace_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_method_unnecessarily_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_existent_any_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_existent_class_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_existent_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_public_any_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_public_class_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_non_public_instance_method_test.rb delete mode 100644 build_lib/mocha/test/acceptance/stubbing_on_non_mock_object_test.rb delete mode 100644 build_lib/mocha/test/acceptance/unstubbing_test.rb delete mode 100644 build_lib/mocha/test/deprecation_disabler.rb delete mode 100644 build_lib/mocha/test/execution_point.rb delete mode 100644 build_lib/mocha/test/method_definer.rb delete mode 100644 build_lib/mocha/test/mini_test_result.rb delete mode 100644 build_lib/mocha/test/simple_counter.rb delete mode 100644 build_lib/mocha/test/test_helper.rb delete mode 100644 build_lib/mocha/test/test_runner.rb delete mode 100644 build_lib/mocha/test/unit/any_instance_method_test.rb delete mode 100644 build_lib/mocha/test/unit/array_inspect_test.rb delete mode 100644 build_lib/mocha/test/unit/backtrace_filter_test.rb delete mode 100644 build_lib/mocha/test/unit/cardinality_test.rb delete mode 100644 build_lib/mocha/test/unit/central_test.rb delete mode 100644 build_lib/mocha/test/unit/change_state_side_effect_test.rb delete mode 100644 build_lib/mocha/test/unit/class_method_test.rb delete mode 100644 build_lib/mocha/test/unit/configuration_test.rb delete mode 100644 build_lib/mocha/test/unit/date_time_inspect_test.rb delete mode 100644 build_lib/mocha/test/unit/exception_raiser_test.rb delete mode 100644 build_lib/mocha/test/unit/expectation_list_test.rb delete mode 100644 build_lib/mocha/test/unit/expectation_test.rb delete mode 100644 build_lib/mocha/test/unit/hash_inspect_test.rb delete mode 100644 build_lib/mocha/test/unit/in_state_ordering_constraint_test.rb delete mode 100644 build_lib/mocha/test/unit/metaclass_test.rb delete mode 100644 build_lib/mocha/test/unit/method_matcher_test.rb delete mode 100644 build_lib/mocha/test/unit/mock_test.rb delete mode 100644 build_lib/mocha/test/unit/mockery_test.rb delete mode 100644 build_lib/mocha/test/unit/multiple_yields_test.rb delete mode 100644 build_lib/mocha/test/unit/no_yields_test.rb delete mode 100644 build_lib/mocha/test/unit/object_inspect_test.rb delete mode 100644 build_lib/mocha/test/unit/object_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/all_of_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/any_of_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/anything_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/equals_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/has_entries_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/has_entry_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/has_key_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/has_value_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/includes_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/instance_of_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/is_a_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/kind_of_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/not_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/regexp_matches_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/responds_with_test.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/stub_matcher.rb delete mode 100644 build_lib/mocha/test/unit/parameter_matchers/yaml_equivalent_test.rb delete mode 100644 build_lib/mocha/test/unit/parameters_matcher_test.rb delete mode 100644 build_lib/mocha/test/unit/return_values_test.rb delete mode 100644 build_lib/mocha/test/unit/sequence_test.rb delete mode 100644 build_lib/mocha/test/unit/single_return_value_test.rb delete mode 100644 build_lib/mocha/test/unit/single_yield_test.rb delete mode 100644 build_lib/mocha/test/unit/state_machine_test.rb delete mode 100644 build_lib/mocha/test/unit/string_inspect_test.rb delete mode 100644 build_lib/mocha/test/unit/yield_parameters_test.rb delete mode 100644 jruby-openssl.gemspec delete mode 100644 lib/1.8/openssl.rb delete mode 100644 lib/1.8/openssl/bn.rb delete mode 100644 lib/1.8/openssl/buffering.rb delete mode 100644 lib/1.8/openssl/cipher.rb delete mode 100644 lib/1.8/openssl/config.rb delete mode 100644 lib/1.8/openssl/digest.rb delete mode 100644 lib/1.8/openssl/dummy.rb delete mode 100644 lib/1.8/openssl/dummyssl.rb delete mode 100644 lib/1.8/openssl/pkcs7.rb delete mode 100644 lib/1.8/openssl/ssl-internal.rb delete mode 100644 lib/1.8/openssl/ssl.rb delete mode 100644 lib/1.8/openssl/x509-internal.rb delete mode 100644 lib/1.8/openssl/x509.rb delete mode 100644 lib/1.9/openssl.rb delete mode 100644 lib/1.9/openssl/bn.rb delete mode 100644 lib/1.9/openssl/buffering.rb delete mode 100644 lib/1.9/openssl/cipher.rb delete mode 100644 lib/1.9/openssl/config.rb delete mode 100644 lib/1.9/openssl/digest.rb delete mode 100644 lib/1.9/openssl/ssl-internal.rb delete mode 100644 lib/1.9/openssl/ssl.rb delete mode 100644 lib/1.9/openssl/x509-internal.rb delete mode 100644 lib/1.9/openssl/x509.rb delete mode 100644 lib/shared/jopenssl/version.rb delete mode 100644 lib/shared/jruby-openssl.rb delete mode 100644 lib/shared/openssl.rb delete mode 100644 lib/shared/openssl/dummy.rb delete mode 100644 lib/shared/openssl/dummyssl.rb delete mode 100644 lib/shared/openssl/pkcs12.rb delete mode 100644 lib/shared/openssl/ssl.rb delete mode 100644 lib/shared/openssl/x509.rb delete mode 100644 nbproject/genfiles.properties delete mode 100644 nbproject/jdk.xml delete mode 100644 nbproject/nbjdk.properties delete mode 100644 nbproject/nbjdk.xml delete mode 100644 nbproject/project.xml delete mode 100644 src/java/org/jruby/ext/openssl/ASN1.java delete mode 100644 src/java/org/jruby/ext/openssl/Attribute.java delete mode 100644 src/java/org/jruby/ext/openssl/BN.java delete mode 100644 src/java/org/jruby/ext/openssl/BouncyCastlePEMHandler.java delete mode 100644 src/java/org/jruby/ext/openssl/Cipher.java delete mode 100644 src/java/org/jruby/ext/openssl/CipherStrings.java delete mode 100644 src/java/org/jruby/ext/openssl/Config.java delete mode 100644 src/java/org/jruby/ext/openssl/DefaultPEMHandler.java delete mode 100644 src/java/org/jruby/ext/openssl/Digest.java delete mode 100644 src/java/org/jruby/ext/openssl/HMAC.java delete mode 100644 src/java/org/jruby/ext/openssl/NetscapeSPKI.java delete mode 100644 src/java/org/jruby/ext/openssl/OSSLLibrary.java delete mode 100644 src/java/org/jruby/ext/openssl/OpenSSLImpl.java delete mode 100644 src/java/org/jruby/ext/openssl/OpenSSLReal.java delete mode 100644 src/java/org/jruby/ext/openssl/PEMHandler.java delete mode 100644 src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java delete mode 100644 src/java/org/jruby/ext/openssl/PKCS7.java delete mode 100644 src/java/org/jruby/ext/openssl/PKey.java delete mode 100644 src/java/org/jruby/ext/openssl/PKeyDH.java delete mode 100644 src/java/org/jruby/ext/openssl/PKeyDSA.java delete mode 100644 src/java/org/jruby/ext/openssl/PKeyRSA.java delete mode 100644 src/java/org/jruby/ext/openssl/Random.java delete mode 100644 src/java/org/jruby/ext/openssl/Request.java delete mode 100644 src/java/org/jruby/ext/openssl/SSL.java delete mode 100644 src/java/org/jruby/ext/openssl/SSLContext.java delete mode 100644 src/java/org/jruby/ext/openssl/SSLSocket.java delete mode 100644 src/java/org/jruby/ext/openssl/SimpleSecretKey.java delete mode 100644 src/java/org/jruby/ext/openssl/Utils.java delete mode 100644 src/java/org/jruby/ext/openssl/X509.java delete mode 100644 src/java/org/jruby/ext/openssl/X509CRL.java delete mode 100644 src/java/org/jruby/ext/openssl/X509Cert.java delete mode 100644 src/java/org/jruby/ext/openssl/X509Extensions.java delete mode 100644 src/java/org/jruby/ext/openssl/X509Name.java delete mode 100644 src/java/org/jruby/ext/openssl/X509Revoked.java delete mode 100644 src/java/org/jruby/ext/openssl/X509Store.java delete mode 100644 src/java/org/jruby/ext/openssl/X509StoreCtx.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/ASN1Registry.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Attribute.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/BIO.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/BIOFilter.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Base64.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Base64BIOFilter.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/CipherBIOFilter.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/CipherSpec.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Digest.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/EVP.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/EncContent.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Encrypt.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Envelope.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/IssuerAndSerial.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/MemBIO.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/MessageDigestBIOFilter.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Mime.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/MimeHeader.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/MimeParam.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/NotVerifiedPKCS7Exception.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/NullSinkBIO.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7Data.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataData.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataDigest.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataEncrypted.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataEnveloped.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataSigned.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7DataSignedAndEnveloped.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKCS7Exception.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/PKey.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/RecipInfo.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/SMIME.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/SignEnvelope.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/Signed.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java delete mode 100644 src/java/org/jruby/ext/openssl/impl/TypeDiscriminating.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/CRL.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Certificate.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/CertificateFile.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/CertificateHashDir.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function0.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function1.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function2.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function3.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function4.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Function5.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Lookup.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/LookupMethod.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Name.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/PKey.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/PolicyTree.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Purpose.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Store.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/StoreContext.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/Trust.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/VerifyParameter.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/X509Aux.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/X509Error.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/X509Object.java delete mode 100644 src/java/org/jruby/ext/openssl/x509store/X509Utils.java delete mode 100644 test/1.8/ssl_server.rb delete mode 100644 test/1.8/test_asn1.rb delete mode 100644 test/1.8/test_cipher.rb delete mode 100644 test/1.8/test_config.rb delete mode 100644 test/1.8/test_digest.rb delete mode 100644 test/1.8/test_ec.rb delete mode 100644 test/1.8/test_hmac.rb delete mode 100644 test/1.8/test_ns_spki.rb delete mode 100644 test/1.8/test_pair.rb delete mode 100644 test/1.8/test_pkcs7.rb delete mode 100644 test/1.8/test_pkey_rsa.rb delete mode 100644 test/1.8/test_ssl.rb delete mode 100644 test/1.8/test_x509cert.rb delete mode 100644 test/1.8/test_x509crl.rb delete mode 100644 test/1.8/test_x509ext.rb delete mode 100644 test/1.8/test_x509name.rb delete mode 100644 test/1.8/test_x509req.rb delete mode 100644 test/1.8/test_x509store.rb delete mode 100644 test/1.8/utils.rb delete mode 100644 test/1.9/ssl_server.rb delete mode 100644 test/1.9/test_asn1.rb delete mode 100644 test/1.9/test_bn.rb delete mode 100644 test/1.9/test_buffering.rb delete mode 100644 test/1.9/test_cipher.rb delete mode 100644 test/1.9/test_config.rb delete mode 100644 test/1.9/test_digest.rb delete mode 100644 test/1.9/test_engine.rb delete mode 100644 test/1.9/test_hmac.rb delete mode 100644 test/1.9/test_ns_spki.rb delete mode 100644 test/1.9/test_ocsp.rb delete mode 100644 test/1.9/test_pair.rb delete mode 100644 test/1.9/test_pkcs12.rb delete mode 100644 test/1.9/test_pkcs7.rb delete mode 100644 test/1.9/test_pkey_dh.rb delete mode 100644 test/1.9/test_pkey_dsa.rb delete mode 100644 test/1.9/test_pkey_ec.rb delete mode 100644 test/1.9/test_pkey_rsa.rb delete mode 100644 test/1.9/test_ssl.rb delete mode 100644 test/1.9/test_ssl_session.rb delete mode 100644 test/1.9/test_x509cert.rb delete mode 100644 test/1.9/test_x509crl.rb delete mode 100644 test/1.9/test_x509ext.rb delete mode 100644 test/1.9/test_x509name.rb delete mode 100644 test/1.9/test_x509req.rb delete mode 100644 test/1.9/test_x509store.rb delete mode 100644 test/1.9/utils.rb delete mode 100644 test/cert_with_ec_pk.cer delete mode 100644 test/fixture/ca-bundle.crt delete mode 120000 test/fixture/ca_path/72fa7371.0 delete mode 100644 test/fixture/ca_path/verisign.pem delete mode 100644 test/fixture/cacert.pem delete mode 100644 test/fixture/cert_localhost.pem delete mode 100644 test/fixture/common.pem delete mode 100644 test/fixture/ids_in_subject_rdn_set.pem delete mode 100644 test/fixture/imaps/cacert.pem delete mode 100644 test/fixture/imaps/server.crt delete mode 100644 test/fixture/imaps/server.key delete mode 100644 test/fixture/key_then_cert.pem delete mode 100644 test/fixture/keypair.pem delete mode 100644 test/fixture/localhost_keypair.pem delete mode 100644 test/fixture/max.pem delete mode 120000 test/fixture/purpose/b70a5bc1.0 delete mode 100644 test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234 delete mode 100644 test/fixture/purpose/ca/ca_config.rb delete mode 100644 test/fixture/purpose/ca/cacert.pem delete mode 100644 test/fixture/purpose/ca/newcerts/2_cert.pem delete mode 100644 test/fixture/purpose/ca/newcerts/3_cert.pem delete mode 100644 test/fixture/purpose/ca/newcerts/4_cert.pem delete mode 100644 test/fixture/purpose/ca/private/cakeypair.pem delete mode 100644 test/fixture/purpose/ca/serial delete mode 100644 test/fixture/purpose/cacert.pem delete mode 100755 test/fixture/purpose/scripts/gen_cert.rb delete mode 100755 test/fixture/purpose/scripts/gen_csr.rb delete mode 100755 test/fixture/purpose/scripts/init_ca.rb delete mode 100644 test/fixture/purpose/sslclient.pem delete mode 100644 test/fixture/purpose/sslclient/csr.pem delete mode 100644 test/fixture/purpose/sslclient/keypair.pem delete mode 100644 test/fixture/purpose/sslclient/sslclient.pem delete mode 100644 test/fixture/purpose/sslserver.pem delete mode 100644 test/fixture/purpose/sslserver/csr.pem delete mode 100644 test/fixture/purpose/sslserver/keypair.pem delete mode 100644 test/fixture/purpose/sslserver/sslserver.pem delete mode 100644 test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem delete mode 100644 test/fixture/selfcert.pem delete mode 100644 test/fixture/verisign.pem delete mode 100644 test/fixture/verisign_c3.pem delete mode 100644 test/java/pkcs7_mime_enveloped.message delete mode 100644 test/java/pkcs7_mime_signed.message delete mode 100644 test/java/pkcs7_multipart_signed.message delete mode 100644 test/java/test_java_attribute.rb delete mode 100644 test/java/test_java_bio.rb delete mode 100644 test/java/test_java_mime.rb delete mode 100644 test/java/test_java_pkcs7.rb delete mode 100644 test/java/test_java_smime.rb delete mode 100755 test/ref/a.out delete mode 100755 test/ref/compile.rb delete mode 100755 test/ref/pkcs1 delete mode 100644 test/ref/pkcs1.c delete mode 100644 test/ruby/envutil.rb delete mode 100644 test/ruby/ut_eof.rb delete mode 100644 test/test_all.rb delete mode 100644 test/test_certificate.rb delete mode 100644 test/test_cipher.rb delete mode 100644 test/test_imaps.rb delete mode 100644 test/test_integration.rb delete mode 100644 test/test_java.rb delete mode 100644 test/test_openssl.rb delete mode 100644 test/test_parse_certificate.rb delete mode 100644 test/test_pkcs7.rb delete mode 100644 test/test_pkey_dsa.rb delete mode 100644 test/test_pkey_rsa.rb delete mode 100644 test/test_ssl.rb delete mode 100644 test/test_x509store.rb delete mode 100644 test/ut_eof.rb diff --git a/History.txt b/History.txt deleted file mode 100644 index 8962405..0000000 --- a/History.txt +++ /dev/null @@ -1,218 +0,0 @@ -== 0.7.7 - -This release includes bug fixes. - - - JRUBY-6622: Support loading encrypted RSA key with PBES2 - - JRUBY-4326: Confusing (and late) OpenSSL error message - - JRUBY-6579: Avoid ClassCastException for public key loading - - JRUBY-6515: sending UTF-8 data over SSL can hang with openssl - - Update tests to sync with CRuby ruby_1_9_3 - -== 0.7.6 - -This release includes initial implementation of PKCS12 by Owen Ou. - - - JRUBY-5066: Implement OpenSSL::PKCS12 (only for simple case) - - JRUBY-6385: Assertion failure with -J-ea - -== 0.7.5 - -This release improved 1.9 mode support with help of -Duncan Mak . Now jruby-ossl gem includes both 1.8 and 1.9 -libraries and part of features should work fine on 1.9 mode, too. - -- JRUBY-6270: Wrong keyUsage check for SSL server -- JRUBY-6260: OpenSSL::ASN1::Integer#value incompatibility -- JRUBY-6044: Improve Ecrypted RSA/DSA pem support -- JRUBY-5972: Allow to load/dump empty PKCS7 data -- JRUBY-5834: Fix X509Name handling; X509Name RDN can include multiple elements -- JRUBY-5362: Improved 1.9 support -- JRUBY-4992: Warn if loaded by non JRuby interpreter - -== 0.7.4 - -- JRUBY-5519: Avoid String encoding dependency in DER loading. PEM loading - failed on JRuby 1.6.x. Fixed. -- JRUBY-5510: Add debug information to released jar -- JRUBY-5478: Update bouncycastle jars to the latest version. (1.46) - -== 0.7.3 - -- JRUBY-5200: Net::IMAP + SSL(imaps) login could hang. Fixed. -- JRUBY-5253: Allow to load the certificate file which includes private - key for activemarchant compatibility. -- JRUBY-5267: Added SSL socket error-checks to avoid busy loop under an - unknown condition. -- JRUBY-5316: Improvements for J9's IBMJCE support. Now all testcases - pass on J9 JDK 6. - -== 0.7.2 - -- JRUBY-5126: Ignore Cipher#reset and Cipher#iv= when it's a stream - cipher (Net::SSH compatibility) -- JRUBY-5125: let Cipher#name for 'rc4' to be 'RC4' (Net::SSH - compatibility) -- JRUBY-5096: Fixed inconsistent Certificate verification behavior -- JRUBY-5060: Avoid NPE from to_pem for empty X509 Objects -- JRUBY-5059: SSLSocket ignores Timeout (Fixed) -- JRUBY-4965: implemented OpenSSL::Config -- JRUBY-5023: make Certificate#signature_algorithm return correct algo - name; "sha1WithRSAEncryption" instead of "SHA1" -- JRUBY-5024: let HMAC.new accept a String as a digest name -- JRUBY-5018: SSLSocket holds selectors, keys, preventing quick - cleanup of resources when dereferenced - -== 0.7.1 - -- NOTE: Now BouncyCastle jars has moved out to its own gem - "bouncy-castle-java" (http://rubygems.org/gems/bouncy-castle-java). - You don't need to care about it because "jruby-openssl" gem depends - on it from now on. - -=== SSL bugfix - -- JRUBY-4826 net/https client possibly raises "rbuf_fill': End of file - reached (EOFError)" for HTTP chunked read. - -=== Misc - -- JRUBY-4900: Set proper String to OpenSSL::OPENSSL_VERSION. Make sure - it's not an OpenSSL artifact: "OpenSSL 0.9.8b 04 May 2006 - (JRuby-OpenSSL fake)" -> "jruby-ossl 0.7.1" -- JRUBY-4975: Moving BouncyCastle jars out to its own gem. - -== 0.7 - -- Follow MRI 1.8.7 openssl API changes -- Fixes so that jruby-openssl can run on appengine -- Many bug and compatibility fixes, see below. -- This is the last release that will be compatible with JRuby 1.4.x. -- Compatibility issues --- JRUBY-4342: Follow ruby-openssl of CRuby 1.8.7. --- JRUBY-4346: Sync tests with tests for ruby-openssl of CRuby 1.8.7. --- JRUBY-4444: OpenSSL crash running RubyGems tests --- JRUBY-4075: Net::SSH gives OpenSSL::Cipher::CipherError "No message - available" --- JRUBY-4076: Net::SSH padding error using 3des-cbc on Solaris --- JRUBY-4541: jruby-openssl doesn't load on App Engine. --- JRUBY-4077: Net::SSH "all authorization methods failed" Solaris -> Solaris --- JRUBY-4535: Issues with the BouncyCastle provider --- JRUBY-4510: JRuby-OpenSSL crashes when JCE fails a initialise bcprov --- JRUBY-4343: Update BouncyCastle jar to upstream version; jdk14-139 -> - jdk15-144 -- Cipher issues --- JRUBY-4012: Initialization vector length handled differently than in MRI - (longer IV sequence are trimmed to fit the required) --- JRUBY-4473: Implemented DSA key generation --- JRUBY-4472: Cipher does not support RC4 and CAST --- JRUBY-4577: InvalidParameterException 'Wrong keysize: must be equal to 112 or - 168' for DES3 + SunJCE -- SSL and X.509(PKIX) issues --- JRUBY-4384: TCP socket connection causes busy loop of SSL server --- JRUBY-4370: Implement SSLContext#ciphers --- JRUBY-4688: SSLContext#ciphers does not accept 'DEFAULT' --- JRUBY-4357: SSLContext#{setup,ssl_version=} are not implemented --- JRUBY-4397: SSLContext#extra_chain_cert and SSLContext#client_ca --- JRUBY-4684: SSLContext#verify_depth is ignored --- JRUBY-4398: SSLContext#options does not affect to SSL sessions --- JRUBY-4360: Implement SSLSocket#verify_result and dependents --- JRUBY-3829: SSLSocket#read should clear given buffer before concatenating - (ByteBuffer.java:328:in `allocate': java.lang.IllegalArgumentException when - returning SOAP queries over a certain size) --- JRUBY-4686: SSLSocket can drop last chunk of data just before inbound channel - close --- JRUBY-4369: X509Store#verify_callback is not called --- JRUBY-4409: OpenSSL::X509::Store#add_file corrupts when it includes - certificates which have the same subject (problem with - ruby-openid-apps-discovery (github jruby-openssl issue #2)) --- JRUBY-4333: PKCS#8 formatted privkey read --- JRUBY-4454: Loading Key file as a Certificate causes NPE --- JRUBY-4455: calling X509::Certificate#sign for the Certificate initialized - from PEM causes IllegalStateException -- PKCS#7 issues --- JRUBY-4379: PKCS7#sign failed for DES3 cipher algorithm --- JRUBY-4428: Allow to use DES-EDE3-CBC in PKCS#7 w/o the Policy Files (rake - test doesn't finish on JDK5 w/o policy files update) -- Misc --- JRUBY-4574: jruby-openssl deprecation warning cleanup --- JRUBY-4591: jruby-1.4 support - -== 0.6 - -- This is a recommended upgrade to jruby-openssl. A security problem - involving peer certificate verification was found where failed - verification silently did nothing, making affected applications - vulnerable to attackers. Attackers could lead a client application - to believe that a secure connection to a rogue SSL server is - legitimate. Attackers could also penetrate client-validated SSL - server applications with a dummy certificate. Your application would - be vulnerable if you're using the 'net/https' library with - OpenSSL::SSL::VERIFY_PEER mode and any version of jruby-openssl - prior to 0.6. Thanks to NaHi (NAKAMURA Hiroshi) for finding the - problem and providing the fix. See - http://www.jruby.org/2009/12/07/vulnerability-in-jruby-openssl.html - for details. -- This release addresses CVE-2009-4123 which was reserved for the - above vulnerability. -- Many fixes from NaHi, including issues related to certificate - verification and certificate store purpose verification. - - implement OpenSSL::X509::Store#set_default_paths - - MRI compat. fix: OpenSSL::X509::Store#add_file - - Fix nsCertType handling. - - Fix Cipher#key_len for DES-EDE3: 16 should be 24. - - Modified test expectations around Cipher#final. -- Public keys are lazily instantiated when the - X509::Certificate#public_key method is called (Dave Garcia) - -== 0.5.2 - -* Multiple bugs fixed: -** JRUBY-3895 Could not verify server signature with net-ssh against Cygwin -** JRUBY-3864 jruby-openssl depends on Base64Coder from JvYAMLb -** JRUBY-3790 JRuby-OpenSSL test_post_connection_check is not passing -** JRUBY-3767 OpenSSL ssl implementation doesn't support client auth -** JRUBY-3673 jRuby-OpenSSL does not properly load certificate authority file - -== 0.5.1 - -* Multiple fixes by Brice Figureau to get net/ssh working. Requires JRuby 1.3.1 - to be 100% -* Fix by Frederic Jean for a character-decoding issue for some certificates - -== 0.5 - -* Fixed JRUBY-3614: Unsupported HMAC algorithm (HMACSHA-256) -* Fixed JRUBY-3570: ActiveMerchant's AuthorizeNet Gateway throws OpenSSL Cert - Validation Error, when there should be no error -* Fixed JRUBY-3557 Class cast exception in PKeyRSA.java -* Fixed JRUBY-3468 X.509 certificates: subjectKeyIdentifier corrupted -* Fixed JRUBY-3285 Unsupported HMAC algorithm (HMACSHA1) error when generating - digest -* Misc code cleanup - -== 0.2 - -- Enable remaining tests; fix a nil string issue in SSLSocket.sysread - (JRUBY-1888) -- Fix socket buffering issue by setting socket IO sync = true -- Fix bad file descriptor issue caused by unnecessary close (JRUBY-2152) -- Fix AES key length (JRUBY-2187) -- Fix cipher initialization (JRUBY-1100) -- Now, only compatible with JRuby 1.1 - -== 0.1.1 - -- Fixed blocker issue preventing HTTPS/SSL from working (JRUBY-1222) - -== 0.1 - -- PLEASE NOTE: This release is not compatible with JRuby releases earlier than - 1.0.3 or 1.1b2. If you must use JRuby 1.0.2 or earlier, please install the - 0.6 release. -- Release coincides with JRuby 1.0.3 and JRuby 1.1b2 releases -- Simultaneous support for JRuby trunk and 1.0 branch -- Start of support for OpenSSL::BN - -== 0.0.5 and prior - -- Initial versions with maintenance updates diff --git a/License.txt b/License.txt deleted file mode 100644 index e013639..0000000 --- a/License.txt +++ /dev/null @@ -1,30 +0,0 @@ -JRuby-OpenSSL is distributed under the same license as JRuby (http://www.jruby.org/). - -Version: CPL 1.0/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Common Public -License Version 1.0 (the "License"); you may not use this file -except in compliance with the License. You may obtain a copy of -the License at http://www.eclipse.org/legal/cpl-v10.html - -Software distributed under the License is distributed on an "AS -IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -implied. See the License for the specific language governing -rights and limitations under the License. - -Copyright (C) 2007 Ola Bini - -Alternatively, the contents of this file may be used under the terms of -either of the GNU General Public License Version 2 or later (the "GPL"), -or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the CPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the CPL, the GPL or the LGPL. - -JRuby-OpenSSL includes software by the Legion of the Bouncy Castle -(http://bouncycastle.org/license.html). diff --git a/README.md b/README.md new file mode 100644 index 0000000..b68d6fd --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +This repository is now defunct. Builds of jruby-openssl are done from +the JRuby repository under the gems/jruby-openssl directory. See +https://jira.codehaus.org/browse/JRUBY-6973 diff --git a/README.txt b/README.txt deleted file mode 100644 index 9af9dd2..0000000 --- a/README.txt +++ /dev/null @@ -1,13 +0,0 @@ -= JRuby-OpenSSL - -* https://github.com/jruby/jruby-ossl - -== DESCRIPTION: - -JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library. - -Please report bugs and incompatibilities (preferably with testcases) to either the JRuby -mailing list [1] or the JRuby bug tracker [2]. - -[1]: http://xircles.codehaus.org/projects/jruby/lists -[2]: http://jira.codehaus.org/browse/JRUBY diff --git a/Rakefile b/Rakefile deleted file mode 100644 index 8bc40be..0000000 --- a/Rakefile +++ /dev/null @@ -1,88 +0,0 @@ -require 'rake' -require 'rake/testtask' - -MANIFEST = FileList["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/**/*", "test/**/*"] -BC_JARS = FileList["build_lib/bc*.jar"] - -task :default => [:java_compile, :test] - -def java_classpath_arg # myriad of ways to discover JRuby classpath - begin - cpath = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR) - cpath += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR) - jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR) - rescue => e - end - unless jruby_cpath - jruby_cpath = ENV['JRUBY_PARENT_CLASSPATH'] || ENV['JRUBY_HOME'] && - FileList["#{ENV['JRUBY_HOME']}/lib/*.jar"].join(File::PATH_SEPARATOR) - end - bc_jars = BC_JARS.join(File::PATH_SEPARATOR) - jruby_cpath ? "-cp \"#{jruby_cpath.gsub('\\', '/')}#{File::PATH_SEPARATOR}#{bc_jars}\"" : "-cp \"#{bc_jars}\"" -end - -desc "Compile the native Java code." -task :java_compile do - mkdir_p "pkg/classes" - - File.open("pkg/compile_options", "w") do |f| - f << "-g -target 1.5 -source 1.5 -Xlint:unchecked -Xlint:deprecation -d pkg/classes" - end - - File.open("pkg/compile_classpath", "w") do |f| - f << java_classpath_arg - end - - File.open("pkg/compile_sourcefiles", "w") do |f| - f << FileList['src/java/**/*.java'].join(' ') - end - - sh "javac @pkg/compile_options @pkg/compile_classpath @pkg/compile_sourcefiles" - sh "jar cf lib/shared/jopenssl.jar -C pkg/classes/ ." -end -file "lib/shared/jopenssl.jar" => :java_compile - -task :more_clean do - rm_f FileList['lib/shared/jopenssl.jar'] -end -task :clean => :more_clean - -File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f.puts n } } - -begin - # easiest way to configure ruby_flags for Hoe. - ENV['RUBY_FLAGS'] ||= [ - (RUBY_VERSION >= '1.9.0' ? '--1.9' : '--1.8'), - '-w', - '-Ibuild_lib:lib/shared:lib:test', - '-J-ea', - ENV['RUBY_DEBUG'] - ].compact.join(' ') - require 'hoe' - Hoe.plugin :gemcutter - hoe = Hoe.spec("jruby-openssl") do |p| - load File.dirname(__FILE__) + "/lib/shared/jopenssl/version.rb" - p.version = Jopenssl::Version::VERSION - p.rubyforge_name = "jruby-extras" - p.urls = ["https://github.com/jruby/jruby-ossl"] - p.author = "Ola Bini and JRuby contributors" - p.email = "ola.bini@gmail.com" - p.summary = "OpenSSL add-on for JRuby" - p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n") - p.description = p.paragraphs_of('README.txt', 3...4).join("\n\n") - p.test_globs = ENV["TEST"] || ["test/test_all.rb"] - p.extra_deps << ['bouncy-castle-java', '>= 1.5.0146.1'] - end - hoe.spec.dependencies.delete_if { |dep| dep.name == "hoe" } - # Either lib/1.8 or lib/1.9 is added to $LOAD_PATH dynamically. - hoe.spec.require_paths = ['lib/shared'] - - task :gemspec do - File.open("#{hoe.name}.gemspec", "w") {|f| f << hoe.spec.to_ruby } - end - task :package => :gemspec -rescue LoadError - puts "You really need Hoe installed to be able to package this gem" -rescue => e - puts "ignoring error while loading hoe: #{e.to_s}" -end diff --git a/TODO-1_9-support.txt b/TODO-1_9-support.txt deleted file mode 100644 index 4de291a..0000000 --- a/TODO-1_9-support.txt +++ /dev/null @@ -1,23 +0,0 @@ -TODO for 1.9 support - -* Implement some mehotds properly - * ASN1 (fix lots of failing tests) - * OpenSSL::ASN1::ObjectId.new for SHA-2 ids such as SHA224 - * X509Name#cmp - * ASN.1 handling - -* Implement some methods - * PKey.read - * PKey::DH#public_key - * SSLSocket#sysread_nonblock - * SSLSocket#syswrite_nonblock - * OCSP - * config file - * SSLSocket#client_ca - can we get CertificateRequest* in ServerHello? - * SSL::Session - can we? - * @crlDisPts of tX509Extension - -* Fixes needed for JRuby - * Implement BasicSocket#connect_address for test_pair.rb - * Stop Socket#accept by Socket#shutdown, not by Socket#close - * busy loop for SSLSocket#read_nonblock (and revert net/protocol.rb) diff --git a/build.properties.SAMPLE b/build.properties.SAMPLE deleted file mode 100644 index 0748537..0000000 --- a/build.properties.SAMPLE +++ /dev/null @@ -1,7 +0,0 @@ -version.target=1.5 -version.source=1.5 -# jruby.home=/path/to/a/jruby/install -# jruby.jar=${jruby.home}/lib/jruby.jar -# set this to an alternate location to compile against a different jruby.jar -jruby.jar=lib/jruby.jar - diff --git a/build.xml b/build.xml deleted file mode 100644 index 67079b7..0000000 --- a/build.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build_lib/bcmail-jdk15-146.jar b/build_lib/bcmail-jdk15-146.jar deleted file mode 100644 index de560b5157b868ab5a656d21c1f2805be491637e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 487135 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

Ye7SupVLC{?Q$P%2~cv8~v z8{(zIcbAV%i+o%ZrZL49RX)F*9E`mzgB!3AoRCs>kTLS;@UQ%&?p0karW?T_F+dYk z2aWeG$znc+Ez9T9p!&{-=_ze?TqK=)Dl*xqQJb{eBehKVgiUa_^t##o=PCrhHMH9bF_+558?vEfh7j~KEY0Tcq$E7elNS^FY2iGR@0(5re`HIbh z%~CffnSPM6;5feY_CU$C9v)&Sog#f5LVN&@VmH5Bq6}ElF#7Ca?7@@D-C7Dg3H2VC zf~>!kq_~U&HkbET`DTqfzVO=4fTHpk9Ngakdk#R+dcJe<6r*AT3y-%1Px5CK-cSp4QJ;B)PG?(f zmj;~~mwS=nI?F?= zdr-hrPH~WOL`CtR4weUpgdnF_vf|oY@Kb!fcDEUQ68A<#REKd~{*%l4uLHk8xBId> zmn-dzS*0ZbF^ruTYd;%~0k%_loZ2(dcZKLx*xYgE3yNOE*A2+%+tYsi^!>g4W{J1C zI&!(Z#TMb8j%YrPH$O z>kGSCQaMetjIStS#-5E^04k z%qxTbUr$)yOtEt`U-~Yg(&DAQqie*RuaFm$#nQov&>jLWk@4x?xDqXX7oqv+U{f}b*TKors z{_%gLCjAE++GSP^RqZC#KMtw=umAg4;=lh99*!s;X?Yznak$PGyQ?Rj!W?Vd%T2<6 z{}*Q_?!W($l|E=?O==IeS=F%%+HP5cSKGYWE_k#}4P6kFc-m*Nkay zqzk#dUVO&&X#|hM{dhHO-!irbHhL-N{?}XRb6=?2XQ3C`x3!Z^_*CL5TwdWrC6<)5 zqec|i*F$$+^jjvbrX*&$TbgxN{<1nMOKUf+ZwGi2>y~_(wc$wYN@`RO!DwsosopWc2v@5?iyh&a9te@alIr+#(udEcA0oTzm~hMh9q%sn_??w z+_)RpE{FW~&3A74_O0%#c=#PM1f;)b1Eeo}!HD}4z2MFY63zO6oV=-zho`gXtW zE53>TQvthfY`COJ;WO%PAbu3wt%qbjw0y0A?|Xh1yLaRKiNbBXKG#ZD3%34A9d~|Q zt~Zn{R)wd}J6fJ$*VNlt-i~nM{CXMKcAO5;8{3bdK*dW(yin-6QK#?hZ4=*DLZ_`8 z-_Fz7n6){vB)K2>EWe^h{CdIz{d!Zl7Lodl#^@Qxb-xuqMEtlApR4+dN~)hfJl~G% z)wQXOBy!h`qW?(Gi^E}Lu%$tZ0`41(GXI$8N zx+b01`e@QOZ(r)p=&WLCrYEJ-H;3suZzgx*)-u$vg}kdyU{`)cpMgSHFwyd~G?Uko zGP}w_(QUKnc6jv-BUBGXIK@dMOs(@Z9+DL5;rEt`ZKiVQit*5zdI5jRMg9+ zaJT)|MPrhK7mZc`E;?zzpM#(`Gxy=;pD5pu;H{u|C5vL*9?%&gNZQ_r7c1eV*Z6t& zZp&g#n=)g&iSJ+KL*(uAA0X?deD5dt!~~$4Om0A?g&~a3F{?tBU_DkI)i#rR`u-I@ zbpE#V+qaqUkrx9IR9c`h`Lf6l*K8#*N5R;f5n(+;%*OT1Cazyfi9viJbiv?4qOS@k zpV`S{6Rolmf9(Jt8SFzsFQNe+dd680cLU53~h> z%YA@XE4HQ3<%KzDV6vOu$sbpZ%96ai$$5%v-hbgP*mYip14xPE=O$)xESD0;!@~>i z@BOwS!Pk5JNBDKSqV4Smw@X6zxBvVJiEm%#k#J9EX@qy3;k;YUgt}Kak%oc8`^h z&)zlht_1&a+<)ce-JsT?`}^0}igHdm+j_?UaObQYSt=a_L=^&m35>o#&S@;v_7Xkr zPbX;<(*w+est(B!PaJlO$#ed60&jmkyrZzkK1PC4!f#Y<+xOj(RV-O0fDq!qVqQ4; zwdHfF1r_D8Mf6a=sDwY_ z2a}tGq`Xs*ra`+b+U}mVZTGZo+qP}nwr$(C?fzQR=Cp0=%)fTTIT3sBwQkO3z46o= z6?sulW>sa@^q-b&X1`2(pnQzM=FTj-`&*p|7gCtvy$ePmn|b$2Ih@*X!3dDX7g6-C z`r7i_eV02Y-caYLjhHBQZN6U$`K|t{1UFB0Zq&}>5=y52goft#j0-1r^FX?JLu)oJ z^>fMUxpAsUYY>&5Gxqg6V(T-=9Y6M_t)DJ4kr(PAzD)f!m13=d@n!_*?AI^4#USz@ zfDD8jR<#tK*Ar)pK>2qs5TLvi^j#7wlgC*j%?-8rAzLv`<0rVjHZ#=?D^+a^0!!xX z4!W7b(3a8tkzd>yZaw;onJO3 zDym^J(`rX!CHsUDaHSZJPOmVtKCsUlwvWP$I!yF2IdeJzW#Hlo#Mp!wx1HA2v*6E? z^!?15`_$G)34MZ5F{x@tb&xceU%Ot)gxzjr;&?+`oB<@knULva;IDY}f%d7vWHo6I ztxZ0Ip;`6SI^U(M>_i_#*-v2D5hzPv%>e8W88V_k>oR5=_>(hV?i+P$ z4LmejzWqK)=Uf-cr^N?P$E;>==Q)Ca&#w)cyF6~Qa`r~G2&Kuo7y%PyN-@I|R*Iiv zT2ad{exvBv}MU%gcI%?x2M}&dN;P>yPtDm7c?-3(;9{Xj2@R)Na}*0NsNm_E_1=r3IIXzj?i}Kf;b%h8D%L3z5@MFpC^~3c7CgwWS{iD{U@#>Iq3e+lrb|-d zJ5twfnu`S2BmH`NztP+CFgI!}v+bTPmO)jV=1IPuUSBaj#M%nwW0n71oR%g&!{GSKwY#qa zjcY=z##hN&weEXj^Kviw5GGcC5>%^y{hl9oUnnzwPOp%sxA`Y+dh(CcuW%;lZ5#E6 zCV_oJC-2|))ptC5BMRl%rpLgwR4PBFs!Im~dM%}}rB*QEX ztJM3jB7+S*ySklD`PXojFB zxTqfCpwCQ^285rd3UBk4y980OMiSj)H0t?R6R3(mQFn5<<55?Z=)PIMJ_?a}@b zTb9`^`$qo*Qr&ofvN2mApkD@r-(1(tN?Y&*0@pxR#{?(zLD+&ZD9RO?OzwDRtJzxkTTd@Nb(^mvR3+c=jfSGWQ*U-YJvQ0vZyMeb zjFCPU3XYMzSlwIoxy-TyP5iI1dli*HBwBBuxF9g7c~Mb0XN&&jpH$7`TwcCz-Oh78 zY9D>mjQ93ppTPwJ<5hXejwoDpduTh=XFLA57$y2+Q{IuyvYq88lGl7Ud=nCQT`R$c zp7!A*hp|z3HC#_g8Sy%MO7cg2^$GMH_^S)rJ;78`8zTS=9(lfXN0Iz;L#GsOu@O&Cp(2}elHm5JSG)yv(pqQc*OD{`kl0e z=v1HC*}iHDyw4?`@s>B2tu>pwURTV2Wctdxb9}YJQ&sf@N3_3xw=I6;`#}5pvg8## z^Ag5q7*U#&^-mJURx*<=!Uy4_H~F(4H9027QG>!9Ip^W;i_r~C0a`MxCo7r9bdh%v zq^$!58XEw(`!RwO+I2eaSrl~B4TwPSG1rTD=jN{O=y12ZFyYPpDIwGcdQ?Dcp;2y& z9e{~z5_yK!)T14oeL;REaFmeg+R?045n~RXJ6A?4sV+r~j{L~K3_dM7|MyNVy3rj(sD>l2Ewh8Oj+G4ltu|q9a^nl65MRCC@U4;0)H>EpfH@#kQ4CN8!XV62 zjx35_cJG1%YWq?}rOMH6*^vev161#ut7%=2LS(;iOj`$c#U1#&OZA(h6f35v>qQXj zkcOgdC@6hnWh7fDXBtjl&k^7C4i_R%6NJ`l=I@;fv!FKpwL`#j>^V4o>{=n~kO=J;iBFm? zqAJyUvPy{p!>|&E#}*6){|eF zy8ns+t6ig3ZDwOS1~riW-L0F>(>FHxiKEC;t&0>ref%JPFr*{puicjVq$WVz7KhyR zVZFq)YZ|?oD@kc>FQD0B-kUI5FGsM}n(FsKYNHSg|I%D z+9y=MZNSGNIK1Usj3Poi8mZs-9uAyQRzU-LHT5!zgzFn;GA{oQU%qRUKFs1x)Js*w zf(Z{&EYRfD(t(t9^*rf7ZI}xco8-^86L=5~a_sg!q{Gl||HAipczh;S7G%PqnSrNb zAnONavnY;`HyO*xbKvJ9#KY*)*Ax){NGS}-)(O6=A+5YosYoLDFYSxreXiVqpOMh| zC=z1*jVUx2O?^nOI9tY3{TNH@Dd`%*+3=NkhCIGTT z{yVYX{O))|Kh8gojDbYZv~Go764U{Hky>4q2rxehiEq-I&rL7az>yg_bIX;TnArz% zb4~Ewfg!|tuPZL&H$4L%C>GmpFKBsV#S!5n(fue|ni%&WVAF=yN!CxUpnHJlWh%I9 zuCQg1N>eHF2(>-nKIB3osg(C1+ixYT`+qJHpDV+jLjw##i}AVmDK0`fT!MghYbJZ{ zeo!m|lFW;^?GWjmG(|BEvn?dXImat9Pw_cPs!t?3o@3t)s>l!8FIF|bUT_|@&z_9S>>xJ+d!A}UcA+YuXr5Bn+y#bH z>DTY%n;(I1@sm}*IBRLBk3L)Wu-o+!q)MW7@C@shn*0A8%4PFST+U{6Xf<7@dq)y? znT)b@$T3EHLf;d^G+s&JD-VSx1;= z!Af>MC2$k#96FugH{I%?^p3;F|1$`qgT$@Pqj5kKtS<{BaK>8NTc_r|G;F)pJvS-) z#bw~Wc?8D#S81wESYBb<7V?WUKBaVPPFeoXv-cm+e$LtP^{K%%WVmh(?Zyzo`3Zw2 zH(6TtsftdCFTKGnOF1ehl4KQ{FupM5ZXfPl)Xkw{m}<_P`1r$|Dh+jk**9f8p=ZzMkZ;8!j-%h zBe+cy9%H?Ut=FTrLizVTLd%=sQIIQnO-Wofb7@lvro!5#7VWp&B(P9RH23aFwfy4XJ)6_@prF^$-q~0ToD2e2zb|KWq1L7dVSstF ziRdSQQbvrPJyIZJE8=^Hj4-CHpHEe^5e&v(eHtG(2)A86RIv+)^-g^j}TB7?!-M(aAWF2~{>9$y@stSV1q3kN_>maRQ^5mtjOQ+_jD`(&X zP>P8U>D+j7IBLM{UexzHs0Yq$o?Uo%jJ;aO)CoI*E>C^-|3bA5wDMdotj%s&Qoq^S zzpF)X1ZrHcs)2C>krfvqRC~Fej=Q2UP8Rvb_U5Ts$YbK?CV#+8So?IE3|9{#4m@>; z23PmJrj30TVBxRkTx^*B!YJy0U^r|u#_V09^-*wt%z3Y?Z{=KKph0FHa843TW48?! znSP8hRcs;tI_t18gS!?^jtR7gyMO<;%V8G_K#D+=yVBXHpNv z0*T9_OVc!@bCv2y&x+yDHTmsn_suK4Gvb<&ZTdyR`NMIxLX>5_^o~3PO=Yof)=YF! z1`F-^)}_6Nuy_=Cp{E92D{Sd}jZh9(cam9FQ9%wi5_4WwE;$;W6i~4=oHi}fGq63A zFk2UO_S~X#b>bB)o_8`?WwX4!%249kIpB(`G-A&9jA8pyl=b^9kVSD4erqI@?%s_x zG4|HASP;jWLX)B!@l#5G%}`bl%_9e_#Xn0-J!?{xhS?-MT4xDO?}qcB&zyS_dv&^( zv0U}VmD*tjQKCY~*!%;vlTDFI~$L{nm7{UKgu511>h_>4J0p zs2sXkpEyw-+Ha^#4S$6Te-&@;OUc=R+`Pa?B>=dFy#3srz^C2Ke;Wsc;V?|Ly`Q3# zfbs7_m_|PQZ@dv*%-YEb!0HYna*OtlY&@qRQf$mc-XoV@rxU}$$jiLp- z$0>^6%OYU5u2?-_ViSG_*a6O^T6%Z_6%mo;)3NKsj$HQZHSR$i=rUj$1W0jhjQ}G& z+m;+8WLm#?n)~&KlghP;tr}Y^ZQFKa+7-M-M~YK`KFw2*ZSA5n=Ehb<^}D3_ASaBl z@-{+g!i(D4r#gck*3m1V^w(Ef;gOsyE(_!Zqjx=d-lR_j38grg#vfqT3V-7le7QX|wtx zl;io1b^7=Zkc_OR&p&s=eHbr^#_5Wx{b3%wD3)xQld#+vb^hv0=<1@}UBi~404Uf3 z97$EkO-`la9p$BI+5-$LDo%>4^i794>ZYWxo1L-d_1^G?2zBUXU!0`x-JZDlV;*X166DtpHgJoHJ#k{ zR|Mb2^b%3#9xb74g^~Euy)C8vqN+QC`wLCB6J;x=F9>Y+~^`KMa|k{{^HbkFDusa z%vUyWUvtsI4m{97eCP1;Sy`iF%a}~S*`L4-GCt5@^cs#W(RcdJF*M%IBly6yZ!_{m zr#=m`Q5s8(ZPT-a1iyb;2Q8xrPa+pVH_X_ux1aN%atE#?*A7i}NXk(*{4$8lC-9}Y z>1*>A_>Q?k&(XPqs*d2<)g%%EBQ0AOG0lW>u9o!^L$|_Ox#n!$=C`@K!r@^bKM8fw ztsrx&6J(E!Gh82{j@k`+`raHhn1n>R%RiTG|K1eR z@lG~pzal^IlJ?+@^OBQ(d{{@q+NRZk>S){HDl95qgmp2@Z9#eLGV-I-(SHC(Gun{~ zO;K@OYlJ&oL#J2J@RM%#f1>xFv`aEC)r5D4^Uoe+uT`VzwiN(Gn1GXUcPqHosI*VV zb`2j$j)H>8 z6mEf_-=57gIk}k$=@j=_qDLjQg4f&Ak|xqJ^BAuYQh9*~9i^%-Z~5W^a^gbr=N=rN zXT>$)1+O2D$V+`j9&CSg1GtUvfwO({bn)j=WkTh*&m#j(sZu(Q3#}oYNhv@RonrFm zQ(aoW08m-yLGhEuV2D`2w9e|bI5Z4-*kG)<+nEioY4%Qn1Mq}_)M-ttMlB6Rcu?`- zy-*$^{BlmvP6{kev7#Vkbg|cMs1DA;?5ydq;)FLC`r>D5V83>$_~&RT*a$`}Uf zLJP`pn6y-D?BH-tyL$zk0|t}n4G$nOx&t-|FDwgemU>$1%>4^HKW89nxz%4&vR`OL z8|plY+swh&7ynLNL9c+G4`i|2`@cvQNy>HpZT(U(Xf&~|II?4iAT`2Ps0jPX#+#3~ zHpSyHFNRXY-sD>SRKPXN>?S@F%ShMvT)J3yEg-hDlLhdB$ex$26qH^F7uy4BR{=OK zUy7`6pqnz@OJub)V0wYkHe`D41EZBz+r}5J-X6Y|W*D>l-Hp1cQdIqwL5MbTl2l6S zNC7Ip$IHXNc=P<&bZwoE)lqdbzf`g2u!ot&SxF%vjVZ6m5*hf%`}!{~l}RBO58;n0 z%7Fe*u0N<;WL_ynj>9q3@1GrL?Ebw;FIE`E+$N!EMi_}6cBaeyAmf@CZ;|ZdwR$^4 z0S7FOx-?r!$5B03bPf)b#4~a?K<&29q@$Vp=Nu;k3F3;$puhu-W^fE4BC{g?sYoj* z0(6t;L zj|A;{WXj&J=3B&i$Ec|Pc+qn%tKN2nLS~`GddSfjjAU~yQ!Iae;TVIw=javoY}?&< zC46WFBTTsx?IJIW-Z~ej=vQ;4m;8h|BVHGQX+5>TQK3U`oZ%LsRhl(@%Z2)3o40$} zgqc9y{-G zaZ;MhZ)ES-tLVAjJmsgX5GC~2z%MFXehM9kSvZDp5lS?6{NZ-y4}~4K*E2Hy1iV!>hdUpc~R+CrtFlJK!~5`jFCuGKNh-K-+qCdJpmk; zL^qsJzLy=3T-MvW;=Uip!Wz}Uv%*vKMm~meBIOF$0!AeZb>@c+6p80VFAa5FTg*7l z;|@42LHQPysb4ysUYg8I{APRCoHb`fj)UO3e0=w-y_ukCXmvV|6YvkaiOIHxq$^`AFYh4P2ZsL`4$(EM;pt4uRYE2-HVYh zueJ6>{9(Orwg;?vQJm-<8QF%7-!4UtOcfeyZz?j-VQxriYtj!l(o1{W=q}pM9Yy31 zso+AnQjs{`*oh3DmG5?DT2SQX3|2{37f&I(bhdeL3W`fdoE73IKj7G&7PaI(cLA2k z5Yl)6-l_fA5 z;`43qr>-I_vso2|7m|X~0U0~XR*;HUdNH1H!2cfAm*W$A!orKAioj#HS3}{3bMgmT zfDJn&!}TqhzdmMej%yxxfEE;>ak4a$3vQKFiVhRL!)pL)EPozY)778&cvaO}RyjYl zgpoFFNDKoX5|Zf}u+)$E29l4=(Y#fT*Ya6R*KfVE1dI%~;yS?uo?KZmOl8VIzTfZa zKWf6-1IoJAcgN$Rwd*%fNzl8kJwtV#+|0qK4(fsU%TMpQhpAXfyOnTNV{p_dl$21l z1?FG*X!Pta?GZ}*GKc~BZVNj+*4!zagDbz9qCp-diIc-S!R`HFUn}^?^LY9;yIFHY zrQK&;YN=PJ8Z=Nu+`3a4c*SPH`i~`XWmS~=a~!JHv3Dmg-a2Hv0v9MPaGI5=#^e9C+s)8c0zuzzfM~? zfJDY&k9eo&Fd}z+B zlj1e{Y|)AY#z}}iq6Kf@I94+|+rjJv%VwWYb#e;)7xf)>k}+uQi}^7;s*Lm>q!Z>| zUqZqI;<;rraEnzbDEwwT`_OU8nFJra+6R6mSFw4rG=_RnK(U~m-S;2|W2q$#ft zTjZPaBJw}4;}1o`S=P0x0Ux3Ox9Po}=kP-rrjV&7e`CzqN3p3Kr$$gE&cCpB*5emM z_2Uog&j}uO!Oz;SAGH|fD$xVuzSQMc;9FdcITyAwV!spn=x9G$b?u5&?OF}pBd)Kw zgXaZ`;>3em-@|k|={GF&dP{Ec1IqY+mt2orr;ExXlFuc9(o?picS)cc?riSO1fYGm zy1YX8evdmOg%{1kSYT_X2WxK-ImPIy!OI=lHh0ccJLR!!^6oy9#G((b@IpXULv8~Z zagU42-OpTaPEHO;?+)OFa1HUz;5C3ESeIl5F)GJ7-&6F@FZ|sX(dx0-U-?uU9fnshJngQpncIt2 z$MwOqyXtqj40fc77|EgiF8d3(;qaOyqRSUFM-RaQv2Iy0gTx0I&`TG>>j#MPUcjwj z_>3CYFX*1b2vuxb$rk_R(nX{3B9aS~2jCbzi_L#(oL{JW;<&_HsVY@fuQb~Du-n8k zb13w%#B=++OFbu-{H9<@h*F0@z>&m9QjOEks4B<_$k8-pQ@xU$A_^<4b%l_M$7TNo zq@+VkG!$J{D^4low7Z?){2;Dhe#2ima);>9P3pkb@$3!4#8%*pB`t_V_Ov$WTp%6~2Uoe@3!hl|W*u}4O+Uq5tw9vu!wEpm=l3?0(kW_kd23MHO& zj77u?wFvNQexb;ADlAFc%9mHN+rhPp*c(PU=Hn_cpB};w9Y><3O|h~{5^wQe=sg~a zivG2;vz@`M+T2}*_ouvO?E=v&tCC^So;LB~M(om{Rsy2)2bW)4+UMm#1|lYqF>cZx z`Ncc@Go~=)-4@S8hv5vB#w!`wbCp;q55b5Qk0w|1WqNHCME6m_rDTSfS(@GMuYOII zoa!6K5d;#1Q-Bi@2~QBp79~67d(!ti#LLlw>K_SCXF=na<;cH*%7w)|I_>o21HBNG z@wRlm_eQ_(Z;So6(?r)xvdO^cT81xHCHRmJG`=n6K7>Zh`8TNzmhwhm4y^_q&gv~h>5o$l{2jv)$Xq6TIZAUeekbo- za~uVx;6S@5f$p(4$Z1PJ@eb-pDB+VM0qRNUgh=M>sNA}dJ3?{3Wb|l4cCn#tC?ZMf!>QYd7DcG zM*}3Ke&VNJZBNWyDOP+e+Be4`B%{7iok*_dYXTQV5I5rKUz}o=Z<^lR2d1MYHwk|Q zy7K+52hAa3ATVx;(4-y@iAP=oXMeo&*OEo{ST~FTjZvb%s3Zn1zn5uaqZ8(QG0zvW zRr(K>#zSXdLDv`z^1_T(BXkpWQE#HI9YNF0;vPFn6ti5n*`mIq!@#5T5SH8AQ%6c=ZG^JQ#%{?eeZ?~5=>uN; zJyQt=i~mPeo~%6ECt8?-Uy$n14AV-MX?YC}7to9ObKL4{v@+HFuJ`xH(DqKLru1~&E; ze@s0r(~i?b`3Rs%+P2v={~%jGe{ocZFY1qJGxA`5xyUX*yqAPqZxJBCf{Mp9EEt*M zIgj(|=<-5?$Ncp2G2X-fJbLB=ODSVXKZs;MvZWo%K>d(p1hnu{<@v-=N0hivHeVYNVoa5! zmpOuwOjmRBW<7F~tmf?&ZbWF}>w{RtnWZ4v2D(lVnmeF8KQtZfo~roucywJ>AE&k~JZ zu;nsanu`enRpJXor?G!zX*umRAi#eRZVWEYWhC!>*;dBe$}X>yLZ3yIr0z{Ar4tbh zc#LOXtk(B@$~EvuPc6f*Jaj(mL%-gznm}m+&6kPaRnp_4ZFi z%f^D?JIu-MKojmid0k6;>TL{@leF6$g~T!9Pn&Me*t(>mW)uO4?)xoPT{M{9)%7)n z)Z1?$pgLkM=C^Q4b6=M{OUeU}mJ0+b>6!1mu2lfbnq z7j+SEfRY=7>8&@XG(d6eriXWZKZ`@n``n-i9-M^pc=qN~A=X+jTDVwMm{V?;#lQI# zq#>a;#FDQGnSg*eYJq_MdwU7;|7kA~Q5Iyj_^UB7R{7_6;W;-wG1pQMWt=paJdTfC zOib7gRE|x}md}iwN(}WrqW} zCYLiMR5pW(1#@g4(agz>1(gXA$Z;){6BOC`9u3!7>K@J%u0+sCXNY*P)DyZdb5ite zG3*b01^nbQMJ04^=CNm{$3++mlq!MP z%+QeDTpg7P+*}-#(@_r;2Gm#>g#=U?#(0U+QBT;Ia1~^Vb)q;5hXr<-&@KUCQbP4s zQWh`+P@a%irUbsvxtD%OqDIR>iI#R!g3H2e2W^C>S;h>+^(-3`3+sOxjBP3v$`X9( zJwEOAy#LJJdnU|&p@R)Sy2NP%uQKf#@-fcJ5eg6Iv(z zP|+HCKhFe|N*@FK2bE|GTqgWqrY?Tk2$H`I@xDLTqD+fEY5KGKb@_g~XH2q)a7ft{ zEwnEJE?Q9Pt$Tk;Mrb%+iXaah$rZ!SegS_KO>LR8$!@H-oVvoighOT46PEk>cN9Er z*lc>2ztqGrZX)$HJ59ZB_t)sLe!;%%x0%{YA;iGmY`T&y{%8_)3m6Zh%Qp%gVenxa z4Q&FPv7d4@p6A7Cs<=za)DH&#x;kxSr>DxzXzKvJq!(Du4sJ?*i=kaGOY>c8BXJZu zi#~jXE6SfV%bv?cTUWrV${Id4e!K4|M|U=c239r_O;5Iod^A~$#ELD{huOo)n)`FD z_I28K?bUnaW`qlDRM#&O4e|415F}*Moqy^bR^FCJ2+jT(#2|O+1ap{aiE$U$y+=b+P)l&OiT<7&5V#3_CUpYY4}MF{1Nk?0t0Cx z0OQ1C#7+Kb1!|`~#di3qmoVs`ojl!uxtqj59to{X(IJ5vLDHv%^tR;mFFu*aXpNMo zC$WFAB*D`IlbUJ?qH6*TiTq@|!$g%V^rG~f{Oa_LsAS!Y7tENa43Qbt-5*p?W~iJc zZ!)pkvwfpjxLIdMjB9$=Fen); zJ7xbxHggOT4f@7W*t@N}uZ#oy_2p`OG8m*w(`~JqWebLcgCEfMWv5G`JOH{7$2aJz ztKr>lbuwDIZ^Ro0;^u9SKj%sbOKSNvm2{pzbC%X>4fRjkzidRYP~JMzEz-_Hwe)pQ zvayxRO-Gw(eAh#VRHf_f{aqR&+$Tp>osxxoP%$|$Z1-GJSj^U3ILvaF;$yeVt;)6$ zE7;v5^<4jj3OyAuJ=lb2QVT8l)f%K-JR_S-@mw_vr^=cMzLh3h)2;U%BEPDtHGI9` zS$wY??dq>LwrwRQoUGVx!Ujj;z^2WiO``L!vZj#1OpDjt`vvbp=SM`5)k-V{jm#QmFscC7}Pycxdv! znGnJLeYJNor~gkM`M+2E$ENt73L|@0J7Z5{LuVHo)Bm9y{r^^OZ0h9lUvp6Z`5>Wy zWdFBCu>H4l1YKO5ER9@UOojjb!P3mq*wDpP!rsQj)QQg6#?aY0RsEL-jylr!YEsX$ zS29av>;cy=S6v&;CX#VWF}A zFcqCPdie9Wsof$U3iCkO| zCHL@@GS?@S@rI!RS6_OXlj25OzrThAV0$a#ZF4(`z?}svCm&{uT=Xs|*r=59(lFz@ z$mSb8fTW%9Bx51aJ|Z~w?eJQV(s!XT zyLPVUs~c;^zvqLyE8)vrhJ5U(lF5jB9&fdf$Yv=T$A_(Oj4kdT%7aWsA-P1kaU`^? zKvl^0J(Z6WX_-emPqEC!!&ey+wC>W6B=y8OkTUAY{wo~LiXV+xu2v|@TwfheDV`dD z4s*!Wv7r%1x!_Rnq9KvH+^V560KWdGH;udOGo&aUva7{GUqyY`W-vwmT#IxbE1p`p zn>B9Z{<5lbk7#h7<7yZ4kBGcN0D#k)8!`w-w%E7WDrG6+N=GMyN1(D2`$RindCA)} zeT;jh$PhRdT(WoJFeGs!g#!c4WL?{yN@CKzzmSmq!WVelsY+uYEU3m7xH|?t%kDRE zLqQlgOS+g0>Q?OFmT9RTqpca7+4+EeNT$A5AhFGflO-S-O3@qIykRylH-Dm0a;{i|XTG_j5c-rdH|MI)`XQtVP5h*B=j|x~yU?Ox;a#MxlFQPa zq6O#l)08)@me(rbapJwwqrSXENmM1u0;N$jOhC> zy^`L0oElRrDRFpZafa{svE2KYsP3fY7J0XbQ_xzisE@vg*-yGcU&9%FB~SRw6zFIw zeILbyfVU#3Cy0%SvLlJysx+{0Xg$pEyc%R;DGs)@SMM-9-jrc%9htqppZklrBvOaZrnZ(Ac!@1Ti-~TBVKD;{qI|<&OBr+ z4R1b*hJ!un=&EvBH`i3CNuV(6lnXhtGoA(=7gFc`+ko(mHmNJlJMSTqR+Qq5^atP2NTetcv0 zG83I39Fxm2X;YRxQ>K-_M@(6mza5HWuzQroyn3X@u(w9+?f+ubr!_*4dp=`hVeGf^ zc<08L_2`Y^_e2ux{w~J1PhN;mVa(Ft&$>Oj5ui*b|IhcB?pjF7S@%efKm0P=&`HMgu~$k6D-ukW0z2itMZoyHqVdITA_Ab~E*tkfo7M{w zd`Q@M2_(6&@V(6w*UUb@!WjTR64g3qo{3b@)B@IZR+%$aTT8`*IZ*QB6vIT-aP{>)>16$sh{>{8! zIZRChGiwq*tZWZ)xN6=oWiD%pVEIXbv((y_06^BVXUgXijx>{1eqA!+v?`lBc}em0 zBYhr6^-D-iL~1oz(LQOn!mo0*>gS3Dwfy8B-VVta_08(Y8JB-27+IUW?J)Z+XKWj9 zYvUZp##>xR?Q;gP_GRHs-xk3B;RRmcg=@DSgO{dFJf%*1vtT&gyUdB&jTLX|jyYicIfvV&N^`YSqA9rrp!RXXWfI)+XRUTBze1cLPFg|# zWTEMd#g!@IyUZ%oL7}dU--113MX9X`T9BY@#bJN;ZLWz&g=R&DT8$L_ad=G640>F5 z)v?W$5A96V&xn!gfwFJGq^1oUcSpcy!~yQJ@|FNF`Pl^Bkqc@Vy z&aVG2y;0Lv$5BQ74wJ#e3=^`QH)=)KCR7J)L1d&t&JLdkle7KrkH_ylVe*IX*1NwRu z3z$8F&g7sLa0&CU;K`Svh=l?1LLbVs86ucHTx@L3sKTL|tv^5W`>74=Jz!9!u4+6akR}(h6qat-H7?^aCsqDluu;>6 zp>QQ8c$3#wS({{N6Oqg+E|V7l%c;|uUdWXAG2u#!tX@DZb*f^rHo8C8gV$B1Vpj2- zr7=%6FomQT&`d>pjK_u`&^VLvvQnV8vZR%6W%qqv5nr}ujy9A&(Ka0?cV=TSb<^A> zl8ae9u{B9v$WdJJUCHA~m95|#^u3hMRLNPVKxmu=&0kPjX22qj@VaMnuTEst77o%K zN=D90a?lYf4>2d@q24bEIU&tSnkU=${8dhtlQ>UXC@xeVaQ&OTu15NFj5DY1cCd`h zHTfi`67-!Ec zVmc#KtYIP%k#Y;=us2gs$KWmea5t?7Ff(j3?Bh1dTXz&)kr$ysMxI+8_Se#a2-8*4 zt#y`bQJ`O-nmaJHojg9fzu-B=Ey7Y6jaI-jpanmvm+qw$c9)3%a^qiWFsz=kici!YN{{346-a6G`H&9yHvsz#8$j=~8lc;He3_Ri4UC_X zGR-lIWr6piQeg~;2kG!RbXnW6Y!7M}K%yiv#&dIAg1s-dUE0VFc}N>ZX<-i>YqN!& zz2n2*4+i1$wLq#wqAiLi-n6*9@9;N?&l|^lhj-g7Gsh5KvNm}~v>2uHh$#dvP5l{1HUl9My)ul`Fv!>(L z5%^`5C=v(JHoK&Yo96!fB)6zjVBH?E-@^jQc~o7iK`O)__&=K;bDs)q=0E*-^iMbb z_nRNpf2-~OBk4pvj7=R}EbZ<7mz;Br@0A;7Kn(?u$u8zAY!EMFHL?It8qpa=uB}yc zb&o*{CdMkI=eL7YLPZ8bo(dDy$ppfiHuzq1?sg`r=id+j$t_Tbn3qy*a}udIF|LM~ z73zM|zStl2qNcKhc6g|~&!w&)#@XmbWa?r*l^kxVYEkNPCq6t$k6MgC{en#QrzU4_ z^-XA&ieD$N1yir1lVy}E580>uDo?bvv=Lph48mhULDZrhk=Tf6khVB{);dVYjrft9 zVHo{wAbWaycE@7EzSo|N*KbJA?J4>Keha?S9tP0|D}w(%3EHyixw|BgLA&7l%-Hu| zBK=}y!1wAOLN37n6Nc3PBZiXl{|Ab*QlO0gP;}*D{=%wOEwRQBGDi)%h{_%eCG1e> zk~hXA5hh+*&TnrjfTHsOB9Q7Cf!19XO>zdj&4v2-`ul)zj0Gg*U|N4t5ve)xErqz1 z`o2-S-y8;`jzvC9H&c|}^g5}5&GY;RSWlbQFe2%U{ZC)K0TiBgNotaU?4TUk;& z`fhfJbJjj(d@V>h9N`#OJMt01iofy48vQ?{y;GDVYLGSBRb94i+qP}nwkylFZQHhO z+g6v+<*vSUW*+{3?wvXFaNlyRT=^0i*b(2}5wga#net3F`8fge7X+fKqJgqPRW9sU zA6F!wUPhsmYKYcCadT|)!fwRAULyzGt&v6SPv`;^cfF*|$ddv{`F%V>?iujFu)`zN z@AQPD|51v^J7ZPuzwPAqua+eJS4*n8SlT%Mrzh5^zxg4nBK)P3-KejA-mg?5*|uCn zYACnp*i<5jZ=DBWL5Z_%3?8|*lVQ`~QB+jC@BaxZ$|KMnQz*+C{^IlJ=Ip4iaCU1( zln!dqo9nj6gLyB5eQaw-|Lg4&#-H?cDOQZTbbVo@V07b<^+FAf&3uZW!73+6*M>7e zj6Q2UElfpJIXY!nJ2wM@wK5-V#kfwkoJ#qE3;^dEVzaof z;DV7E{X`igPwEvSf#pk6gh^ z99lhss(blTTTmlyVJ$l+5Qnxn#1xWcZry0$X^aAy#2%_1g`J2-1Qejw@ey~9@au~vq zstqZu$eYuU-aJM%^-e^GYp#{MQj;W4SStS+%H!9AvUiat>642W1qgi#M%zSAJPf7s zDsFEbUb?u|HaZo-QlccHJ&NCya&zGt*nVhCJ`O~4R724+Pff4frVRTz$*_^Dthh|S zmm5E$beEil+3`Mk$&<5jb2;md3a*YC11v~AdaW94Pok8sFpr5En7TB%LQ!Jo7D3bX zQ%1g3p;yAl(gPAq}kho`j#(f>NNrtJm7dUI@^w306 zNLW-@mN<1B8(x$L0H8Br3>jAiXnxd~JhH-DyK7G!W5QdzZ_gD6k2~Q}yVIC3M#cPn z;uW-UMNkAv(BTpnLk1a;fNC#|Uj|*Eo(iZ&YT# zO>0pII9JpV9q9~zSYyp_P-9YD@4%%E+Dbp)Z%w_IP_9uCoO!eL^iF9)Dqa~anZpRw z*MjUdx->6TmaQrOD;r~~%1WgRTxzA=K}2C_n)}10^h8xi&4t@7nKA`*R#5*Q`HZGR z#%InI?Qs&KhU2W^u}y>1C#lcPRv}?M3JnyU%AZ7ck*ccpa6c5_At%b}1r4BPKgE z!b3DfXhUSee6?W}F*C!$@Qr91Bat8Ug<*(5ZivthRpB1-A}&ls2H^?u5a5G0WKr$F z+#=J4CVa$c0*DLIx;8ItVk%;xqB>BrBDjS_osM1Mtl?4ZIFN|W4Ot1?7?_BRuwEiE zV>v`-hqaOrhkRnsP#R(2m>cv4ytxSbBR_%JG>(4|hk@D*9|3zuuSF39zuzGd(?g$| zcl+{C8X)5#)o0MMA8`WxY|l&ZiRKv`F9QAqND2Iqhh7g<2eBDp1Y+M;1!6xWAf97* zs20$}H9ck((=$JY1=@0u=qJ!asK=$38C|JI@;A z4YeP;6Ncg^_gd1xx5&(H)dM)_U^20_+mLVxn-s- zJWfchnLXe?Kgb-&|Ne<;zFI(?5hrM*Xs3jdbXKyrhbz1DSk>bt!u0Y{QKE_0t;Mg8 z#Q8oq4rxR_qja#;x|^BOq&4x>y{dVmY0}*TvL;($7aS^Ul)4ywUc?=xL#FY zUY~~e0D^Ufti^RWRz6040H_4hyE%^)e|y%6}1AIvEK25-3j$D*vk%E0-*JptrsKx*iy zqkhrDc-#RSgkWmsb5?NSQpBZ`fM-F(I9z$tVw^X)k9M=w& zYBt+NN~FOcS|wZ5YPwc^_F6VaecFC!w@t$^FeCKQf4YCnb)4-sZL@n^T|mPFSs)Y$ zT~Q4~Lod+A;?PV+oeC(P|@Iw$N1Up|-Q!vfyvYqM=am zqM?=gwHyF6lOG|J!ZD+@T-ZTZGZt+HY^vM2BA6(43)D2hLY!$8Z^B_TYT+2`MpG+h z1l;I0xEP&ohs8p15s~>vmYlYR5ldBm(XI!}l7`3z=29$7%*a zE)j9$W-}n^XR~kwcOxzNP6&(H%CfG+&S|;bg(2(Wp>1EAtNC=o=0;=R2t?Kn)q zHVy^P-79d(#ZWRpdNW}CX~(QMi#}?`n$;-PDwx&0gcU97aq`pTZ+-!OlywbvPRv$| zhRikTgAvvhV+;)&`c{=%(NU6zWzkR1zSDGBX4&t3Z%bitL9AETT$Ldgqd2f$N2>za zJ7pDrW@W&48nHHzZ*LEEHO#|yt;^N2UDZnAv59-gG&k37vuQZxzap(;iMQ$SAL7wm zYnzJYV@mdP31dDoFHS3}uyZ9U@TAqtle8nB(s#C`r6%JlgRCUjg=@UD<$_y)rqpx~ zX5{!*k-WGHv3d$l!?B`Rm5<9LQ_518%+kutw22XG)MHr0ypH~4CeUeR5^=sz)f2Fu zn20LtxC0M0)atjq3(0!gR~cIN@Lb#Aw>?RW%Z0J=idmhOnz>h|vRMuqCO=mpI@$KE zUf-(Gx>o7;=W%vnb3d~HPFH3{EU!z6fAMlIx`m6vF@(Ye!3sc@;ymVQD8n+Y5LF_BzRVh%n1mZ<=T7d8&-Xwo(^))GqZSunN84 zy(gF5A7n6(pCQi(JTeI+Gpr51MygG!7anXP;n5Z<3MPY`L2{F_NVvm+>>_QJ0@Mbd zNm?Y$(;3DE_aHq>0(yi0AaRl4#5*Vq5<;#?bI=qh55gkF&cjas5+W6zZ_ zS&~)$NG|JU!PAz>f7GZWNJSFf&c?t@t4eM=(*e>gB{$3(uyOZl*H|S}_fgCgFMC3g z`-iuSY(7)C;*aa7pq$jD({-;jGleU0vh2?1ittlP$2nzL?YOA)?$>*DwGF+hT+os} zby+`B58qaasX-Gv+pN@|2c71g<5xte5I7SGOw7|84V*n%a#>FN zo)P+40eNiB`SezJZA+QBeZ1l=>6vSoRClhNL$;C5OvxwJTXQ70Dt9#*yEz+V>jOG1 z?plg@K8LNJdt$P)HACuVd)4%bDtqZ&QYPi)n9Jr-kG4=!4C;cIdKCshdL{c>uP8Q# z?Gb{40fADXRfLpx%rwU5f(gK|je)L!mOu|cOkfp;)twfoAsA?#ay_Iw1;q#^=m`w; zJsGIa(!GOpp6>h02k_)Ls?)83@nCPea3-VxAK5zxAXv5C@X-S z8W0ya(jMjIP7MIstusL6%QryfD>op$QJfEnqezd7V>-zW#J*<)rM`0nmA;1rZGov` z9CXMFJZaY#M8%^RM3`kJ!4NY&eLW^e9F#!Z0RKe_- zzA_FWGwDT#Ve}5)p@!Nsc}E>^!|WNq0u9My_);B_zP3iE9lA5wjii}whu%(c#LO{$ z3XNXF&=0L)_)gqWhw3wbij{7?5)Q>hB94HD$}@jfV|-H%VDhL&sqehrP29iMgyg<5 zBNX>x7F>be;yJI%)5a3a+fclh=?YOF2p>dvV>%CtPz~I#F}}FTPGg&8_n&7WF>;Dt zwKF94@drS@L}Y>e;A108(3xxglG^U9k`=^zkK6k5Ks2Pj^Fcf<7RR$Mir_hVR5`4k)R3Sv z*dKt{UCTJ3lZdR44vUW%$s57)9ZTt4OC`(hw&&Sg7QgN!X=#qx{+JHpSjp`x%ItD4D6Hku$U(qBRvP=3+I>tT zyHd)&bY{|YE^;nEm$0U%w~e^B|jw$^5LO63(`KS)G zLmVHx6XM(60sgdW5HrAB@bPde-A0d>Iw~fGNuQVa<$|uw*T#aX-ZV&$2TsKaJ>-PY z?>UpF*hpqu5c@qQyYSpFnkgA9){JK4EOwHl`WDW@c6cL~q(er{EC_U?$P_ zpTvFwqeGE8XihBDtgpmpYWTU{zI zEa6o<8_@>*g(*rD=kt2HJ)m6cM#Xnqx`!E21!`$)x7w5}A7uTuf0!auz*3H>M^WKB z5p^{Nx~s>!a4lRSmOko8RC-!Jew8=m=K+nH{cpx^(ej&$AK+w84!80lCbEitwM>qe z&g#)&_Iq3ZRbd#ZDx};Jeow`X<>k&29rWsM5b$2d{tyP1nBZ5(J}FE~(;%02#Z}JT zrU_!kVXRP?Vz?2Pd!*sqiSpHM9C=P*$lw1M8(#jA0jq}m@xu%A-!LKFzhXjRB^gmW z7blPZn+lSXyeE$=h%nY?4ZVgJB_IkU=qoYug%C$ot{_lQvsfGu3`N+BYf38~YwhGt zdWZgY_>)X22A=PIAKx_F)=R^t!XRt*X4c!y%)FJG-_Pd*jv#<0h#qODcG4XtCo0sm zeF_G5(CHc(OckeV&?!3cgaHOEB&!j2jpE#FbjjXi$wX;9c~y6y-_p&_&qC)MgDJZ%2YgaMEg* zYPs1{#~s7y1^+~>%j{ZJZhM6n9yrCI*BG^FS7C!H2i19$DYS%3T~NZDr8$KvifLNO z>cqp&T-T#JGquk-M5w>H((ho!oK}JAS-k^y6t5KCO6VrRQo43kBS6TC=|06OLqt>q zc`?qttTnNX+#1LSN(kD9@1R4YrvCY~f!!*2g-H{Hu5R_n1>!}#l*;QAA zHS#VSPkEd%nH)#<7fn_QGb`B#J=ufM)o}68WhZ1-j1ITxTPhj-Z(rY>WA9Gh6_x0c z*048dd&RJkzdQQW8?&Zc>JOI@o7j^#ifj36;w@dCR+4c1-v>G!@`k`i7lI_=Kn-KF z0OJFQCklv15Ja;J5#l(yN+1ll!yI_h1r->B(UDye%7o$qngy-I4-_oB;+s;#cf{M(4$LJ@VziKYj#){aXzD&!h8y`l9a`_%H6S9^v;76Ut;t)2l@e zXUxuMv3YVqB(<7?jyF6hRV&gGgik8F-BCE8r8$8u#cgLNYD_0WS>8MRY05?JS5NWW53sJe>#(u!LG&ol_yU3<9w`7+fkW1u?FM0 zfO9#k*>P~R%lj_OQ-0V(qOqFPg-8#}(sf5rRk=nxf~IVVC8ewkH3m;hiE~FqB7a*u z-nkUMkja`dv*H()?4~@HC!g=A5*Vy7pYSB+$U{L&e2B=pP#mOi%W`ry_5;dTVwgr+ zDjX~>=Ax3PRzZ$PW*QliJWnq?Zpu>QyFv&xP$oI+Qeq2A$JQwG5)DPDF+hY-mQxs7 z+mfl$+SPkgpvoB3y3-&=JCx|m=bUT;(NwHYT#_7RNJ&01Rn#qz^+Z^Uunwcql-oyD zHu3_;PG`oVQI!G3JZjN}A#GuzjmEYo_gMVssG7Sv6J<>f35OZAXc7_bIXIho-q=fx zjas-d;FP$t0OlmQyHJzFl2npSkgznq(#%qMQJwNUOKyVMNoK`(qM=|Tndus*Xevn! z{M1T2JE=v6CLu|dnJ`N&WVQ6cDa1uwGjsYRIXWAgg$dNHHgH*yEJij*Ny+75#uV|o z&ME^SI8(ye5$o=;F*$l@MOL9H6*@Be3@SY{a<%9Jysn$7W@_c5d4s_H;B-@LcbwwF zK&$;A5dTZMXwaQl@?tGU#zuJgc=3<2K0ex(u(dg1PcmA4e@VnUU+BKc(({L6vMn>O2^*lX|ou zD@u$YkCl?_6e%UCh8H?RD!C!aOF3G!JJhSTpt8A>l!DUma@d}cT2}SVp!x}}%vT5} z%_l6jf}Mla&fY+XKt8~Qz|Tt#vkE8$;DDl6FdwxLW2=));AjtI(>tuxVXZYdIG+G)QsO*4wc6 zK`ciob<}JOdp1w5iVf?=gr5XmS4dY`ISzOCeiK}?h)a56zOT1S(YTO$&u;dD6;w4z zwl}Dw)+COz&u496ZIp~!Rp~Y$<&kZ!x2UF-7=GdOX7y!RaXj^TX8J@Gw$x5hC49&k zh`Y1)2|2M?pO<|-2Gi~zuEcH$}x^XKWwG`CVPdCU3%#EKBBH! zUZ)6_9u;i%REH*T@mHA~--IsIxSm+2*QuL;lSCijLE?@}o`>iQ{h&o!We%>F8zh53 z>cp%yg2-1Lq}U{h7D#r0eL%7cB@+y!GyFNUlAe0U6Z+#Or5-ypn1BWn+fi!}Zd$4x z&iwU)50V=bxLtqHuv=!3u3Kl&tvk@PE_pskU2;8AUD{&ITJxC;Qv1#mQWp>uYzs5j zkBzxYV#vHpQ-Ex5D~x7u3=kN8yq61oiQ))^kHRqLm~?=-MPNMW7su$OIF$327M!NNDyKqz3y9u|htH+pRhhdCAH8Z5))L+&Tp9k~nmaWe@1Q^7IyK<7tU zy#zhQiMwRqyahKG|1PVLHkVO%9$#A$-ZMZ{gL_I#5EBz@y(h4JnW0NBSSZ^sS_x2QdIl$1@)nI0#UD!Fk+k-+Wloz%PPG}_0}p#vl0~mMv=(h zZ*dJC|0du5hwaVoPOH0sHb-MHKh5C_JW$p63o?^Om-G!B{h<+u6P~o;=34|&E>E1P z_`=x8<>pOcM%?J?-H-;=VHb3jjQxnT&Qg}HUH`!s0CG>y0ah=nt-Tl|Qxdg(gV4vX z*dEjG>44^WekjkoJ-A}Q0+FBoQ2TgoZB9r_(2S`we2;dT_fPR0b31OSwL|oDOTFRP zejG*p7&$RI+I}B@_zE;A3{NnOV_-Tzw#`K4Yo!5Ey&3n~nXH>?zA5_b7IVbx%Fl>exsg{JuVchqg%^p^mS@y3&~f@=#uaK@vYUhDs|8Pdr&} zN70-(dqEacmBI|lX&y>Im6TeTQCYiCY`HxD$g7;XXp8ZHqB%vS27xGqhEx!P=LNf> zwB%Gfr;H9SVE=yd`Fv&)ZAm3#ptiG3@>Uw^YTbFoD zHq&ZMCHn)Gn_(8+b|iQxnfe)PgV0}=}uRbw9(Kl-DEO^URW?VZb>S8 zucx1jLmPd({FF1PB89yotRYQ3<{9dVI;13i@l-w8=BzV|x~&^a9f~|%%DC|)PABx( zpw|f!*<_VED^f|ND;;FDDIZkaansC0NUqA8fpwK7Lw%ImqaQ_H6W!m^%0X_uVPY@G zHlw%E?5%Y6nJ(n9Q=}C; zQTc&DS)wVG8kYo9TKs6%C>3i5x0=4))EZT`II_R(Q9k!DZq;UWzfbv@S;TqAXk!+H<4x}}eu3ax0DZJT&vDz&*b7bGc?4YP?iao60Xa5*>7HD&wM*W#5(N@Xl5tj^cV7?7sV| z;QZ}58za`tzA{8dXkD4j<>MMifrimzD9TlxeqG@BPTaN{hZX}R{zzbi8Dp{!tlw$!IOepP4k?O|z!VA&njMqqM05vV7D#do5(uTm_qPXEIfw}n!$8WySS!ZYqaq`BGnF9liKuOk_=;zbO)&KQ5;xxOA0~n(hyD( z9MU4yj%Z`_Er_D#Zvk*kNGw~1@LEIX?`iC2*qdBqV5tySR zm^=hWdOpfSl3nVixRv<_qlww113Uo#WO~6-sgXUB@XU7r(Vo7 z?poo)okx(LKDu>&-6HO1diWD8vwNPXedG+_$>oR(;n4K$49CwK0~Kc+e!E)Kwt!i{ zh~SS5A@b!qV&ZDpG;QvRCNt6jAPK$V47%dQAWfF&o^9H?Ss=liyv8*ZXr_6wPX8!E zKfO1PTL7j`zekTltQmc+8f%A3qBBmqCUICHl7r>G;XQ)s%N%;){X&cG`uu$p8$(wS ze(O;Tn+`?B%N$q6qg0J`@xr%AmJLbvr#3tfP#m)&(f2!{To7dMz@A5pU+BjO?6_lBmc1>mm+C}x-Z8IIts3glF48ex5_i`t?b zmu;@v7LiZG?a3_s)#rqj9_g*tV^#ufazL@fOdIjIn(8aO@z`=)5^PO1Dq^ zf9ic^6hBhJcfCjY*B4Nhf35d!jQ^MVNyydm|Hz+ml(&?=XI{KhwuCf+1O_4m1QP9Z z2c-~1!PX!^uu6CBkVB2jW@($#N_Xd7_(iJeX-M|eXUAs72mC32=Z;XliGOXu z`v-~x3iClmOt{8f5W9R5Ig0}KsO;9mr3-HG^6rI&{HkMJwlQ)yT&Ec*aE>P zCSIH@~>{6RFIyJAqfo8G-M?@LmTeD~93@#-Y2 z`D1Ue)<{g@zmX;l-l*01Jt$wH|B0}EMyJ;wKY#qt`Hr&xnTE>y?-9oI-?0q-OQ?;g zTPtImqWHFgwg$JgHn*UOYTHs00-;f$Qq!hNZ;DZ_fYk%pXPH1oW$8+=LHzdZTdDJP z82y{i%p#a^5B^$&Gq)kjM0rJ5;LDJ~`H}0M=gfcWk<|D1?UDXR5P;yoq1}A902(QC zC<=PIMQ25J2QO*9vh?UQ(N&q56oNGgv+cS&mufR}YLv}phUOfthc}^-Mp$`9(^{wv zIhd)bm|k@`2F9=jHp|7rW2N;0DKoX&TW&C+x=VC&RyB?FXOhCDVMP4JPJp>Te;MHYp&&%@a8*QR$?{`jj~;$|{Re_9d$UHWpFZ^q@(VtJ=$+g1t4SCeK*j=a5lZ?Wx8J zIeiJCNA^}nkNrrYdq=>%P{DX69f)uhDJHc44E$S3Yb}E?5Y!D~#Y&d~IZM4bg)A5f zy>lCtD2KlUE2w#oC5TI4*J%14jJDb zleE#lQNE-=!WiC)RH>NbcW+6+xtZiKcz4DcbzoSOEUwmm1d!ofODk>TmjlqVVYlHZ zGQ5CRNLljjFCHA8NZ|_Y3l_w1s2Lt2blh18@`?ngOW@|m9mnm%d+YnObO8JX_w)UIXP$>ok0-iy);3lC z($exVxak!D*?b@x;1&(Razq+{Pz%8#h{O>f-0hh$L6KAijP4-24>6kVBf5`M3mu%H zGu+A|=x# z^Mv?G!{+ZLlbX?uKS1RJ z3eCHe!1R!SOEJO3hHsRT`m_1-7vUrOa*xx(%yRa|2eYp_;I_V<=FSm|`A5&-0u8BS7rKwHwo#t^{<~a68 z1d4lv3*s~?=Mf1If*irtYi;m{s=i6Lo-pgenrMwE_lMMLYiSi~8+Exgs%}thE&p9m zFcP0(0#ff6=ymtC(_ZqOY4QdV-`?m;E!F3Lq(2Cw{GQ}*7QQarzokE#|0Vr>KPLQ_ zY*(Xhss2y43kCi;(cHYasx&~S0$~UVqM)UfOj@Ftn)(AxC(HyZl#Dq(gP_@U&;3ui zUw@rvEUp&k*bzDZEBz<&uO4Pe83`t`u|ZDv-Its*K6gLEuh+{oeIS^9ZJ;o3-Kka` zR0TiH6&2@bG$$Ii4hG`>OB$ifj7?O61-fQqs?364nf{$E&6(i~4UNWf)R~Eivb?1E zgg4cwK(ZSrD=tKa$ZY2FXyimmQj^(=u*&@t?MAWWhn`ZbYe@&`g&DtSRSD@L^khQN zPS@CyDGs`uVXZ?ctrd;%0AaDFeBYm$yIR<#xWRz@ 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

eJAu=orbF-J*`kk#W2lRpziSwAyM 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℘I)M~8HuA$H%nZkT6U|qMD;^kAV!|Ey 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%0DQ5p#1QndAOP9n8XraI@i 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

w;L$^}KFuOaKap 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 z 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

Mr_x+XJ0Y@O@Xln(-8Sd7Z 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
  • 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

    h*448rO&VTI(k7(%cdcD&`V`xQfz{ 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 @kY#Pd{u{{s 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

    #AAH7l#DMvd5w4B1XV35BG)$i zp_h!;Q^_K!j25q!@*)E|I#q9KX6~e?p?P0-F%p9ckgWM4H;q?LKe8|j(wS-lK~DOFi@8O^5B-mYqWMho2n zt`QIjp8=AAJt6m^aBUBz@)oH2<1FS;6txTT+)Y&!C2qWb7H}nj2pYPoOBf^0)j#Vd zQ-5LQ;yQD#)z6(`PIY#6Hqv@HXj4IP z{^w?M^oIfKq@nm;O^pTI!tQ$-E~xe&!A;`zVTVT2jYu_yYfqxE+uppD%0A=V3X=qj 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 AGef<6We|m?j1^ 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

    {qn&?516p%HMw?_FvPjFR_+ZaKL=%bS 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 z

    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

    `gsx529~Nse=DB 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%0A(nl~y^)u*u*IZ>vrdFttkx^{ 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 z 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�-jWQjS!IF$t8nPC z5ye+gZ_3iGaPVSamO^K=+fIvAib4^CPUimSYlI*)_MZQTl+;%4el9YDyYt8TXa9s=x8S2GmwfZ3 zL~9}=2ZS4fWJdUeG8uMtXtbM2Shl$D zyMNer!8&L$+jJ7Ftg|(*Y+HNl?dxn`LIyY{YWz%Ga0qhx7s?c9+#Ufb?@rxMT zu zo53;x#`Indxj*nx&*Z#WTug&j6DsANwZ(LQJc7h7C@r1XIBk)a ziaDK3srTQE&bAh|?}bpl0yt^EAzLNn(VfB*DU$-kM@Snf-F!ov|o*BdC@} zrh^a4%a88O7EOY%q`}l;YQ~HZnS1-C(Og2%5yb>y9oV24TFT0I2kfB;Os{&HUEr@) z$7KmZ$*k=Ad&g#CR~(!`3(&68?S!o47TOrTMlRgjxU?diV@F7>MatXtv=XV3MXu>Q zvf(o*;wOqt4d&K4CBoYqG+~i?4cEyrmG~9?-Dy4weHI@reB}$W^5um8`(V$U;VAfa zXofB+mA@z}yn{h6>Pf8N1@@nMd=G_g0_D(+IzRtYF55)+BA0>yE#1%UiU^?#C(eYG zw9ao6q8H$Q-ieP!?gOR7_(d@v-L}8h&>PQANVrqRDB3gs9JWKM4Kz(NZ-cK&6g7## z8KDz399LlGd}x=+r7_-$>k=~CYqefs5z$deviV(RfHugnFGTNyXlfV>Zc2-88y&@w zEowC^yQcdE-IkCYp$#=@xf=aiO=0<_Dwt8yVPK)0DCuZ2E+OXQPn2vFbUvG~G5M@yZ>PgEzl*hD4%*B~DAoJ07&l>r&=YT$&NcMazFIj5o z#B0ca95bMr_xNbPUiwt2WVxx)gPO3+h?=P6?yuz~8_z^Vy{07elJ;}?Ad(z~VBDn76ganK$ro70 z3lx(ox1Y42X1W-xE@%Uz4O(AKSWq};-x#y$Y4*Ex?3_U-6W4L#vt&WrM27}w4XoV| zM4GCX$==%kN71fmxV}&??e7D>O3F^!4Z@$CFu@aFWY;%?;2sc6cPP~OsZcOhNTT(e zxepT`I$*_y^S6nFn&s_)@1Xa^Oa&rb*knwR;BoBavmb|%q>DjNMFXM) zp^Vfjr%RW%2-kC`DU5N$wp?5xRR093PZ^a;h|0-hctu7=i>5+5_vDKyhvpjrS4W4c zg*GAvE4~l*7yD}a>$C&32AR0-?4EWF=M=^I-%8^^p+W_v2yf(IG{M@)nh}QZ2$r1H zM*6hMkTE6I!3@!}RQ#B>IP7%%fboSt6&k3;^bFEUka|Y-{PYz)J{BF6Ch2c<5Rp7% zqSCc`V#qF^VAy!1*Xzr0xvk)GX^7RhqXbBc#AJ|9E3Zy&(K=>b7%y;a3JF|Jkj(6? zo}VT|OW1NTG!h-|26t70k&@3^X0%m1&1~pvD?U1M*l9)b+l2c?2lh#dP-N_@;-BMB z&Vp#uEODvc(&7`dg)-73Ac0Kc?G<#Ch2|lC>6qNScHA^I&EbH*aI$gPZ{|ROj z1+hLsHy{n4t4J&>eWL26bC+3T?}b%B@t2$AfzB;a%t_u)#;=LTu`?l$G21Ma$5{RC zmrD__1f`(-moBvp(WCqqj-um4bSzp#0RiUD_cjJRCbb1KGZl#2Uys zp9+)jzAKJ8Oh+APT-kA#6edx)X~`4)<;IuwJE1dm$4Aw2Xs@hDsq!-65yPuqxe3Ac z@HdsydMy5m*(WR9FG6QpWTxzg_5J1rLkpSU=INws?S5&ga!K~*8^*7;LRr}@Yg8Hf zLrNtJi(Tjs*BUMmTpo7fNR)Bnu#|AN5NhkicDJ)*D;j1je7!_vikcja@Tyh?;}w^H zqjCUKiLCwdRH!nuF|_q+xKysj_WZkmcK2 zW?%MpU>tzfWJ7E2u>13hwrRAl$Mo0Bw2M`BhTb5T4JOc(PEyh_xbYK)x zHfa?|iJ}8D-H=v2.0.0 was installed but the "use_test_unit_gem" MOCHA_OPTIONS was not specified, a "comparison of Fixnum with Hash failed" exception was being raised when running the performance tests. This was because bits of the test-unit gem were being loaded accidentally and a Hash was being incorrectly supplied to the TestRunner.run method. -* Explicitly require rubygems for running tests via rake using test-unit gem. -* Handle newer versions of test-unit gem (v2.0.2 to v2.0.9) -* Handle newer versions of minitest gem (v1.4.0 to v1.6.0) -* Added warnings about monkey-patching test-unit and minitest to aid debugging. These are enabled by including "debug" in the MOCHA_OPTIONS environment variable. This is now a comma-separated list, so that we can specify multiple options e.g. MOCHA_OPTIONS=debug,use_test_unit_gem -* Eloy Duran (alloy) made the unit tests run on 1.9.2dev r25249. -* Eloy Duran (alloy) also improved some MiniTest TestResult code I'd written and got the acceptance tests running on Ruby 1.9 HEAD. There are still 4 failures because for some reason the backtrace line numbers are off by one. And the minitest_test test case does not run when the whole suite is run with MiniTest. These issues still need investigation. -* Fixed some acceptance tests to run in Ruby 1.9.2 - it's no longer possible to subvert the protection of a method by calling it via Object#send. -* Fixed "test:performance" rake task so it runs in Ruby 1.9.2. -* Fix test incorrectly failing under Rubinius 1.0. This test imposed too many constraints. It appears that Object#inspect legitimately calls Object#object_id in Rubinius. But we're only interested in what 'id' methods Mocha::ObjectMethods#mocha_inspect calls. By stubbing Object#inspect we can relax the constraints imposed by the test. -* Luke Redpath (lukeredpath) added new shorthand "any" and "all" composite parameter matchers using "&" and "|". This provides an alternative syntax for expecting any or all matchers to pass, e.g. foo.expects(:bar).with(equals(1) | equals(2)). -* Improved documentation for Expectation#raises. A number of people have suggested an extension to the API to cope with custom exceptions that have extra constructor parameters. However, since the arguments supplied to Expectation#raises are just passed on to Kernel#raise, it's possible to pass in an instance of an exception. Thus no change to the API is required, but it does seem worthwhile pointing this out in the docs. -* Corrected RDoc example for Expectation#never thanks to Red David (reddavis). -* Improved RDoc including a change suggested by Rohit Arondekar (rohit). -* Updated gemspec as requested by Sam Woodard (shwoodard). - -= 0.9.8 (645024765b2d92018efc511652e1174163844e39) -* Fixed bug "NameError raised when using Mocha as a Rails plug-in" - http://floehopper.lighthouseapp.com/projects/22289/tickets/53. Since 0.9.6 the Rails plugin has been broken. See bug report for details. You will need to explicitly load Mocha *after* the test framework has been loaded, e.g. by adding "require 'mocha'" at the bottom of test/test_helper.rb. -* Make Mocha::ParameterMatchers#regexp_matches, #includes, #has_value, #has_key more robust. Thanks to Sander Hartlage. -* Allow passing a block to Mocha::Configuration methods to only change configuration for the duration of the block. Thanks to Dan Manges. -* Fixed bug "doc generation fails in 0.9.7 gem" - http://floehopper.lighthouseapp.com/projects/22289/tickets/51. -* Remove rdoc template incorporating google analytics from source control. The file just needs to exist locally and be ignored by source control. This should stop the warning showing up on e.g. RunCodeRun build results. - -= 0.9.7 (80d816f250dc13aaf856f3f9cbd97ebe9c371839) -* Although I had provided a deprecation warning for people using Mocha::Standalone, I had assumed people wouldn't be explicitly loading the mocha/standalone.rb file. It turns out this assumption was incorrect at least in the case of Rspec. This is now fixed. - -= 0.9.6 (57f8f77d715b7f1d9efee2e1a9438f7905c0006b) -* Version 2.0.1 of the test-unit gem introduced a private 'run_test' method on TestCase which clashed with the public TestRunner#run_test method. So this latter method has been renamed to 'run_as_test'. -* Stop requiring rubygems - this should be an environmental choice for the user. http://gist.github.com/54177 - describes why requiring rubygems in your library code is a bad idea. -* It seems like overkill to vendorize coderay and meta_project when they're only needed to generate the examples for documentation and for publishing files on RubyForge. So I'm removing them and installing them locally as gems when I need them. -* Added support for 'test-unit' gem (version >= 2.0). Note that as with other versions of Test::Unit I'm completely replacing the TestCase#run method. Unfortunately in version 2.0.0 this method differs slightly from the same method in version 2.0.1 & 2.0.2, so we have to provide different implementations to ensure that the internal working of Test::Unit are not compromised by Mocha. Note also that unless the 'test-unit' gem is loaded, requiring 'test/unit' leads to a mixture of stdlib and gem classes being loaded causing errors. To avoid a dependency on rubygems, the gem is loaded only if MOCHA_OPTIONS is set to 'use_test_unit_gem' - this option is only intended for use in running Mocha's own tests. It might be worthwhile to create a shim gem like minitest_tu_shim to allow the test-unit gem to completely replace the stdlib, but that's a job for another day. The changes in the Rakefile are to make the default task run with the 'test-unit' gem (version >= 2.0). -* Renamed Mocha::Standalone to Mocha::API to better reflect its purpose. Added a deprecation warning for those who are referencing Mocha::Standalone. -* Fix exception raised by HasEntry#matches? if first param is not a Hash (thanks to Taylor Barstow). -* Ken Collins reported [1] that Mocha is always loading MiniTest if it is available and loading it causes some Rails/ActionPack tests to break. I've removed the loading of MiniTest, but this now means the user has to ensure that if they want to use MiniTest in conjunction with Mocha, he must load MiniTest before loading Mocha. [1] http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2060 -* Implemented Bacon integration (thanks to Ubiratan Pires Alberton), but this was then removed after deciding only to maintain integration with Test::Unit and MiniTest which are both Ruby standard libraries. See mailing list for details. -* Don't monkey-patch MiniTest if it's already been monkey-patched by Mocha. -* Fixed bug: MiniTest integration was counting ExpectationErrors as errors not failures. http://floehopper.lighthouseapp.com/projects/22289-mocha/tickets/41. -* Fixed bug: Some Bacon tests were failing in Ruby 1.9.1. http://floehopper.lighthouseapp.com/projects/22289-mocha/tickets/43. -* Chad Humphries pointed out that in Ruby 1.9.1, if you are not using Test::Unit or MiniTest, Mocha will attempt to load and monkey-patch Test::Unit. Mocha will now only monkey-patch Test::Unit and/or MiniTest if they have already been loaded. MiniTest tests will now run in both Ruby 1.8.6 (with MiniTest gem) and in Ruby 1.9.1 (with MiniTest std lib). See Ligthouse ticket - http://floehopper.lighthouseapp.com/projects/22289/tickets/49. -* Made Mocha compatible with minitest 1.4.0 and above (thanks to Denis Defreyne). - -= 0.9.5 (93cad010345ce5d68f31422cfc32ed9dd6de13ec) -* Fixed Lighthouse bug #32 - stub_everything should mean mock responds to anything. -* Added Expectation#twice to improve readability. Thanks to pull request from Celestino Gomes. -* In Ruby 1.9.1, requiring 'test/unit' loads a thin wrapper around MiniTest and Test::Unit::TestCase ends up inheriting from MiniTest::Unit::TestCase. So we need to avoid including the Mocha modules more than once to avoid nasty consequences. Thanks to Matthias Hennemeyer for help with this. -* Ruby 1.9 includes rake, but not rake/contrib. For the moment I've moved the sshpublisher require into the only rake task that needs it, so that I can at least run the tests in Ruby 1.9. It looks like I will need to build a rake/contrib gem or similar to get this working properly - http://intertwingly.net/blog/2008/01/07/Rake-Contrib-for-1-9 - -= 0.9.4 (8a59c6ff0f99f34b02bd99f19536a7893be2b340) -* Added mocha.gemspec file generated with Chad Woolley's new rake task, so that a floehopper-mocha gem will get built on GitHub. -* Add rake task to update mocha.gemspec with unique version, which will cause gem to be auto-built on github -* As Tobias Crawley correctly pointed out in feature request #23055 "stubs(with_hash) not working with existing object" [1], following the principle of least surprise, it should be possible to call ObjectMethods#expects & ObjectMethods#stubs with a Hash of method_names vs return_values like you can with Mock#expects & Mock#stubs. I've also updated & improved the docs to reflect the changes. [1] http://rubyforge.org/tracker/index.php?func=detail&aid=23055&group_id=1917&atid=7480 -* Removed deprecated gem autorequire. - -= 0.9.3 (8219bb2d2881c8529c93fc21e97a11d01203c759) -* Added support for MiniTest thanks to Jeff Smick. -* Fixed a possible bug with some of the non-default Configuration options relating to the argument to Object#respond_to? -* As per Jay Fields recommendations [1] and with further impetus from a talk at Ruby Manor, any methods added to core classes are now added by including a module. This means that Mocha is a better citizen of the Ruby world and it's behaviour is more easily extended. [1] http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html & http://blog.jayfields.com/2008/07/ruby-redefine-method-behavior.html -* Removed deprecated gem autorequire. - -= 0.9.2 (r355) -* Improved documentation to address [#22530] 'Mock methods with multiple return values not possible?' -* respond_with parameter matcher was not available in tests. -* Patch [#22630] Fix for a bug in running Rails tests with Ruby 1.8.7. Array#flatten was being called which in turn was checking whether each element responded to #to_ary. This check was using the two parameter version of #respond_to?, but Mock was only defining a one parameter version. - -= 0.9.1 (r349) - -* Fixed bug #21465 - expects & stubs should support method names as strings (as well as symbols) or fail fast. Convert all expectation method names to a symbol in case they were supplied as a string. -* By removing Mock#unexpected_method_called we reduce the number of methods vulnerable to the problem that surfaced in bug #21563. -* Fix bug #21563 - stubbing 'verified?' method is unsafe. Instance method names on the Mock class should be more obscure. -* Performance improvement. StubbaExampleTest goes twice as fast on my local machine. -* Added primitive performance test to default rake task. -* Fix format of case statements which don't work in Ruby 1.9 and make others consistent. -* There is no point in running (potentially expensive) checks if configuration is set to allow such checks to fail. This is a relatively quick fix in response to Chris McGrath's performance problems. -* Fix for bug #21161 - 'uninitialized constant Deprecation in stubba.rb'. -* It's more readable to talk about 'once' and 'twice' rather than '1 time' and '2 times'. -* Fix bug #20883 - never should raise when called to prevent follow up errors. Fail fast when there are no matching invokable expectations and handle the stub_everything case sensibly. This might not be entirely backwards compatible, but I think the benefits outweigh the risks. The most likely change is that a test that was already failing will now fail faster, which doesn't seem so awful. - -= 0.9.0 (r316) - -* Configurable warnings or errors - * when a method on a non-public method is stubbed - * when a method on a non-existent method is stubbed - * when a method on a non-mock object is stubbed - * when a method is stubbed unnecessarily (i.e. the stubbed method is not called during the test) - -* Improved error messages - * User-friendly list of unsatisfied expectations, satisfied expectations and state machines. - * Improved readability of cardinality description. - * Display sensible failure message for any_instance expectations e.g. "#.bar - expected calls: 1, actual calls: 0" - -* Parameter matchers - * New to this release - * optionally (allows matching of optional parameters if available) - * yaml_equivalent (allows matching of YAML that represents the specified object) - * responds_with (tests the quack not the duck) - * Nesting of parameter matchers is now supported. - -* Optional block passed into mock initializer is evaluated in the context of the new mock instance and can be used as a shortcut to set up expectations. - -* Added JMock-style sequences for constraining the order of expected invocations. See Standalone#sequence and Expectation#in_sequence. - -* Added JMock-style states for constraining the order of expected invocations. See Standalone#states, Expectation#then, Expectation#when and StateMachine. - -* Compatibility with versions of Ruby - * Compatibility with Ruby v1.9. All test errors and warnings fixed. - * Nasty fix so that TestCaseAdaptor works consistently with earlier versions of Test::Unit as well as more recent versions. - * Added platform to gem specification to avoid bug in rubygems 0.9.5 - see http://www.dcmanges.com/blog/rubygems-0-9-5-platform-bug and http://rubygems.org/read/chapter/20#platform. - * Make ExpectationRaiser deal with subclasses of Interrupt which seem to need a message supplied in the raise statement in Ruby 1.8.6 (but not 1.8.4 or 1.9). Not sure this is really Mocha's responsibility. - -* Added deprecation warning in stubba.rb which is no longer needed and will be removed. - -* Supply positioning information to evals to improve any error messages. See http://ola-bini.blogspot.com/2008/01/ruby-antipattern-using-eval-without.html - -* Bug fixes - * 18914 in revision 296 - http://rubyforge.org/tracker/index.php?func=detail&aid=18914&group_id=1917&atid=7477 - * 18917 in revision 295 - http://rubyforge.org/tracker/index.php?func=detail&aid=18917&group_id=1917&atid=7477 - * 18336 in revision 287 - http://rubyforge.org/tracker/index.php?func=detail&aid=18336&group_id=1917&atid=7477 - * 17835 in revision 255 - http://rubyforge.org/tracker/index.php?func=detail&aid=17835&group_id=1917&atid=7477 - * 17412 in revision 242 - http://rubyforge.org/tracker/index.php?func=detail&aid=17412&group_id=1917&atid=7477 - * 15977 in revision 198 - http://rubyforge.org/tracker/index.php?func=detail&aid=15977&group_id=1917&atid=7477 - * 11885 in revision 156 - http://rubyforge.org/tracker/index.php?func=detail&aid=11885&group_id=1917&atid=7477 - -= 0.5.5 (r167) - -- Renamed Matches parameter matcher to RegexpMatches for clarity. -- Added noframes tag to rdoc index to assist Google. - -= 0.5.4 (r166) - -- Added matches parameter matcher for matching regular expressions. - -= 0.5.3 (r165) - -- Attempt to fix packaging problems by switching to newer version (1.15.1) of gnutar and setting COPY_EXTENDED_ATTRIBUTES_DISABLE environment variable. -- Removed unused ExpectationSequenceError exception. -- Added instance_of and kind_of parameter matchers. -- Added Google Webmaster meta tag to rdoc template header. -- Put Google Webmaster meta tag in the right header i.e. the one for the index page. - -= 0.5.2 (r159) - -- Fix bug 11885 - "never doesn't work with stub_everything" submitted by Alexander Lang. In fixing this bug, also fixed undiscoverd bug where expected & actual invocation counts were being incorrectly reported which seems to have been introduced when fixes were added for invocation dispatch (see MockedMethodDispatchAcceptanceTest). -- Previously when an expectation did not allow more invocations, it was treated as not matching. Now we prefer matching expectations which allow more invocations, but still match expectations which cannot allow more invocations. I think this may be overcomplicating things, but let's see how it goes. - -= 0.5.1 (r149) - -- Fixed bug #11583 "Mocha 0.5.0 throwing unexpected warnings". Also switched on ruby warning for all rake test tasks. Fixed majority of warnings, but some left to fix. - -= 0.5.0 (r147) - -- Parameter Matchers - I’ve added a few Hamcrest-style parameter matchers which are designed to be used inside Expectation#with. The following matchers are currently available: anything(), includes(), has_key(), has_value(), has_entry(), all_of() & any_of(). More to follow soon. The idea is eventually to get rid of the nasty parameter_block option on Expectation#with. - - object = mock() - object.expects(:method).with(has_key('key_1')) - object.method('key_1' => 1, 'key_2' => 2) - # no verification error raised - - object = mock() - object.expects(:method).with(has_key('key_1')) - object.method('key_2' => 2) - # verification error raised, because method was not called with Hash containing key: 'key_1' - -- Values Returned and Exceptions Raised on Consecutive Invocations - Allow multiple calls to Expectation#returns and Expectation#raises to build up a sequence of responses to invocations on the mock. Added syntactic sugar method Expectation#then to allow more readable expectations. - - object = mock() - object.stubs(:method).returns(1, 2).then.raises(Exception).then.returns(4) - object.method # => 1 - object.method # => 2 - object.method # => raises exception of class Exception - object.method # => 4 - -- Yields on Consecutive Invocations - Allow multiple calls to yields on single expectation to allow yield parameters to be specified for consecutive invocations. - - object = mock() - object.stubs(:method).yields(1, 2).then.yields(3) - object.method { |*values| p values } # => [1, 2] - object.method { |*values| p values } # => [3] - -- Multiple Yields on Single Invocation - Added Expectation#multiple_yields to allow a mocked or stubbed method to yield multiple times for a single invocation. - - object = mock() - object.stubs(:method).multiple_yields([1, 2], [3]) - object.method { |*values| p values } # => [1, 2] # => [3] - -- Invocation Dispatch - Expectations were already being matched in reverse order i.e. the most recently defined one was being found first. This is still the case, but we now stop matching an expectation when its maximum number of expected invocations is reached. c.f. JMock v1. A stub will never stop matching by default. Hopefully this means we can soon get rid of the need to pass a Proc to Expectation#returns. - - object = mock() - object.stubs(:method).returns(2) - object.expects(:method).once.returns(1) - object.method # => 1 - object.method # => 2 - object.method # => 2 - # no verification error raised - - # The following should still work... - - Time.stubs(:now).returns(Time.parse('Mon Jan 01 00:00:00 UTC 2007')) - Time.now # => Mon Jan 01 00:00:00 UTC 2007 - Time.stubs(:now).returns(Time.parse('Thu Feb 01 00:00:00 UTC 2007')) - Time.now # => Thu Feb 01 00:00:00 UTC 2007 - -- Deprecate passing an instance of Proc to Expectation#returns. -- Explicitly include all Rakefile dependencies in project. -- Fixed old Stubba example. -- Fix so that it is possible for a stubbed method to raise an Interrupt exception without a message in Ruby 1.8.6 -- Added responds_like and quacks_like. -- Capture standard object methods before Mocha adds any. -- Added Expectation#once method to make interface less surprising. -- Use Rake::TestTask to run tests. Created three separate tasks to run unit, integration & acceptance tests. Split inspect_test into one file per TestCase. Deleted superfluous all_tests file. -- Fiddled with mocha_inspect and tests to give more sensible results on x86 platform. -- Fixed bug #7834 "infinite_range.rb makes incorrect assumption about to_f" logged by James Moore. - -= 0.4.0 (r92) - -- Allow naming of mocks (patch from Chris Roos). -- Specify multiple return values for consecutive calls. -- Improved consistency of expectation error messages. -- Allow mocking of Object instance methods e.g. kind_of?, type. -- Provide aliased versions of #expects and #stubs to allow mocking of these methods. -- Added at_least, at_most, at_most_once methods to expectation. -- Allow expects and stubs to take a hash of method and return values. -- Eliminate warning: "instance variable @yield not initialized" (patch from Xavier Shay). -- Restore instance methods on partial mocks (patch from Chris Roos). -- Allow stubbing of a method with non-word characters in its name (patch from Paul Battley). -- Removed coupling to Test::Unit. -- Allow specified exception instance to be raised (patch from Chris Roos). -- Make mock object_id appear in hex like normal Ruby inspect (patch from Paul Battley). -- Fix path to object.rb in rdoc rake task (patch from Tomas Pospisek). -- Reverse order in which expectations are matched, so that last expectation is matched first. This allows e.g. a call to #stubs to be effectively overridden by a call to #expects (patch from Tobias Lutke). -- Stubba & SmartTestCase modules incorporated into Mocha module so only need to require 'mocha' - no longer need to require 'stubba'. -- AutoMocha removed. - -= 0.3.3 - -- Quick bug fix to restore instance methods on partial mocks (for Kevin Clark). - -= 0.3.2 - -- Examples added. - -= 0.3.1 - -- Dual licensing with MIT license added. - -= 0.3.0 - -* Rails plugin. -* Auto-verify for expectations on concrete classes. -* Include each expectation verification in the test result assertion count. -* Filter out noise from assertion backtraces. -* Point assertion backtrace to line where failing expectation was created. -* New yields method for expectations. -* Create stubs which stub all method calls. -* Mocks now respond_to? expected methods. - -= 0.2.1 - -* Rename MochaAcceptanceTest::Rover#move method to avoid conflict with Rake (in Ruby 1.8.4 only?) - -= 0.2.0 - -* Small change to SetupAndTeardown#teardown_stubs suggested by Luke Redpath (http://www.lukeredpath.co.uk) to allow use of Stubba with RSpec (http://rspec.rubyforge.org). -* Reorganized directory structure and extracted addition of setup and teardown methods into SmartTestCase mini-library. -* Addition of auto-verify for Mocha (but not Stubba). This means there is more significance in the choice of expects or stubs in that any expects on a mock will automatically get verified. - -So instead of... - - wotsit = Mocha.new - wotsit.expects(:thingummy).with(5).returns(10) - doobrey = Doobrey.new(wotsit) - doobrey.hoojamaflip - wotsit.verify - -you need to do... - - wotsit = mock() - wotsit.expects(:thingummy).with(5).returns(10) - doobrey = Doobrey.new(wotsit) - doobrey.hoojamaflip - # no need to verify - -There are also shortcuts as follows... - -instead of... - - wotsit = Mocha.new - wotsit.expects(:thingummy).returns(10) - wotsit.expects(:summat).returns(25) - -you can have... - - wotsit = mock(:thingummy => 5, :summat => 25) - -and instead of... - - wotsit = Mocha.new - wotsit.stubs(:thingummy).returns(10) - wotsit.stubs(:summat).returns(25) - -you can have... - - wotsit = stub(:thingummy => 5, :summat => 25) - -= 0.1.2 - -* Minor tweaks - -= 0.1.1 - -* Initial release. diff --git a/build_lib/mocha/Rakefile b/build_lib/mocha/Rakefile deleted file mode 100644 index 5427bef..0000000 --- a/build_lib/mocha/Rakefile +++ /dev/null @@ -1,216 +0,0 @@ -require 'rake/rdoctask' -require 'rake/gempackagetask' -require 'rake/testtask' - -module Mocha - VERSION = "0.9.10" -end - -desc "Run all tests" -task 'default' => ['test:units', 'test:acceptance', 'test:performance'] - -namespace 'test' do - - unit_tests = FileList['test/unit/**/*_test.rb'] - acceptance_tests = FileList['test/acceptance/*_test.rb'] - - desc "Run unit tests" - Rake::TestTask.new('units') do |t| - t.libs << 'test' - t.test_files = unit_tests - t.verbose = true - t.warning = true - end - - desc "Run acceptance tests" - Rake::TestTask.new('acceptance') do |t| - t.libs << 'test' - t.test_files = acceptance_tests - t.verbose = true - t.warning = true - end - - # require 'rcov/rcovtask' - # Rcov::RcovTask.new('coverage') do |t| - # t.libs << 'test' - # t.test_files = unit_tests + acceptance_tests - # t.verbose = true - # t.warning = true - # t.rcov_opts << '--sort coverage' - # t.rcov_opts << '--xref' - # end - - desc "Run performance tests" - task 'performance' do - require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'stubba_example_test') - require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'mocha_example_test') - iterations = 1000 - puts "\nBenchmarking with #{iterations} iterations..." - [MochaExampleTest, StubbaExampleTest].each do |test_case| - puts "#{test_case}: #{benchmark_test_case(test_case, iterations)} seconds." - end - end - -end - -def benchmark_test_case(klass, iterations) - require 'benchmark' - load 'test/unit/ui/console/testrunner.rb' unless defined?(Test::Unit::UI::Console::TestRunner) - unless $silent_option - begin - load 'test/unit/ui/console/outputlevel.rb' unless defined?(Test::Unit::UI::Console::OutputLevel::SILENT) - $silent_option = { :output_level => Test::Unit::UI::Console::OutputLevel::SILENT } - rescue LoadError - $silent_option = Test::Unit::UI::SILENT - end - end - time = Benchmark.realtime { iterations.times { Test::Unit::UI::Console::TestRunner.run(klass, $silent_option) } } -end - -desc 'Generate RDoc' -Rake::RDocTask.new('rdoc') do |task| - task.main = 'README.rdoc' - task.title = "Mocha #{Mocha::VERSION}" - task.rdoc_dir = 'doc' - template = File.expand_path(File.join(File.dirname(__FILE__), "templates", "html_with_google_analytics.rb")) - if File.exist?(template) - puts "*** Using RDoc template incorporating Google Analytics" - task.template = template - end - task.rdoc_files.include( - 'README.rdoc', - 'RELEASE.rdoc', - 'COPYING.rdoc', - 'MIT-LICENSE.rdoc', - 'agiledox.txt', - 'lib/mocha/api.rb', - 'lib/mocha/mock.rb', - 'lib/mocha/expectation.rb', - 'lib/mocha/object.rb', - 'lib/mocha/parameter_matchers.rb', - 'lib/mocha/parameter_matchers', - 'lib/mocha/state_machine.rb', - 'lib/mocha/configuration.rb', - 'lib/mocha/stubbing_error.rb' - ) -end - -desc "Generate all documentation" -task 'generate_docs' => ['clobber_rdoc', 'rdoc', 'examples', 'agiledox.txt'] - -desc "Upload RDoc to RubyForge" -task 'publish_docs' do - require 'rake/contrib/sshpublisher' - Rake::SshDirPublisher.new("jamesmead@rubyforge.org", "/var/www/gforge-projects/mocha", "doc").upload -end - -desc "Generate agiledox-like documentation for tests" -file 'agiledox.txt' do - File.open('agiledox.txt', 'w') do |output| - tests = FileList['test/**/*_test.rb'] - tests.each do |file| - m = %r".*/([^/].*)_test.rb".match(file) - output << m[1]+" should:\n" - test_definitions = File::readlines(file).select {|line| line =~ /.*def test.*/} - test_definitions.sort.each do |definition| - m = %r"test_(should_)?(.*)".match(definition) - output << " - "+m[2].gsub(/_/," ") << "\n" - end - end - end -end - -desc "Convert example ruby files to syntax-highlighted html" -task 'examples' do - require 'coderay' - mkdir_p 'doc/examples' - File.open('doc/examples/coderay.css', 'w') do |output| - output << CodeRay::Encoders[:html]::CSS.new.stylesheet - end - ['mocha', 'stubba', 'misc'].each do |filename| - File.open("doc/examples/#{filename}.html", 'w') do |file| - file << "" - file << "" - file << %q() - file << "" - file << "" - file << CodeRay.scan_file("examples/#{filename}.rb").html.div - file << "" - file << "" - end - end -end - -Gem.manage_gems if Gem::RubyGemsVersion < '1.2.0' - -def build_specification(version = Mocha::VERSION) - Gem::Specification.new do |s| - s.name = "mocha" - s.summary = "Mocking and stubbing library" - s.version = version - s.platform = Gem::Platform::RUBY - s.author = 'James Mead' - s.description = <<-EOF - Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes. - EOF - s.email = 'mocha-developer@googlegroups.com' - s.homepage = 'http://mocha.rubyforge.org' - s.rubyforge_project = 'mocha' - - s.has_rdoc = true - s.extra_rdoc_files = ['README.rdoc', 'COPYING.rdoc'] - s.rdoc_options << '--title' << 'Mocha' << '--main' << 'README.rdoc' << '--line-numbers' - - s.add_dependency('rake') - s.files = FileList['{lib,test,examples}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a - end -end - -specification = build_specification - -Rake::GemPackageTask.new(specification) do |package| - package.need_zip = true - package.need_tar = true -end - -desc 'Generate updated gemspec with unique version, which will cause gem to be auto-built on github.' -task :gemspec do - File.open('mocha.gemspec', 'w') do |output| - output << build_specification(Mocha::VERSION + '.' + Time.now.strftime('%Y%m%d%H%M%S')).to_ruby - end -end - -task 'verify_user' do - raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER'] -end - -task 'verify_password' do - raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD'] -end - -desc "Publish package files on RubyForge." -task 'publish_packages' => ['verify_user', 'verify_password', 'clobber_package', 'package'] do - require 'meta_project' - require 'rake/contrib/xforge' - release_files = FileList[ - "pkg/mocha-#{Mocha::VERSION}.gem", - "pkg/mocha-#{Mocha::VERSION}.tgz", - "pkg/mocha-#{Mocha::VERSION}.zip" - ] - - Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new('mocha')) do |release| - release.user_name = ENV['RUBYFORGE_USER'] - release.password = ENV['RUBYFORGE_PASSWORD'] - release.files = release_files.to_a - release.release_name = "Mocha #{Mocha::VERSION}" - release.release_changes = '' - release.release_notes = '' - end -end - -desc "Do a full release." -task 'release' => ['default', 'generate_docs', 'publish_packages', 'publish_docs', 'gemspec'] do - puts - puts "*** Remember to commit newly generated gemspec after release ***" - puts -end diff --git a/build_lib/mocha/examples/misc.rb b/build_lib/mocha/examples/misc.rb deleted file mode 100644 index 9c9b9fb..0000000 --- a/build_lib/mocha/examples/misc.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'test/unit' -require 'mocha' - -class MiscExampleTest < Test::Unit::TestCase - - def test_mocking_a_class_method - product = Product.new - Product.expects(:find).with(1).returns(product) - assert_equal product, Product.find(1) - end - - def test_mocking_an_instance_method_on_a_real_object - product = Product.new - product.expects(:save).returns(true) - assert product.save - end - - def test_stubbing_instance_methods_on_real_objects - prices = [stub(:pence => 1000), stub(:pence => 2000)] - product = Product.new - product.stubs(:prices).returns(prices) - assert_equal [1000, 2000], product.prices.collect {|p| p.pence} - end - - def test_stubbing_an_instance_method_on_all_instances_of_a_class - Product.any_instance.stubs(:name).returns('stubbed_name') - product = Product.new - assert_equal 'stubbed_name', product.name - end - - def test_traditional_mocking - object = mock() - object.expects(:expected_method).with(:p1, :p2).returns(:result) - assert_equal :result, object.expected_method(:p1, :p2) - end - - def test_shortcuts - object = stub(:method1 => :result1, :method2 => :result2) - assert_equal :result1, object.method1 - assert_equal :result2, object.method2 - end - -end \ No newline at end of file diff --git a/build_lib/mocha/examples/mocha.rb b/build_lib/mocha/examples/mocha.rb deleted file mode 100644 index 6893ad0..0000000 --- a/build_lib/mocha/examples/mocha.rb +++ /dev/null @@ -1,25 +0,0 @@ -class Enterprise - - def initialize(dilithium) - @dilithium = dilithium - end - - def go(warp_factor) - warp_factor.times { @dilithium.nuke(:anti_matter) } - end - -end - -require 'test/unit' -require 'mocha' - -class EnterpriseTest < Test::Unit::TestCase - - def test_should_boldly_go - dilithium = mock() - dilithium.expects(:nuke).with(:anti_matter).at_least_once # auto-verified at end of test - enterprise = Enterprise.new(dilithium) - enterprise.go(2) - end - -end diff --git a/build_lib/mocha/examples/stubba.rb b/build_lib/mocha/examples/stubba.rb deleted file mode 100644 index 75cbd21..0000000 --- a/build_lib/mocha/examples/stubba.rb +++ /dev/null @@ -1,64 +0,0 @@ -class Order - - attr_accessor :shipped_on - - def total_cost - line_items.inject(0) { |total, line_item| total + line_item.price } + shipping_cost - end - - def total_weight - line_items.inject(0) { |total, line_item| total + line_item.weight } - end - - def shipping_cost - total_weight * 5 + 10 - end - - class << self - - def find_all - # Database.connection.execute('select * from orders... - end - - def number_shipped_since(date) - find_all.select { |order| order.shipped_on > date }.length - end - - def unshipped_value - find_all.inject(0) { |total, order| order.shipped_on ? total : total + order.total_cost } - end - - end - -end - -require 'test/unit' -require 'mocha' - -class OrderTest < Test::Unit::TestCase - - # illustrates stubbing instance method - def test_should_calculate_shipping_cost_based_on_total_weight - order = Order.new - order.stubs(:total_weight).returns(10) - assert_equal 60, order.shipping_cost - end - - # illustrates stubbing class method - def test_should_count_number_of_orders_shipped_after_specified_date - now = Time.now; week_in_secs = 7 * 24 * 60 * 60 - order_1 = Order.new; order_1.shipped_on = now - 1 * week_in_secs - order_2 = Order.new; order_2.shipped_on = now - 3 * week_in_secs - Order.stubs(:find_all).returns([order_1, order_2]) - assert_equal 1, Order.number_shipped_since(now - 2 * week_in_secs) - end - - # illustrates stubbing instance method for all instances of a class - def test_should_calculate_value_of_unshipped_orders - Order.stubs(:find_all).returns([Order.new, Order.new, Order.new]) - Order.any_instance.stubs(:shipped_on).returns(nil) - Order.any_instance.stubs(:total_cost).returns(10) - assert_equal 30, Order.unshipped_value - end - -end diff --git a/build_lib/mocha/lib/mocha.rb b/build_lib/mocha/lib/mocha.rb deleted file mode 100644 index d4fc7bc..0000000 --- a/build_lib/mocha/lib/mocha.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'mocha/options' -require 'mocha_standalone' -require 'mocha/configuration' -require 'mocha/integration' diff --git a/build_lib/mocha/lib/mocha/any_instance_method.rb b/build_lib/mocha/lib/mocha/any_instance_method.rb deleted file mode 100644 index 045caf0..0000000 --- a/build_lib/mocha/lib/mocha/any_instance_method.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'mocha/class_method' - -module Mocha - - class AnyInstanceMethod < ClassMethod - - def unstub - remove_new_method - restore_original_method - stubbee.any_instance.reset_mocha - end - - def mock - stubbee.any_instance.mocha - end - - def hide_original_method - if method_exists?(method) - begin - stubbee.send(:alias_method, hidden_method, method) - rescue NameError - # deal with nasties like ActiveRecord::Associations::AssociationProxy - end - end - end - - def define_new_method - stubbee.class_eval(%{ - def #{method}(*args, &block) - self.class.any_instance.mocha.method_missing(:#{method}, *args, &block) - end - }, __FILE__, __LINE__) - end - - def remove_new_method - stubbee.send(:remove_method, method) - end - - def restore_original_method - if method_exists?(hidden_method) - begin - stubbee.send(:alias_method, method, hidden_method) - stubbee.send(:remove_method, hidden_method) - rescue NameError - # deal with nasties like ActiveRecord::Associations::AssociationProxy - end - end - end - - def method_exists?(method) - return true if stubbee.public_instance_methods(false).include?(method) - return true if stubbee.protected_instance_methods(false).include?(method) - return true if stubbee.private_instance_methods(false).include?(method) - return false - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/api.rb b/build_lib/mocha/lib/mocha/api.rb deleted file mode 100644 index 863175b..0000000 --- a/build_lib/mocha/lib/mocha/api.rb +++ /dev/null @@ -1,173 +0,0 @@ -require 'mocha/parameter_matchers' -require 'mocha/mockery' -require 'mocha/sequence' - -module Mocha # :nodoc: - - # Methods added to Test::Unit::TestCase or equivalent. - module API - - include ParameterMatchers - - # :call-seq: mock(name, &block) -> mock object - # mock(expected_methods = {}, &block) -> mock object - # mock(name, expected_methods = {}, &block) -> mock object - # - # Creates a mock object. - # - # +name+ is a +String+ identifier for the mock object. - # - # +expected_methods+ is a +Hash+ with expected method name symbols as keys and corresponding return values as values. - # - # Note that (contrary to expectations set up by #stub) these expectations must be fulfilled during the test. - # def test_product - # product = mock('ipod_product', :manufacturer => 'ipod', :price => 100) - # assert_equal 'ipod', product.manufacturer - # assert_equal 100, product.price - # # an error will be raised unless both Product#manufacturer and Product#price have been called - # end - # - # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs. - # def test_product - # product = mock('ipod_product') do - # expects(:manufacturer).returns('ipod') - # expects(:price).returns(100) - # end - # assert_equal 'ipod', product.manufacturer - # assert_equal 100, product.price - # # an error will be raised unless both Product#manufacturer and Product#price have been called - # end - def mock(*arguments, &block) - name = arguments.shift if arguments.first.is_a?(String) - expectations = arguments.shift || {} - mock = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block) - mock.expects(expectations) - mock - end - - # :call-seq: stub(name, &block) -> mock object - # stub(stubbed_methods = {}, &block) -> mock object - # stub(name, stubbed_methods = {}, &block) -> mock object - # - # Creates a mock object. - # - # +name+ is a +String+ identifier for the mock object. - # - # +stubbed_methods+ is a +Hash+ with stubbed method name symbols as keys and corresponding return values as values. - # Note that (contrary to expectations set up by #mock) these expectations need not be fulfilled during the test. - # def test_product - # product = stub('ipod_product', :manufacturer => 'ipod', :price => 100) - # assert_equal 'ipod', product.manufacturer - # assert_equal 100, product.price - # # an error will not be raised even if Product#manufacturer and Product#price have not been called - # end - # - # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs. - # def test_product - # product = stub('ipod_product') do - # stubs(:manufacturer).returns('ipod') - # stubs(:price).returns(100) - # end - # assert_equal 'ipod', product.manufacturer - # assert_equal 100, product.price - # # an error will not be raised even if Product#manufacturer and Product#price have not been called - # end - def stub(*arguments, &block) - name = arguments.shift if arguments.first.is_a?(String) - expectations = arguments.shift || {} - stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block) - stub.stubs(expectations) - stub - end - - # :call-seq: stub_everything(name, &block) -> mock object - # stub_everything(stubbed_methods = {}, &block) -> mock object - # stub_everything(name, stubbed_methods = {}, &block) -> mock object - # - # Creates a mock object that accepts calls to any method. - # - # By default it will return +nil+ for any method call. - # - # +block+ is a block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs. - # - # +name+ and +stubbed_methods+ work in the same way as for #stub. - # def test_product - # product = stub_everything('ipod_product', :price => 100) - # assert_nil product.manufacturer - # assert_nil product.any_old_method - # assert_equal 100, product.price - # end - def stub_everything(*arguments, &block) - name = arguments.shift if arguments.first.is_a?(String) - expectations = arguments.shift || {} - stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block) - stub.stub_everything - stub.stubs(expectations) - stub - end - - # :call-seq: sequence(name) -> sequence - # - # Returns a new sequence that is used to constrain the order in which expectations can occur. - # - # Specify that an expected invocation must occur in within a named +sequence+ by using Expectation#in_sequence. - # - # See also Expectation#in_sequence. - # breakfast = sequence('breakfast') - # - # egg = mock('egg') - # egg.expects(:crack).in_sequence(breakfast) - # egg.expects(:fry).in_sequence(breakfast) - # egg.expects(:eat).in_sequence(breakfast) - def sequence(name) - Sequence.new(name) - end - - # :call-seq: states(name) -> state_machine - # - # Returns a new +state_machine+ that is used to constrain the order in which expectations can occur. - # - # Specify the initial +state+ of the +state_machine+ by using StateMachine#starts_as. - # - # Specify that an expected invocation should change the +state+ of the +state_machine+ by using Expectation#then. - # - # Specify that an expected invocation should be constrained to occur within a particular +state+ by using Expectation#when. - # - # A test can contain multiple +state_machines+. - # - # See also Expectation#then, Expectation#when and StateMachine. - # power = states('power').starts_as('off') - # - # radio = mock('radio') - # radio.expects(:switch_on).then(power.is('on')) - # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on')) - # radio.expects(:adjust_volume).with(+5).when(power.is('on')) - # radio.expects(:select_channel).with('BBC World Service').when(power.is('on')) - # radio.expects(:adjust_volume).with(-5).when(power.is('on')) - # radio.expects(:switch_off).then(power.is('off')) - def states(name) - Mockery.instance.new_state_machine(name) - end - - def mocha_setup # :nodoc: - end - - def mocha_verify(assertion_counter = nil) # :nodoc: - Mockery.instance.verify(assertion_counter) - end - - def mocha_teardown # :nodoc: - Mockery.instance.teardown - Mockery.reset_instance - end - - end - - def self.const_missing(name) - return super unless name == :Standalone - require 'mocha/deprecation' - Deprecation.warning "Mocha::Standalone has been renamed to Mocha::API" - return API - end - -end diff --git a/build_lib/mocha/lib/mocha/argument_iterator.rb b/build_lib/mocha/lib/mocha/argument_iterator.rb deleted file mode 100644 index ff58b48..0000000 --- a/build_lib/mocha/lib/mocha/argument_iterator.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Mocha - - class ArgumentIterator - - def initialize(argument) - @argument = argument - end - - def each(&block) - if @argument.is_a?(Hash) then - @argument.each do |method_name, return_value| - block.call(method_name, return_value) - end - else - block.call(@argument) - end - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/backtrace_filter.rb b/build_lib/mocha/lib/mocha/backtrace_filter.rb deleted file mode 100644 index 69215e7..0000000 --- a/build_lib/mocha/lib/mocha/backtrace_filter.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Mocha - - class BacktraceFilter - - LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR - - def initialize(lib_directory = LIB_DIRECTORY) - @lib_directory = lib_directory - end - - def filtered(backtrace) - backtrace.reject { |location| Regexp.new(@lib_directory).match(File.expand_path(location)) } - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/cardinality.rb b/build_lib/mocha/lib/mocha/cardinality.rb deleted file mode 100644 index b0c0ddf..0000000 --- a/build_lib/mocha/lib/mocha/cardinality.rb +++ /dev/null @@ -1,95 +0,0 @@ -module Mocha - - class Cardinality - - INFINITY = 1 / 0.0 - - class << self - - def exactly(count) - new(count, count) - end - - def at_least(count) - new(count, INFINITY) - end - - def at_most(count) - new(0, count) - end - - def times(range_or_count) - case range_or_count - when Range then new(range_or_count.first, range_or_count.last) - else new(range_or_count, range_or_count) - end - end - - end - - def initialize(required, maximum) - @required, @maximum = required, maximum - end - - def invocations_allowed?(invocation_count) - invocation_count < maximum - end - - def satisfied?(invocations_so_far) - invocations_so_far >= required - end - - def needs_verifying? - !allowed_any_number_of_times? - end - - def verified?(invocation_count) - (invocation_count >= required) && (invocation_count <= maximum) - end - - def allowed_any_number_of_times? - required == 0 && infinite?(maximum) - end - - def used?(invocation_count) - (invocation_count > 0) || (maximum == 0) - end - - def mocha_inspect - if allowed_any_number_of_times? - "allowed any number of times" - else - if required == 0 && maximum == 0 - "expected never" - elsif required == maximum - "expected exactly #{times(required)}" - elsif infinite?(maximum) - "expected at least #{times(required)}" - elsif required == 0 - "expected at most #{times(maximum)}" - else - "expected between #{required} and #{times(maximum)}" - end - end - end - - protected - - attr_reader :required, :maximum - - def times(number) - case number - when 0 then "no times" - when 1 then "once" - when 2 then "twice" - else "#{number} times" - end - end - - def infinite?(number) - number.respond_to?(:infinite?) && number.infinite? - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/central.rb b/build_lib/mocha/lib/mocha/central.rb deleted file mode 100644 index d46507b..0000000 --- a/build_lib/mocha/lib/mocha/central.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Mocha - - class Central - - attr_accessor :stubba_methods - - def initialize - self.stubba_methods = [] - end - - def stub(method) - unless stubba_methods.include?(method) - method.stub - stubba_methods.push(method) - end - end - - def unstub(method) - if stubba_methods.include?(method) - method.unstub - stubba_methods.delete(method) - end - end - - def unstub_all - while stubba_methods.any? do - unstub(stubba_methods.first) - end - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/change_state_side_effect.rb b/build_lib/mocha/lib/mocha/change_state_side_effect.rb deleted file mode 100644 index fe85d6e..0000000 --- a/build_lib/mocha/lib/mocha/change_state_side_effect.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Mocha - - class ChangeStateSideEffect - - def initialize(state) - @state = state - end - - def perform - @state.activate - end - - def mocha_inspect - "then #{@state.mocha_inspect}" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/class_method.rb b/build_lib/mocha/lib/mocha/class_method.rb deleted file mode 100644 index 853f505..0000000 --- a/build_lib/mocha/lib/mocha/class_method.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'mocha/metaclass' - -module Mocha - - class ClassMethod - - attr_reader :stubbee, :method - - def initialize(stubbee, method) - @stubbee = stubbee - @method = RUBY_VERSION < '1.9' ? method.to_s : method.to_sym - end - - def stub - hide_original_method - define_new_method - end - - def unstub - remove_new_method - restore_original_method - stubbee.reset_mocha - end - - def mock - stubbee.mocha - end - - def hide_original_method - if method_exists?(method) - begin - stubbee.__metaclass__.send(:alias_method, hidden_method, method) - rescue NameError - # deal with nasties like ActiveRecord::Associations::AssociationProxy - end - end - end - - def define_new_method - stubbee.__metaclass__.class_eval(%{ - def #{method}(*args, &block) - mocha.method_missing(:#{method}, *args, &block) - end - }, __FILE__, __LINE__) - end - - def remove_new_method - stubbee.__metaclass__.send(:remove_method, method) - end - - def restore_original_method - if method_exists?(hidden_method) - begin - stubbee.__metaclass__.send(:alias_method, method, hidden_method) - stubbee.__metaclass__.send(:remove_method, hidden_method) - rescue NameError - # deal with nasties like ActiveRecord::Associations::AssociationProxy - end - end - end - - def hidden_method - if RUBY_VERSION < '1.9' - method_name = method.to_s.gsub(/\W/) { |s| "_substituted_character_#{s[0]}_" } - else - method_name = method.to_s.gsub(/\W/) { |s| "_substituted_character_#{s.ord}_" } - end - hidden_method = "__stubba__#{method_name}__stubba__" - RUBY_VERSION < '1.9' ? hidden_method.to_s : hidden_method.to_sym - end - - def eql?(other) - return false unless (other.class == self.class) - (stubbee.object_id == other.stubbee.object_id) and (method == other.method) - end - - alias_method :==, :eql? - - def to_s - "#{stubbee}.#{method}" - end - - def method_exists?(method) - symbol = method.to_sym - metaclass = stubbee.__metaclass__ - metaclass.public_method_defined?(symbol) || metaclass.protected_method_defined?(symbol) || metaclass.private_method_defined?(symbol) - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/configuration.rb b/build_lib/mocha/lib/mocha/configuration.rb deleted file mode 100644 index 6c62342..0000000 --- a/build_lib/mocha/lib/mocha/configuration.rb +++ /dev/null @@ -1,79 +0,0 @@ -module Mocha # :nodoc: - - # Configuration settings - class Configuration - - DEFAULTS = { :stubbing_method_unnecessarily => :allow, :stubbing_method_on_non_mock_object => :allow, :stubbing_non_existent_method => :allow, :stubbing_non_public_method => :allow } - - class << self - - # :call-seq: allow(action, &block) - # - # Allow the specified action (as a symbol). - # The actions currently available are :stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method. - # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value. - def allow(action, &block) - change_config action, :allow, &block - end - - def allow?(action) # :nodoc: - configuration[action] == :allow - end - - # :call-seq: warn_when(action, &block) - # - # Warn if the specified action (as a symbol) is attempted. - # The actions currently available are :stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method. - # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value. - def warn_when(action, &block) - change_config action, :warn, &block - end - - def warn_when?(action) # :nodoc: - configuration[action] == :warn - end - - # :call-seq: prevent(action, &block) - # - # Raise a StubbingError if the specified action (as a symbol) is attempted. - # The actions currently available are :stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method. - # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value. - def prevent(action, &block) - change_config action, :prevent, &block - end - - def prevent?(action) # :nodoc: - configuration[action] == :prevent - end - - def reset_configuration # :nodoc: - @configuration = nil - end - - private - - def configuration # :nodoc: - @configuration ||= DEFAULTS.dup - end - - def change_config(action, new_value, &block) # :nodoc: - if block_given? - temporarily_change_config action, new_value, &block - else - configuration[action] = new_value - end - end - - def temporarily_change_config(action, new_value, &block) # :nodoc: - original_value = configuration[action] - configuration[action] = new_value - yield - ensure - configuration[action] = original_value - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/deprecation.rb b/build_lib/mocha/lib/mocha/deprecation.rb deleted file mode 100644 index 7448510..0000000 --- a/build_lib/mocha/lib/mocha/deprecation.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Mocha - - class Deprecation - - class << self - - attr_accessor :mode, :messages - - def warning(message) - @messages << message - $stderr.puts "Mocha deprecation warning: #{message}" unless mode == :disabled - $stderr.puts caller.join("\n ") if mode == :debug - end - - end - - self.mode = :enabled - self.messages = [] - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/exception_raiser.rb b/build_lib/mocha/lib/mocha/exception_raiser.rb deleted file mode 100644 index 9e009cb..0000000 --- a/build_lib/mocha/lib/mocha/exception_raiser.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Mocha # :nodoc: - - class ExceptionRaiser # :nodoc: - - def initialize(exception, message) - @exception, @message = exception, message - end - - def evaluate - raise @exception, @exception.to_s if @exception.is_a?(Module) && @exception.ancestors.include?(Interrupt) - raise @exception, @message if @message - raise @exception - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/expectation.rb b/build_lib/mocha/lib/mocha/expectation.rb deleted file mode 100644 index 11b4e6d..0000000 --- a/build_lib/mocha/lib/mocha/expectation.rb +++ /dev/null @@ -1,479 +0,0 @@ -require 'mocha/method_matcher' -require 'mocha/parameters_matcher' -require 'mocha/expectation_error' -require 'mocha/return_values' -require 'mocha/exception_raiser' -require 'mocha/yield_parameters' -require 'mocha/is_a' -require 'mocha/in_state_ordering_constraint' -require 'mocha/change_state_side_effect' -require 'mocha/cardinality' - -module Mocha # :nodoc: - - # Methods on expectations returned from Mock#expects, Mock#stubs, Object#expects and Object#stubs. - class Expectation - - # :call-seq: times(range) -> expectation - # - # Modifies expectation so that the number of calls to the expected method must be within a specific +range+. - # - # +range+ can be specified as an exact integer or as a range of integers - # object = mock() - # object.expects(:expected_method).times(3) - # 3.times { object.expected_method } - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).times(3) - # 2.times { object.expected_method } - # # => verify fails - # - # object = mock() - # object.expects(:expected_method).times(2..4) - # 3.times { object.expected_method } - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).times(2..4) - # object.expected_method - # # => verify fails - def times(range) - @cardinality = Cardinality.times(range) - self - end - - # :call-seq: twice() -> expectation - # - # Modifies expectation so that the expected method must be called exactly twice. - # object = mock() - # object.expects(:expected_method).twice - # object.expected_method - # object.expected_method - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).twice - # object.expected_method - # object.expected_method - # object.expected_method - # # => verify fails - # - # object = mock() - # object.expects(:expected_method).twice - # object.expected_method - # # => verify fails - def twice - @cardinality = Cardinality.exactly(2) - self - end - - # :call-seq: once() -> expectation - # - # Modifies expectation so that the expected method must be called exactly once. - # Note that this is the default behaviour for an expectation, but you may wish to use it for clarity/emphasis. - # object = mock() - # object.expects(:expected_method).once - # object.expected_method - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).once - # object.expected_method - # object.expected_method - # # => verify fails - # - # object = mock() - # object.expects(:expected_method).once - # # => verify fails - def once - @cardinality = Cardinality.exactly(1) - self - end - - # :call-seq: never() -> expectation - # - # Modifies expectation so that the expected method must never be called. - # object = mock() - # object.expects(:expected_method).never - # object.expected_method - # # => verify fails - # - # object = mock() - # object.expects(:expected_method).never - # # => verify succeeds - def never - @cardinality = Cardinality.exactly(0) - self - end - - # :call-seq: at_least(minimum_number_of_times) -> expectation - # - # Modifies expectation so that the expected method must be called at least a +minimum_number_of_times+. - # object = mock() - # object.expects(:expected_method).at_least(2) - # 3.times { object.expected_method } - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).at_least(2) - # object.expected_method - # # => verify fails - def at_least(minimum_number_of_times) - @cardinality = Cardinality.at_least(minimum_number_of_times) - self - end - - # :call-seq: at_least_once() -> expectation - # - # Modifies expectation so that the expected method must be called at least once. - # object = mock() - # object.expects(:expected_method).at_least_once - # object.expected_method - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).at_least_once - # # => verify fails - def at_least_once - at_least(1) - self - end - - # :call-seq: at_most(maximum_number_of_times) -> expectation - # - # Modifies expectation so that the expected method must be called at most a +maximum_number_of_times+. - # object = mock() - # object.expects(:expected_method).at_most(2) - # 2.times { object.expected_method } - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).at_most(2) - # 3.times { object.expected_method } - # # => verify fails - def at_most(maximum_number_of_times) - @cardinality = Cardinality.at_most(maximum_number_of_times) - self - end - - # :call-seq: at_most_once() -> expectation - # - # Modifies expectation so that the expected method must be called at most once. - # object = mock() - # object.expects(:expected_method).at_most_once - # object.expected_method - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).at_most_once - # 2.times { object.expected_method } - # # => verify fails - def at_most_once() - at_most(1) - self - end - - # :call-seq: with(*expected_parameters, &matching_block) -> expectation - # - # Modifies expectation so that the expected method must be called with +expected_parameters+. - # object = mock() - # object.expects(:expected_method).with(:param1, :param2) - # object.expected_method(:param1, :param2) - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).with(:param1, :param2) - # object.expected_method(:param3) - # # => verify fails - # May be used with parameter matchers in Mocha::ParameterMatchers. - # - # If a +matching_block+ is given, the block is called with the parameters passed to the expected method. - # The expectation is matched if the block evaluates to +true+. - # object = mock() - # object.expects(:expected_method).with() { |value| value % 4 == 0 } - # object.expected_method(16) - # # => verify succeeds - # - # object = mock() - # object.expects(:expected_method).with() { |value| value % 4 == 0 } - # object.expected_method(17) - # # => verify fails - def with(*expected_parameters, &matching_block) - @parameters_matcher = ParametersMatcher.new(expected_parameters, &matching_block) - self - end - - # :call-seq: yields(*parameters) -> expectation - # - # Modifies expectation so that when the expected method is called, it yields with the specified +parameters+. - # object = mock() - # object.expects(:expected_method).yields('result') - # yielded_value = nil - # object.expected_method { |value| yielded_value = value } - # yielded_value # => 'result' - # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then. - # object = mock() - # object.stubs(:expected_method).yields(1).then.yields(2) - # yielded_values_from_first_invocation = [] - # yielded_values_from_second_invocation = [] - # object.expected_method { |value| yielded_values_from_first_invocation << value } # first invocation - # object.expected_method { |value| yielded_values_from_second_invocation << value } # second invocation - # yielded_values_from_first_invocation # => [1] - # yielded_values_from_second_invocation # => [2] - def yields(*parameters) - @yield_parameters.add(*parameters) - self - end - - # :call-seq: multiple_yields(*parameter_groups) -> expectation - # - # Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified +parameter_groups+. - # object = mock() - # object.expects(:expected_method).multiple_yields(['result_1', 'result_2'], ['result_3']) - # yielded_values = [] - # object.expected_method { |*values| yielded_values << values } - # yielded_values # => [['result_1', 'result_2'], ['result_3]] - # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then. - # object = mock() - # object.stubs(:expected_method).multiple_yields([1, 2], [3]).then.multiple_yields([4], [5, 6]) - # yielded_values_from_first_invocation = [] - # yielded_values_from_second_invocation = [] - # object.expected_method { |*values| yielded_values_from_first_invocation << values } # first invocation - # object.expected_method { |*values| yielded_values_from_second_invocation << values } # second invocation - # yielded_values_from_first_invocation # => [[1, 2], [3]] - # yielded_values_from_second_invocation # => [[4], [5, 6]] - def multiple_yields(*parameter_groups) - @yield_parameters.multiple_add(*parameter_groups) - self - end - - # :call-seq: returns(value) -> expectation - # returns(*values) -> expectation - # - # Modifies expectation so that when the expected method is called, it returns the specified +value+. - # object = mock() - # object.stubs(:stubbed_method).returns('result') - # object.stubbed_method # => 'result' - # object.stubbed_method # => 'result' - # If multiple +values+ are given, these are returned in turn on consecutive calls to the method. - # object = mock() - # object.stubs(:stubbed_method).returns(1, 2) - # object.stubbed_method # => 1 - # object.stubbed_method # => 2 - # May be called multiple times on the same expectation. Also see Expectation#then. - # object = mock() - # object.stubs(:expected_method).returns(1, 2).then.returns(3) - # object.expected_method # => 1 - # object.expected_method # => 2 - # object.expected_method # => 3 - # May be called in conjunction with Expectation#raises on the same expectation. - # object = mock() - # object.stubs(:expected_method).returns(1, 2).then.raises(Exception) - # object.expected_method # => 1 - # object.expected_method # => 2 - # object.expected_method # => raises exception of class Exception1 - # Note that in Ruby a method returning multiple values is exactly equivalent to a method returning an Array of those values. - # object = mock() - # object.stubs(:expected_method).returns([1, 2]) - # x, y = object.expected_method - # x # => 1 - # y # => 2 - def returns(*values) - @return_values += ReturnValues.build(*values) - self - end - - # :call-seq: raises(exception = RuntimeError, message = nil) -> expectation - # - # Modifies expectation so that when the expected method is called, it raises the specified +exception+ with the specified +message+ i.e. calls Kernel#raise(exception, message). - # object = mock() - # object.expects(:expected_method).raises(Exception, 'message') - # object.expected_method # => raises exception of class Exception and with message 'message' - # Note that if you have a custom exception class with extra constructor parameters, you can pass in an instance of the exception (just as you can for Kernel#raise). - # object = mock() - # object.expects(:expected_method).raises(MyException.new('message', 1, 2, 3)) - # object.expected_method # => raises the specified instance of MyException - # May be called multiple times on the same expectation. Also see Expectation#then. - # object = mock() - # object.stubs(:expected_method).raises(Exception1).then.raises(Exception2) - # object.expected_method # => raises exception of class Exception1 - # object.expected_method # => raises exception of class Exception2 - # May be called in conjunction with Expectation#returns on the same expectation. - # object = mock() - # object.stubs(:expected_method).raises(Exception).then.returns(2, 3) - # object.expected_method # => raises exception of class Exception1 - # object.expected_method # => 2 - # object.expected_method # => 3 - def raises(exception = RuntimeError, message = nil) - @return_values += ReturnValues.new(ExceptionRaiser.new(exception, message)) - self - end - - # :call-seq: then() -> expectation - # then(state_machine.is(state)) -> expectation - # - # then() is used as syntactic sugar to improve readability. It has no effect on state of the expectation. - # object = mock() - # object.stubs(:expected_method).returns(1, 2).then.raises(Exception).then.returns(4) - # object.expected_method # => 1 - # object.expected_method # => 2 - # object.expected_method # => raises exception of class Exception - # object.expected_method # => 4 - # - # then(state_machine.is(state)) is used to change the +state_machine+ to the specified +state+ when the invocation occurs. - # - # See also API#states, StateMachine and Expectation#when. - # power = states('power').starts_as('off') - # - # radio = mock('radio') - # radio.expects(:switch_on).then(power.is('on')) - # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on')) - # radio.expects(:adjust_volume).with(+5).when(power.is('on')) - # radio.expects(:select_channel).with('BBC World Service').when(power.is('on')) - # radio.expects(:adjust_volume).with(-5).when(power.is('on')) - # radio.expects(:switch_off).then(power.is('off')) - def then(*parameters) - if parameters.length == 1 - state = parameters.first - add_side_effect(ChangeStateSideEffect.new(state)) - end - self - end - - # :call-seq: when(state_machine.is(state)) -> exception - # - # Constrains the expectation to occur only when the +state_machine+ is in the named +state+. - # - # See also API#states, StateMachine#starts_as and Expectation#then. - # power = states('power').starts_as('off') - # - # radio = mock('radio') - # radio.expects(:switch_on).then(power.is('on')) - # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on')) - # radio.expects(:adjust_volume).with(+5).when(power.is('on')) - # radio.expects(:select_channel).with('BBC World Service').when(power.is('on')) - # radio.expects(:adjust_volume).with(-5).when(power.is('on')) - # radio.expects(:switch_off).then(power.is('off')) - def when(state_predicate) - add_ordering_constraint(InStateOrderingConstraint.new(state_predicate)) - self - end - - # :call-seq: in_sequence(*sequences) -> expectation - # - # Constrains this expectation so that it must be invoked at the current point in the sequence. - # - # To expect a sequence of invocations, write the expectations in order and add the in_sequence(sequence) clause to each one. - # - # Expectations in a sequence can have any invocation count. - # - # If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the sequence. - # - # See also API#sequence. - # breakfast = sequence('breakfast') - # - # egg = mock('egg') - # egg.expects(:crack).in_sequence(breakfast) - # egg.expects(:fry).in_sequence(breakfast) - # egg.expects(:eat).in_sequence(breakfast) - def in_sequence(*sequences) - sequences.each { |sequence| add_in_sequence_ordering_constraint(sequence) } - self - end - - # :stopdoc: - - attr_reader :backtrace - - def initialize(mock, expected_method_name, backtrace = nil) - @mock = mock - @method_matcher = MethodMatcher.new(expected_method_name.to_sym) - @parameters_matcher = ParametersMatcher.new - @ordering_constraints = [] - @side_effects = [] - @cardinality, @invocation_count = Cardinality.exactly(1), 0 - @return_values = ReturnValues.new - @yield_parameters = YieldParameters.new - @backtrace = backtrace || caller - end - - def add_ordering_constraint(ordering_constraint) - @ordering_constraints << ordering_constraint - end - - def add_in_sequence_ordering_constraint(sequence) - sequence.constrain_as_next_in_sequence(self) - end - - def add_side_effect(side_effect) - @side_effects << side_effect - end - - def perform_side_effects - @side_effects.each { |side_effect| side_effect.perform } - end - - def in_correct_order? - @ordering_constraints.all? { |ordering_constraint| ordering_constraint.allows_invocation_now? } - end - - def matches_method?(method_name) - @method_matcher.match?(method_name) - end - - def match?(actual_method_name, *actual_parameters) - @method_matcher.match?(actual_method_name) && @parameters_matcher.match?(actual_parameters) && in_correct_order? - end - - def invocations_allowed? - @cardinality.invocations_allowed?(@invocation_count) - end - - def satisfied? - @cardinality.satisfied?(@invocation_count) - end - - def invoke - @invocation_count += 1 - perform_side_effects() - if block_given? then - @yield_parameters.next_invocation.each do |yield_parameters| - yield(*yield_parameters) - end - end - @return_values.next - end - - def verified?(assertion_counter = nil) - assertion_counter.increment if assertion_counter && @cardinality.needs_verifying? - @cardinality.verified?(@invocation_count) - end - - def used? - @cardinality.used?(@invocation_count) - end - - def mocha_inspect - message = "#{@cardinality.mocha_inspect}, " - message << case @invocation_count - when 0 then "not yet invoked" - when 1 then "already invoked once" - when 2 then "already invoked twice" - else "already invoked #{@invocation_count} times" - end - message << ": " - message << method_signature - message << "; #{@ordering_constraints.map { |oc| oc.mocha_inspect }.join("; ")}" unless @ordering_constraints.empty? - message - end - - def method_signature - "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}" - end - - # :startdoc: - - end - -end diff --git a/build_lib/mocha/lib/mocha/expectation_error.rb b/build_lib/mocha/lib/mocha/expectation_error.rb deleted file mode 100644 index f05544b..0000000 --- a/build_lib/mocha/lib/mocha/expectation_error.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'mocha/backtrace_filter' - -module Mocha - - class ExpectationError < Exception - - def initialize(message = nil, backtrace = []) - super(message) - filter = BacktraceFilter.new - set_backtrace(filter.filtered(backtrace)) - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/expectation_list.rb b/build_lib/mocha/lib/mocha/expectation_list.rb deleted file mode 100644 index 788d07c..0000000 --- a/build_lib/mocha/lib/mocha/expectation_list.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Mocha # :nodoc: - - class ExpectationList - - def initialize - @expectations = [] - end - - def add(expectation) - @expectations.unshift(expectation) - expectation - end - - def matches_method?(method_name) - @expectations.any? { |expectation| expectation.matches_method?(method_name) } - end - - def match(method_name, *arguments) - matching_expectations(method_name, *arguments).first - end - - def match_allowing_invocation(method_name, *arguments) - matching_expectations(method_name, *arguments).detect { |e| e.invocations_allowed? } - end - - def verified?(assertion_counter = nil) - @expectations.all? { |expectation| expectation.verified?(assertion_counter) } - end - - def to_a - @expectations - end - - def to_set - @expectations.to_set - end - - def length - @expectations.length - end - - private - - def matching_expectations(method_name, *arguments) - @expectations.select { |e| e.match?(method_name, *arguments) } - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/in_state_ordering_constraint.rb b/build_lib/mocha/lib/mocha/in_state_ordering_constraint.rb deleted file mode 100644 index 1ff0898..0000000 --- a/build_lib/mocha/lib/mocha/in_state_ordering_constraint.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Mocha - - class InStateOrderingConstraint - - def initialize(state_predicate) - @state_predicate = state_predicate - end - - def allows_invocation_now? - @state_predicate.active? - end - - def mocha_inspect - "when #{@state_predicate.mocha_inspect}" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/inspect.rb b/build_lib/mocha/lib/mocha/inspect.rb deleted file mode 100644 index bca613d..0000000 --- a/build_lib/mocha/lib/mocha/inspect.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'date' - -module Mocha - - module ObjectMethods - def mocha_inspect - address = self.__id__ * 2 - address += 0x100000000 if address < 0 - inspect =~ /#" : inspect - end - end - - module StringMethods - def mocha_inspect - inspect.gsub(/\"/, "'") - end - end - - module ArrayMethods - def mocha_inspect - "[#{collect { |member| member.mocha_inspect }.join(', ')}]" - end - end - - module HashMethods - def mocha_inspect - "{#{collect { |key, value| "#{key.mocha_inspect} => #{value.mocha_inspect}" }.join(', ')}}" - end - end - - module TimeMethods - def mocha_inspect - "#{inspect} (#{to_f} secs)" - end - end - - module DateMethods - def mocha_inspect - to_s - end - end - -end - -class Object - include Mocha::ObjectMethods -end - -class String - include Mocha::StringMethods -end - -class Array - include Mocha::ArrayMethods -end - -class Hash - include Mocha::HashMethods -end - -class Time - include Mocha::TimeMethods -end - -class Date - include Mocha::DateMethods -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/instance_method.rb b/build_lib/mocha/lib/mocha/instance_method.rb deleted file mode 100644 index 49669ae..0000000 --- a/build_lib/mocha/lib/mocha/instance_method.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'mocha/class_method' - -module Mocha - - class InstanceMethod < ClassMethod - - def method_exists?(method) - return true if stubbee.public_methods(false).include?(method) - return true if stubbee.protected_methods(false).include?(method) - return true if stubbee.private_methods(false).include?(method) - return false - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/integration.rb b/build_lib/mocha/lib/mocha/integration.rb deleted file mode 100644 index cacb75c..0000000 --- a/build_lib/mocha/lib/mocha/integration.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Mocha - - module Integration - - class << self - - def monkey_patches - patches = [] - if test_unit_testcase_defined? && !test_unit_testcase_inherits_from_miniunit_testcase? - patches << 'mocha/integration/test_unit' - end - if mini_unit_testcase_defined? - patches << 'mocha/integration/mini_test' - end - patches - end - - def test_unit_testcase_defined? - defined?(Test) && defined?(Test::Unit) && defined?(Test::Unit::TestCase) - end - - def mini_unit_testcase_defined? - defined?(MiniTest) && defined?(MiniTest::Unit) && defined?(MiniTest::Unit::TestCase) - end - - def test_unit_testcase_inherits_from_miniunit_testcase? - test_unit_testcase_defined? && mini_unit_testcase_defined? && Test::Unit::TestCase.ancestors.include?(MiniTest::Unit::TestCase) - end - - end - - end - -end - -Mocha::Integration.monkey_patches.each do |patch| - require patch -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test.rb b/build_lib/mocha/lib/mocha/integration/mini_test.rb deleted file mode 100644 index a684148..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'mocha/api' - -if !MiniTest::Unit::TestCase.ancestors.include?(Mocha::API) - - require 'mocha/integration/mini_test/exception_translation' - require 'mocha/integration/mini_test/version_13' - require 'mocha/integration/mini_test/version_140' - require 'mocha/integration/mini_test/version_141' - require 'mocha/integration/mini_test/version_142_and_above' - - module MiniTest - class Unit - class TestCase - - include Mocha::API - - alias_method :run_before_mocha, :run - remove_method :run - - mini_test_version = begin - MiniTest::Unit::VERSION - rescue LoadError - 'unknown' - end - - $stderr.puts "Detected MiniTest version: #{mini_test_version}" if $options['debug'] - - if (mini_test_version >= '1.3.0') && (mini_test_version <= '1.3.1') - include Mocha::Integration::MiniTest::Version13 - elsif (mini_test_version == '1.4.0') - include Mocha::Integration::MiniTest::Version140 - elsif (mini_test_version == '1.4.1') - include Mocha::Integration::MiniTest::Version141 - elsif (mini_test_version >= '1.4.2') && (mini_test_version <= '1.6.0') - include Mocha::Integration::MiniTest::Version142AndAbove - elsif (mini_test_version > '1.6.0') - $stderr.puts "*** MiniTest integration has not been verified but patching anyway ***" if $options['debug'] - include Mocha::Integration::MiniTest::Version142AndAbove - else - $stderr.puts "*** No Mocha integration for MiniTest version ***" if $options['debug'] - end - - end - end - end -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/assertion_counter.rb b/build_lib/mocha/lib/mocha/integration/mini_test/assertion_counter.rb deleted file mode 100644 index c303d6a..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/assertion_counter.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Mocha - - module Integration - - module MiniTest - - class AssertionCounter - - def initialize(test_case) - @test_case = test_case - end - - def increment - @test_case._assertions += 1 - end - - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/exception_translation.rb b/build_lib/mocha/lib/mocha/integration/mini_test/exception_translation.rb deleted file mode 100644 index e8993c0..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/exception_translation.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module MiniTest - - def self.translate(exception) - return exception unless exception.kind_of?(::Mocha::ExpectationError) - translated_exception = ::MiniTest::Assertion.new(exception.message) - translated_exception.set_backtrace(exception.backtrace) - translated_exception - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/version_13.rb b/build_lib/mocha/lib/mocha/integration/mini_test/version_13.rb deleted file mode 100644 index 2301c11..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/version_13.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'mocha/integration/mini_test/assertion_counter' - -module Mocha - - module Integration - - module MiniTest - - module Version13 - def self.included(mod) - $stderr.puts "Monkey patching MiniTest v1.3" if $options['debug'] - end - def run runner - assertion_counter = AssertionCounter.new(self) - result = '.' - begin - begin - @passed = nil - self.setup - self.__send__ self.name - mocha_verify(assertion_counter) - @passed = true - rescue Exception => e - @passed = false - result = runner.puke(self.class, self.name, Mocha::Integration::MiniTest.translate(e)) - ensure - begin - self.teardown - rescue Exception => e - result = runner.puke(self.class, self.name, Mocha::Integration::MiniTest.translate(e)) - end - end - ensure - mocha_teardown - end - result - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/version_140.rb b/build_lib/mocha/lib/mocha/integration/mini_test/version_140.rb deleted file mode 100644 index 6862e65..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/version_140.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'mocha/integration/mini_test/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module MiniTest - - module Version140 - def self.included(mod) - $stderr.puts "Monkey patching MiniTest v1.4.0" if $options['debug'] - end - def run runner - assertion_counter = AssertionCounter.new(self) - result = '.' - begin - begin - @passed = nil - self.setup - self.__send__ self.__name__ - mocha_verify(assertion_counter) - @passed = true - rescue Exception => e - @passed = false - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - ensure - begin - self.teardown - rescue Exception => e - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - end - end - ensure - mocha_teardown - end - result - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/version_141.rb b/build_lib/mocha/lib/mocha/integration/mini_test/version_141.rb deleted file mode 100644 index 7966b03..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/version_141.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'mocha/integration/mini_test/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module MiniTest - - module Version141 - def self.included(mod) - $stderr.puts "Monkey patching MiniTest v1.4.1" - end - def run runner - trap 'INFO' do - warn '%s#%s %.2fs' % [self.class, self.__name__, - (Time.now - runner.start_time)] - runner.status $stderr - end - - assertion_counter = AssertionCounter.new(self) - result = '.' - begin - begin - @passed = nil - self.setup - self.__send__ self.__name__ - mocha_verify(assertion_counter) - @passed = true - rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS - raise - rescue Exception => e - @passed = false - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - ensure - begin - self.teardown - rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS - raise - rescue Exception => e - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - end - trap 'INFO', 'DEFAULT' - end - ensure - mocha_teardown - end - result - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/mini_test/version_142_and_above.rb b/build_lib/mocha/lib/mocha/integration/mini_test/version_142_and_above.rb deleted file mode 100644 index 169a265..0000000 --- a/build_lib/mocha/lib/mocha/integration/mini_test/version_142_and_above.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'mocha/integration/mini_test/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module MiniTest - - module Version142AndAbove - def self.included(mod) - $stderr.puts "Monkey patching MiniTest >= v1.4.2" if $options['debug'] - end - def run runner - trap 'INFO' do - warn '%s#%s %.2fs' % [self.class, self.__name__, - (Time.now - runner.start_time)] - runner.status $stderr - end if ::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL - - assertion_counter = AssertionCounter.new(self) - result = '.' - begin - begin - @passed = nil - self.setup - self.__send__ self.__name__ - mocha_verify(assertion_counter) - @passed = true - rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS - raise - rescue Exception => e - @passed = false - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - ensure - begin - self.teardown - rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS - raise - rescue Exception => e - result = runner.puke(self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)) - end - trap 'INFO', 'DEFAULT' if ::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL - end - ensure - mocha_teardown - end - result - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/test_unit.rb b/build_lib/mocha/lib/mocha/integration/test_unit.rb deleted file mode 100644 index fa46da3..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'mocha/api' - -if !Test::Unit::TestCase.ancestors.include?(Mocha::API) - - require 'mocha/integration/test_unit/gem_version_200' - require 'mocha/integration/test_unit/gem_version_201_to_202' - require 'mocha/integration/test_unit/gem_version_203_to_209' - require 'mocha/integration/test_unit/ruby_version_185_and_below' - require 'mocha/integration/test_unit/ruby_version_186_and_above' - - module Test - module Unit - class TestCase - - include Mocha::API - - alias_method :run_before_mocha, :run - remove_method :run - - test_unit_version = begin - load 'test/unit/version.rb' - Test::Unit::VERSION - rescue LoadError - '1.x' - end - - if $options['debug'] - $stderr.puts "Detected Ruby version: #{RUBY_VERSION}" - $stderr.puts "Detected Test::Unit version: #{test_unit_version}" - end - - if (test_unit_version == '1.x') || (test_unit_version == '1.2.3') - if RUBY_VERSION < '1.8.6' - include Mocha::Integration::TestUnit::RubyVersion185AndBelow - else - include Mocha::Integration::TestUnit::RubyVersion186AndAbove - end - elsif (test_unit_version == '2.0.0') - include Mocha::Integration::TestUnit::GemVersion200 - elsif (test_unit_version >= '2.0.1') && (test_unit_version <= '2.0.2') - include Mocha::Integration::TestUnit::GemVersion201To202 - elsif (test_unit_version >= '2.0.3') && (test_unit_version <= '2.0.9') - include Mocha::Integration::TestUnit::GemVersion203To209 - elsif (test_unit_version > '2.0.9') - $stderr.puts "*** Test::Unit integration has not been verified but patching anyway ***" if $options['debug'] - include Mocha::Integration::TestUnit::GemVersion203To209 - else - $stderr.puts "*** No Mocha integration for Test::Unit version ***" if $options['debug'] - end - - end - end - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/assertion_counter.rb b/build_lib/mocha/lib/mocha/integration/test_unit/assertion_counter.rb deleted file mode 100644 index 61c4779..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/assertion_counter.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Mocha - - module Integration - - module TestUnit - - class AssertionCounter - - def initialize(test_result) - @test_result = test_result - end - - def increment - @test_result.add_assertion - end - - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_200.rb b/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_200.rb deleted file mode 100644 index ca470be..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_200.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'test/unit/testcase' -require 'mocha/integration/test_unit/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module TestUnit - - module GemVersion200 - def self.included(mod) - $stderr.puts "Monkey patching Test::Unit gem v2.0.0" if $options['debug'] - end - def run(result) - assertion_counter = AssertionCounter.new(result) - begin - @_result = result - yield(Test::Unit::TestCase::STARTED, name) - begin - begin - run_setup - __send__(@method_name) - mocha_verify(assertion_counter) - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Exception - @interrupted = true - raise unless handle_exception($!) - ensure - begin - run_teardown - rescue Exception - raise unless handle_exception($!) - end - end - ensure - mocha_teardown - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - ensure - @_result = nil - end - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_201_to_202.rb b/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_201_to_202.rb deleted file mode 100644 index 8ac7fee..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'test/unit/testcase' -require 'mocha/integration/test_unit/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module TestUnit - - module GemVersion201To202 - def self.included(mod) - $stderr.puts "Monkey patching Test::Unit gem >= v2.0.1 and <= v2.0.2" if $options['debug'] - end - def run(result) - assertion_counter = AssertionCounter.new(result) - begin - @_result = result - yield(Test::Unit::TestCase::STARTED, name) - begin - begin - run_setup - run_test - mocha_verify(assertion_counter) - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Exception - @interrupted = true - raise unless handle_exception($!) - ensure - begin - run_teardown - rescue Exception - raise unless handle_exception($!) - end - end - ensure - mocha_teardown - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - ensure - @_result = nil - end - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_203_to_209.rb b/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_203_to_209.rb deleted file mode 100644 index bd68b10..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/gem_version_203_to_209.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'test/unit/testcase' -require 'mocha/integration/test_unit/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module TestUnit - - module GemVersion203To209 - def self.included(mod) - $stderr.puts "Monkey patching Test::Unit gem >= v2.0.3 and <= v2.0.9" if $options['debug'] - end - def run(result) - assertion_counter = AssertionCounter.new(result) - begin - @_result = result - yield(Test::Unit::TestCase::STARTED, name) - begin - begin - run_setup - run_test - mocha_verify(assertion_counter) - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Exception - @interrupted = true - raise unless handle_exception($!) - ensure - begin - run_teardown - rescue Exception - raise unless handle_exception($!) - end - end - ensure - mocha_teardown - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - ensure - # @_result = nil # For test-spec's after_all :< - end - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb b/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb deleted file mode 100644 index 46deb8c..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'test/unit/testcase' -require 'mocha/integration/test_unit/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module TestUnit - - module RubyVersion185AndBelow - def self.included(mod) - $stderr.puts "Monkey patching Test::Unit for Ruby <= v1.8.5" if $options['debug'] - end - def run(result) - assertion_counter = AssertionCounter.new(result) - yield(Test::Unit::TestCase::STARTED, name) - @_result = result - begin - begin - setup - __send__(@method_name) - mocha_verify(assertion_counter) - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue StandardError, ScriptError - add_error($!) - ensure - begin - teardown - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue StandardError, ScriptError - add_error($!) - end - end - ensure - mocha_teardown - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb b/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb deleted file mode 100644 index aad0343..0000000 --- a/build_lib/mocha/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'test/unit/testcase' -require 'mocha/integration/test_unit/assertion_counter' -require 'mocha/expectation_error' - -module Mocha - - module Integration - - module TestUnit - - module RubyVersion186AndAbove - def self.included(mod) - $stderr.puts "Monkey patching Test::Unit for Ruby >= v1.8.6" if $options['debug'] - end - def run(result) - assertion_counter = AssertionCounter.new(result) - yield(Test::Unit::TestCase::STARTED, name) - @_result = result - begin - begin - setup - __send__(@method_name) - mocha_verify(assertion_counter) - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue Exception - raise if Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS.include? $!.class - add_error($!) - ensure - begin - teardown - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue Exception - raise if Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS.include? $!.class - add_error($!) - end - end - ensure - mocha_teardown - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - end - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/is_a.rb b/build_lib/mocha/lib/mocha/is_a.rb deleted file mode 100644 index ee23c86..0000000 --- a/build_lib/mocha/lib/mocha/is_a.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Object - - # :stopdoc: - - alias_method :__is_a__, :is_a? - - # :startdoc: - -end diff --git a/build_lib/mocha/lib/mocha/logger.rb b/build_lib/mocha/lib/mocha/logger.rb deleted file mode 100644 index 9f09300..0000000 --- a/build_lib/mocha/lib/mocha/logger.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Mocha - - class Logger - - def initialize(io) - @io = io - end - - def warn(message) - @io.puts "WARNING: #{message}" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/metaclass.rb b/build_lib/mocha/lib/mocha/metaclass.rb deleted file mode 100644 index 3c3680d..0000000 --- a/build_lib/mocha/lib/mocha/metaclass.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Mocha - - module ObjectMethods - def __metaclass__ - class << self; self; end - end - end - -end - -class Object - include Mocha::ObjectMethods -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/method_matcher.rb b/build_lib/mocha/lib/mocha/method_matcher.rb deleted file mode 100644 index 6ce5f6d..0000000 --- a/build_lib/mocha/lib/mocha/method_matcher.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Mocha - - class MethodMatcher - - attr_reader :expected_method_name - - def initialize(expected_method_name) - @expected_method_name = expected_method_name - end - - def match?(actual_method_name) - @expected_method_name == actual_method_name - end - - def mocha_inspect - "#{@expected_method_name}" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/mock.rb b/build_lib/mocha/lib/mocha/mock.rb deleted file mode 100644 index 42f75e3..0000000 --- a/build_lib/mocha/lib/mocha/mock.rb +++ /dev/null @@ -1,200 +0,0 @@ -require 'mocha/expectation' -require 'mocha/expectation_list' -require 'mocha/metaclass' -require 'mocha/names' -require 'mocha/method_matcher' -require 'mocha/parameters_matcher' -require 'mocha/unexpected_invocation' -require 'mocha/argument_iterator' -require 'mocha/mockery' - -module Mocha # :nodoc: - - # Traditional mock object. - # - # Methods return an Expectation which can be further modified by methods on Expectation. - class Mock - - # :call-seq: expects(method_name) -> expectation - # expects(method_names_vs_return_values) -> last expectation - # - # Adds an expectation that a method identified by +method_name+ Symbol/String must be called exactly once with any parameters. - # Returns the new expectation which can be further modified by methods on Expectation. - # object = mock() - # object.expects(:method1) - # object.method1 - # # no error raised - # - # object = mock() - # object.expects(:method1) - # # error raised, because method1 not called exactly once - # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+. - # object = mock() - # object.expects(:method1 => :result1, :method2 => :result2) - # - # # exactly equivalent to - # - # object = mock() - # object.expects(:method1).returns(:result1) - # object.expects(:method2).returns(:result2) - # - # Aliased by \_\_expects\_\_ - def expects(method_name_or_hash, backtrace = nil) - iterator = ArgumentIterator.new(method_name_or_hash) - iterator.each { |*args| - method_name = args.shift - ensure_method_not_already_defined(method_name) - expectation = Expectation.new(self, method_name, backtrace) - expectation.returns(args.shift) if args.length > 0 - @expectations.add(expectation) - } - end - - # :call-seq: stubs(method_name) -> expectation - # stubs(method_names_vs_return_values) -> last expectation - # - # Adds an expectation that a method identified by +method_name+ Symbol/String may be called any number of times with any parameters. - # Returns the new expectation which can be further modified by methods on Expectation. - # object = mock() - # object.stubs(:method1) - # object.method1 - # object.method1 - # # no error raised - # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+. - # object = mock() - # object.stubs(:method1 => :result1, :method2 => :result2) - # - # # exactly equivalent to - # - # object = mock() - # object.stubs(:method1).returns(:result1) - # object.stubs(:method2).returns(:result2) - # - # Aliased by \_\_stubs\_\_ - def stubs(method_name_or_hash, backtrace = nil) - iterator = ArgumentIterator.new(method_name_or_hash) - iterator.each { |*args| - method_name = args.shift - ensure_method_not_already_defined(method_name) - expectation = Expectation.new(self, method_name, backtrace) - expectation.at_least(0) - expectation.returns(args.shift) if args.length > 0 - @expectations.add(expectation) - } - end - - # :call-seq: responds_like(responder) -> mock - # - # Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time. - # - # A +NoMethodError+ will be raised if the +responder+ does not respond_to? a method invocation (even if the method has been expected or stubbed). - # - # The +mock+ will delegate its respond_to? method to the +responder+. - # class Sheep - # def chew(grass); end - # def self.number_of_legs; end - # end - # - # sheep = mock('sheep') - # sheep.expects(:chew) - # sheep.expects(:foo) - # sheep.respond_to?(:chew) # => true - # sheep.respond_to?(:foo) # => true - # sheep.chew - # sheep.foo - # # no error raised - # - # sheep = mock('sheep') - # sheep.responds_like(Sheep.new) - # sheep.expects(:chew) - # sheep.expects(:foo) - # sheep.respond_to?(:chew) # => true - # sheep.respond_to?(:foo) # => false - # sheep.chew - # sheep.foo # => raises NoMethodError exception - # - # sheep_class = mock('sheep_class') - # sheep_class.responds_like(Sheep) - # sheep_class.stubs(:number_of_legs).returns(4) - # sheep_class.expects(:foo) - # sheep_class.respond_to?(:number_of_legs) # => true - # sheep_class.respond_to?(:foo) # => false - # assert_equal 4, sheep_class.number_of_legs - # sheep_class.foo # => raises NoMethodError exception - # - # Aliased by +quacks_like+ - def responds_like(object) - @responder = object - self - end - - # :stopdoc: - - def initialize(name = nil, &block) - @name = name || DefaultName.new(self) - @expectations = ExpectationList.new - @everything_stubbed = false - @responder = nil - instance_eval(&block) if block - end - - attr_reader :everything_stubbed, :expectations - - alias_method :__expects__, :expects - - alias_method :__stubs__, :stubs - - alias_method :quacks_like, :responds_like - - def stub_everything - @everything_stubbed = true - end - - def method_missing(symbol, *arguments, &block) - if @responder and not @responder.respond_to?(symbol) - raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}" - end - if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments) - matching_expectation_allowing_invocation.invoke(&block) - else - if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed) - message = UnexpectedInvocation.new(self, symbol, *arguments).to_s - message << Mockery.instance.mocha_inspect - raise ExpectationError.new(message, caller) - end - end - end - - def respond_to?(symbol, include_private = false) - if @responder then - if @responder.method(:respond_to?).arity > 1 - @responder.respond_to?(symbol, include_private) - else - @responder.respond_to?(symbol) - end - else - @everything_stubbed || @expectations.matches_method?(symbol) - end - end - - def __verified__?(assertion_counter = nil) - @expectations.verified?(assertion_counter) - end - - def mocha_inspect - @name.mocha_inspect - end - - def inspect - mocha_inspect - end - - def ensure_method_not_already_defined(method_name) - self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name) - end - - # :startdoc: - - end - -end diff --git a/build_lib/mocha/lib/mocha/mockery.rb b/build_lib/mocha/lib/mocha/mockery.rb deleted file mode 100644 index 6fd5e5a..0000000 --- a/build_lib/mocha/lib/mocha/mockery.rb +++ /dev/null @@ -1,181 +0,0 @@ -require 'mocha/central' -require 'mocha/mock' -require 'mocha/names' -require 'mocha/state_machine' -require 'mocha/logger' -require 'mocha/configuration' -require 'mocha/stubbing_error' - -module Mocha - - class Mockery - - class << self - - def instance - @instance ||= new - end - - def reset_instance - @instance = nil - end - - end - - def named_mock(name, &block) - add_mock(Mock.new(Name.new(name), &block)) - end - - def unnamed_mock(&block) - add_mock(Mock.new(&block)) - end - - def mock_impersonating(object, &block) - add_mock(Mock.new(ImpersonatingName.new(object), &block)) - end - - def mock_impersonating_any_instance_of(klass, &block) - add_mock(Mock.new(ImpersonatingAnyInstanceName.new(klass), &block)) - end - - def new_state_machine(name) - add_state_machine(StateMachine.new(name)) - end - - def verify(assertion_counter = nil) - unless mocks.all? { |mock| mock.__verified__?(assertion_counter) } - message = "not all expectations were satisfied\n#{mocha_inspect}" - if unsatisfied_expectations.empty? - backtrace = caller - else - backtrace = unsatisfied_expectations[0].backtrace - end - raise ExpectationError.new(message, backtrace) - end - expectations.each do |e| - unless Mocha::Configuration.allow?(:stubbing_method_unnecessarily) - unless e.used? - on_stubbing_method_unnecessarily(e) - end - end - end - end - - def teardown - stubba.unstub_all - reset - end - - def stubba - @stubba ||= Central.new - end - - def mocks - @mocks ||= [] - end - - def state_machines - @state_machines ||= [] - end - - def mocha_inspect - message = "" - message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map { |e| e.mocha_inspect }.join("\n- ")}\n" unless unsatisfied_expectations.empty? - message << "satisfied expectations:\n- #{satisfied_expectations.map { |e| e.mocha_inspect }.join("\n- ")}\n" unless satisfied_expectations.empty? - message << "states:\n- #{state_machines.map { |sm| sm.mocha_inspect }.join("\n- ")}" unless state_machines.empty? - message - end - - def on_stubbing(object, method) - method = RUBY_VERSION < '1.9' ? method.to_s : method.to_sym - unless Mocha::Configuration.allow?(:stubbing_non_existent_method) - unless object.method_exists?(method, include_public_methods = true) - on_stubbing_non_existent_method(object, method) - end - end - unless Mocha::Configuration.allow?(:stubbing_non_public_method) - if object.method_exists?(method, include_public_methods = false) - on_stubbing_non_public_method(object, method) - end - end - unless Mocha::Configuration.allow?(:stubbing_method_on_non_mock_object) - on_stubbing_method_on_non_mock_object(object, method) - end - end - - def on_stubbing_non_existent_method(object, method) - if Mocha::Configuration.prevent?(:stubbing_non_existent_method) - raise StubbingError.new("stubbing non-existent method: #{object.mocha_inspect}.#{method}", caller) - end - if Mocha::Configuration.warn_when?(:stubbing_non_existent_method) - logger.warn "stubbing non-existent method: #{object.mocha_inspect}.#{method}" - end - end - - def on_stubbing_non_public_method(object, method) - if Mocha::Configuration.prevent?(:stubbing_non_public_method) - raise StubbingError.new("stubbing non-public method: #{object.mocha_inspect}.#{method}", caller) - end - if Mocha::Configuration.warn_when?(:stubbing_non_public_method) - logger.warn "stubbing non-public method: #{object.mocha_inspect}.#{method}" - end - end - - def on_stubbing_method_on_non_mock_object(object, method) - if Mocha::Configuration.prevent?(:stubbing_method_on_non_mock_object) - raise StubbingError.new("stubbing method on non-mock object: #{object.mocha_inspect}.#{method}", caller) - end - if Mocha::Configuration.warn_when?(:stubbing_method_on_non_mock_object) - logger.warn "stubbing method on non-mock object: #{object.mocha_inspect}.#{method}" - end - end - - def on_stubbing_method_unnecessarily(expectation) - if Mocha::Configuration.prevent?(:stubbing_method_unnecessarily) - raise StubbingError.new("stubbing method unnecessarily: #{expectation.method_signature}", expectation.backtrace) - end - if Mocha::Configuration.warn_when?(:stubbing_method_unnecessarily) - logger.warn "stubbing method unnecessarily: #{expectation.method_signature}" - end - end - - attr_writer :logger - - def logger - @logger ||= Logger.new($stderr) - end - - - private - - def expectations - mocks.map { |mock| mock.expectations.to_a }.flatten - end - - def unsatisfied_expectations - expectations.reject { |e| e.verified? } - end - - def satisfied_expectations - expectations.select { |e| e.verified? } - end - - def add_mock(mock) - mocks << mock - mock - end - - def add_state_machine(state_machine) - state_machines << state_machine - state_machine - end - - def reset - @stubba = nil - @mocks = nil - @state_machines = nil - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/module_method.rb b/build_lib/mocha/lib/mocha/module_method.rb deleted file mode 100644 index 7169e61..0000000 --- a/build_lib/mocha/lib/mocha/module_method.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'mocha/class_method' - -module Mocha - - class ModuleMethod < ClassMethod - - def method_exists?(method) - return true if stubbee.public_methods(false).include?(method) - return true if stubbee.protected_methods(false).include?(method) - return true if stubbee.private_methods(false).include?(method) - return false - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/multiple_yields.rb b/build_lib/mocha/lib/mocha/multiple_yields.rb deleted file mode 100644 index 8186c30..0000000 --- a/build_lib/mocha/lib/mocha/multiple_yields.rb +++ /dev/null @@ -1,20 +0,0 @@ -module Mocha # :nodoc: - - class MultipleYields # :nodoc: - - attr_reader :parameter_groups - - def initialize(*parameter_groups) - @parameter_groups = parameter_groups - end - - def each - @parameter_groups.each do |parameter_group| - yield(parameter_group) - end - end - - end - -end - diff --git a/build_lib/mocha/lib/mocha/names.rb b/build_lib/mocha/lib/mocha/names.rb deleted file mode 100644 index f59ebed..0000000 --- a/build_lib/mocha/lib/mocha/names.rb +++ /dev/null @@ -1,53 +0,0 @@ -module Mocha - - class ImpersonatingName - - def initialize(object) - @object = object - end - - def mocha_inspect - @object.mocha_inspect - end - - end - - class ImpersonatingAnyInstanceName - - def initialize(klass) - @klass = klass - end - - def mocha_inspect - "#" - end - - end - - class Name - - def initialize(name) - @name = name - end - - def mocha_inspect - "#" - end - - end - - class DefaultName - - def initialize(mock) - @mock = mock - end - - def mocha_inspect - address = @mock.__id__ * 2 - address += 0x100000000 if address < 0 - "#" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/no_yields.rb b/build_lib/mocha/lib/mocha/no_yields.rb deleted file mode 100644 index b0fba41..0000000 --- a/build_lib/mocha/lib/mocha/no_yields.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Mocha # :nodoc: - - class NoYields # :nodoc: - - def each - end - - end - -end - diff --git a/build_lib/mocha/lib/mocha/object.rb b/build_lib/mocha/lib/mocha/object.rb deleted file mode 100644 index 296000e..0000000 --- a/build_lib/mocha/lib/mocha/object.rb +++ /dev/null @@ -1,220 +0,0 @@ -require 'mocha/mockery' -require 'mocha/instance_method' -require 'mocha/class_method' -require 'mocha/module_method' -require 'mocha/any_instance_method' -require 'mocha/argument_iterator' - -module Mocha - - # Methods added all objects to allow mocking and stubbing on real objects. - # - # Methods return a Mocha::Expectation which can be further modified by methods on Mocha::Expectation. - module ObjectMethods - - def mocha # :nodoc: - @mocha ||= Mocha::Mockery.instance.mock_impersonating(self) - end - - def reset_mocha # :nodoc: - @mocha = nil - end - - def stubba_method # :nodoc: - Mocha::InstanceMethod - end - - def stubba_object # :nodoc: - self - end - - # :call-seq: expects(method_name) -> expectation - # expects(method_names_vs_return_values) -> last expectation - # - # Adds an expectation that a method identified by +method_name+ Symbol must be called exactly once with any parameters. - # Returns the new expectation which can be further modified by methods on Mocha::Expectation. - # product = Product.new - # product.expects(:save).returns(true) - # assert_equal true, product.save - # - # The original implementation of Product#save is replaced temporarily. - # - # The original implementation of Product#save is restored at the end of the test. - # - # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+. - # product = Product.new - # product.expects(:valid? => true, :save => true) - # - # # exactly equivalent to - # - # product = Product.new - # product.expects(:valid?).returns(true) - # product.expects(:save).returns(true) - def expects(method_name_or_hash) - expectation = nil - mockery = Mocha::Mockery.instance - iterator = ArgumentIterator.new(method_name_or_hash) - iterator.each { |*args| - method_name = args.shift - mockery.on_stubbing(self, method_name) - method = stubba_method.new(stubba_object, method_name) - mockery.stubba.stub(method) - expectation = mocha.expects(method_name, caller) - expectation.returns(args.shift) if args.length > 0 - } - expectation - end - - # :call-seq: stubs(method_name) -> expectation - # stubs(method_names_vs_return_values) -> last expectation - # - # Adds an expectation that a method identified by +method_name+ Symbol may be called any number of times with any parameters. - # Returns the new expectation which can be further modified by methods on Mocha::Expectation. - # product = Product.new - # product.stubs(:save).returns(true) - # assert_equal true, product.save - # - # The original implementation of Product#save is replaced temporarily. - # - # The original implementation of Product#save is restored at the end of the test. - # - # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+. - # product = Product.new - # product.stubs(:valid? => true, :save => true) - # - # # exactly equivalent to - # - # product = Product.new - # product.stubs(:valid?).returns(true) - # product.stubs(:save).returns(true) - def stubs(method_name_or_hash) - expectation = nil - mockery = Mocha::Mockery.instance - iterator = ArgumentIterator.new(method_name_or_hash) - iterator.each { |*args| - method_name = args.shift - mockery.on_stubbing(self, method_name) - method = stubba_method.new(stubba_object, method_name) - mockery.stubba.stub(method) - expectation = mocha.stubs(method_name, caller) - expectation.returns(args.shift) if args.length > 0 - } - expectation - end - - # :call-seq: unstub(*method_names) - # - # Removes the method stub added by calls to #expects or #stubs. - # Restores the original behaviour of the method before it was stubbed. - # multiplier = Multiplier.new - # multiplier.double(2) # => 4 - # multiplier.stubs(:double).raises - # multiplier.double(2) # => raises exception - # multiplier.unstubs(:double) - # multiplier.double(2) # => 4 - # - # The original implementation of Multiplier#double is replaced temporarily. - # - # The original implementation of Multiplier#double is restored when #unstub is called. - # - # WARNING: If you #unstub a method which still has unsatisfied expectations, you may be removing - # the only way those expectations can be satisfied. Use #unstub with care. - # - # If multiple +method_names+ are supplied, each method is unstubbed. - # multiplier.unstub(:double, :triple) - # - # # exactly equivalent to - # - # multiplier.unstub(:double) - # multiplier.unstub(:triple) - def unstub(*method_names) - mockery = Mocha::Mockery.instance - method_names.each do |method_name| - method = stubba_method.new(stubba_object, method_name) - mockery.stubba.unstub(method) - end - end - - def method_exists?(method, include_public_methods = true) # :nodoc: - if include_public_methods - return true if public_methods(include_superclass_methods = true).include?(method) - return true if respond_to?(method.to_sym) - end - return true if protected_methods(include_superclass_methods = true).include?(method) - return true if private_methods(include_superclass_methods = true).include?(method) - return false - end - - end - - module ModuleMethods # :nodoc: - - def stubba_method - Mocha::ModuleMethod - end - - end - - # Methods added all classes to allow mocking and stubbing on real objects. - module ClassMethods - - def stubba_method # :nodoc: - Mocha::ClassMethod - end - - class AnyInstance # :nodoc: - - def initialize(klass) - @stubba_object = klass - end - - def mocha - @mocha ||= Mocha::Mockery.instance.mock_impersonating_any_instance_of(@stubba_object) - end - - def stubba_method - Mocha::AnyInstanceMethod - end - - def stubba_object - @stubba_object - end - - def method_exists?(method, include_public_methods = true) - if include_public_methods - return true if @stubba_object.public_instance_methods(include_superclass_methods = true).include?(method) - end - return true if @stubba_object.protected_instance_methods(include_superclass_methods = true).include?(method) - return true if @stubba_object.private_instance_methods(include_superclass_methods = true).include?(method) - return false - end - - end - - # :call-seq: any_instance -> mock object - # - # Returns a mock object which will detect calls to any instance of this class. - # Product.any_instance.stubs(:save).returns(false) - # product_1 = Product.new - # assert_equal false, product_1.save - # product_2 = Product.new - # assert_equal false, product_2.save - def any_instance - @any_instance ||= AnyInstance.new(self) - end - - end - -end - -class Object # :nodoc: - include Mocha::ObjectMethods -end - -class Module # :nodoc: - include Mocha::ModuleMethods -end - -class Class # :nodoc: - include Mocha::ClassMethods -end diff --git a/build_lib/mocha/lib/mocha/options.rb b/build_lib/mocha/lib/mocha/options.rb deleted file mode 100644 index e41db53..0000000 --- a/build_lib/mocha/lib/mocha/options.rb +++ /dev/null @@ -1 +0,0 @@ -$options = (ENV['MOCHA_OPTIONS'] || '').split(',').inject({}) { |hash, key| hash[key] = true; hash } diff --git a/build_lib/mocha/lib/mocha/parameter_matchers.rb b/build_lib/mocha/lib/mocha/parameter_matchers.rb deleted file mode 100644 index 7ce445f..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Mocha - - # Used as parameters for Expectation#with to restrict the parameter values which will match the expectation. Can be nested. - module ParameterMatchers; end - -end - -require 'mocha/parameter_matchers/object' - -require 'mocha/parameter_matchers/all_of' -require 'mocha/parameter_matchers/any_of' -require 'mocha/parameter_matchers/any_parameters' -require 'mocha/parameter_matchers/anything' -require 'mocha/parameter_matchers/equals' -require 'mocha/parameter_matchers/has_entry' -require 'mocha/parameter_matchers/has_entries' -require 'mocha/parameter_matchers/has_key' -require 'mocha/parameter_matchers/has_value' -require 'mocha/parameter_matchers/includes' -require 'mocha/parameter_matchers/instance_of' -require 'mocha/parameter_matchers/is_a' -require 'mocha/parameter_matchers/kind_of' -require 'mocha/parameter_matchers/not' -require 'mocha/parameter_matchers/optionally' -require 'mocha/parameter_matchers/regexp_matches' -require 'mocha/parameter_matchers/responds_with' -require 'mocha/parameter_matchers/yaml_equivalent' diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/all_of.rb b/build_lib/mocha/lib/mocha/parameter_matchers/all_of.rb deleted file mode 100644 index 50bf05b..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/all_of.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: all_of(*parameter_matchers) -> parameter_matcher - # - # Matches if all +parameter_matchers+ match. - # object = mock() - # object.expects(:method_1).with(all_of(includes(1), includes(3))) - # object.method_1([1, 3]) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(all_of(includes(1), includes(3))) - # object.method_1([1, 2]) - # # error raised, because method_1 was not called with object including 1 and 3 - def all_of(*matchers) - AllOf.new(*matchers) - end - - class AllOf < Base # :nodoc: - - def initialize(*matchers) - @matchers = matchers - end - - def matches?(available_parameters) - parameter = available_parameters.shift - @matchers.all? { |matcher| matcher.to_matcher.matches?([parameter]) } - end - - def mocha_inspect - "all_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/any_of.rb b/build_lib/mocha/lib/mocha/parameter_matchers/any_of.rb deleted file mode 100644 index b391ff3..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/any_of.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: any_of(*parameter_matchers) -> parameter_matcher - # - # Matches if any +parameter_matchers+ match. - # object = mock() - # object.expects(:method_1).with(any_of(1, 3)) - # object.method_1(1) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(any_of(1, 3)) - # object.method_1(3) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(any_of(1, 3)) - # object.method_1(2) - # # error raised, because method_1 was not called with 1 or 3 - def any_of(*matchers) - AnyOf.new(*matchers) - end - - class AnyOf < Base # :nodoc: - - def initialize(*matchers) - @matchers = matchers - end - - def matches?(available_parameters) - parameter = available_parameters.shift - @matchers.any? { |matcher| matcher.to_matcher.matches?([parameter]) } - end - - def mocha_inspect - "any_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/any_parameters.rb b/build_lib/mocha/lib/mocha/parameter_matchers/any_parameters.rb deleted file mode 100644 index 11dae83..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/any_parameters.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: any_parameters() -> parameter_matcher - # - # Matches any parameters. - # object = mock() - # object.expects(:method_1).with(any_parameters) - # object.method_1(1, 2, 3, 4) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(any_parameters) - # object.method_1(5, 6, 7, 8, 9, 0) - # # no error raised - def any_parameters - AnyParameters.new - end - - class AnyParameters < Base # :nodoc: - - def matches?(available_parameters) - while available_parameters.length > 0 do - available_parameters.shift - end - return true - end - - def mocha_inspect - "any_parameters" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/anything.rb b/build_lib/mocha/lib/mocha/parameter_matchers/anything.rb deleted file mode 100644 index 90510e2..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/anything.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: anything() -> parameter_matcher - # - # Matches any object. - # object = mock() - # object.expects(:method_1).with(anything) - # object.method_1('foo') - # # no error raised - def anything - Anything.new - end - - class Anything < Base # :nodoc: - - def matches?(available_parameters) - available_parameters.shift - return true - end - - def mocha_inspect - "anything" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/base.rb b/build_lib/mocha/lib/mocha/parameter_matchers/base.rb deleted file mode 100644 index 099f0df..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/base.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Mocha - - module ParameterMatchers - - class Base - - def to_matcher # :nodoc: - self - end - - # :call-seq: &(matcher) -> parameter_matcher - # - # A short hand way of specifying multiple matchers that should - # all match. - # - # Returns a new +AllOf+ parameter matcher combining the - # given matcher and the receiver. - # - # The following statements are equivalent: - # object = mock() - # object.expects(:run).with(all_of(has_key(:foo), has_key(:bar))) - # object.run(:foo => 'foovalue', :bar => 'barvalue') - # - # # with the shorthand - # object.expects(:run).with(has_key(:foo) & has_key(:bar)) - # object.run(:foo => 'foovalue', :bar => 'barvalue) - def &(matcher) - AllOf.new(self, matcher) - end - - # :call-seq: |(matcher) -> parameter_matcher - # - # A short hand way of specifying multiple matchers, only at least - # one of which should pass. - # - # Returns a new +AnyOf+ parameter matcher combining the - # given matcher and the receiver. - # - # The following statements are equivalent: - # object = mock() - # object.expects(:run).with(any_of(has_key(:foo), has_key(:bar))) - # object.run(:foo => 'foovalue') - # - # # with the shorthand - # object.expects(:run).with(has_key(:foo) | has_key(:bar)) - # object.run(:foo => 'foovalue') - # - # This shorthand will not work with an implicit equals match. Instead, - # an explicit equals matcher should be used: - # - # object.expects(:run).with(equals(1) | equals(2)) - # object.run(1) # passes - # object.run(2) # passes - # object.run(3) # fails - def |(matcher) - AnyOf.new(self, matcher) - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/equals.rb b/build_lib/mocha/lib/mocha/parameter_matchers/equals.rb deleted file mode 100644 index bdc61a0..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/equals.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: equals(value) -> parameter_matcher - # - # Matches +Object+ equalling +value+. - # object = mock() - # object.expects(:method_1).with(equals(2)) - # object.method_1(2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(equals(2)) - # object.method_1(3) - # # error raised, because method_1 was not called with Object equalling 3 - def equals(value) - Equals.new(value) - end - - class Equals < Base # :nodoc: - - def initialize(value) - @value = value - end - - def matches?(available_parameters) - parameter = available_parameters.shift - parameter == @value - end - - def mocha_inspect - @value.mocha_inspect - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/has_entries.rb b/build_lib/mocha/lib/mocha/parameter_matchers/has_entries.rb deleted file mode 100644 index 03e968f..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/has_entries.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'mocha/parameter_matchers/base' -require 'mocha/parameter_matchers/all_of' -require 'mocha/parameter_matchers/has_entry' - -module Mocha - - module ParameterMatchers - - # :call-seq: has_entries(entries) -> parameter_matcher - # - # Matches +Hash+ containing all +entries+. - # object = mock() - # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2)) - # object.method_1('key_1' => 1, 'key_2' => 2, 'key_3' => 3) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2)) - # object.method_1('key_1' => 1, 'key_2' => 99) - # # error raised, because method_1 was not called with Hash containing entries: 'key_1' => 1, 'key_2' => 2 - def has_entries(entries) - HasEntries.new(entries) - end - - class HasEntries < Base # :nodoc: - - def initialize(entries) - @entries = entries - end - - def matches?(available_parameters) - parameter = available_parameters.shift - has_entry_matchers = @entries.map { |key, value| HasEntry.new(key, value) } - AllOf.new(*has_entry_matchers).matches?([parameter]) - end - - def mocha_inspect - "has_entries(#{@entries.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/has_entry.rb b/build_lib/mocha/lib/mocha/parameter_matchers/has_entry.rb deleted file mode 100644 index aff9dc3..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/has_entry.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: has_entry(key, value) -> parameter_matcher - # has_entry(key => value) -> parameter_matcher - # - # Matches +Hash+ containing entry with +key+ and +value+. - # object = mock() - # object.expects(:method_1).with(has_entry('key_1', 1)) - # object.method_1('key_1' => 1, 'key_2' => 2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(has_entry('key_1' => 1)) - # object.method_1('key_1' => 1, 'key_2' => 2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(has_entry('key_1', 1)) - # object.method_1('key_1' => 2, 'key_2' => 1) - # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1 - # - # object = mock() - # object.expects(:method_1).with(has_entry('key_1' => 1)) - # object.method_1('key_1' => 2, 'key_2' => 1) - # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1 - def has_entry(*options) - key, value = options.shift, options.shift - key, value = key.to_a[0][0..1] if key.is_a?(Hash) - HasEntry.new(key, value) - end - - class HasEntry < Base # :nodoc: - - def initialize(key, value) - @key, @value = key, value - end - - def matches?(available_parameters) - parameter = available_parameters.shift - return false unless parameter.respond_to?(:keys) && parameter.respond_to?(:[]) - matching_keys = parameter.keys.select { |key| @key.to_matcher.matches?([key]) } - matching_keys.any? { |key| @value.to_matcher.matches?([parameter[key]]) } - end - - def mocha_inspect - "has_entry(#{@key.mocha_inspect} => #{@value.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/has_key.rb b/build_lib/mocha/lib/mocha/parameter_matchers/has_key.rb deleted file mode 100644 index 23fffb9..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/has_key.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: has_key(key) -> parameter_matcher - # - # Matches +Hash+ containing +key+. - # object = mock() - # object.expects(:method_1).with(has_key('key_1')) - # object.method_1('key_1' => 1, 'key_2' => 2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(has_key('key_1')) - # object.method_1('key_2' => 2) - # # error raised, because method_1 was not called with Hash containing key: 'key_1' - def has_key(key) - HasKey.new(key) - end - - class HasKey < Base # :nodoc: - - def initialize(key) - @key = key - end - - def matches?(available_parameters) - parameter = available_parameters.shift - return false unless parameter.respond_to?(:keys) - parameter.keys.any? { |key| @key.to_matcher.matches?([key]) } - end - - def mocha_inspect - "has_key(#{@key.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/has_value.rb b/build_lib/mocha/lib/mocha/parameter_matchers/has_value.rb deleted file mode 100644 index 16c8b4d..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/has_value.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: has_value(value) -> parameter_matcher - # - # Matches +Hash+ containing +value+. - # object = mock() - # object.expects(:method_1).with(has_value(1)) - # object.method_1('key_1' => 1, 'key_2' => 2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(has_value(1)) - # object.method_1('key_2' => 2) - # # error raised, because method_1 was not called with Hash containing value: 1 - def has_value(value) - HasValue.new(value) - end - - class HasValue < Base # :nodoc: - - def initialize(value) - @value = value - end - - def matches?(available_parameters) - parameter = available_parameters.shift - return false unless parameter.respond_to?(:values) - parameter.values.any? { |value| @value.to_matcher.matches?([value]) } - end - - def mocha_inspect - "has_value(#{@value.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/includes.rb b/build_lib/mocha/lib/mocha/parameter_matchers/includes.rb deleted file mode 100644 index 2717503..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/includes.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: includes(item) -> parameter_matcher - # - # Matches any object that responds true to include?(item) - # object = mock() - # object.expects(:method_1).with(includes('foo')) - # object.method_1(['foo', 'bar']) - # # no error raised - # - # object.method_1(['baz']) - # # error raised, because ['baz'] does not include 'foo'. - def includes(item) - Includes.new(item) - end - - class Includes < Base # :nodoc: - - def initialize(item) - @item = item - end - - def matches?(available_parameters) - parameter = available_parameters.shift - return false unless parameter.respond_to?(:include?) - return parameter.include?(@item) - end - - def mocha_inspect - "includes(#{@item.mocha_inspect})" - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/instance_of.rb b/build_lib/mocha/lib/mocha/parameter_matchers/instance_of.rb deleted file mode 100644 index 49b4a47..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/instance_of.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: instance_of(klass) -> parameter_matcher - # - # Matches any object that is an instance of +klass+ - # object = mock() - # object.expects(:method_1).with(instance_of(String)) - # object.method_1('string') - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(instance_of(String)) - # object.method_1(99) - # # error raised, because method_1 was not called with an instance of String - def instance_of(klass) - InstanceOf.new(klass) - end - - class InstanceOf < Base # :nodoc: - - def initialize(klass) - @klass = klass - end - - def matches?(available_parameters) - parameter = available_parameters.shift - parameter.instance_of?(@klass) - end - - def mocha_inspect - "instance_of(#{@klass.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/is_a.rb b/build_lib/mocha/lib/mocha/parameter_matchers/is_a.rb deleted file mode 100644 index a721db5..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/is_a.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: is_a(klass) -> parameter_matcher - # - # Matches any object that is a +klass+ - # object = mock() - # object.expects(:method_1).with(is_a(Integer)) - # object.method_1(99) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(is_a(Integer)) - # object.method_1('string') - # # error raised, because method_1 was not called with an Integer - def is_a(klass) - IsA.new(klass) - end - - class IsA < Base # :nodoc: - - def initialize(klass) - @klass = klass - end - - def matches?(available_parameters) - parameter = available_parameters.shift - parameter.is_a?(@klass) - end - - def mocha_inspect - "is_a(#{@klass.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/kind_of.rb b/build_lib/mocha/lib/mocha/parameter_matchers/kind_of.rb deleted file mode 100644 index 710d709..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/kind_of.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: kind_of(klass) -> parameter_matcher - # - # Matches any object that is a kind of +klass+ - # object = mock() - # object.expects(:method_1).with(kind_of(Integer)) - # object.method_1(99) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(kind_of(Integer)) - # object.method_1('string') - # # error raised, because method_1 was not called with a kind of Integer - def kind_of(klass) - KindOf.new(klass) - end - - class KindOf < Base # :nodoc: - - def initialize(klass) - @klass = klass - end - - def matches?(available_parameters) - parameter = available_parameters.shift - parameter.kind_of?(@klass) - end - - def mocha_inspect - "kind_of(#{@klass.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/not.rb b/build_lib/mocha/lib/mocha/parameter_matchers/not.rb deleted file mode 100644 index 7a9cf27..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/not.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: Not(parameter_matcher) -> parameter_matcher - # - # Matches if +parameter_matcher+ does not match. - # object = mock() - # object.expects(:method_1).with(Not(includes(1))) - # object.method_1([0, 2, 3]) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(Not(includes(1))) - # object.method_1([0, 1, 2, 3]) - # # error raised, because method_1 was not called with object not including 1 - def Not(matcher) - Not.new(matcher) - end - - class Not < Base # :nodoc: - - def initialize(matcher) - @matcher = matcher - end - - def matches?(available_parameters) - parameter = available_parameters.shift - !@matcher.matches?([parameter]) - end - - def mocha_inspect - "Not(#{@matcher.mocha_inspect})" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/object.rb b/build_lib/mocha/lib/mocha/parameter_matchers/object.rb deleted file mode 100644 index 56a1940..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/object.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'mocha/parameter_matchers/equals' - -module Mocha - - module ObjectMethods - def to_matcher # :nodoc: - Mocha::ParameterMatchers::Equals.new(self) - end - end - -end - -class Object - include Mocha::ObjectMethods -end diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/optionally.rb b/build_lib/mocha/lib/mocha/parameter_matchers/optionally.rb deleted file mode 100644 index fc2c3a9..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/optionally.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Mocha - - module ParameterMatchers - - # :call-seq: optionally(*parameter_matchers) -> parameter_matcher - # - # Matches optional parameters if available. - # object = mock() - # object.expects(:method_1).with(1, 2, optionally(3, 4)) - # object.method_1(1, 2) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(1, 2, optionally(3, 4)) - # object.method_1(1, 2, 3) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(1, 2, optionally(3, 4)) - # object.method_1(1, 2, 3, 4) - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(1, 2, optionally(3, 4)) - # object.method_1(1, 2, 3, 5) - # # error raised, because optional parameters did not match - def optionally(*matchers) - Optionally.new(*matchers) - end - - class Optionally < Base # :nodoc: - - def initialize(*parameters) - @matchers = parameters.map { |parameter| parameter.to_matcher } - end - - def matches?(available_parameters) - index = 0 - while (available_parameters.length > 0) && (index < @matchers.length) do - matcher = @matchers[index] - return false unless matcher.matches?(available_parameters) - index += 1 - end - return true - end - - def mocha_inspect - "optionally(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })" - end - - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/regexp_matches.rb b/build_lib/mocha/lib/mocha/parameter_matchers/regexp_matches.rb deleted file mode 100644 index 65a5be9..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/regexp_matches.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'mocha/parameter_matchers/base' - -module Mocha - - module ParameterMatchers - - # :call-seq: regexp_matches(regular_expression) -> parameter_matcher - # - # Matches any object that matches +regular_expression+. - # object = mock() - # object.expects(:method_1).with(regexp_matches(/e/)) - # object.method_1('hello') - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(regexp_matches(/a/)) - # object.method_1('hello') - # # error raised, because method_1 was not called with a parameter that matched the - # # regular expression - def regexp_matches(regexp) - RegexpMatches.new(regexp) - end - - class RegexpMatches < Base # :nodoc: - - def initialize(regexp) - @regexp = regexp - end - - def matches?(available_parameters) - parameter = available_parameters.shift - return false unless parameter.respond_to?(:=~) - parameter =~ @regexp - end - - def mocha_inspect - "regexp_matches(#{@regexp.mocha_inspect})" - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/responds_with.rb b/build_lib/mocha/lib/mocha/parameter_matchers/responds_with.rb deleted file mode 100644 index 4355796..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/responds_with.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'mocha/parameter_matchers/base' -require 'yaml' - -module Mocha - - module ParameterMatchers - - # :call-seq: responds_with(message, result) -> parameter_matcher - # - # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck. - # object = mock() - # object.expects(:method_1).with(responds_with(:upcase, "FOO")) - # object.method_1("foo") - # # no error raised, because "foo".upcase == "FOO" - # - # object = mock() - # object.expects(:method_1).with(responds_with(:upcase, "BAR")) - # object.method_1("foo") - # # error raised, because "foo".upcase != "BAR" - def responds_with(message, result) - RespondsWith.new(message, result) - end - - class RespondsWith < Base # :nodoc: - - def initialize(message, result) - @message, @result = message, result - end - - def matches?(available_parameters) - parameter = available_parameters.shift - parameter.__send__(@message) == @result - end - - def mocha_inspect - "responds_with(#{@message.mocha_inspect}, #{@result.mocha_inspect})" - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/parameter_matchers/yaml_equivalent.rb b/build_lib/mocha/lib/mocha/parameter_matchers/yaml_equivalent.rb deleted file mode 100644 index 6449717..0000000 --- a/build_lib/mocha/lib/mocha/parameter_matchers/yaml_equivalent.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'mocha/parameter_matchers/base' -require 'yaml' - -module Mocha - - module ParameterMatchers - - # :call-seq: yaml_equivalent(object) -> parameter_matcher - # - # Matches any YAML that represents the specified +object+ - # object = mock() - # object.expects(:method_1).with(yaml_equivalent(1, 2, 3)) - # object.method_1("--- \n- 1\n- 2\n- 3\n") - # # no error raised - # - # object = mock() - # object.expects(:method_1).with(yaml_equivalent(1, 2, 3)) - # object.method_1("--- \n- 1\n- 2\n") - # # error raised, because method_1 was not called with YAML representing the specified Array - def yaml_equivalent(object) - YamlEquivalent.new(object) - end - - class YamlEquivalent < Base # :nodoc: - - def initialize(object) - @object = object - end - - def matches?(available_parameters) - parameter = available_parameters.shift - @object == YAML.load(parameter) - end - - def mocha_inspect - "yaml_equivalent(#{@object.mocha_inspect})" - end - - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/parameters_matcher.rb b/build_lib/mocha/lib/mocha/parameters_matcher.rb deleted file mode 100644 index d43ae43..0000000 --- a/build_lib/mocha/lib/mocha/parameters_matcher.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'mocha/inspect' -require 'mocha/parameter_matchers' - -module Mocha - - class ParametersMatcher - - def initialize(expected_parameters = [ParameterMatchers::AnyParameters.new], &matching_block) - @expected_parameters, @matching_block = expected_parameters, matching_block - end - - def match?(actual_parameters = []) - if @matching_block - return @matching_block.call(*actual_parameters) - else - return parameters_match?(actual_parameters) - end - end - - def parameters_match?(actual_parameters) - matchers.all? { |matcher| matcher.matches?(actual_parameters) } && (actual_parameters.length == 0) - end - - def mocha_inspect - signature = matchers.mocha_inspect - signature = signature.gsub(/^\[|\]$/, '') - signature = signature.gsub(/^\{|\}$/, '') if matchers.length == 1 - "(#{signature})" - end - - def matchers - @expected_parameters.map { |parameter| parameter.to_matcher } - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/pretty_parameters.rb b/build_lib/mocha/lib/mocha/pretty_parameters.rb deleted file mode 100644 index 59ed636..0000000 --- a/build_lib/mocha/lib/mocha/pretty_parameters.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'mocha/inspect' - -module Mocha - - class PrettyParameters - - def initialize(params) - @params = params - @params_string = params.mocha_inspect - end - - def pretty - remove_outer_array_braces! - remove_outer_hash_braces! - @params_string - end - - def remove_outer_array_braces! - @params_string = @params_string.gsub(/^\[|\]$/, '') - end - - def remove_outer_hash_braces! - @params_string = @params_string.gsub(/^\{|\}$/, '') if @params.length == 1 - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/return_values.rb b/build_lib/mocha/lib/mocha/return_values.rb deleted file mode 100644 index d93fb1a..0000000 --- a/build_lib/mocha/lib/mocha/return_values.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'mocha/single_return_value' - -module Mocha # :nodoc: - - class ReturnValues # :nodoc: - - def self.build(*values) - new(*values.map { |value| SingleReturnValue.new(value) }) - end - - attr_accessor :values - - def initialize(*values) - @values = values - end - - def next - case @values.length - when 0 then nil - when 1 then @values.first.evaluate - else @values.shift.evaluate - end - end - - def +(other) - self.class.new(*(@values + other.values)) - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/sequence.rb b/build_lib/mocha/lib/mocha/sequence.rb deleted file mode 100644 index ed9852e..0000000 --- a/build_lib/mocha/lib/mocha/sequence.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Mocha # :nodoc: - - class Sequence - - class InSequenceOrderingConstraint - - def initialize(sequence, index) - @sequence, @index = sequence, index - end - - def allows_invocation_now? - @sequence.satisfied_to_index?(@index) - end - - def mocha_inspect - "in sequence #{@sequence.mocha_inspect}" - end - - end - - def initialize(name) - @name = name - @expectations = [] - end - - def constrain_as_next_in_sequence(expectation) - index = @expectations.length - @expectations << expectation - expectation.add_ordering_constraint(InSequenceOrderingConstraint.new(self, index)) - end - - def satisfied_to_index?(index) - @expectations[0...index].all? { |expectation| expectation.satisfied? } - end - - def mocha_inspect - "#{@name.mocha_inspect}" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/single_return_value.rb b/build_lib/mocha/lib/mocha/single_return_value.rb deleted file mode 100644 index 98bc4be..0000000 --- a/build_lib/mocha/lib/mocha/single_return_value.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'mocha/is_a' - -module Mocha # :nodoc: - - class SingleReturnValue # :nodoc: - - def initialize(value) - @value = value - end - - def evaluate - @value - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/single_yield.rb b/build_lib/mocha/lib/mocha/single_yield.rb deleted file mode 100644 index 5af5716..0000000 --- a/build_lib/mocha/lib/mocha/single_yield.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Mocha # :nodoc: - - class SingleYield # :nodoc: - - attr_reader :parameters - - def initialize(*parameters) - @parameters = parameters - end - - def each - yield(@parameters) - end - - end - -end - diff --git a/build_lib/mocha/lib/mocha/standalone.rb b/build_lib/mocha/lib/mocha/standalone.rb deleted file mode 100644 index 1183205..0000000 --- a/build_lib/mocha/lib/mocha/standalone.rb +++ /dev/null @@ -1 +0,0 @@ -require 'mocha/api' \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/state_machine.rb b/build_lib/mocha/lib/mocha/state_machine.rb deleted file mode 100644 index 1b9781a..0000000 --- a/build_lib/mocha/lib/mocha/state_machine.rb +++ /dev/null @@ -1,91 +0,0 @@ -module Mocha # :nodoc: - - # A state machine that is used to constrain the order of invocations. - # An invocation can be constrained to occur when a state is, or is_not, active. - class StateMachine - - class State # :nodoc: - - def initialize(state_machine, state) - @state_machine, @state = state_machine, state - end - - def activate - @state_machine.current_state = @state - end - - def active? - @state_machine.current_state == @state - end - - def mocha_inspect - "#{@state_machine.name} is #{@state.mocha_inspect}" - end - - end - - class StatePredicate # :nodoc: - - def initialize(state_machine, state) - @state_machine, @state = state_machine, state - end - - def active? - @state_machine.current_state != @state - end - - def mocha_inspect - "#{@state_machine.name} is not #{@state.mocha_inspect}" - end - - end - - attr_reader :name # :nodoc: - - attr_accessor :current_state # :nodoc: - - def initialize(name) # :nodoc: - @name = name - @current_state = nil - end - - # :call-seq: starts_as(initial_state) -> state_machine - # - # Put the +state_machine+ into the +initial_state+. - def starts_as(initial_state) - become(initial_state) - self - end - - # :call-seq: become(next_state) - # - # Put the +state_machine+ into the +next_state+. - def become(next_state) - @current_state = next_state - end - - # :call-seq: is(state) - # - # Determines whether the +state_machine+ is in the specified +state+. - def is(state) - State.new(self, state) - end - - # :call-seq: is_not(state) - # - # Determines whether the +state_machine+ is not in the specified +state+. - def is_not(state) - StatePredicate.new(self, state) - end - - def mocha_inspect # :nodoc: - if @current_state - "#{@name} is #{@current_state.mocha_inspect}" - else - "#{@name} has no current state" - end - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/stubbing_error.rb b/build_lib/mocha/lib/mocha/stubbing_error.rb deleted file mode 100644 index 34be289..0000000 --- a/build_lib/mocha/lib/mocha/stubbing_error.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'mocha/backtrace_filter' - -module Mocha # :nodoc: - - # Exception raised when an action prevented by Configuration#prevent is attempted. - class StubbingError < StandardError - - def initialize(message = nil, backtrace = []) # :nodoc: - super(message) - filter = BacktraceFilter.new - set_backtrace(filter.filtered(backtrace)) - end - - end - -end diff --git a/build_lib/mocha/lib/mocha/unexpected_invocation.rb b/build_lib/mocha/lib/mocha/unexpected_invocation.rb deleted file mode 100644 index 2eabb6a..0000000 --- a/build_lib/mocha/lib/mocha/unexpected_invocation.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Mocha # :nodoc: - - class UnexpectedInvocation - - def initialize(mock, symbol, *arguments) - @mock = mock - @method_matcher = MethodMatcher.new(symbol) - @parameters_matcher = ParametersMatcher.new(arguments) - end - - def to_s - method_signature = "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}" - "unexpected invocation: #{method_signature}\n" - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha/yield_parameters.rb b/build_lib/mocha/lib/mocha/yield_parameters.rb deleted file mode 100644 index 7d6ad12..0000000 --- a/build_lib/mocha/lib/mocha/yield_parameters.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'mocha/no_yields' -require 'mocha/single_yield' -require 'mocha/multiple_yields' - -module Mocha # :nodoc: - - class YieldParameters # :nodoc: - - def initialize - @parameter_groups = [] - end - - def next_invocation - case @parameter_groups.length - when 0 then NoYields.new - when 1 then @parameter_groups.first - else @parameter_groups.shift - end - end - - def add(*parameters) - @parameter_groups << SingleYield.new(*parameters) - end - - def multiple_add(*parameter_groups) - @parameter_groups << MultipleYields.new(*parameter_groups) - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/lib/mocha_standalone.rb b/build_lib/mocha/lib/mocha_standalone.rb deleted file mode 100644 index e3dc645..0000000 --- a/build_lib/mocha/lib/mocha_standalone.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'mocha/api' -require 'mocha/object' \ No newline at end of file diff --git a/build_lib/mocha/lib/stubba.rb b/build_lib/mocha/lib/stubba.rb deleted file mode 100644 index ba4d93f..0000000 --- a/build_lib/mocha/lib/stubba.rb +++ /dev/null @@ -1,4 +0,0 @@ -# for backwards compatibility -require 'mocha' -require 'mocha/deprecation' -Mocha::Deprecation.warning "require 'stubba' is no longer needed and stubba.rb will soon be removed" diff --git a/build_lib/mocha/test/acceptance/acceptance_test_helper.rb b/build_lib/mocha/test/acceptance/acceptance_test_helper.rb deleted file mode 100644 index 8a3d0aa..0000000 --- a/build_lib/mocha/test/acceptance/acceptance_test_helper.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'test_runner' -require 'mocha/configuration' - -module AcceptanceTest - - class FakeLogger - - attr_reader :warnings - - def initialize - @warnings = [] - end - - def warn(message) - @warnings << message - end - - end - - attr_reader :logger - - include TestRunner - - def setup_acceptance_test - Mocha::Configuration.reset_configuration - @logger = FakeLogger.new - mockery = Mocha::Mockery.instance - @original_logger = mockery.logger - mockery.logger = @logger - end - - def teardown_acceptance_test - Mocha::Configuration.reset_configuration - Mocha::Mockery.instance.logger = @original_logger - end - -end diff --git a/build_lib/mocha/test/acceptance/api_test.rb b/build_lib/mocha/test/acceptance/api_test.rb deleted file mode 100644 index 5e56aff..0000000 --- a/build_lib/mocha/test/acceptance/api_test.rb +++ /dev/null @@ -1,139 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha_standalone' -require 'simple_counter' - -class NotATestUnitAssertionFailedError < StandardError -end - -class NotATestUnitTestCase - - include Mocha::API - - attr_reader :assertion_counter - - def initialize - @assertion_counter = SimpleCounter.new - end - - def run(test_method) - mocha_setup - begin - prepare - begin - send(test_method) - mocha_verify(@assertion_counter) - rescue Mocha::ExpectationError => e - new_error = NotATestUnitAssertionFailedError.new(e.message) - new_error.set_backtrace(e.backtrace) - raise new_error - ensure - cleanup - end - ensure - mocha_teardown - end - end - - def prepare - end - - def cleanup - end - -end - -class SampleTest < NotATestUnitTestCase - - def mocha_with_fulfilled_expectation - mockee = mock() - mockee.expects(:blah) - mockee.blah - end - - def mocha_with_unfulfilled_expectation - mockee = mock() - mockee.expects(:blah) - end - - def mocha_with_unexpected_invocation - mockee = mock() - mockee.blah - end - - def stubba_with_fulfilled_expectation - stubbee = Class.new { define_method(:blah) {} }.new - stubbee.expects(:blah) - stubbee.blah - end - - def stubba_with_unfulfilled_expectation - stubbee = Class.new { define_method(:blah) {} }.new - stubbee.expects(:blah) - end - - def mocha_with_matching_parameter - mockee = mock() - mockee.expects(:blah).with(has_key(:wibble)) - mockee.blah(:wibble => 1) - end - - def mocha_with_non_matching_parameter - mockee = mock() - mockee.expects(:blah).with(has_key(:wibble)) - mockee.blah(:wobble => 2) - end - -end - -require 'test/unit' - -class APITest < Test::Unit::TestCase - - attr_reader :sample_test - - include AcceptanceTest - - def setup - @sample_test = SampleTest.new - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_pass_mocha_test - assert_nothing_raised { sample_test.run(:mocha_with_fulfilled_expectation) } - assert_equal 1, sample_test.assertion_counter.count - end - - def test_should_fail_mocha_test_due_to_unfulfilled_exception - assert_raises(NotATestUnitAssertionFailedError) { sample_test.run(:mocha_with_unfulfilled_expectation) } - assert_equal 1, sample_test.assertion_counter.count - end - - def test_should_fail_mocha_test_due_to_unexpected_invocation - assert_raises(NotATestUnitAssertionFailedError) { sample_test.run(:mocha_with_unexpected_invocation) } - assert_equal 0, sample_test.assertion_counter.count - end - - def test_should_pass_stubba_test - assert_nothing_raised { sample_test.run(:stubba_with_fulfilled_expectation) } - assert_equal 1, sample_test.assertion_counter.count - end - - def test_should_fail_stubba_test - assert_raises(NotATestUnitAssertionFailedError) { sample_test.run(:stubba_with_unfulfilled_expectation) } - assert_equal 1, sample_test.assertion_counter.count - end - - def test_should_pass_mocha_test_with_matching_parameter - assert_nothing_raised { sample_test.run(:mocha_with_matching_parameter) } - assert_equal 1, sample_test.assertion_counter.count - end - - def test_should_fail_mocha_test_with_non_matching_parameter - assert_raises(NotATestUnitAssertionFailedError) { sample_test.run(:mocha_with_non_matching_parameter) } - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/bug_18914_test.rb b/build_lib/mocha/test/acceptance/bug_18914_test.rb deleted file mode 100644 index b28d365..0000000 --- a/build_lib/mocha/test/acceptance/bug_18914_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class Bug18914Test < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - class AlwaysEql - - def my_method - true - end - - def ==(o) - true - end - - def eql?(o) - true - end - - end - - def test_should_not_allow_stubbing_of_non_mock_instance_disrupted_by_legitimate_overriding_of_eql_method - - always_eql_1 = AlwaysEql.new - always_eql_1.stubs(:my_method).returns(false) - - always_eql_2 = AlwaysEql.new - always_eql_2.stubs(:my_method).returns(false) - - assert_equal false, always_eql_2.my_method - end - -end diff --git a/build_lib/mocha/test/acceptance/bug_21465_test.rb b/build_lib/mocha/test/acceptance/bug_21465_test.rb deleted file mode 100644 index bc25145..0000000 --- a/build_lib/mocha/test/acceptance/bug_21465_test.rb +++ /dev/null @@ -1,34 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class Bug21465Test < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_expected_method_name_to_be_a_string - test_result = run_as_test do - mock = mock() - mock.expects('wibble') - mock.wibble - end - assert_passed(test_result) - end - - def test_should_allow_stubbed_method_name_to_be_a_string - test_result = run_as_test do - mock = mock() - mock.stubs('wibble') - mock.wibble - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/bug_21563_test.rb b/build_lib/mocha/test/acceptance/bug_21563_test.rb deleted file mode 100644 index f59395e..0000000 --- a/build_lib/mocha/test/acceptance/bug_21563_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class Bug21563Test < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_of_verified_method - test_result = run_as_test do - object = Object.new - object.stubs(:verified?).returns(false) - assert !object.verified? - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/exception_rescue_test.rb b/build_lib/mocha/test/acceptance/exception_rescue_test.rb deleted file mode 100644 index cceeab9..0000000 --- a/build_lib/mocha/test/acceptance/exception_rescue_test.rb +++ /dev/null @@ -1,58 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class ExceptionRescueTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_unexpected_invocation_exception_is_not_caught_by_standard_rescue - test_result = run_as_test do - mock = mock('mock') - begin - mock.some_method - rescue => e - flunk "should not rescue #{e.class}" - end - end - assert_failed(test_result) - failure_message_lines = test_result.failure_messages.first.split("\n") - assert_equal "unexpected invocation: #.some_method()", failure_message_lines.first - end - - def test_invocation_never_expected_exception_is_not_caught_by_standard_rescue - test_result = run_as_test do - mock = mock('mock') - mock.expects(:some_method).never - begin - mock.some_method - rescue => e - flunk "should not rescue #{e.class}" - end - end - assert_failed(test_result) - failure_message_lines = test_result.failure_messages.first.split("\n") - assert_equal "unexpected invocation: #.some_method()", failure_message_lines.first - end - - def test_unsatisfied_expectation_exception_is_not_caught_by_standard_rescue - test_result = run_as_test do - mock = mock('mock') - mock.expects(:some_method) - end - assert_failed(test_result) - failure_message_lines = test_result.failure_messages.first.split("\n") - assert_equal [ - "not all expectations were satisfied", - "unsatisfied expectations:", - "- expected exactly once, not yet invoked: #.some_method(any_parameters)" - ], failure_message_lines - end -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/expected_invocation_count_test.rb b/build_lib/mocha/test/acceptance/expected_invocation_count_test.rb deleted file mode 100644 index 88374e7..0000000 --- a/build_lib/mocha/test/acceptance/expected_invocation_count_test.rb +++ /dev/null @@ -1,196 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class ExpectedInvocationCountTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_pass_if_method_is_never_expected_and_is_never_called - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).never - 0.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_fail_fast_if_method_is_never_expected_but_is_called_once - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).never - 1.times { mock.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nsatisfied expectations:\n- expected never, not yet invoked: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_pass_if_method_is_expected_twice_and_is_called_twice - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).twice - 2.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_fail_if_method_is_expected_twice_but_is_called_once - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).twice - 1.times { mock.method } - end - assert_failed(test_result) - assert_equal ["not all expectations were satisfied\nunsatisfied expectations:\n- expected exactly twice, already invoked once: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_fail_fast_if_method_is_expected_twice_but_is_called_three_times - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).twice - 3.times { mock.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nsatisfied expectations:\n- expected exactly twice, already invoked twice: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_pass_if_method_is_expected_between_two_and_four_times_and_is_called_twice - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).times(2..4) - 2.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_pass_if_method_is_expected_between_two_and_four_times_and_is_called_three_times - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).times(2..4) - 3.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_pass_if_method_is_expected_between_two_and_four_times_and_is_called_four_times - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).times(2..4) - 4.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_fail_if_method_is_expected_between_two_and_four_times_and_is_called_once - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).times(2..4) - 1.times { mock.method } - end - assert_failed(test_result) - assert_equal ["not all expectations were satisfied\nunsatisfied expectations:\n- expected between 2 and 4 times, already invoked once: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_fail_fast_if_method_is_expected_between_two_and_four_times_and_is_called_five_times - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).times(2..4) - 5.times { mock.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nsatisfied expectations:\n- expected between 2 and 4 times, already invoked 4 times: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_pass_if_method_is_expected_at_least_once_and_is_called_once - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_least_once - 1.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_pass_if_method_is_expected_at_least_once_and_is_called_twice - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_least_once - 2.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_fail_if_method_is_expected_at_least_once_but_is_never_called - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_least_once - 0.times { mock.method } - end - assert_failed(test_result) - assert_equal ["not all expectations were satisfied\nunsatisfied expectations:\n- expected at least once, not yet invoked: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_pass_if_method_is_expected_at_most_once_and_is_never_called - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_most_once - 0.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_pass_if_method_is_expected_at_most_once_and_called_once - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_most_once - 1.times { mock.method } - end - assert_passed(test_result) - end - - def test_should_fail_fast_if_method_is_expected_at_most_once_but_is_called_twice - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).at_most_once - 2.times { mock.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nsatisfied expectations:\n- expected at most once, already invoked once: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_pass_if_method_is_never_expected_and_is_never_called_even_if_everything_is_stubbed - test_result = run_as_test do - stub = stub_everything('stub') - stub.expects(:method).never - 0.times { stub.method } - end - assert_passed(test_result) - end - - def test_should_fail_fast_if_method_is_never_expected_but_is_called_once_even_if_everything_is_stubbed - test_result = run_as_test do - stub = stub_everything('stub') - stub.expects(:method).never - 1.times { stub.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nsatisfied expectations:\n- expected never, not yet invoked: #.method(any_parameters)\n"], test_result.failure_messages - end - - def test_should_fail_fast_if_there_is_no_matching_expectation - test_result = run_as_test do - mock = mock('mock') - mock.expects(:method).with(1) - 1.times { mock.method } - end - assert_failed(test_result) - assert_equal ["unexpected invocation: #.method()\nunsatisfied expectations:\n- expected exactly once, not yet invoked: #.method(1)\n"], test_result.failure_messages - end - -end diff --git a/build_lib/mocha/test/acceptance/failure_messages_test.rb b/build_lib/mocha/test/acceptance/failure_messages_test.rb deleted file mode 100644 index 6809110..0000000 --- a/build_lib/mocha/test/acceptance/failure_messages_test.rb +++ /dev/null @@ -1,64 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class FailureMessagesTest < Test::Unit::TestCase - - OBJECT_ADDRESS_PATTERN = '0x[0-9A-Fa-f]{1,12}' - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - class Foo; end - - def test_should_display_class_name_when_expectation_was_on_class - test_result = run_as_test do - Foo.expects(:bar) - end - assert_match Regexp.new('FailureMessagesTest::Foo'), test_result.failures[0].message - end - - def test_should_display_class_name_and_address_when_expectation_was_on_instance - test_result = run_as_test do - Foo.new.expects(:bar) - end - assert_match Regexp.new("#"), test_result.failures[0].message - end - - def test_should_display_class_name_and_any_instance_prefix_when_expectation_was_on_any_instance - test_result = run_as_test do - Foo.any_instance.expects(:bar) - end - assert_match Regexp.new('#'), test_result.failures[0].message - end - - def test_should_display_mock_name_when_expectation_was_on_named_mock - test_result = run_as_test do - foo = mock('foo') - foo.expects(:bar) - end - assert_match Regexp.new('#'), test_result.failures[0].message - end - - def test_should_display_mock_address_when_expectation_was_on_unnamed_mock - test_result = run_as_test do - foo = mock() - foo.expects(:bar) - end - assert_match Regexp.new("#"), test_result.failures[0].message - end - - def test_should_display_string_when_expectation_was_on_string - test_result = run_as_test do - 'Foo'.expects(:bar) - end - assert_match Regexp.new("'Foo'"), test_result.failures[0].message - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/minitest_test.rb b/build_lib/mocha/test/acceptance/minitest_test.rb deleted file mode 100644 index 0abfb3b..0000000 --- a/build_lib/mocha/test/acceptance/minitest_test.rb +++ /dev/null @@ -1,157 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) - -if defined?(MiniTest) - $stderr.puts "TODO: Running suite with MiniTest, running the MiniTestAdapterTest results in an error so skipping it for now." -else - begin - require 'rubygems' - gem 'minitest' - rescue Gem::LoadError - # MiniTest gem not available - end - - begin - require 'minitest/unit' - rescue LoadError - # MiniTest not available - end - - if defined?(MiniTest) - - # monkey-patch MiniTest now that it has hopefully been loaded - require 'mocha/integration/mini_test' - - class MiniTestSampleTest < MiniTest::Unit::TestCase - - def test_mocha_with_fulfilled_expectation - mockee = mock() - mockee.expects(:blah) - mockee.blah - end - - def test_mocha_with_unfulfilled_expectation - mockee = mock() - mockee.expects(:blah) - end - - def test_mocha_with_unexpected_invocation - mockee = mock() - mockee.blah - end - - def test_stubba_with_fulfilled_expectation - stubbee = Class.new { define_method(:blah) {} }.new - stubbee.expects(:blah) - stubbee.blah - end - - def test_stubba_with_unfulfilled_expectation - stubbee = Class.new { define_method(:blah) {} }.new - stubbee.expects(:blah) - end - - def test_mocha_with_matching_parameter - mockee = mock() - mockee.expects(:blah).with(has_key(:wibble)) - mockee.blah(:wibble => 1) - end - - def test_mocha_with_non_matching_parameter - mockee = mock() - mockee.expects(:blah).with(has_key(:wibble)) - mockee.blah(:wobble => 2) - end - - end - - class MiniTestTest < Test::Unit::TestCase - - def setup - @output = StringIO.new - MiniTest::Unit.output = @output - @runner = MiniTest::Unit.new - end - - attr_reader :runner - - def test_should_pass_mocha_test - runner.run(%w(-n test_mocha_with_fulfilled_expectation)) - - assert_equal 0, runner.failures - assert_equal 0, runner.errors - assert_equal 1, runner.assertion_count - end - - def test_should_fail_mocha_test_due_to_unfulfilled_expectation - runner.run(%w(-n test_mocha_with_unfulfilled_expectation)) - - assert_equal 1, runner.failures - assert_equal 0, runner.errors - assert_equal 1, runner.assertion_count - assert_not_all_expectation_were_satisfied - end - - def test_should_fail_mocha_test_due_to_unexpected_invocation - runner.run(%w(-n test_mocha_with_unexpected_invocation)) - - assert_equal 1, runner.failures - assert_equal 0, runner.errors - assert_equal 0, runner.assertion_count - assert_unexpected_invocation - end - - def test_should_pass_stubba_test - runner.run(%w(-n test_stubba_with_fulfilled_expectation)) - - assert_equal 0, runner.failures - assert_equal 0, runner.errors - assert_equal 1, runner.assertion_count - end - - def test_should_fail_stubba_test_due_to_unfulfilled_expectation - runner.run(%w(-n test_stubba_with_unfulfilled_expectation)) - - assert_equal 1, runner.failures - assert_equal 0, runner.errors - assert_equal 1, runner.assertion_count - assert_not_all_expectation_were_satisfied - end - - def test_should_pass_mocha_test_with_matching_parameter - runner.run(%w(-n test_mocha_with_matching_parameter)) - - assert_equal 0, runner.failures - assert_equal 0, runner.errors - assert_equal 1, runner.assertion_count - end - - def test_should_fail_mocha_test_with_non_matching_parameter - runner.run(%w(-n test_mocha_with_non_matching_parameter)) - - assert_equal 1, runner.failures - assert_equal 0, runner.errors - assert_equal 0, runner.assertion_count # unexpected invocation occurs before expectation is verified - assert_unexpected_invocation - end - - private - - def output - @output.rewind - @output.read - end - - def assert_unexpected_invocation - assert_match Regexp.new('unexpected invocation'), output, "MiniTest output:\n#{output}" - end - - def assert_not_all_expectation_were_satisfied - assert_match Regexp.new('not all expectations were satisfied'), output, "MiniTest output:\n#{output}" - end - - end - - else - $stderr.puts "MiniTest is not available, so MiniTestAdapterTest has not been run." - end -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/mocha_example_test.rb b/build_lib/mocha/test/acceptance/mocha_example_test.rb deleted file mode 100644 index d2a476f..0000000 --- a/build_lib/mocha/test/acceptance/mocha_example_test.rb +++ /dev/null @@ -1,98 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha' - -class MochaExampleTest < Test::Unit::TestCase - - class Rover - - def initialize(left_track, right_track, steps_per_metre, steps_per_degree) - @left_track, @right_track, @steps_per_metre, @steps_per_degree = left_track, right_track, steps_per_metre, steps_per_degree - end - - def forward(metres) - @left_track.step(metres * @steps_per_metre) - @right_track.step(metres * @steps_per_metre) - wait - end - - def backward(metres) - forward(-metres) - end - - def left(degrees) - @left_track.step(-degrees * @steps_per_degree) - @right_track.step(+degrees * @steps_per_degree) - wait - end - - def right(degrees) - left(-degrees) - end - - def wait - while (@left_track.moving? or @right_track.moving?); end - end - - end - - def test_should_step_both_tracks_forward_ten_steps - left_track = mock('left_track') - right_track = mock('right_track') - steps_per_metre = 5 - rover = Rover.new(left_track, right_track, steps_per_metre, nil) - - left_track.expects(:step).with(10) - right_track.expects(:step).with(10) - - left_track.stubs(:moving?).returns(false) - right_track.stubs(:moving?).returns(false) - - rover.forward(2) - end - - def test_should_step_both_tracks_backward_ten_steps - left_track = mock('left_track') - right_track = mock('right_track') - steps_per_metre = 5 - rover = Rover.new(left_track, right_track, steps_per_metre, nil) - - left_track.expects(:step).with(-10) - right_track.expects(:step).with(-10) - - left_track.stubs(:moving?).returns(false) - right_track.stubs(:moving?).returns(false) - - rover.backward(2) - end - - def test_should_step_left_track_forwards_five_steps_and_right_track_backwards_five_steps - left_track = mock('left_track') - right_track = mock('right_track') - steps_per_degree = 5.0 / 90.0 - rover = Rover.new(left_track, right_track, nil, steps_per_degree) - - left_track.expects(:step).with(+5) - right_track.expects(:step).with(-5) - - left_track.stubs(:moving?).returns(false) - right_track.stubs(:moving?).returns(false) - - rover.right(90) - end - - def test_should_step_left_track_backwards_five_steps_and_right_track_forwards_five_steps - left_track = mock('left_track') - right_track = mock('right_track') - steps_per_degree = 5.0 / 90.0 - rover = Rover.new(left_track, right_track, nil, steps_per_degree) - - left_track.expects(:step).with(-5) - right_track.expects(:step).with(+5) - - left_track.stubs(:moving?).returns(false) - right_track.stubs(:moving?).returns(false) - - rover.left(90) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/mocha_test_result_test.rb b/build_lib/mocha/test/acceptance/mocha_test_result_test.rb deleted file mode 100644 index 28033e6..0000000 --- a/build_lib/mocha/test/acceptance/mocha_test_result_test.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' -require 'execution_point' - -class MochaTestResultTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_include_expectation_verification_in_assertion_count - test_result = run_as_test do - object = mock() - object.expects(:message) - object.message - end - assert_equal 1, test_result.assertion_count - end - - def test_should_include_assertions_in_assertion_count - test_result = run_as_test do - assert true - end - assert_equal 1, test_result.assertion_count - end - - def test_should_not_include_stubbing_expectation_verification_in_assertion_count - test_result = run_as_test do - object = mock() - object.stubs(:message) - object.message - end - assert_equal 0, test_result.assertion_count - end - - def test_should_include_expectation_verification_failure_in_failure_count - test_result = run_as_test do - object = mock() - object.expects(:message) - end - assert_equal 1, test_result.failure_count - end - - def test_should_include_unexpected_verification_failure_in_failure_count - test_result = run_as_test do - object = mock() - object.message - end - assert_equal 1, test_result.failure_count - end - - def test_should_include_assertion_failure_in_failure_count - test_result = run_as_test do - flunk - end - assert_equal 1, test_result.failure_count - end - - def test_should_display_backtrace_indicating_line_number_where_unexpected_method_was_called - execution_point = nil - test_result = run_as_test do - object = mock() - execution_point = ExecutionPoint.current; object.message - end - assert_equal 1, test_result.failure_count - assert_equal execution_point, ExecutionPoint.new(test_result.failures[0].location) - end - - def test_should_display_backtrace_indicating_line_number_where_failing_assertion_was_called - execution_point = nil - test_result = run_as_test do - execution_point = ExecutionPoint.current; flunk - end - assert_equal 1, test_result.failure_count - assert_equal execution_point, ExecutionPoint.new(test_result.failures[0].location) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/mock_test.rb b/build_lib/mocha/test/acceptance/mock_test.rb deleted file mode 100644 index 9170c33..0000000 --- a/build_lib/mocha/test/acceptance/mock_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class MockTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_build_mock_and_explicitly_add_an_expectation_which_is_satisfied - test_result = run_as_test do - foo = mock() - foo.expects(:bar) - foo.bar - end - assert_passed(test_result) - end - - def test_should_build_mock_and_explicitly_add_an_expectation_which_is_not_satisfied - test_result = run_as_test do - foo = mock() - foo.expects(:bar) - end - assert_failed(test_result) - end - - def test_should_build_named_mock_and_explicitly_add_an_expectation_which_is_satisfied - test_result = run_as_test do - foo = mock('foo') - foo.expects(:bar) - foo.bar - end - assert_passed(test_result) - end - - def test_should_build_named_mock_and_explicitly_add_an_expectation_which_is_not_satisfied - test_result = run_as_test do - foo = mock('foo') - foo.expects(:bar) - end - assert_failed(test_result) - end - - def test_should_build_mock_incorporating_two_expectations_which_are_satisifed - test_result = run_as_test do - foo = mock(:bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - end - assert_passed(test_result) - end - - def test_should_build_mock_incorporating_two_expectations_the_first_of_which_is_not_satisifed - test_result = run_as_test do - foo = mock(:bar => 'bar', :baz => 'baz') - foo.baz - end - assert_failed(test_result) - end - - def test_should_build_mock_incorporating_two_expectations_the_second_of_which_is_not_satisifed - test_result = run_as_test do - foo = mock(:bar => 'bar', :baz => 'baz') - foo.bar - end - assert_failed(test_result) - end - - def test_should_build_named_mock_incorporating_two_expectations_which_are_satisifed - test_result = run_as_test do - foo = mock('foo', :bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - end - assert_passed(test_result) - end - - def test_should_build_named_mock_incorporating_two_expectations_the_first_of_which_is_not_satisifed - test_result = run_as_test do - foo = mock('foo', :bar => 'bar', :baz => 'baz') - foo.baz - end - assert_failed(test_result) - end - - def test_should_build_named_mock_incorporating_two_expectations_the_second_of_which_is_not_satisifed - test_result = run_as_test do - foo = mock('foo', :bar => 'bar', :baz => 'baz') - foo.bar - end - assert_failed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/mock_with_initializer_block_test.rb b/build_lib/mocha/test/acceptance/mock_with_initializer_block_test.rb deleted file mode 100644 index cc8eda6..0000000 --- a/build_lib/mocha/test/acceptance/mock_with_initializer_block_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class MockWithInitializerBlockTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_expect_two_method_invocations_and_receive_both_of_them - test_result = run_as_test do - mock = mock() do - expects(:method_1) - expects(:method_2) - end - mock.method_1 - mock.method_2 - end - assert_passed(test_result) - end - - def test_should_expect_two_method_invocations_but_receive_only_one_of_them - test_result = run_as_test do - mock = mock() do - expects(:method_1) - expects(:method_2) - end - mock.method_1 - end - assert_failed(test_result) - end - - def test_should_stub_methods - test_result = run_as_test do - mock = mock() do - stubs(:method_1).returns(1) - stubs(:method_2).returns(2) - end - assert_equal 1, mock.method_1 - assert_equal 2, mock.method_2 - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/mocked_methods_dispatch_test.rb b/build_lib/mocha/test/acceptance/mocked_methods_dispatch_test.rb deleted file mode 100644 index 5c8b1f9..0000000 --- a/build_lib/mocha/test/acceptance/mocked_methods_dispatch_test.rb +++ /dev/null @@ -1,78 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class MockedMethodDispatchTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_find_latest_matching_expectation - test_result = run_as_test do - mock = mock() - mock.stubs(:method).returns(1) - mock.stubs(:method).returns(2) - assert_equal 2, mock.method - assert_equal 2, mock.method - assert_equal 2, mock.method - end - assert_passed(test_result) - end - - def test_should_find_latest_expectation_which_has_not_stopped_matching - test_result = run_as_test do - mock = mock() - mock.stubs(:method).returns(1) - mock.stubs(:method).once.returns(2) - assert_equal 2, mock.method - assert_equal 1, mock.method - assert_equal 1, mock.method - end - assert_passed(test_result) - end - - def test_should_keep_finding_later_stub_and_so_never_satisfy_earlier_expectation - test_result = run_as_test do - mock = mock() - mock.expects(:method).returns(1) - mock.stubs(:method).returns(2) - assert_equal 2, mock.method - assert_equal 2, mock.method - assert_equal 2, mock.method - end - assert_failed(test_result) - end - - def test_should_find_later_expectation_until_it_stops_matching_then_find_earlier_stub - test_result = run_as_test do - mock = mock() - mock.stubs(:method).returns(1) - mock.expects(:method).returns(2) - assert_equal 2, mock.method - assert_equal 1, mock.method - assert_equal 1, mock.method - end - assert_passed(test_result) - end - - def test_should_find_latest_expectation_with_range_of_expected_invocation_count_which_has_not_stopped_matching - test_result = run_as_test do - mock = mock() - mock.stubs(:method).returns(1) - mock.stubs(:method).times(2..3).returns(2) - assert_equal 2, mock.method - assert_equal 2, mock.method - assert_equal 2, mock.method - assert_equal 1, mock.method - assert_equal 1, mock.method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/optional_parameters_test.rb b/build_lib/mocha/test/acceptance/optional_parameters_test.rb deleted file mode 100644 index 01de731..0000000 --- a/build_lib/mocha/test/acceptance/optional_parameters_test.rb +++ /dev/null @@ -1,70 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class OptionalParameterMatcherTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_pass_if_all_required_parameters_match_and_no_optional_parameters_are_supplied - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2) - end - assert_passed(test_result) - end - - def test_should_pass_if_all_required_and_optional_parameters_match_and_some_optional_parameters_are_supplied - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2, 3) - end - assert_passed(test_result) - end - - def test_should_pass_if_all_required_and_optional_parameters_match_and_all_optional_parameters_are_supplied - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2, 3, 4) - end - assert_passed(test_result) - end - - def test_should_fail_if_all_required_and_optional_parameters_match_but_too_many_optional_parameters_are_supplied - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2, 3, 4, 5) - end - assert_failed(test_result) - end - - def test_should_fail_if_all_required_parameters_match_but_some_optional_parameters_do_not_match - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2, 4) - end - assert_failed(test_result) - end - - def test_should_fail_if_all_required_parameters_match_but_no_optional_parameters_match - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(1, 2, optionally(3, 4)) - mock.method(1, 2, 4, 5) - end - assert_failed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/parameter_matcher_test.rb b/build_lib/mocha/test/acceptance/parameter_matcher_test.rb deleted file mode 100644 index 1c73f73..0000000 --- a/build_lib/mocha/test/acceptance/parameter_matcher_test.rb +++ /dev/null @@ -1,246 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class ParameterMatcherTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_match_hash_parameter_with_specified_key - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:key_1)) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_key - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:key_1)) - mock.method(:key_2 => 'value_2') - end - assert_failed(test_result) - end - - def test_should_match_hash_parameter_with_specified_value - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_value('value_1')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_value - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_value('value_1')) - mock.method(:key_2 => 'value_2') - end - assert_failed(test_result) - end - - def test_should_match_hash_parameter_with_specified_key_value_pair - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entry(:key_1, 'value_1')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_key_value_pair - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entry(:key_1, 'value_2')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_failed(test_result) - end - - def test_should_match_hash_parameter_with_specified_hash_entry - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entry(:key_1 => 'value_1')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_hash_entry - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entry(:key_1 => 'value_2')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2') - end - assert_failed(test_result) - end - - def test_should_match_hash_parameter_with_specified_entries - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entries(:key_1 => 'value_1', :key_2 => 'value_2')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2', :key_3 => 'value_3') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_entries - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entries(:key_1 => 'value_1', :key_2 => 'value_2')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_3') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_matches_regular_expression - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(regexp_matches(/meter/)) - mock.method('this parameter should match') - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_match_regular_expression - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(regexp_matches(/something different/)) - mock.method('this parameter should not match') - end - assert_failed(test_result) - end - - def test_should_match_hash_parameter_with_specified_entries_using_nested_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entries(:key_1 => regexp_matches(/value_1/), kind_of(Symbol) => 'value_2')) - mock.method(:key_1 => 'value_1', :key_2 => 'value_2', :key_3 => 'value_3') - end - assert_passed(test_result) - end - - def test_should_not_match_hash_parameter_with_specified_entries_using_nested_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_entries(:key_1 => regexp_matches(/value_1/), kind_of(String) => 'value_2')) - mock.method(:key_1 => 'value_2', :key_2 => 'value_3') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_matches_any_value - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(any_of('value_1', 'value_2')).times(2) - mock.method('value_1') - mock.method('value_2') - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_match_any_value - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(any_of('value_1', 'value_2')) - mock.method('value_3') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_matches_any_of_the_given_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:foo) | has_key(:bar)).times(2) - mock.method(:foo => 'fooval') - mock.method(:bar => 'barval') - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_match_any_of_the_given_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:foo) | has_key(:bar)) - mock.method(:baz => 'bazval') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_matches_all_values - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(all_of('value_1', 'value_1')) - mock.method('value_1') - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_match_all_values - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(all_of('value_1', 'value_2')) - mock.method('value_1') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_matches_all_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:foo) & has_key(:bar)) - mock.method(:foo => 'fooval', :bar => 'barval') - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_match_all_matchers - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(has_key(:foo) & has_key(:bar)) - mock.method(:foo => 'fooval', :baz => 'bazval') - end - assert_failed(test_result) - end - - def test_should_match_parameter_that_responds_with_specified_value - klass = Class.new do - def quack - 'quack' - end - end - duck = klass.new - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(responds_with(:quack, 'quack')) - mock.method(duck) - end - assert_passed(test_result) - end - - def test_should_not_match_parameter_that_does_not_respond_with_specified_value - klass = Class.new do - def quack - 'woof' - end - end - duck = klass.new - test_result = run_as_test do - mock = mock() - mock.expects(:method).with(responds_with(:quack, 'quack')) - mock.method(duck) - end - assert_failed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/partial_mocks_test.rb b/build_lib/mocha/test/acceptance/partial_mocks_test.rb deleted file mode 100644 index c494f78..0000000 --- a/build_lib/mocha/test/acceptance/partial_mocks_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class PartialMockTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_pass_if_all_expectations_are_satisfied - test_result = run_as_test do - partial_mock_one = "partial_mock_one" - partial_mock_two = "partial_mock_two" - - partial_mock_one.expects(:first) - partial_mock_one.expects(:second) - partial_mock_two.expects(:third) - - partial_mock_one.first - partial_mock_one.second - partial_mock_two.third - end - assert_passed(test_result) - end - - def test_should_fail_if_all_expectations_are_not_satisfied - test_result = run_as_test do - partial_mock_one = "partial_mock_one" - partial_mock_two = "partial_mock_two" - - partial_mock_one.expects(:first) - partial_mock_one.expects(:second) - partial_mock_two.expects(:third) - - partial_mock_one.first - partial_mock_two.third - end - assert_failed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/return_value_test.rb b/build_lib/mocha/test/acceptance/return_value_test.rb deleted file mode 100644 index a1abcb5..0000000 --- a/build_lib/mocha/test/acceptance/return_value_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class ReturnValueTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_build_mock_and_explicitly_add_an_expectation_with_a_return_value - test_result = run_as_test do - foo = mock('foo') - foo.expects(:bar).returns('bar') - assert_equal 'bar', foo.bar - end - assert_passed(test_result) - end - - def test_should_build_mock_incorporating_two_expectations_with_return_values - test_result = run_as_test do - foo = mock('foo', :bar => 'bar', :baz => 'baz') - assert_equal 'bar', foo.bar - assert_equal 'baz', foo.baz - end - assert_passed(test_result) - end - - def test_should_build_stub_and_explicitly_add_an_expectation_with_a_return_value - test_result = run_as_test do - foo = stub('foo') - foo.stubs(:bar).returns('bar') - assert_equal 'bar', foo.bar - end - assert_passed(test_result) - end - - def test_should_build_stub_incorporating_two_expectations_with_return_values - test_result = run_as_test do - foo = stub('foo', :bar => 'bar', :baz => 'baz') - assert_equal 'bar', foo.bar - assert_equal 'baz', foo.baz - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/sequence_test.rb b/build_lib/mocha/test/acceptance/sequence_test.rb deleted file mode 100644 index 0eb8c99..0000000 --- a/build_lib/mocha/test/acceptance/sequence_test.rb +++ /dev/null @@ -1,186 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class SequenceTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_constrain_invocations_to_occur_in_expected_order - test_result = run_as_test do - mock = mock() - sequence = sequence('one') - - mock.expects(:first).in_sequence(sequence) - mock.expects(:second).in_sequence(sequence) - - mock.second - end - assert_failed(test_result) - end - - def test_should_allow_invocations_in_sequence - test_result = run_as_test do - mock = mock() - sequence = sequence('one') - - mock.expects(:first).in_sequence(sequence) - mock.expects(:second).in_sequence(sequence) - - mock.first - mock.second - end - assert_passed(test_result) - end - - def test_should_constrain_invocations_to_occur_in_expected_order_even_if_expected_on_different_mocks - test_result = run_as_test do - mock_one = mock('1') - mock_two = mock('2') - sequence = sequence('one') - - mock_one.expects(:first).in_sequence(sequence) - mock_two.expects(:second).in_sequence(sequence) - - mock_two.second - end - assert_failed(test_result) - end - - def test_should_allow_invocations_in_sequence_even_if_expected_on_different_mocks - test_result = run_as_test do - mock_one = mock('1') - mock_two = mock('2') - sequence = sequence('one') - - mock_one.expects(:first).in_sequence(sequence) - mock_two.expects(:second).in_sequence(sequence) - - mock_one.first - mock_two.second - end - assert_passed(test_result) - end - - def test_should_constrain_invocations_to_occur_in_expected_order_even_if_expected_on_partial_mocks - test_result = run_as_test do - partial_mock_one = "1" - partial_mock_two = "2" - sequence = sequence('one') - - partial_mock_one.expects(:first).in_sequence(sequence) - partial_mock_two.expects(:second).in_sequence(sequence) - - partial_mock_two.second - end - assert_failed(test_result) - end - - def test_should_allow_invocations_in_sequence_even_if_expected_on_partial_mocks - test_result = run_as_test do - partial_mock_one = "1" - partial_mock_two = "2" - sequence = sequence('one') - - partial_mock_one.expects(:first).in_sequence(sequence) - partial_mock_two.expects(:second).in_sequence(sequence) - - partial_mock_one.first - partial_mock_two.second - end - assert_passed(test_result) - end - - def test_should_allow_stub_expectations_to_be_skipped_in_sequence - test_result = run_as_test do - mock = mock() - sequence = sequence('one') - - mock.expects(:first).in_sequence(sequence) - mock.stubs(:second).in_sequence(sequence) - mock.expects(:third).in_sequence(sequence) - - mock.first - mock.third - end - assert_passed(test_result) - end - - def test_should_regard_sequences_as_independent_of_each_other - test_result = run_as_test do - mock = mock() - sequence_one = sequence('one') - sequence_two = sequence('two') - - mock.expects(:first).in_sequence(sequence_one) - mock.expects(:second).in_sequence(sequence_one) - - mock.expects(:third).in_sequence(sequence_two) - mock.expects(:fourth).in_sequence(sequence_two) - - mock.first - mock.third - mock.second - mock.fourth - end - assert_passed(test_result) - end - - def test_should_include_sequence_in_failure_message - test_result = run_as_test do - mock = mock() - sequence = sequence('one') - - mock.expects(:first).in_sequence(sequence) - mock.expects(:second).in_sequence(sequence) - - mock.second - end - assert_failed(test_result) - assert_match Regexp.new("in sequence 'one'"), test_result.failures.first.message - end - - def test_should_allow_expectations_to_be_in_more_than_one_sequence - test_result = run_as_test do - mock = mock() - sequence_one = sequence('one') - sequence_two = sequence('two') - - mock.expects(:first).in_sequence(sequence_one) - mock.expects(:second).in_sequence(sequence_two) - mock.expects(:three).in_sequence(sequence_one).in_sequence(sequence_two) - - mock.first - mock.three - end - assert_failed(test_result) - assert_match Regexp.new("in sequence 'one'"), test_result.failures.first.message - assert_match Regexp.new("in sequence 'two'"), test_result.failures.first.message - end - - def test_should_have_shortcut_for_expectations_to_be_in_more_than_one_sequence - test_result = run_as_test do - mock = mock() - sequence_one = sequence('one') - sequence_two = sequence('two') - - mock.expects(:first).in_sequence(sequence_one) - mock.expects(:second).in_sequence(sequence_two) - mock.expects(:three).in_sequence(sequence_one, sequence_two) - - mock.first - mock.three - end - assert_failed(test_result) - assert_match Regexp.new("in sequence 'one'"), test_result.failures.first.message - assert_match Regexp.new("in sequence 'two'"), test_result.failures.first.message - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/states_test.rb b/build_lib/mocha/test/acceptance/states_test.rb deleted file mode 100644 index e6f4d10..0000000 --- a/build_lib/mocha/test/acceptance/states_test.rb +++ /dev/null @@ -1,70 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StatesTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_constrain_expectations_to_occur_within_a_given_state - test_result = run_as_test do - mock = mock() - readiness = states('readiness') - - mock.stubs(:first).when(readiness.is('ready')) - mock.stubs(:second).then(readiness.is('ready')) - - mock.first - end - assert_failed(test_result) - end - - def test_should_allow_expectations_to_occur_in_correct_state - test_result = run_as_test do - mock = mock() - readiness = states('readiness') - - mock.stubs(:first).when(readiness.is('ready')) - mock.stubs(:second).then(readiness.is('ready')) - - mock.second - mock.first - end - assert_passed(test_result) - end - - def test_should_be_able_to_start_in_a_specific_state - test_result = run_as_test do - mock = mock() - readiness = states('readiness') - - mock.stubs(:first).when(readiness.is('ready')) - - readiness.starts_as('ready') - mock.first - end - assert_passed(test_result) - end - - def test_should_switch_state_when_method_raises_an_exception - test_result = run_as_test do - mock = mock() - readiness = states('readiness') - - mock.expects(:first).raises().then(readiness.is('ready')) - mock.expects(:second).when(readiness.is('ready')) - - mock.first rescue nil - mock.second - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_any_instance_method_test.rb b/build_lib/mocha/test/acceptance/stub_any_instance_method_test.rb deleted file mode 100644 index cbb9e5d..0000000 --- a/build_lib/mocha/test/acceptance/stub_any_instance_method_test.rb +++ /dev/null @@ -1,198 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubAnyInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_stub_method_within_test - klass = Class.new do - def my_instance_method - :original_return_value - end - end - instance = klass.new - test_result = run_as_test do - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_leave_stubbed_public_method_unchanged_after_test - klass = Class.new do - def my_instance_method - :original_return_value - end - end - instance = klass.new - run_as_test do - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.public_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.my_instance_method - end - - def test_should_leave_stubbed_protected_method_unchanged_after_test - klass = Class.new do - def my_instance_method - :original_return_value - end - protected :my_instance_method - def my_unprotected_instance_method - my_instance_method - end - end - instance = klass.new - run_as_test do - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.protected_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.my_unprotected_instance_method - end - - def test_should_leave_stubbed_private_method_unchanged_after_test - klass = Class.new do - def my_instance_method - :original_return_value - end - private :my_instance_method - end - instance = klass.new - run_as_test do - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.private_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.send(:my_instance_method) - end - - def test_should_reset_expectations_after_test - klass = Class.new do - def my_instance_method - :original_return_value - end - end - instance = klass.new - run_as_test do - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert_equal 0, klass.any_instance.mocha.expectations.length - end - - def test_should_be_able_to_stub_a_superclass_method - superklass = Class.new do - def my_superclass_method - :original_return_value - end - end - klass = Class.new(superklass) - instance = klass.new - test_result = run_as_test do - klass.any_instance.stubs(:my_superclass_method).returns(:new_return_value) - assert_equal :new_return_value, instance.my_superclass_method - end - assert_passed(test_result) - assert instance.public_methods(true).any? { |m| m.to_s == 'my_superclass_method' } - assert !klass.public_methods(false).any? { |m| m.to_s == 'my_superclass_method' } - assert_equal :original_return_value, instance.my_superclass_method - end - - def test_should_be_able_to_stub_method_if_ruby18_public_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def public_instance_methods(include_superclass = true) - ['my_instance_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.new.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_public_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def public_instance_methods(include_superclass = true) - [:my_instance_method] - end - end - end - test_result = run_as_test do - ruby19_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.new.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_protected_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def protected_instance_methods(include_superclass = true) - ['my_instance_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.new.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_protected_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def protected_instance_methods(include_superclass = true) - [:my_instance_method] - end - end - end - test_result = run_as_test do - ruby19_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.new.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_private_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def private_instance_methods(include_superclass = true) - ['my_instance_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.new.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_private_instance_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def private_instance_methods(include_superclass = true) - [:my_instance_method] - end - end - end - test_result = run_as_test do - ruby19_klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.new.my_instance_method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_class_method_test.rb b/build_lib/mocha/test/acceptance/stub_class_method_test.rb deleted file mode 100644 index a704081..0000000 --- a/build_lib/mocha/test/acceptance/stub_class_method_test.rb +++ /dev/null @@ -1,206 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubClassMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_stub_method_within_test - klass = Class.new do - class << self - def my_class_method - :original_return_value - end - end - end - test_result = run_as_test do - klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_leave_stubbed_public_method_unchanged_after_test - klass = Class.new do - class << self - def my_class_method - :original_return_value - end - end - end - run_as_test do - klass.stubs(:my_class_method).returns(:new_return_value) - end - assert klass.public_methods(false).any? { |m| m.to_s == 'my_class_method' } - assert_equal :original_return_value, klass.my_class_method - end - - def test_should_leave_stubbed_protected_method_unchanged_after_test - klass = Class.new do - class << self - def my_class_method - :original_return_value - end - protected :my_class_method - def my_unprotected_class_method - my_class_method - end - end - end - run_as_test do - klass.stubs(:my_class_method).returns(:new_return_value) - end - assert klass.protected_methods(false).any? { |m| m.to_s == 'my_class_method' } - assert_equal :original_return_value, klass.my_unprotected_class_method - end - - def test_should_leave_stubbed_private_method_unchanged_after_test - klass = Class.new do - class << self - def my_class_method - :original_return_value - end - private :my_class_method - end - end - run_as_test do - klass.stubs(:my_class_method).returns(:new_return_value) - end - assert klass.private_methods(false).any? { |m| m.to_s == 'my_class_method' } - assert_equal :original_return_value, klass.send(:my_class_method) - end - - def test_should_reset_class_expectations_after_test - klass = Class.new do - class << self - def my_class_method - :original_return_value - end - end - end - run_as_test do - klass.stubs(:my_class_method) - end - assert_equal 0, klass.mocha.expectations.length - end - - def test_should_be_able_to_stub_a_superclass_method - superklass = Class.new do - class << self - def my_superclass_method - :original_return_value - end - end - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.stubs(:my_superclass_method).returns(:new_return_value) - assert_equal :new_return_value, klass.my_superclass_method - end - assert_passed(test_result) - superklass_public_methods = superklass.public_methods - superklass.superclass.public_methods - assert superklass_public_methods.any? { |m| m.to_s == 'my_superclass_method' } - klass_public_methods = klass.public_methods - klass.superclass.public_methods - assert !klass_public_methods.any? { |m| m.to_s == 'my_superclass_method' } - assert_equal :original_return_value, superklass.my_superclass_method - end - - def test_should_be_able_to_stub_method_if_ruby18_public_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def public_methods(include_superclass = true) - ['my_class_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_public_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def public_methods(include_superclass = true) - [:my_class_method] - end - end - end - test_result = run_as_test do - ruby19_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_protected_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def protected_methods(include_superclass = true) - ['my_class_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_protected_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def protected_methods(include_superclass = true) - [:my_class_method] - end - end - end - test_result = run_as_test do - ruby19_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_private_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_klass = Class.new do - class << self - def private_methods(include_superclass = true) - ['my_class_method'] - end - end - end - test_result = run_as_test do - ruby18_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_klass.my_class_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_private_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_klass = Class.new do - class << self - def private_methods(include_superclass = true) - [:my_class_method] - end - end - end - test_result = run_as_test do - ruby19_klass.stubs(:my_class_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_klass.my_class_method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_everything_test.rb b/build_lib/mocha/test/acceptance/stub_everything_test.rb deleted file mode 100644 index 8945a3b..0000000 --- a/build_lib/mocha/test/acceptance/stub_everything_test.rb +++ /dev/null @@ -1,56 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubEverythingTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_build_stub_and_explicitly_add_an_expectation - test_result = run_as_test do - foo = stub_everything() - foo.stubs(:bar) - foo.bar - foo.unexpected_invocation - end - assert_passed(test_result) - end - - def test_should_build_named_stub_and_explicitly_add_an_expectation - test_result = run_as_test do - foo = stub_everything('foo') - foo.stubs(:bar) - foo.bar - foo.unexpected_invocation - end - assert_passed(test_result) - end - - def test_should_build_stub_incorporating_two_expectations - test_result = run_as_test do - foo = stub_everything(:bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - foo.unexpected_invocation - end - assert_passed(test_result) - end - - def test_should_build_named_stub_incorporating_two_expectations - test_result = run_as_test do - foo = stub_everything('foo', :bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - foo.unexpected_invocation - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_instance_method_test.rb b/build_lib/mocha/test/acceptance/stub_instance_method_test.rb deleted file mode 100644 index 6139f6f..0000000 --- a/build_lib/mocha/test/acceptance/stub_instance_method_test.rb +++ /dev/null @@ -1,206 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_leave_stubbed_public_method_unchanged_after_test - instance = Class.new do - def my_instance_method - :original_return_value - end - end.new - run_as_test do - instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.public_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.my_instance_method - end - - def test_should_leave_stubbed_protected_method_unchanged_after_test - instance = Class.new do - def my_instance_method - :original_return_value - end - protected :my_instance_method - def my_unprotected_instance_method - my_instance_method - end - end.new - run_as_test do - instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.protected_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.my_unprotected_instance_method - end - - def test_should_leave_stubbed_private_method_unchanged_after_test - instance = Class.new do - def my_instance_method - :original_return_value - end - private :my_instance_method - end.new - run_as_test do - instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert instance.private_methods(false).any? { |m| m.to_s == 'my_instance_method' } - assert_equal :original_return_value, instance.send(:my_instance_method) - end - - def test_should_reset_expectations_after_test - instance = Class.new do - def my_instance_method - :original_return_value - end - end.new - run_as_test do - instance.stubs(:my_instance_method).returns(:new_return_value) - end - assert_equal 0, instance.mocha.expectations.length - end - - def test_should_be_able_to_stub_a_superclass_method - superklass = Class.new do - def my_superclass_method - :original_return_value - end - end - klass = Class.new(superklass) - instance = klass.new - test_result = run_as_test do - instance.stubs(:my_superclass_method).returns(:new_return_value) - assert_equal :new_return_value, instance.my_superclass_method - end - assert_passed(test_result) - assert instance.public_methods(true).any? { |m| m.to_s == 'my_superclass_method' } - assert !instance.public_methods(false).any? { |m| m.to_s == 'my_superclass_method' } - assert_equal :original_return_value, instance.my_superclass_method - end - - def test_should_be_able_to_stub_method_if_ruby18_public_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby18_instance = Class.new do - def public_methods(include_superclass = true) - ['my_instance_method'] - end - end.new - test_result = run_as_test do - ruby18_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_public_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby19_instance = Class.new do - def public_methods(include_superclass = true) - [:my_instance_method] - end - end.new - test_result = run_as_test do - ruby19_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_protected_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby18_instance = Class.new do - def protected_methods(include_superclass = true) - ['my_instance_method'] - end - end.new - test_result = run_as_test do - ruby18_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_protected_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby19_instance = Class.new do - def protected_methods(include_superclass = true) - [:my_instance_method] - end - end.new - test_result = run_as_test do - ruby19_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_private_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby18_instance = Class.new do - def private_methods(include_superclass = true) - ['my_instance_method'] - end - end.new - test_result = run_as_test do - ruby18_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_private_methods_include_method_but_method_does_not_exist_like_active_record_association_proxy - ruby19_instance = Class.new do - def private_methods(include_superclass = true) - [:my_instance_method] - end - end.new - test_result = run_as_test do - ruby19_instance.stubs(:my_instance_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_instance.my_instance_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_specify_expectations_on_multiple_methods_in_a_single_call_to_expects - instance = Class.new do - def my_instance_method_1 - :original_return_value_1 - end - def my_instance_method_2 - :original_return_value_2 - end - end.new - run_as_test do - instance.expects( - :my_instance_method_1 => :new_return_value_1, - :my_instance_method_2 => :new_return_value_2 - ) - assert_equal :new_return_value_1, instance.my_instance_method_1 - assert_equal :new_return_value_2, instance.my_instance_method_2 - end - end - - def test_should_be_able_to_specify_expectations_on_multiple_methods_in_a_single_call_to_stubs - instance = Class.new do - def my_instance_method_1 - :original_return_value_1 - end - def my_instance_method_2 - :original_return_value_2 - end - end.new - run_as_test do - instance.stubs( - :my_instance_method_1 => :new_return_value_1, - :my_instance_method_2 => :new_return_value_2 - ) - assert_equal :new_return_value_1, instance.my_instance_method_1 - assert_equal :new_return_value_2, instance.my_instance_method_2 - end - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_module_method_test.rb b/build_lib/mocha/test/acceptance/stub_module_method_test.rb deleted file mode 100644 index b6fb0d2..0000000 --- a/build_lib/mocha/test/acceptance/stub_module_method_test.rb +++ /dev/null @@ -1,163 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubModuleMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_stub_method_within_test - mod = Module.new { def self.my_module_method; :original_return_value; end } - test_result = run_as_test do - mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_leave_stubbed_public_method_unchanged_after_test - mod = Module.new { class << self; def my_module_method; :original_return_value; end; public :my_module_method; end } - run_as_test do - mod.stubs(:my_module_method).returns(:new_return_value) - end - assert mod.public_methods(false).any? { |m| m.to_s == 'my_module_method' } - assert_equal :original_return_value, mod.my_module_method - end - - def test_should_leave_stubbed_protected_method_unchanged_after_test - mod = Module.new { class << self; def my_module_method; :original_return_value; end; protected :my_module_method; def my_unprotected_module_method; my_module_method; end; end } - run_as_test do - mod.stubs(:my_module_method).returns(:new_return_value) - end - assert mod.protected_methods(false).any? { |m| m.to_s == 'my_module_method' } - assert_equal :original_return_value, mod.my_unprotected_module_method - end - - def test_should_leave_stubbed_private_method_unchanged_after_test - mod = Module.new { class << self; def my_module_method; :original_return_value; end; private :my_module_method; end } - run_as_test do - mod.stubs(:my_module_method).returns(:new_return_value) - end - assert mod.private_methods(false).any? { |m| m.to_s == 'my_module_method' } - assert_equal :original_return_value, mod.send(:my_module_method) - end - - def test_should_reset_expectations_after_test - mod = Module.new { def self.my_module_method; :original_return_value; end } - run_as_test do - mod.stubs(:my_module_method) - end - assert_equal 0, mod.mocha.expectations.length - end - - def test_should_be_able_to_stub_a_superclass_method - supermod = Module.new { def self.my_superclass_method; :original_return_value; end } - mod = Module.new { include supermod } - test_result = run_as_test do - mod.stubs(:my_superclass_method).returns(:new_return_value) - assert_equal :new_return_value, mod.my_superclass_method - end - assert_passed(test_result) - assert supermod.public_methods.any? { |m| m.to_s == 'my_superclass_method' } - assert !mod.public_methods(false).any? { |m| m.to_s == 'my_superclass_method' } - assert_equal :original_return_value, supermod.my_superclass_method - end - - def test_should_be_able_to_stub_method_if_ruby18_public_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_mod = Module.new do - class << self - def public_methods(include_superclass = true) - ['my_module_method'] - end - end - end - test_result = run_as_test do - ruby18_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_public_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_mod = Module.new do - class << self - def public_methods(include_superclass = true) - [:my_module_method] - end - end - end - test_result = run_as_test do - ruby19_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby_18_protected_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_mod = Module.new do - class << self - def protected_methods(include_superclass = true) - ['my_module_method'] - end - end - end - test_result = run_as_test do - ruby18_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_protected_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_mod = Module.new do - class << self - def protected_methods(include_superclass = true) - [:my_module_method] - end - end - end - test_result = run_as_test do - ruby19_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby18_private_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby18_mod = Module.new do - class << self - def private_methods(include_superclass = true) - ['my_module_method'] - end - end - end - test_result = run_as_test do - ruby18_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby18_mod.my_module_method - end - assert_passed(test_result) - end - - def test_should_be_able_to_stub_method_if_ruby19_private_methods_include_method_but_method_does_not_actually_exist_like_active_record_association_proxy - ruby19_mod = Module.new do - class << self - def private_methods(include_superclass = true) - [:my_module_method] - end - end - end - test_result = run_as_test do - ruby19_mod.stubs(:my_module_method).returns(:new_return_value) - assert_equal :new_return_value, ruby19_mod.my_module_method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stub_test.rb b/build_lib/mocha/test/acceptance/stub_test.rb deleted file mode 100644 index 759fd5d..0000000 --- a/build_lib/mocha/test/acceptance/stub_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_build_stub_and_explicitly_add_an_expectation - test_result = run_as_test do - foo = stub() - foo.stubs(:bar) - foo.bar - end - assert_passed(test_result) - end - - def test_should_build_named_stub_and_explicitly_add_an_expectation - test_result = run_as_test do - foo = stub('foo') - foo.stubs(:bar) - foo.bar - end - assert_passed(test_result) - end - - def test_should_build_stub_incorporating_two_expectations - test_result = run_as_test do - foo = stub(:bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - end - assert_passed(test_result) - end - - def test_should_build_named_stub_incorporating_two_expectations - test_result = run_as_test do - foo = stub('foo', :bar => 'bar', :baz => 'baz') - foo.bar - foo.baz - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stubba_example_test.rb b/build_lib/mocha/test/acceptance/stubba_example_test.rb deleted file mode 100644 index 092ce1f..0000000 --- a/build_lib/mocha/test/acceptance/stubba_example_test.rb +++ /dev/null @@ -1,102 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha' - -class Widget - - def model - 'original_model' - end - - class << self - - def find(options) - [] - end - - def create(attributes) - Widget.new - end - - end - -end - -module Thingy - - def self.wotsit - :hoojamaflip - end - -end - -class StubbaExampleTest < Test::Unit::TestCase - - def test_should_stub_instance_method - widget = Widget.new - widget.expects(:model).returns('different_model') - assert_equal 'different_model', widget.model - end - - def test_should_stub_module_method - should_stub_module_method - end - - def test_should_stub_module_method_again - should_stub_module_method - end - - def test_should_stub_class_method - should_stub_class_method - end - - def test_should_stub_class_method_again - should_stub_class_method - end - - def test_should_stub_instance_method_on_any_instance_of_a_class - should_stub_instance_method_on_any_instance_of_a_class - end - - def test_should_stub_instance_method_on_any_instance_of_a_class_again - should_stub_instance_method_on_any_instance_of_a_class - end - - def test_should_stub_two_different_class_methods - should_stub_two_different_class_methods - end - - def test_should_stub_two_different_class_methods_again - should_stub_two_different_class_methods - end - - private - - def should_stub_module_method - Thingy.expects(:wotsit).returns(:dooda) - assert_equal :dooda, Thingy.wotsit - end - - def should_stub_class_method - widgets = [Widget.new] - Widget.expects(:find).with(:all).returns(widgets) - assert_equal widgets, Widget.find(:all) - end - - def should_stub_two_different_class_methods - found_widgets = [Widget.new] - created_widget = Widget.new - Widget.expects(:find).with(:all).returns(found_widgets) - Widget.expects(:create).with(:model => 'wombat').returns(created_widget) - assert_equal found_widgets, Widget.find(:all) - assert_equal created_widget, Widget.create(:model => 'wombat') - end - - def should_stub_instance_method_on_any_instance_of_a_class - Widget.any_instance.expects(:model).at_least_once.returns('another_model') - widget_1 = Widget.new - widget_2 = Widget.new - assert_equal 'another_model', widget_1.model - assert_equal 'another_model', widget_2.model - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stubba_test.rb b/build_lib/mocha/test/acceptance/stubba_test.rb deleted file mode 100644 index 6c7f386..0000000 --- a/build_lib/mocha/test/acceptance/stubba_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'deprecation_disabler' - -class StubbaTest < Test::Unit::TestCase - - include DeprecationDisabler - - def test_should_report_deprecation_of_stubba_which_will_be_removed_in_a_future_release - disable_deprecations do - load 'stubba.rb' - end - assert Mocha::Deprecation.messages.include?("require 'stubba' is no longer needed and stubba.rb will soon be removed") - end - -end diff --git a/build_lib/mocha/test/acceptance/stubba_test_result_test.rb b/build_lib/mocha/test/acceptance/stubba_test_result_test.rb deleted file mode 100644 index 65436e1..0000000 --- a/build_lib/mocha/test/acceptance/stubba_test_result_test.rb +++ /dev/null @@ -1,66 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' -require 'execution_point' - -class StubbaTestResultTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_include_expectation_verification_in_assertion_count - test_result = run_as_test do - object = Class.new { def message; end }.new - object.expects(:message) - object.message - end - assert_equal 1, test_result.assertion_count - end - - def test_should_include_assertions_in_assertion_count - test_result = run_as_test do - assert true - end - assert_equal 1, test_result.assertion_count - end - - def test_should_not_include_stubbing_expectation_verification_in_assertion_count - test_result = run_as_test do - object = Class.new { def message; end }.new - object.stubs(:message) - object.message - end - assert_equal 0, test_result.assertion_count - end - - def test_should_include_expectation_verification_failure_in_failure_count - test_result = run_as_test do - object = Class.new { def message; end }.new - object.expects(:message) - end - assert_equal 1, test_result.failure_count - end - - def test_should_include_assertion_failure_in_failure_count - test_result = run_as_test do - flunk - end - assert_equal 1, test_result.failure_count - end - - def test_should_display_backtrace_indicating_line_number_where_failing_assertion_was_called - execution_point = nil - test_result = run_as_test do - execution_point = ExecutionPoint.current; flunk - end - assert_equal 1, test_result.failure_count - assert_equal execution_point, ExecutionPoint.new(test_result.failures[0].location) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stubbing_error_backtrace_test.rb b/build_lib/mocha/test/acceptance/stubbing_error_backtrace_test.rb deleted file mode 100644 index ca81ef6..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_error_backtrace_test.rb +++ /dev/null @@ -1,64 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' -require 'execution_point' - -class StubbingErrorBacktraceTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_display_backtrace_indicating_line_number_where_attempt_to_stub_non_existent_method_was_made - execution_point = nil - object = Object.new - Mocha::Configuration.prevent(:stubbing_non_existent_method) - test_result = run_as_test do - execution_point = ExecutionPoint.current; object.stubs(:non_existent_method) - end - assert_equal 1, test_result.error_count - assert_equal execution_point, ExecutionPoint.new(test_result.errors[0].exception.backtrace) - end - - def test_should_display_backtrace_indicating_line_number_where_attempt_to_stub_non_public_method_was_made - execution_point = nil - object = Class.new do - def non_public_method; end - private :non_public_method - end.new - Mocha::Configuration.prevent(:stubbing_non_public_method) - test_result = run_as_test do - execution_point = ExecutionPoint.current; object.stubs(:non_public_method) - end - assert_equal 1, test_result.error_count - assert_equal execution_point, ExecutionPoint.new(test_result.errors[0].exception.backtrace) - end - - def test_should_display_backtrace_indicating_line_number_where_attempt_to_stub_method_on_non_mock_object_was_made - execution_point = nil - object = Object.new - Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object) - test_result = run_as_test do - execution_point = ExecutionPoint.current; object.stubs(:any_method) - end - assert_equal 1, test_result.error_count - assert_equal execution_point, ExecutionPoint.new(test_result.errors[0].exception.backtrace) - end - - def test_should_display_backtrace_indicating_line_number_where_method_was_unnecessarily_stubbed - execution_point = nil - object = Object.new - Mocha::Configuration.prevent(:stubbing_method_unnecessarily) - test_result = run_as_test do - execution_point = ExecutionPoint.current; object.stubs(:unused_method) - end - assert_equal 1, test_result.error_count - assert_equal execution_point, ExecutionPoint.new(test_result.errors[0].exception.backtrace) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_method_unnecessarily_test.rb b/build_lib/mocha/test/acceptance/stubbing_method_unnecessarily_test.rb deleted file mode 100644 index 38260bc..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_method_unnecessarily_test.rb +++ /dev/null @@ -1,65 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingMethodUnnecessarilyTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_method_unnecessarily - Mocha::Configuration.allow(:stubbing_method_unnecessarily) - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:public_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?('stubbing method unnecessarily: #.public_method(any_parameters)') - end - - def test_should_warn_when_stubbing_method_unnecessarily - Mocha::Configuration.warn_when(:stubbing_method_unnecessarily) - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:public_method) - end - assert_passed(test_result) - assert @logger.warnings.include?('stubbing method unnecessarily: #.public_method(any_parameters)') - end - - def test_should_prevent_stubbing_method_unnecessarily - Mocha::Configuration.prevent(:stubbing_method_unnecessarily) - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:public_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?('Mocha::StubbingError: stubbing method unnecessarily: #.public_method(any_parameters)') - end - - def test_should_default_to_allow_stubbing_method_unnecessarily - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:public_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?('stubbing method unnecessarily: #.public_method(any_parameters)') - end - - def test_should_allow_stubbing_method_when_stubbed_method_is_invoked - Mocha::Configuration.prevent(:stubbing_method_unnecessarily) - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:public_method) - mock.public_method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stubbing_non_existent_any_instance_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_existent_any_instance_method_test.rb deleted file mode 100644 index db22fe6..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +++ /dev/null @@ -1,130 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonExistentAnyInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_non_existent_any_instance_method - Mocha::Configuration.allow(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.any_instance.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{klass.any_instance.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_warn_when_stubbing_non_existent_any_instance_method - Mocha::Configuration.warn_when(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.any_instance.stubs(:non_existent_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-existent method: #{klass.any_instance.mocha_inspect}.non_existent_method") - end - - def test_should_prevent_stubbing_non_existent_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.any_instance.stubs(:non_existent_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-existent method: #{klass.any_instance.mocha_inspect}.non_existent_method") - end - - def test_should_default_to_allow_stubbing_non_existent_any_instance_method - klass = Class.new - test_result = run_as_test do - klass.any_instance.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{klass.any_instance.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_public_method; end - public :existing_public_method - end - test_result = run_as_test do - klass.any_instance.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_protected_method; end - protected :existing_protected_method - end - test_result = run_as_test do - klass.any_instance.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_private_method; end - private :existing_private_method - end - test_result = run_as_test do - klass.any_instance.stubs(:existing_private_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_any_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_public_method; end - public :existing_public_method - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.any_instance.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_any_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_protected_method; end - protected :existing_protected_method - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.any_instance.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_any_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_private_method; end - private :existing_private_method - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.any_instance.stubs(:existing_private_method) - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_non_existent_class_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_existent_class_method_test.rb deleted file mode 100644 index c139012..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_existent_class_method_test.rb +++ /dev/null @@ -1,157 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonExistentClassMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_non_existent_class_method - Mocha::Configuration.allow(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{klass.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_warn_when_stubbing_non_existent_class_method - Mocha::Configuration.warn_when(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.stubs(:non_existent_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-existent method: #{klass.mocha_inspect}.non_existent_method") - end - - def test_should_prevent_stubbing_non_existent_class_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new - test_result = run_as_test do - klass.stubs(:non_existent_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-existent method: #{klass.mocha_inspect}.non_existent_method") - end - - def test_should_default_to_allow_stubbing_non_existent_class_method - klass = Class.new - test_result = run_as_test do - klass.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{klass.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_class_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - class << self - def existing_public_method; end - public :existing_public_method - end - end - test_result = run_as_test do - klass.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_method_to_which_class_responds - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - class << self - def respond_to?(method, include_private = false) - (method == :method_to_which_class_responds) - end - end - end - test_result = run_as_test do - klass.stubs(:method_to_which_class_responds) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_class_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - class << self - def existing_protected_method; end - protected :existing_protected_method - end - end - test_result = run_as_test do - klass.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_class_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - class << self - def existing_private_method; end - private :existing_private_method - end - end - test_result = run_as_test do - klass.stubs(:existing_private_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - class << self - def existing_public_method; end - public :existing_public_method - end - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - class << self - def existing_protected_method; end - protected :existing_protected_method - end - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - class << self - def existing_private_method; end - protected :existing_private_method - end - end - klass = Class.new(superklass) - test_result = run_as_test do - klass.stubs(:existing_private_method) - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_non_existent_instance_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_existent_instance_method_test.rb deleted file mode 100644 index e1a029b..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_existent_instance_method_test.rb +++ /dev/null @@ -1,147 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonExistentInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_non_existent_instance_method - Mocha::Configuration.allow(:stubbing_non_existent_method) - instance = Class.new.new - test_result = run_as_test do - instance.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{instance.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_warn_when_stubbing_non_existent_instance_method - Mocha::Configuration.warn_when(:stubbing_non_existent_method) - instance = Class.new.new - test_result = run_as_test do - instance.stubs(:non_existent_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-existent method: #{instance.mocha_inspect}.non_existent_method") - end - - def test_should_prevent_stubbing_non_existent_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - instance = Class.new.new - test_result = run_as_test do - instance.stubs(:non_existent_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-existent method: #{instance.mocha_inspect}.non_existent_method") - end - - def test_should_default_to_allow_stubbing_non_existent_instance_method - instance = Class.new.new - test_result = run_as_test do - instance.stubs(:non_existent_method) - end - assert !@logger.warnings.include?("stubbing non-existent method: #{instance.mocha_inspect}.non_existent_method") - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_public_method; end - public :existing_public_method - end - instance = klass.new - test_result = run_as_test do - instance.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_method_to_which_instance_responds - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def respond_to?(method, include_private = false) - (method == :method_to_which_instance_responds) - end - end - instance = klass.new - test_result = run_as_test do - instance.stubs(:method_to_which_instance_responds) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_protected_method; end - protected :existing_protected_method - end - instance = klass.new - test_result = run_as_test do - instance.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_instance_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - klass = Class.new do - def existing_private_method; end - private :existing_private_method - end - instance = klass.new - test_result = run_as_test do - instance.stubs(:existing_private_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_public_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_public_method; end - public :existing_public_method - end - instance = Class.new(superklass).new - test_result = run_as_test do - instance.stubs(:existing_public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_protected_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_protected_method; end - protected :existing_protected_method - end - instance = Class.new(superklass).new - test_result = run_as_test do - instance.stubs(:existing_protected_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_existing_private_instance_superclass_method - Mocha::Configuration.prevent(:stubbing_non_existent_method) - superklass = Class.new do - def existing_private_method; end - private :existing_private_method - end - instance = Class.new(superklass).new - test_result = run_as_test do - instance.stubs(:existing_private_method) - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_non_public_any_instance_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_public_any_instance_method_test.rb deleted file mode 100644 index b2a9bc8..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_public_any_instance_method_test.rb +++ /dev/null @@ -1,130 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonPublicAnyInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_private_any_instance_method - Mocha::Configuration.allow(:stubbing_non_public_method) - klass = Class.new do - def private_method; end - private :private_method - end - test_result = run_as_test do - klass.any_instance.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.private_method") - end - - def test_should_allow_stubbing_protected_any_instance_method - Mocha::Configuration.allow(:stubbing_non_public_method) - klass = Class.new do - def protected_method; end - protected :protected_method - end - test_result = run_as_test do - klass.any_instance.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.protected_method") - end - - def test_should_warn_when_stubbing_private_any_instance_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - klass = Class.new do - def private_method; end - private :private_method - end - test_result = run_as_test do - klass.any_instance.stubs(:private_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.private_method") - end - - def test_should_warn_when_stubbing_protected_any_instance_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - klass = Class.new do - def protected_method; end - protected :protected_method - end - test_result = run_as_test do - klass.any_instance.stubs(:protected_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.protected_method") - end - - def test_should_prevent_stubbing_private_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - def private_method; end - private :private_method - end - test_result = run_as_test do - klass.any_instance.stubs(:private_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{klass.any_instance.mocha_inspect}.private_method") - end - - def test_should_prevent_stubbing_protected_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - def protected_method; end - protected :protected_method - end - test_result = run_as_test do - klass.any_instance.stubs(:protected_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{klass.any_instance.mocha_inspect}.protected_method") - end - - def test_should_default_to_allow_stubbing_private_any_instance_method - klass = Class.new do - def private_method; end - private :private_method - end - test_result = run_as_test do - klass.any_instance.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.private_method") - end - - def test_should_default_to_allow_stubbing_protected_any_instance_method - klass = Class.new do - def protected_method; end - protected :protected_method - end - test_result = run_as_test do - klass.any_instance.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.any_instance.mocha_inspect}.protected_method") - end - - def test_should_allow_stubbing_public_any_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - def public_method; end - public :public_method - end - test_result = run_as_test do - klass.any_instance.stubs(:public_method) - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/stubbing_non_public_class_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_public_class_method_test.rb deleted file mode 100644 index 37c27b0..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_public_class_method_test.rb +++ /dev/null @@ -1,163 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonPublicClassMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_private_class_method - Mocha::Configuration.allow(:stubbing_non_public_method) - klass = Class.new do - class << self - def private_method; end - private :private_method - end - end - test_result = run_as_test do - klass.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.private_method") - end - - def test_should_allow_stubbing_protected_class_method - Mocha::Configuration.allow(:stubbing_non_public_method) - klass = Class.new do - class << self - def protected_method; end - protected :protected_method - end - end - test_result = run_as_test do - klass.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.protected_method") - end - - def test_should_warn_when_stubbing_private_class_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - klass = Class.new do - class << self - def private_method; end - private :private_method - end - end - test_result = run_as_test do - klass.stubs(:private_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.private_method") - end - - def test_should_warn_when_stubbing_protected_class_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - klass = Class.new do - class << self - def protected_method; end - protected :protected_method - end - end - test_result = run_as_test do - klass.stubs(:protected_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.protected_method") - end - - def test_should_prevent_stubbing_private_class_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - class << self - def private_method; end - private :private_method - end - end - test_result = run_as_test do - klass.stubs(:private_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{klass.mocha_inspect}.private_method") - end - - def test_should_prevent_stubbing_protected_class_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - class << self - def protected_method; end - protected :protected_method - end - end - test_result = run_as_test do - klass.stubs(:protected_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{klass.mocha_inspect}.protected_method") - end - - def test_should_default_to_allow_stubbing_private_class_method - klass = Class.new do - class << self - def private_method; end - private :private_method - end - end - test_result = run_as_test do - klass.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.private_method") - end - - def test_should_default_to_allow_stubbing_protected_class_method - klass = Class.new do - class << self - def protected_method; end - protected :protected_method - end - end - test_result = run_as_test do - klass.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{klass.mocha_inspect}.protected_method") - end - - def test_should_allow_stubbing_public_class_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - class << self - def public_method; end - public :public_method - end - end - test_result = run_as_test do - klass.stubs(:public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_method_to_which_class_responds - Mocha::Configuration.prevent(:stubbing_non_public_method) - klass = Class.new do - class << self - def respond_to?(method, include_private_methods = false) - (method == :method_to_which_class_responds) - end - end - end - test_result = run_as_test do - klass.stubs(:method_to_which_class_responds) - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_non_public_instance_method_test.rb b/build_lib/mocha/test/acceptance/stubbing_non_public_instance_method_test.rb deleted file mode 100644 index 8f64e44..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_non_public_instance_method_test.rb +++ /dev/null @@ -1,143 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingNonPublicInstanceMethodTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_private_instance_method - Mocha::Configuration.allow(:stubbing_non_public_method) - instance = Class.new do - def private_method; end - private :private_method - end.new - test_result = run_as_test do - instance.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.private_method") - end - - def test_should_allow_stubbing_protected_instance_method - Mocha::Configuration.allow(:stubbing_non_public_method) - instance = Class.new do - def protected_method; end - protected :protected_method - end.new - test_result = run_as_test do - instance.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.protected_method") - end - - def test_should_warn_when_stubbing_private_instance_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - instance = Class.new do - def private_method; end - private :private_method - end.new - test_result = run_as_test do - instance.stubs(:private_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.private_method") - end - - def test_should_warn_when_stubbing_protected_instance_method - Mocha::Configuration.warn_when(:stubbing_non_public_method) - instance = Class.new do - def protected_method; end - protected :protected_method - end.new - test_result = run_as_test do - instance.stubs(:protected_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.protected_method") - end - - def test_should_prevent_stubbing_private_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - instance = Class.new do - def private_method; end - private :private_method - end.new - test_result = run_as_test do - instance.stubs(:private_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{instance.mocha_inspect}.private_method") - end - - def test_should_prevent_stubbing_protected_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - instance = Class.new do - def protected_method; end - protected :protected_method - end.new - test_result = run_as_test do - instance.stubs(:protected_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing non-public method: #{instance.mocha_inspect}.protected_method") - end - - def test_should_default_to_allow_stubbing_private_instance_method - instance = Class.new do - def private_method; end - private :private_method - end.new - test_result = run_as_test do - instance.stubs(:private_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.private_method") - end - - def test_should_default_to_allow_stubbing_protected_instance_method - instance = Class.new do - def protected_method; end - protected :protected_method - end.new - test_result = run_as_test do - instance.stubs(:protected_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing non-public method: #{instance.mocha_inspect}.protected_method") - end - - def test_should_allow_stubbing_public_instance_method - Mocha::Configuration.prevent(:stubbing_non_public_method) - instance = Class.new do - def public_method; end - public :public_method - end.new - test_result = run_as_test do - instance.stubs(:public_method) - end - assert_passed(test_result) - end - - def test_should_allow_stubbing_method_to_which_instance_responds - Mocha::Configuration.prevent(:stubbing_non_public_method) - instance = Class.new do - def respond_to?(method, include_private_methods = false) - (method == :method_to_which_instance_responds) - end - end.new - test_result = run_as_test do - instance.stubs(:method_to_which_instance_responds) - end - assert_passed(test_result) - end - -end diff --git a/build_lib/mocha/test/acceptance/stubbing_on_non_mock_object_test.rb b/build_lib/mocha/test/acceptance/stubbing_on_non_mock_object_test.rb deleted file mode 100644 index 0369140..0000000 --- a/build_lib/mocha/test/acceptance/stubbing_on_non_mock_object_test.rb +++ /dev/null @@ -1,64 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class StubbingOnNonMockObjectTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_should_allow_stubbing_method_on_non_mock_object - Mocha::Configuration.allow(:stubbing_method_on_non_mock_object) - non_mock_object = Class.new { def existing_method; end } - test_result = run_as_test do - non_mock_object.stubs(:existing_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing method on non-mock object: #{non_mock_object.mocha_inspect}.existing_method") - end - - def test_should_warn_on_stubbing_method_on_non_mock_object - Mocha::Configuration.warn_when(:stubbing_method_on_non_mock_object) - non_mock_object = Class.new { def existing_method; end } - test_result = run_as_test do - non_mock_object.stubs(:existing_method) - end - assert_passed(test_result) - assert @logger.warnings.include?("stubbing method on non-mock object: #{non_mock_object.mocha_inspect}.existing_method") - end - - def test_should_prevent_stubbing_method_on_non_mock_object - Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object) - non_mock_object = Class.new { def existing_method; end } - test_result = run_as_test do - non_mock_object.stubs(:existing_method) - end - assert_failed(test_result) - assert test_result.error_messages.include?("Mocha::StubbingError: stubbing method on non-mock object: #{non_mock_object.mocha_inspect}.existing_method") - end - - def test_should_default_to_allow_stubbing_method_on_non_mock_object - non_mock_object = Class.new { def existing_method; end } - test_result = run_as_test do - non_mock_object.stubs(:existing_method) - end - assert_passed(test_result) - assert !@logger.warnings.include?("stubbing method on non-mock object: #{non_mock_object.mocha_inspect}.existing_method") - end - - def test_should_allow_stubbing_method_on_mock_object - Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object) - test_result = run_as_test do - mock = mock('mock') - mock.stubs(:any_method) - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/acceptance/unstubbing_test.rb b/build_lib/mocha/test/acceptance/unstubbing_test.rb deleted file mode 100644 index 87fc0f4..0000000 --- a/build_lib/mocha/test/acceptance/unstubbing_test.rb +++ /dev/null @@ -1,122 +0,0 @@ -require File.expand_path('../acceptance_test_helper', __FILE__) -require 'mocha' - -class UnstubbingTest < Test::Unit::TestCase - - include AcceptanceTest - - def setup - setup_acceptance_test - end - - def teardown - teardown_acceptance_test - end - - def test_unstubbing_an_instance_method_should_restore_original_behaviour - klass = Class.new do - def my_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - object.stubs(:my_instance_method).returns(:new_return_value) - object.unstub(:my_instance_method) - assert_equal :original_return_value, object.my_instance_method - end - assert_passed(test_result) - end - - def test_unstubbing_a_class_method_should_restore_original_behaviour - klass = Class.new do - def self.my_class_method; :original_return_value; end - end - test_result = run_as_test do - klass.stubs(:my_class_method).returns(:new_return_value) - klass.unstub(:my_class_method) - assert_equal :original_return_value, klass.my_class_method - end - assert_passed(test_result) - end - - def test_unstubbing_a_module_method_should_restore_original_behaviour - mod = Module.new do - def self.my_module_method; :original_return_value; end - end - test_result = run_as_test do - mod.stubs(:my_module_method).returns(:new_return_value) - mod.unstub(:my_module_method) - assert_equal :original_return_value, mod.my_module_method - end - assert_passed(test_result) - end - - def test_unstubbing_an_any_instance_method_should_restore_original_behaviour - klass = Class.new do - def my_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - klass.any_instance.stubs(:my_instance_method).returns(:new_return_value) - klass.any_instance.unstub(:my_instance_method) - assert_equal :original_return_value, object.my_instance_method - end - assert_passed(test_result) - end - - def test_unstubbing_multiple_methods_should_restore_original_behaviour - klass = Class.new do - def my_first_instance_method; :original_return_value; end - def my_second_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - object.stubs(:my_first_instance_method).returns(:new_return_value) - object.stubs(:my_second_instance_method).returns(:new_return_value) - object.unstub(:my_first_instance_method, :my_second_instance_method) - assert_equal :original_return_value, object.my_first_instance_method - assert_equal :original_return_value, object.my_second_instance_method - end - assert_passed(test_result) - end - - def test_unstubbing_a_method_multiple_times_should_restore_original_behaviour - klass = Class.new do - def my_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - object.stubs(:my_instance_method).returns(:new_return_value) - object.unstub(:my_instance_method) - object.unstub(:my_instance_method) - assert_equal :original_return_value, object.my_instance_method - end - assert_passed(test_result) - end - - def test_unstubbing_a_non_stubbed_method_should_do_nothing - klass = Class.new do - def my_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - object.unstub(:my_instance_method) - assert_equal :original_return_value, object.my_instance_method - end - assert_passed(test_result) - end - - def test_unstubbing_a_method_which_was_stubbed_multiple_times_should_restore_orginal_behaviour - klass = Class.new do - def my_instance_method; :original_return_value; end - end - test_result = run_as_test do - object = klass.new - object.stubs(:my_instance_method).with(:first).returns(:first_new_return_value) - object.stubs(:my_instance_method).with(:second).returns(:second_new_return_value) - object.unstub(:my_instance_method) - assert_equal :original_return_value, object.my_instance_method - end - assert_passed(test_result) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/deprecation_disabler.rb b/build_lib/mocha/test/deprecation_disabler.rb deleted file mode 100644 index c57fb3c..0000000 --- a/build_lib/mocha/test/deprecation_disabler.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'mocha/deprecation' - -module DeprecationDisabler - - def disable_deprecations - original_mode = Mocha::Deprecation.mode - Mocha::Deprecation.mode = :disabled - begin - yield - ensure - Mocha::Deprecation.mode = original_mode - end - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/execution_point.rb b/build_lib/mocha/test/execution_point.rb deleted file mode 100644 index 5824d2a..0000000 --- a/build_lib/mocha/test/execution_point.rb +++ /dev/null @@ -1,36 +0,0 @@ -class ExecutionPoint - - attr_reader :backtrace - - def self.current - new(caller) - end - - def initialize(backtrace) - @backtrace = backtrace - end - - def file_name - return "unknown" unless @backtrace && @backtrace.first - /\A(.*?):\d+/.match(@backtrace.first)[1] - end - - def line_number - return "unknown" unless @backtrace && @backtrace.first - Integer(/\A.*?:(\d+)/.match(@backtrace.first)[1]) - end - - def ==(other) - return false unless other.is_a?(ExecutionPoint) - (file_name == other.file_name) and (line_number == other.line_number) - end - - def to_s - "file: #{file_name}; line: #{line_number}" - end - - def inspect - to_s - end - -end diff --git a/build_lib/mocha/test/method_definer.rb b/build_lib/mocha/test/method_definer.rb deleted file mode 100644 index 816aa49..0000000 --- a/build_lib/mocha/test/method_definer.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'mocha/metaclass' - -module Mocha - - module ObjectMethods - def define_instance_method(method_symbol, &block) - __metaclass__.send(:define_method, method_symbol, block) - end - - def replace_instance_method(method_symbol, &block) - raise "Cannot replace #{method_symbol} as #{self} does not respond to it." unless self.respond_to?(method_symbol) - define_instance_method(method_symbol, &block) - end - - def define_instance_accessor(*symbols) - symbols.each { |symbol| __metaclass__.send(:attr_accessor, symbol) } - end - end - -end - -class Object - include Mocha::ObjectMethods -end \ No newline at end of file diff --git a/build_lib/mocha/test/mini_test_result.rb b/build_lib/mocha/test/mini_test_result.rb deleted file mode 100644 index 891b684..0000000 --- a/build_lib/mocha/test/mini_test_result.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'stringio' -require 'test/unit/testcase' -require 'minitest/unit' - -class MiniTestResult - def self.parse_failure(raw) - matches = %r{(Failure)\:\n([^\(]+)\(([^\)]+)\) \[([^\]]+)\]\:\n(.*)\n}m.match(raw) - return nil unless matches - Failure.new(matches[2], matches[3], [matches[4]], matches[5]) - end - - def self.parse_error(raw) - matches = %r{(Error)\:\n([^\(]+)\(([^\)]+)\)\:\n(.+?)\n.+ (.*)\n}m.match(raw) - return nil unless matches - Error.new(matches[2], matches[3], matches[4], [matches[5]]) - end - - class Failure - attr_reader :method, :test_case, :location, :message - def initialize(method, test_case, location, message) - @method, @test_case, @location, @message = method, test_case, location, message - end - end - - class Error - class Exception - attr_reader :message, :backtrace - def initialize(message, location) - @message, @backtrace = message, location - end - end - - attr_reader :method, :test_case, :exception - def initialize(method, test_case, message, backtrace) - @method, @test_case, @exception = method, test_case, Exception.new(message, backtrace) - end - end - - def initialize(runner, test) - @runner, @test = runner, test - end - - def failure_count - @runner.failures - end - - def assertion_count - @test._assertions - end - - def error_count - @runner.errors - end - - def passed? - @test.passed? - end - - def failures - @runner.report.map { |puked| MiniTestResult.parse_failure(puked) }.compact - end - - def errors - @runner.report.map { |puked| MiniTestResult.parse_error(puked) }.compact - end - - def failure_messages - failures.map(&:message) - end - - def error_messages - errors.map { |e| e.exception.message } - end -end \ No newline at end of file diff --git a/build_lib/mocha/test/simple_counter.rb b/build_lib/mocha/test/simple_counter.rb deleted file mode 100644 index a7b5b37..0000000 --- a/build_lib/mocha/test/simple_counter.rb +++ /dev/null @@ -1,13 +0,0 @@ -class SimpleCounter - - attr_reader :count - - def initialize - @count = 0 - end - - def increment - @count += 1 - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/test_helper.rb b/build_lib/mocha/test/test_helper.rb deleted file mode 100644 index 6deff8d..0000000 --- a/build_lib/mocha/test/test_helper.rb +++ /dev/null @@ -1,17 +0,0 @@ -unless defined?(STANDARD_OBJECT_PUBLIC_INSTANCE_METHODS) - STANDARD_OBJECT_PUBLIC_INSTANCE_METHODS = Object.public_instance_methods -end - -$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")) -$:.unshift File.expand_path(File.join(File.dirname(__FILE__))) -$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'unit')) -$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'unit', 'parameter_matchers')) -$:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'acceptance')) - -require 'mocha/options' -if $options['use_test_unit_gem'] - require 'rubygems' - gem 'test-unit' -end - -require 'test/unit' \ No newline at end of file diff --git a/build_lib/mocha/test/test_runner.rb b/build_lib/mocha/test/test_runner.rb deleted file mode 100644 index 140a305..0000000 --- a/build_lib/mocha/test/test_runner.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'test/unit/testcase' - -if defined?(MiniTest) - require 'mocha/integration/mini_test' - require File.expand_path('../mini_test_result', __FILE__) -else - require 'test/unit/testresult' -end - -module TestRunner - def run_as_test(test_result = nil, &block) - test_class = Class.new(Test::Unit::TestCase) do - define_method(:test_me, &block) - end - test = test_class.new(:test_me) - - if defined?(Test::Unit::TestResult) - test_result ||= Test::Unit::TestResult.new - test.run(test_result) {} - class << test_result - attr_reader :failures, :errors - def failure_messages - failures.map { |failure| failure.message } - end - def error_messages - errors.map { |error| error.message } - end - end - else - runner = MiniTest::Unit.new - test.run(runner) - test_result = MiniTestResult.new(runner, test) - end - - test_result - end - - def assert_passed(test_result) - flunk "Test failed unexpectedly with message: #{test_result.failures}" if test_result.failure_count > 0 - flunk "Test failed unexpectedly with message: #{test_result.errors}" if test_result.error_count > 0 - end - - def assert_failed(test_result) - flunk "Test passed unexpectedly" if test_result.passed? - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/any_instance_method_test.rb b/build_lib/mocha/test/unit/any_instance_method_test.rb deleted file mode 100644 index 5b892f9..0000000 --- a/build_lib/mocha/test/unit/any_instance_method_test.rb +++ /dev/null @@ -1,126 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'method_definer' -require 'mocha/mock' -require 'mocha/any_instance_method' - -class AnyInstanceMethodTest < Test::Unit::TestCase - - include Mocha - - def test_should_hide_original_method - klass = Class.new { def method_x; end } - method = AnyInstanceMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method.to_sym - - method.hide_original_method - - assert klass.method_defined?(hidden_method_x) - end - - def test_should_not_hide_original_method_if_it_is_not_defined - klass = Class.new - method = AnyInstanceMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method.to_sym - - method.hide_original_method - - assert_equal false, klass.method_defined?(hidden_method_x) - end - - def test_should_define_a_new_method - klass = Class.new { def method_x; end } - method = AnyInstanceMethod.new(klass, :method_x) - mocha = Mock.new - mocha.expects(:method_x).with(:param1, :param2).returns(:result) - any_instance = Object.new - any_instance.define_instance_method(:mocha) { mocha } - klass.define_instance_method(:any_instance) { any_instance } - - method.hide_original_method - method.define_new_method - - instance = klass.new - result = instance.method_x(:param1, :param2) - - assert_equal :result, result - assert mocha.__verified__? - end - - def test_should_restore_original_method - klass = Class.new { def method_x; end } - method = AnyInstanceMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method.to_sym - klass.send(:define_method, hidden_method_x, Proc.new { :original_result }) - - method.remove_new_method - method.restore_original_method - - instance = klass.new - assert_equal :original_result, instance.method_x - assert !klass.method_defined?(hidden_method_x) - end - - def test_should_not_restore_original_method_if_hidden_method_not_defined - klass = Class.new { def method_x; :new_result; end } - method = AnyInstanceMethod.new(klass, :method_x) - - method.restore_original_method - - instance = klass.new - assert_equal :new_result, instance.method_x - end - - def test_should_call_remove_new_method - klass = Class.new { def method_x; end } - any_instance = Mock.new - any_instance.stubs(:reset_mocha) - klass.define_instance_method(:any_instance) { any_instance } - method = AnyInstanceMethod.new(klass, :method_x) - method.replace_instance_method(:restore_original_method) { } - method.define_instance_accessor(:remove_called) - method.replace_instance_method(:remove_new_method) { self.remove_called = true } - - method.unstub - - assert method.remove_called - end - - def test_should_call_restore_original_method - klass = Class.new { def method_x; end } - any_instance = Mock.new - any_instance.stubs(:reset_mocha) - klass.define_instance_method(:any_instance) { any_instance } - method = AnyInstanceMethod.new(klass, :method_x) - method.replace_instance_method(:remove_new_method) { } - method.define_instance_accessor(:restore_called) - method.replace_instance_method(:restore_original_method) { self.restore_called = true } - - method.unstub - - assert method.restore_called - end - - def test_should_call_reset_mocha - klass = Class.new { def method_x; end } - any_instance = Class.new { attr_accessor :mocha_was_reset; def reset_mocha; self.mocha_was_reset = true; end }.new - klass.define_instance_method(:any_instance) { any_instance } - method = AnyInstanceMethod.new(klass, :method_x) - method.replace_instance_method(:remove_new_method) { } - method.replace_instance_method(:restore_original_method) { } - - method.unstub - - assert any_instance.mocha_was_reset - end - - def test_should_return_any_instance_mocha_for_stubbee - mocha = Object.new - any_instance = Object.new - any_instance.define_instance_method(:mocha) { mocha } - stubbee = Class.new - stubbee.define_instance_method(:any_instance) { any_instance } - method = AnyInstanceMethod.new(stubbee, :method_name) - assert_equal stubbee.any_instance.mocha, method.mock - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/array_inspect_test.rb b/build_lib/mocha/test/unit/array_inspect_test.rb deleted file mode 100644 index 0f6e349..0000000 --- a/build_lib/mocha/test/unit/array_inspect_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/inspect' - -class ArrayInspectTest < Test::Unit::TestCase - - def test_should_use_inspect - array = [1, 2] - assert_equal array.inspect, array.mocha_inspect - end - - def test_should_use_mocha_inspect_on_each_item - array = [1, 2, "chris"] - assert_equal "[1, 2, 'chris']", array.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/backtrace_filter_test.rb b/build_lib/mocha/test/unit/backtrace_filter_test.rb deleted file mode 100644 index e744b70..0000000 --- a/build_lib/mocha/test/unit/backtrace_filter_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/backtrace_filter' - -class BacktraceFilterTest < Test::Unit::TestCase - - include Mocha - - def test_should_exclude_mocha_locations_from_backtrace - mocha_lib = "/username/workspace/mocha_wibble/lib/" - backtrace = [ mocha_lib + 'exclude/me/1', mocha_lib + 'exclude/me/2', '/keep/me', mocha_lib + 'exclude/me/3'] - filter = BacktraceFilter.new(mocha_lib) - assert_equal ['/keep/me'], filter.filtered(backtrace) - end - - def test_should_determine_path_for_mocha_lib_directory - assert_match Regexp.new("/lib/$"), BacktraceFilter::LIB_DIRECTORY - end - -end diff --git a/build_lib/mocha/test/unit/cardinality_test.rb b/build_lib/mocha/test/unit/cardinality_test.rb deleted file mode 100644 index 782e3a4..0000000 --- a/build_lib/mocha/test/unit/cardinality_test.rb +++ /dev/null @@ -1,56 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/cardinality' - -class CardinalityTest < Test::Unit::TestCase - - include Mocha - - def test_should_allow_invocations_if_invocation_count_has_not_yet_reached_maximum - cardinality = Cardinality.new(2, 3) - assert cardinality.invocations_allowed?(0) - assert cardinality.invocations_allowed?(1) - assert cardinality.invocations_allowed?(2) - assert !cardinality.invocations_allowed?(3) - end - - def test_should_be_satisfied_if_invocations_so_far_have_reached_required_threshold - cardinality = Cardinality.new(2, 3) - assert !cardinality.satisfied?(0) - assert !cardinality.satisfied?(1) - assert cardinality.satisfied?(2) - assert cardinality.satisfied?(3) - end - - def test_should_describe_cardinality - assert_equal 'allowed any number of times', Cardinality.at_least(0).mocha_inspect - - assert_equal 'expected at most once', Cardinality.at_most(1).mocha_inspect - assert_equal 'expected at most twice', Cardinality.at_most(2).mocha_inspect - assert_equal 'expected at most 3 times', Cardinality.at_most(3).mocha_inspect - - assert_equal 'expected at least once', Cardinality.at_least(1).mocha_inspect - assert_equal 'expected at least twice', Cardinality.at_least(2).mocha_inspect - assert_equal 'expected at least 3 times', Cardinality.at_least(3).mocha_inspect - - assert_equal 'expected never', Cardinality.exactly(0).mocha_inspect - assert_equal 'expected exactly once', Cardinality.exactly(1).mocha_inspect - assert_equal 'expected exactly twice', Cardinality.exactly(2).mocha_inspect - assert_equal 'expected exactly 3 times', Cardinality.times(3).mocha_inspect - - assert_equal 'expected between 2 and 4 times', Cardinality.times(2..4).mocha_inspect - assert_equal 'expected between 1 and 3 times', Cardinality.times(1..3).mocha_inspect - end - - def test_should_need_verifying - assert Cardinality.exactly(2).needs_verifying? - assert Cardinality.at_least(3).needs_verifying? - assert Cardinality.at_most(2).needs_verifying? - assert Cardinality.times(4).needs_verifying? - assert Cardinality.times(2..4).needs_verifying? - end - - def test_should_not_need_verifying - assert_equal false, Cardinality.at_least(0).needs_verifying? - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/central_test.rb b/build_lib/mocha/test/unit/central_test.rb deleted file mode 100644 index cba1c84..0000000 --- a/build_lib/mocha/test/unit/central_test.rb +++ /dev/null @@ -1,91 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/central' -require 'mocha/mock' -require 'method_definer' - -class CentralTest < Test::Unit::TestCase - - include Mocha - - def test_should_start_with_empty_stubba_methods - stubba = Central.new - - assert_equal [], stubba.stubba_methods - end - - def test_should_stub_method_if_not_already_stubbed - method = Mock.new - method.expects(:stub) - stubba = Central.new - - stubba.stub(method) - - assert method.__verified__? - end - - def test_should_not_stub_method_if_already_stubbed - method = Mock.new - method.expects(:stub).times(0) - stubba = Central.new - stubba_methods = Mock.new - stubba_methods.stubs(:include?).with(method).returns(true) - stubba.stubba_methods = stubba_methods - - stubba.stub(method) - - assert method.__verified__? - end - - def test_should_record_method - method = Mock.new - method.expects(:stub) - stubba = Central.new - - stubba.stub(method) - - assert_equal [method], stubba.stubba_methods - end - - def test_should_unstub_specified_method - stubba = Central.new - method_1 = Mock.new - method_2 = Mock.new - method_2.expects(:unstub) - stubba.stubba_methods = [method_1, method_2] - - stubba.unstub(method_2) - - assert_equal [method_1], stubba.stubba_methods - assert method_2.__verified__? - end - - def test_should_not_unstub_specified_method_if_not_already_stubbed - stubba = Central.new - method_1 = Mock.new - method_2 = Mock.new - method_2.expects(:unstub).never - stubba.stubba_methods = [method_1] - - stubba.unstub(method_2) - - assert_equal [method_1], stubba.stubba_methods - assert method_2.__verified__? - end - - def test_should_unstub_all_methods - stubba = Central.new - method_1 = Mock.new - method_1.expects(:unstub) - method_2 = Mock.new - method_2.expects(:unstub) - stubba.stubba_methods = [method_1, method_2] - - stubba.unstub_all - - assert_equal [], stubba.stubba_methods - assert method_1.__verified__? - assert method_2.__verified__? - end - -end diff --git a/build_lib/mocha/test/unit/change_state_side_effect_test.rb b/build_lib/mocha/test/unit/change_state_side_effect_test.rb deleted file mode 100644 index be49434..0000000 --- a/build_lib/mocha/test/unit/change_state_side_effect_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/change_state_side_effect' - -class ChangeStateSideEffectTest < Test::Unit::TestCase - - include Mocha - - class FakeState - - attr_reader :active - attr_writer :description - - def activate - @active = true - end - - def mocha_inspect - @description - end - - end - - def test_should_activate_the_given_state - state = FakeState.new - side_effect = ChangeStateSideEffect.new(state) - - side_effect.perform - - assert state.active - end - - def test_should_describe_itself_in_terms_of_the_activated_state - state = FakeState.new - state.description = 'the-new-state' - side_effect = ChangeStateSideEffect.new(state) - - assert_equal 'then the-new-state', side_effect.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/class_method_test.rb b/build_lib/mocha/test/unit/class_method_test.rb deleted file mode 100644 index a0f8c1c..0000000 --- a/build_lib/mocha/test/unit/class_method_test.rb +++ /dev/null @@ -1,237 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'method_definer' -require 'mocha/mock' - -require 'mocha/class_method' - -class ClassMethodTest < Test::Unit::TestCase - - include Mocha - - def test_should_provide_hidden_version_of_method_name_starting_with_prefix - method = ClassMethod.new(nil, :original_method_name) - assert_match(/^__stubba__/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_ending_with_suffix - method = ClassMethod.new(nil, :original_method_name) - assert_match(/__stubba__$/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_including_original_method_name - method = ClassMethod.new(nil, :original_method_name) - assert_match(/original_method_name/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_substituting_question_mark - method = ClassMethod.new(nil, :question_mark?) - assert_no_match(/\?/, method.hidden_method.to_s) - assert_match(/question_mark_substituted_character_63/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_substituting_exclamation_mark - method = ClassMethod.new(nil, :exclamation_mark!) - assert_no_match(/!/, method.hidden_method.to_s) - assert_match(/exclamation_mark_substituted_character_33/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_substituting_equals_sign - method = ClassMethod.new(nil, :equals_sign=) - assert_no_match(/\=/, method.hidden_method.to_s) - assert_match(/equals_sign_substituted_character_61/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_substituting_brackets - method = ClassMethod.new(nil, :[]) - assert_no_match(/\[\]/, method.hidden_method.to_s) - assert_match(/substituted_character_91__substituted_character_93/, method.hidden_method.to_s) - end - - def test_should_provide_hidden_version_of_method_name_substituting_plus_sign - method = ClassMethod.new(nil, :+) - assert_no_match(/\+/, method.hidden_method.to_s) - assert_match(/substituted_character_43/, method.hidden_method.to_s) - end - - def test_should_hide_original_method - klass = Class.new { def self.method_x; end } - method = ClassMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method - - method.hide_original_method - - assert klass.respond_to?(hidden_method_x) - end - - def test_should_respond_to_original_method_name_after_original_method_has_been_hidden - klass = Class.new { def self.original_method_name; end } - method = ClassMethod.new(klass, :original_method_name) - hidden_method_x = method.hidden_method - - method.hide_original_method - - assert klass.respond_to?(:original_method_name) - end - - def test_should_not_hide_original_method_if_method_not_defined - klass = Class.new - method = ClassMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method - - method.hide_original_method - - assert_equal false, klass.respond_to?(hidden_method_x) - end - - def test_should_define_a_new_method_which_should_call_mocha_method_missing - klass = Class.new { def self.method_x; end } - mocha = Mocha::Mock.new - klass.define_instance_method(:mocha) { mocha } - mocha.expects(:method_x).with(:param1, :param2).returns(:result) - method = ClassMethod.new(klass, :method_x) - - method.hide_original_method - method.define_new_method - result = klass.method_x(:param1, :param2) - - assert_equal :result, result - assert mocha.__verified__? - end - - def test_should_remove_new_method - klass = Class.new { def self.method_x; end } - method = ClassMethod.new(klass, :method_x) - - method.remove_new_method - - assert_equal false, klass.respond_to?(:method_x) - end - - def test_should_restore_original_method - klass = Class.new { def self.method_x; end } - method = ClassMethod.new(klass, :method_x) - hidden_method_x = method.hidden_method.to_sym - klass.define_instance_method(hidden_method_x) { :original_result } - - method.remove_new_method - method.restore_original_method - - assert_equal :original_result, klass.method_x - assert_equal false, klass.respond_to?(hidden_method_x) - end - - def test_should_not_restore_original_method_if_hidden_method_is_not_defined - klass = Class.new { def self.method_x; :new_result; end } - method = ClassMethod.new(klass, :method_x) - - method.restore_original_method - - assert_equal :new_result, klass.method_x - end - - def test_should_call_hide_original_method - klass = Class.new { def self.method_x; end } - method = ClassMethod.new(klass, :method_x) - method.hide_original_method - method.define_instance_accessor(:hide_called) - method.replace_instance_method(:hide_original_method) { self.hide_called = true } - - method.stub - - assert method.hide_called - end - - def test_should_call_define_new_method - klass = Class.new { def self.method_x; end } - method = ClassMethod.new(klass, :method_x) - method.define_instance_accessor(:define_called) - method.replace_instance_method(:define_new_method) { self.define_called = true } - - method.stub - - assert method.define_called - end - - def test_should_call_remove_new_method - klass = Class.new { def self.method_x; end } - klass.define_instance_method(:reset_mocha) { } - method = ClassMethod.new(klass, :method_x) - method.define_instance_accessor(:remove_called) - method.replace_instance_method(:remove_new_method) { self.remove_called = true } - - method.unstub - - assert method.remove_called - end - - def test_should_call_restore_original_method - klass = Class.new { def self.method_x; end } - klass.define_instance_method(:reset_mocha) { } - method = ClassMethod.new(klass, :method_x) - method.define_instance_accessor(:restore_called) - method.replace_instance_method(:restore_original_method) { self.restore_called = true } - - method.unstub - - assert method.restore_called - end - - def test_should_call_reset_mocha - klass = Class.new { def self.method_x; end } - klass.define_instance_accessor(:reset_called) - klass.define_instance_method(:reset_mocha) { self.reset_called = true } - method = ClassMethod.new(klass, :method_x) - method.replace_instance_method(:restore_original_method) { } - - method.unstub - - assert klass.reset_called - end - - def test_should_return_mock_for_stubbee - mocha = Object.new - stubbee = Object.new - stubbee.define_instance_accessor(:mocha) { mocha } - stubbee.mocha = nil - method = ClassMethod.new(stubbee, :method_name) - assert_equal stubbee.mocha, method.mock - end - - def test_should_not_be_equal_if_other_object_has_a_different_class - class_method = ClassMethod.new(Object.new, :method) - other_object = Object.new - assert class_method != other_object - end - - def test_should_not_be_equal_if_other_class_method_has_different_stubbee - stubbee_1 = Object.new - stubbee_2 = Object.new - class_method_1 = ClassMethod.new(stubbee_1, :method) - class_method_2 = ClassMethod.new(stubbee_2, :method) - assert class_method_1 != class_method_2 - end - - def test_should_not_be_equal_if_other_class_method_has_different_method - stubbee = Object.new - class_method_1 = ClassMethod.new(stubbee, :method_1) - class_method_2 = ClassMethod.new(stubbee, :method_2) - assert class_method_1 != class_method_2 - end - - def test_should_be_equal_if_other_class_method_has_same_stubbee_and_same_method_so_no_attempt_is_made_to_stub_a_method_twice - stubbee = Object.new - class_method_1 = ClassMethod.new(stubbee, :method) - class_method_2 = ClassMethod.new(stubbee, :method) - assert class_method_1 == class_method_2 - end - - def test_should_be_equal_if_other_class_method_has_same_stubbee_and_same_method_but_stubbee_equal_method_lies_like_active_record_association_proxy - stubbee = Class.new do - def equal?(other); false; end - end.new - class_method_1 = ClassMethod.new(stubbee, :method) - class_method_2 = ClassMethod.new(stubbee, :method) - assert class_method_1 == class_method_2 - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/configuration_test.rb b/build_lib/mocha/test/unit/configuration_test.rb deleted file mode 100644 index 62922e5..0000000 --- a/build_lib/mocha/test/unit/configuration_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require "mocha/configuration" - -class ConfigurationTest < Test::Unit::TestCase - def test_allow_temporarily_changes_config_when_given_block - Mocha::Configuration.warn_when(:stubbing_method_unnecessarily) - yielded = false - Mocha::Configuration.allow(:stubbing_method_unnecessarily) do - yielded = true - assert Mocha::Configuration.allow?(:stubbing_method_unnecessarily) - end - assert yielded - assert Mocha::Configuration.warn_when?(:stubbing_method_unnecessarily) - end - - def test_prevent_temporarily_changes_config_when_given_block - Mocha::Configuration.allow(:stubbing_method_unnecessarily) - yielded = false - Mocha::Configuration.prevent(:stubbing_method_unnecessarily) do - yielded = true - assert Mocha::Configuration.prevent?(:stubbing_method_unnecessarily) - end - assert yielded - assert Mocha::Configuration.allow?(:stubbing_method_unnecessarily) - end - - def test_warn_when_temporarily_changes_config_when_given_block - Mocha::Configuration.allow(:stubbing_method_unnecessarily) - yielded = false - Mocha::Configuration.warn_when(:stubbing_method_unnecessarily) do - yielded = true - assert Mocha::Configuration.warn_when?(:stubbing_method_unnecessarily) - end - assert yielded - assert Mocha::Configuration.allow?(:stubbing_method_unnecessarily) - end -end - diff --git a/build_lib/mocha/test/unit/date_time_inspect_test.rb b/build_lib/mocha/test/unit/date_time_inspect_test.rb deleted file mode 100644 index f03c544..0000000 --- a/build_lib/mocha/test/unit/date_time_inspect_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/inspect' - -class DateTimeInspectTest < Test::Unit::TestCase - - def test_should_use_include_date_in_seconds - time = Time.now - assert_equal "#{time.inspect} (#{time.to_f} secs)", time.mocha_inspect - end - - def test_should_use_to_s_for_date - date = Date.new(2006, 1, 1) - assert_equal date.to_s, date.mocha_inspect - end - - def test_should_use_to_s_for_datetime - datetime = DateTime.new(2006, 1, 1) - assert_equal datetime.to_s, datetime.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/exception_raiser_test.rb b/build_lib/mocha/test/unit/exception_raiser_test.rb deleted file mode 100644 index 79cbeab..0000000 --- a/build_lib/mocha/test/unit/exception_raiser_test.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/exception_raiser' -require 'timeout' - -class ExceptionRaiserTest < Test::Unit::TestCase - - include Mocha - - def test_should_raise_exception_with_specified_class_and_default_message - exception_class = Class.new(StandardError) - raiser = ExceptionRaiser.new(exception_class, nil) - exception = assert_raises(exception_class) { raiser.evaluate } - assert_equal exception_class.to_s, exception.message - end - - def test_should_raise_exception_with_specified_class_and_message - exception_class = Class.new(StandardError) - raiser = ExceptionRaiser.new(exception_class, 'message') - exception = assert_raises(exception_class) { raiser.evaluate } - assert_equal 'message', exception.message - end - - def test_should_raise_exception_instance - exception_class = Class.new(StandardError) - raiser = ExceptionRaiser.new(exception_class.new('message'), nil) - exception = assert_raises(exception_class) { raiser.evaluate } - assert_equal 'message', exception.message - end - - def test_should_raise_interrupt_exception_with_default_message_so_it_works_in_ruby_1_8_6 - raiser = ExceptionRaiser.new(Interrupt, nil) - assert_raises(Interrupt) { raiser.evaluate } - end - - def test_should_raise_subclass_of_interrupt_exception_with_default_message_so_it_works_in_ruby_1_8_6 - exception_class = Class.new(Interrupt) - raiser = ExceptionRaiser.new(exception_class, nil) - assert_raises(exception_class) { raiser.evaluate } - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/expectation_list_test.rb b/build_lib/mocha/test/unit/expectation_list_test.rb deleted file mode 100644 index b53e073..0000000 --- a/build_lib/mocha/test/unit/expectation_list_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/expectation_list' -require 'mocha/expectation' -require 'set' -require 'method_definer' - -class ExpectationListTest < Test::Unit::TestCase - - include Mocha - - def test_should_return_added_expectation - expectation_list = ExpectationList.new - expectation = Expectation.new(nil, :my_method) - assert_same expectation, expectation_list.add(expectation) - end - - def test_should_find_matching_expectation - expectation_list = ExpectationList.new - expectation1 = Expectation.new(nil, :my_method).with(:argument1, :argument2) - expectation2 = Expectation.new(nil, :my_method).with(:argument3, :argument4) - expectation_list.add(expectation1) - expectation_list.add(expectation2) - assert_same expectation1, expectation_list.match(:my_method, :argument1, :argument2) - end - - def test_should_find_most_recent_matching_expectation - expectation_list = ExpectationList.new - expectation1 = Expectation.new(nil, :my_method).with(:argument1, :argument2) - expectation2 = Expectation.new(nil, :my_method).with(:argument1, :argument2) - expectation_list.add(expectation1) - expectation_list.add(expectation2) - assert_same expectation2, expectation_list.match(:my_method, :argument1, :argument2) - end - - def test_should_find_matching_expectation_allowing_invocation - expectation_list = ExpectationList.new - expectation1 = Expectation.new(nil, :my_method).with(:argument1, :argument2) - expectation2 = Expectation.new(nil, :my_method).with(:argument3, :argument4) - expectation1.define_instance_method(:invocations_allowed?) { true } - expectation2.define_instance_method(:invocations_allowed?) { true } - expectation_list.add(expectation1) - expectation_list.add(expectation2) - assert_same expectation1, expectation_list.match_allowing_invocation(:my_method, :argument1, :argument2) - end - - def test_should_find_most_recent_matching_expectation_allowing_invocation - expectation_list = ExpectationList.new - expectation1 = Expectation.new(nil, :my_method) - expectation2 = Expectation.new(nil, :my_method) - expectation1.define_instance_method(:invocations_allowed?) { true } - expectation2.define_instance_method(:invocations_allowed?) { false } - expectation_list.add(expectation1) - expectation_list.add(expectation2) - assert_same expectation1, expectation_list.match_allowing_invocation(:my_method) - end - -end diff --git a/build_lib/mocha/test/unit/expectation_test.rb b/build_lib/mocha/test/unit/expectation_test.rb deleted file mode 100644 index c1af92b..0000000 --- a/build_lib/mocha/test/unit/expectation_test.rb +++ /dev/null @@ -1,480 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'method_definer' -require 'mocha/expectation' -require 'mocha/sequence' -require 'execution_point' -require 'simple_counter' - -class ExpectationTest < Test::Unit::TestCase - - include Mocha - - def new_expectation - Expectation.new(nil, :expected_method) - end - - def test_should_match_calls_to_same_method_with_any_parameters - assert new_expectation.match?(:expected_method, 1, 2, 3) - end - - def test_should_match_calls_to_same_method_with_exactly_zero_parameters - expectation = new_expectation.with() - assert expectation.match?(:expected_method) - end - - def test_should_not_match_calls_to_same_method_with_more_than_zero_parameters - expectation = new_expectation.with() - assert !expectation.match?(:expected_method, 1, 2, 3) - end - - def test_should_match_calls_to_same_method_with_expected_parameter_values - expectation = new_expectation.with(1, 2, 3) - assert expectation.match?(:expected_method, 1, 2, 3) - end - - def test_should_match_calls_to_same_method_with_parameters_constrained_as_expected - expectation = new_expectation.with() {|x, y, z| x + y == z} - assert expectation.match?(:expected_method, 1, 2, 3) - end - - def test_should_not_match_calls_to_different_method_with_parameters_constrained_as_expected - expectation = new_expectation.with() {|x, y, z| x + y == z} - assert !expectation.match?(:different_method, 1, 2, 3) - end - - def test_should_not_match_calls_to_different_methods_with_no_parameters - assert !new_expectation.match?(:unexpected_method) - end - - def test_should_not_match_calls_to_same_method_with_too_few_parameters - expectation = new_expectation.with(1, 2, 3) - assert !expectation.match?(:unexpected_method, 1, 2) - end - - def test_should_not_match_calls_to_same_method_with_too_many_parameters - expectation = new_expectation.with(1, 2) - assert !expectation.match?(:unexpected_method, 1, 2, 3) - end - - def test_should_not_match_calls_to_same_method_with_unexpected_parameter_values - expectation = new_expectation.with(1, 2, 3) - assert !expectation.match?(:unexpected_method, 1, 0, 3) - end - - def test_should_not_match_calls_to_same_method_with_parameters_not_constrained_as_expected - expectation = new_expectation.with() {|x, y, z| x + y == z} - assert !expectation.match?(:expected_method, 1, 0, 3) - end - - def test_should_allow_invocations_until_expected_invocation_count_is_one_and_actual_invocation_count_would_be_two - expectation = new_expectation.times(1) - assert expectation.invocations_allowed? - expectation.invoke - assert !expectation.invocations_allowed? - end - - def test_should_allow_invocations_until_expected_invocation_count_is_two_and_actual_invocation_count_would_be_three - expectation = new_expectation.times(2) - assert expectation.invocations_allowed? - expectation.invoke - assert expectation.invocations_allowed? - expectation.invoke - assert !expectation.invocations_allowed? - end - - def test_should_allow_invocations_until_expected_invocation_count_is_a_range_from_two_to_three_and_actual_invocation_count_would_be_four - expectation = new_expectation.times(2..3) - assert expectation.invocations_allowed? - expectation.invoke - assert expectation.invocations_allowed? - expectation.invoke - assert expectation.invocations_allowed? - expectation.invoke - assert !expectation.invocations_allowed? - end - - def test_should_store_provided_backtrace - backtrace = Object.new - expectation = Expectation.new(nil, :expected_method, backtrace) - assert_equal backtrace, expectation.backtrace - end - - def test_should_default_backtrace_to_caller - execution_point = ExecutionPoint.current; expectation = Expectation.new(nil, :expected_method) - assert_equal execution_point, ExecutionPoint.new(expectation.backtrace) - end - - def test_should_not_yield - yielded = false - new_expectation.invoke() { yielded = true } - assert_equal false, yielded - end - - def test_should_yield_no_parameters - expectation = new_expectation().yields() - yielded_parameters = nil - expectation.invoke() { |*parameters| yielded_parameters = parameters } - assert_equal Array.new, yielded_parameters - end - - def test_should_yield_with_specified_parameters - expectation = new_expectation().yields(1, 2, 3) - yielded_parameters = nil - expectation.invoke() { |*parameters| yielded_parameters = parameters } - assert_equal [1, 2, 3], yielded_parameters - end - - def test_should_yield_different_parameters_on_consecutive_invocations - expectation = new_expectation().yields(1, 2, 3).yields(4, 5) - yielded_parameters = [] - expectation.invoke() { |*parameters| yielded_parameters << parameters } - expectation.invoke() { |*parameters| yielded_parameters << parameters } - assert_equal [[1, 2, 3], [4, 5]], yielded_parameters - end - - def test_should_yield_multiple_times_for_single_invocation - expectation = new_expectation().multiple_yields([1, 2, 3], [4, 5]) - yielded_parameters = [] - expectation.invoke() { |*parameters| yielded_parameters << parameters } - assert_equal [[1, 2, 3], [4, 5]], yielded_parameters - end - - def test_should_yield_multiple_times_for_first_invocation_and_once_for_second_invocation - expectation = new_expectation().multiple_yields([1, 2, 3], [4, 5]).then.yields(6, 7) - yielded_parameters = [] - expectation.invoke() { |*parameters| yielded_parameters << parameters } - expectation.invoke() { |*parameters| yielded_parameters << parameters } - assert_equal [[1, 2, 3], [4, 5], [6, 7]], yielded_parameters - end - - def test_should_return_specified_value - expectation = new_expectation.returns(99) - assert_equal 99, expectation.invoke - end - - def test_should_return_same_specified_value_multiple_times - expectation = new_expectation.returns(99) - assert_equal 99, expectation.invoke - assert_equal 99, expectation.invoke - end - - def test_should_return_specified_values_on_consecutive_calls - expectation = new_expectation.returns(99, 100, 101) - assert_equal 99, expectation.invoke - assert_equal 100, expectation.invoke - assert_equal 101, expectation.invoke - end - - def test_should_return_specified_values_on_consecutive_calls_even_if_values_are_modified - values = [99, 100, 101] - expectation = new_expectation.returns(*values) - values.shift - assert_equal 99, expectation.invoke - assert_equal 100, expectation.invoke - assert_equal 101, expectation.invoke - end - - def test_should_return_nil_by_default - assert_nil new_expectation.invoke - end - - def test_should_return_nil_if_no_value_specified - expectation = new_expectation.returns() - assert_nil expectation.invoke - end - - def test_should_raise_runtime_exception - expectation = new_expectation.raises - assert_raise(RuntimeError) { expectation.invoke } - end - - def test_should_raise_custom_exception - exception = Class.new(Exception) - expectation = new_expectation.raises(exception) - assert_raise(exception) { expectation.invoke } - end - - def test_should_raise_same_instance_of_custom_exception - exception_klass = Class.new(StandardError) - expected_exception = exception_klass.new - expectation = new_expectation.raises(expected_exception) - actual_exception = assert_raise(exception_klass) { expectation.invoke } - assert_same expected_exception, actual_exception - end - - def test_should_use_the_default_exception_message - expectation = new_expectation.raises(Exception) - exception = assert_raise(Exception) { expectation.invoke } - assert_equal Exception.new.message, exception.message - end - - def test_should_raise_custom_exception_with_message - exception_msg = "exception message" - expectation = new_expectation.raises(Exception, exception_msg) - exception = assert_raise(Exception) { expectation.invoke } - assert_equal exception_msg, exception.message - end - - def test_should_return_values_then_raise_exception - expectation = new_expectation.returns(1, 2).then.raises() - assert_equal 1, expectation.invoke - assert_equal 2, expectation.invoke - assert_raise(RuntimeError) { expectation.invoke } - end - - def test_should_raise_exception_then_return_values - expectation = new_expectation.raises().then.returns(1, 2) - assert_raise(RuntimeError) { expectation.invoke } - assert_equal 1, expectation.invoke - assert_equal 2, expectation.invoke - end - - def test_should_verify_successfully_if_expected_call_was_made - expectation = new_expectation - expectation.invoke - assert expectation.verified? - end - - def test_should_not_verify_successfully_if_call_expected_once_but_invoked_twice - expectation = new_expectation.once - expectation.invoke - expectation.invoke - assert !expectation.verified? - end - - def test_should_not_verify_successfully_if_call_expected_once_but_not_invoked - expectation = new_expectation.once - assert !expectation.verified? - end - - def test_should_verify_successfully_if_call_expected_once_and_invoked_once - expectation = new_expectation.once - expectation.invoke - assert expectation.verified? - end - - def test_should_not_verify_successfully_if_call_expected_twice_and_invoked_three_times - expectation = new_expectation.twice - expectation.invoke - expectation.invoke - expectation.invoke - assert !expectation.verified? - end - - def test_should_not_verify_successfully_if_call_expected_twice_but_invoked_once - expectation = new_expectation.twice - expectation.invoke - assert !expectation.verified? - end - - def test_should_verify_successfully_if_call_expected_twice_and_invoked_twice - expectation = new_expectation.twice - expectation.invoke - expectation.invoke - assert expectation.verified? - end - - def test_should_verify_successfully_if_expected_call_was_made_at_least_once - expectation = new_expectation.at_least_once - 3.times {expectation.invoke} - assert expectation.verified? - end - - def test_should_not_verify_successfully_if_expected_call_was_not_made_at_least_once - expectation = new_expectation.with(1, 2, 3).at_least_once - assert !expectation.verified? - assert_match(/expected at least once, not yet invoked/i, expectation.mocha_inspect) - end - - def test_should_verify_successfully_if_expected_call_was_made_expected_number_of_times - expectation = new_expectation.times(2) - 2.times {expectation.invoke} - assert expectation.verified? - end - - def test_should_not_verify_successfully_if_expected_call_was_made_too_few_times - expectation = new_expectation.times(2) - 1.times {expectation.invoke} - assert !expectation.verified? - assert_match(/expected exactly twice, already invoked once/i, expectation.mocha_inspect) - end - - def test_should_not_verify_successfully_if_expected_call_was_made_too_many_times - expectation = new_expectation.times(2) - 3.times {expectation.invoke} - assert !expectation.verified? - end - - def test_should_increment_assertion_counter_for_expectation_because_it_does_need_verifyng - expectation = new_expectation - expectation.invoke - assertion_counter = SimpleCounter.new - expectation.verified?(assertion_counter) - assert_equal 1, assertion_counter.count - end - - def test_should_not_increment_assertion_counter_for_stub_because_it_does_not_need_verifying - stub = Expectation.new(nil, :expected_method).at_least(0) - assertion_counter = SimpleCounter.new - stub.verified?(assertion_counter) - assert_equal 0, assertion_counter.count - end - - def test_should_store_backtrace_from_point_where_expectation_was_created - execution_point = ExecutionPoint.current; expectation = Expectation.new(nil, :expected_method) - assert_equal execution_point, ExecutionPoint.new(expectation.backtrace) - end - - class FakeMock - - def initialize(name) - @name = name - end - - def mocha_inspect - @name - end - - end - - def test_should_raise_error_with_message_indicating_which_method_was_expected_to_be_called_on_which_mock_object_with_which_parameters_and_in_what_sequences - mock = FakeMock.new('mock') - sequence_one = Sequence.new('one') - sequence_two = Sequence.new('two') - expectation = Expectation.new(mock, :expected_method).with(1, 2, {'a' => true}, {:b => false}, [1, 2, 3]).in_sequence(sequence_one, sequence_two) - assert !expectation.verified? - assert_match "mock.expected_method(1, 2, {'a' => true}, {:b => false}, [1, 2, 3]); in sequence 'one'; in sequence 'two'", expectation.mocha_inspect - end - - class FakeConstraint - - def initialize(allows_invocation_now) - @allows_invocation_now = allows_invocation_now - end - - def allows_invocation_now? - @allows_invocation_now - end - - end - - def test_should_be_in_correct_order_if_all_ordering_constraints_allow_invocation_now - constraint_one = FakeConstraint.new(allows_invocation_now = true) - constraint_two = FakeConstraint.new(allows_invocation_now = true) - expectation = Expectation.new(nil, :method_one) - expectation.add_ordering_constraint(constraint_one) - expectation.add_ordering_constraint(constraint_two) - assert expectation.in_correct_order? - end - - def test_should_not_be_in_correct_order_if_one_ordering_constraint_does_not_allow_invocation_now - constraint_one = FakeConstraint.new(allows_invocation_now = true) - constraint_two = FakeConstraint.new(allows_invocation_now = false) - expectation = Expectation.new(nil, :method_one) - expectation.add_ordering_constraint(constraint_one) - expectation.add_ordering_constraint(constraint_two) - assert !expectation.in_correct_order? - end - - def test_should_match_if_all_ordering_constraints_allow_invocation_now - constraint_one = FakeConstraint.new(allows_invocation_now = true) - constraint_two = FakeConstraint.new(allows_invocation_now = true) - expectation = Expectation.new(nil, :method_one) - expectation.add_ordering_constraint(constraint_one) - expectation.add_ordering_constraint(constraint_two) - assert expectation.match?(:method_one) - end - - def test_should_not_match_if_one_ordering_constraints_does_not_allow_invocation_now - constraint_one = FakeConstraint.new(allows_invocation_now = true) - constraint_two = FakeConstraint.new(allows_invocation_now = false) - expectation = Expectation.new(nil, :method_one) - expectation.add_ordering_constraint(constraint_one) - expectation.add_ordering_constraint(constraint_two) - assert !expectation.match?(:method_one) - end - - def test_should_not_be_satisfied_when_required_invocation_has_not_been_made - expectation = Expectation.new(nil, :method_one).times(1) - assert !expectation.satisfied? - end - - def test_should_be_satisfied_when_required_invocation_has_been_made - expectation = Expectation.new(nil, :method_one).times(1) - expectation.invoke - assert expectation.satisfied? - end - - def test_should_not_be_satisfied_when_minimum_number_of_invocations_has_not_been_made - expectation = Expectation.new(nil, :method_one).at_least(2) - expectation.invoke - assert !expectation.satisfied? - end - - def test_should_be_satisfied_when_minimum_number_of_invocations_has_been_made - expectation = Expectation.new(nil, :method_one).at_least(2) - 2.times { expectation.invoke } - assert expectation.satisfied? - end - - class FakeSequence - - attr_reader :expectations - - def initialize - @expectations = [] - end - - def constrain_as_next_in_sequence(expectation) - @expectations << expectation - end - - end - - def test_should_tell_sequences_to_constrain_expectation_as_next_in_sequence - sequence_one = FakeSequence.new - sequence_two = FakeSequence.new - expectation = Expectation.new(nil, :method_one) - assert_equal expectation, expectation.in_sequence(sequence_one, sequence_two) - assert_equal [expectation], sequence_one.expectations - assert_equal [expectation], sequence_two.expectations - end - - class FakeState - - def initialize - @active = false - end - - def activate - @active = true - end - - def active? - @active - end - - end - - def test_should_change_state_when_expectation_is_invoked - state = FakeState.new - expectation = Expectation.new(nil, :method_one) - - expectation.then(state) - - expectation.invoke - assert state.active? - end - - def test_should_match_when_state_is_active - state = FakeState.new - expectation = Expectation.new(nil, :method_one) - - expectation.when(state) - assert !expectation.match?(:method_one) - - state.activate - assert expectation.match?(:method_one) - end - -end diff --git a/build_lib/mocha/test/unit/hash_inspect_test.rb b/build_lib/mocha/test/unit/hash_inspect_test.rb deleted file mode 100644 index 388b0c1..0000000 --- a/build_lib/mocha/test/unit/hash_inspect_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/inspect' - -class HashInspectTest < Test::Unit::TestCase - - def test_should_keep_spacing_between_key_value - hash = {:a => true} - assert_equal '{:a => true}', hash.mocha_inspect - end - - def test_should_use_mocha_inspect_on_each_item - hash = {:a => 'mocha'} - assert_equal "{:a => 'mocha'}", hash.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/in_state_ordering_constraint_test.rb b/build_lib/mocha/test/unit/in_state_ordering_constraint_test.rb deleted file mode 100644 index 25f4ea2..0000000 --- a/build_lib/mocha/test/unit/in_state_ordering_constraint_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/in_state_ordering_constraint' - -class InStateOrderingConstraintTest < Test::Unit::TestCase - - include Mocha - - class FakeStatePredicate - - attr_writer :active, :description - - def active? - @active - end - - def mocha_inspect - @description - end - - end - - def test_should_allow_invocation_when_state_is_active - state_predicate = FakeStatePredicate.new - ordering_constraint = InStateOrderingConstraint.new(state_predicate) - - state_predicate.active = true - assert ordering_constraint.allows_invocation_now? - - state_predicate.active = false - assert !ordering_constraint.allows_invocation_now? - end - - def test_should_describe_itself_in_terms_of_the_state_predicates_description - state_predicate = FakeStatePredicate.new - ordering_constraint = InStateOrderingConstraint.new(state_predicate) - - state_predicate.description = 'the-state-predicate' - - assert_equal 'when the-state-predicate', ordering_constraint.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/metaclass_test.rb b/build_lib/mocha/test/unit/metaclass_test.rb deleted file mode 100644 index 6056142..0000000 --- a/build_lib/mocha/test/unit/metaclass_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/metaclass' - -class MetaclassTest < Test::Unit::TestCase - - def test_should_return_objects_singleton_class - object = Object.new - assert_raises(NoMethodError) { object.success? } - - object = Object.new - assert object.__metaclass__.ancestors.include?(Object) - assert object.__metaclass__.ancestors.include?(Kernel) - assert object.__metaclass__.is_a?(Class) - - object.__metaclass__.class_eval { def success?; true; end } - assert object.success? - - object = Object.new - assert_raises(NoMethodError) { object.success? } - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/method_matcher_test.rb b/build_lib/mocha/test/unit/method_matcher_test.rb deleted file mode 100644 index 8230b48..0000000 --- a/build_lib/mocha/test/unit/method_matcher_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/method_matcher' - -class MethodMatcherTest < Test::Unit::TestCase - - include Mocha - - def test_should_match_if_actual_method_name_is_same_as_expected_method_name - method_matcher = MethodMatcher.new(:method_name) - assert method_matcher.match?(:method_name) - end - - def test_should_not_match_if_actual_method_name_is_not_same_as_expected_method_name - method_matcher = MethodMatcher.new(:method_name) - assert !method_matcher.match?(:different_method_name) - end - - def test_should_describe_what_method_is_expected - method_matcher = MethodMatcher.new(:method_name) - assert_equal "method_name", method_matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/mock_test.rb b/build_lib/mocha/test/unit/mock_test.rb deleted file mode 100644 index f7f4aa1..0000000 --- a/build_lib/mocha/test/unit/mock_test.rb +++ /dev/null @@ -1,302 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/mock' -require 'mocha/expectation_error' -require 'set' -require 'simple_counter' - -class MockTest < Test::Unit::TestCase - - include Mocha - - def test_should_set_single_expectation - mock = Mock.new - mock.expects(:method1).returns(1) - assert_nothing_raised(ExpectationError) do - assert_equal 1, mock.method1 - end - end - - def test_should_build_and_store_expectations - mock = Mock.new - expectation = mock.expects(:method1) - assert_not_nil expectation - assert_equal [expectation], mock.expectations.to_a - end - - def test_should_not_stub_everything_by_default - mock = Mock.new - assert_equal false, mock.everything_stubbed - end - - def test_should_stub_everything - mock = Mock.new - mock.stub_everything - assert_equal true, mock.everything_stubbed - end - - def test_should_be_able_to_extend_mock_object_with_module - mock = Mock.new - assert_nothing_raised(ExpectationError) { mock.extend(Module.new) } - end - - def test_should_be_equal - mock = Mock.new - assert_equal true, mock.eql?(mock) - end - - if RUBY_VERSION < '1.9' - OBJECT_METHODS = STANDARD_OBJECT_PUBLIC_INSTANCE_METHODS.reject { |m| m =~ /^__.*__$/ } - else - OBJECT_METHODS = STANDARD_OBJECT_PUBLIC_INSTANCE_METHODS.reject { |m| m =~ /^__.*__$/ || m == :object_id } - end - - def test_should_be_able_to_mock_standard_object_methods - mock = Mock.new - OBJECT_METHODS.each { |method| mock.__expects__(method.to_sym).returns(method) } - OBJECT_METHODS.each { |method| assert_equal method, mock.__send__(method.to_sym) } - assert mock.__verified__? - end - - def test_should_be_able_to_stub_standard_object_methods - mock = Mock.new - OBJECT_METHODS.each { |method| mock.__stubs__(method.to_sym).returns(method) } - OBJECT_METHODS.each { |method| assert_equal method, mock.__send__(method.to_sym) } - end - - def test_should_create_and_add_expectations - mock = Mock.new - expectation1 = mock.expects(:method1) - expectation2 = mock.expects(:method2) - assert_equal [expectation1, expectation2].to_set, mock.expectations.to_set - end - - def test_should_pass_backtrace_into_expectation - mock = Mock.new - backtrace = Object.new - expectation = mock.expects(:method1, backtrace) - assert_equal backtrace, expectation.backtrace - end - - def test_should_pass_backtrace_into_stub - mock = Mock.new - backtrace = Object.new - stub = mock.stubs(:method1, backtrace) - assert_equal backtrace, stub.backtrace - end - - def test_should_create_and_add_stubs - mock = Mock.new - stub1 = mock.stubs(:method1) - stub2 = mock.stubs(:method2) - assert_equal [stub1, stub2].to_set, mock.expectations.to_set - end - - def test_should_invoke_expectation_and_return_result - mock = Mock.new - mock.expects(:my_method).returns(:result) - result = mock.my_method - assert_equal :result, result - end - - def test_should_not_raise_error_if_stubbing_everything - mock = Mock.new - mock.stub_everything - result = nil - assert_nothing_raised(ExpectationError) do - result = mock.unexpected_method - end - assert_nil result - end - - def test_should_raise_assertion_error_for_unexpected_method_call - mock = Mock.new - error = assert_raise(ExpectationError) do - mock.unexpected_method_called(:my_method, :argument1, :argument2) - end - assert_match(/unexpected invocation/, error.message) - assert_match(/my_method/, error.message) - assert_match(/argument1/, error.message) - assert_match(/argument2/, error.message) - end - - def test_should_not_verify_successfully_because_not_all_expectations_have_been_satisfied - mock = Mock.new - mock.expects(:method1) - mock.expects(:method2) - mock.method1 - assert !mock.__verified__? - end - - def test_should_increment_assertion_counter_for_every_verified_expectation - mock = Mock.new - - mock.expects(:method1) - mock.method1 - - mock.expects(:method2) - mock.method2 - - assertion_counter = SimpleCounter.new - - mock.__verified__?(assertion_counter) - - assert_equal 2, assertion_counter.count - end - - def test_should_yield_supplied_parameters_to_block - mock = Mock.new - parameters_for_yield = [1, 2, 3] - mock.expects(:method1).yields(*parameters_for_yield) - yielded_parameters = nil - mock.method1() { |*parameters| yielded_parameters = parameters } - assert_equal parameters_for_yield, yielded_parameters - end - - def test_should_set_up_multiple_expectations_with_return_values - mock = Mock.new - mock.expects(:method1 => :result1, :method2 => :result2) - assert_equal :result1, mock.method1 - assert_equal :result2, mock.method2 - end - - def test_should_set_up_multiple_stubs_with_return_values - mock = Mock.new - mock.stubs(:method1 => :result1, :method2 => :result2) - assert_equal :result1, mock.method1 - assert_equal :result2, mock.method2 - end - - def test_should_keep_returning_specified_value_for_stubs - mock = Mock.new - mock.stubs(:method1).returns(1) - assert_equal 1, mock.method1 - assert_equal 1, mock.method1 - end - - def test_should_keep_returning_specified_value_for_expects - mock = Mock.new - mock.expects(:method1).times(2).returns(1) - assert_equal 1, mock.method1 - assert_equal 1, mock.method1 - end - - def test_should_match_most_recent_call_to_expects - mock = Mock.new - mock.expects(:method1).returns(0) - mock.expects(:method1).returns(1) - assert_equal 1, mock.method1 - end - - def test_should_match_most_recent_call_to_stubs - mock = Mock.new - mock.stubs(:method1).returns(0) - mock.stubs(:method1).returns(1) - assert_equal 1, mock.method1 - end - - def test_should_match_most_recent_call_to_stubs_or_expects - mock = Mock.new - mock.stubs(:method1).returns(0) - mock.expects(:method1).returns(1) - assert_equal 1, mock.method1 - end - - def test_should_match_most_recent_call_to_expects_or_stubs - mock = Mock.new - mock.expects(:method1).returns(0) - mock.stubs(:method1).returns(1) - assert_equal 1, mock.method1 - end - - def test_should_respond_to_expected_method - mock = Mock.new - mock.expects(:method1) - assert_equal true, mock.respond_to?(:method1) - end - - def test_should_not_respond_to_unexpected_method - mock = Mock.new - assert_equal false, mock.respond_to?(:method1) - end - - def test_should_respond_to_methods_which_the_responder_does_responds_to - instance = Class.new do - define_method(:respond_to?) { |symbol| true } - end.new - mock = Mock.new - mock.responds_like(instance) - assert_equal true, mock.respond_to?(:invoked_method) - end - - def test_should_not_respond_to_methods_which_the_responder_does_not_responds_to - instance = Class.new do - define_method(:respond_to?) { |symbol| false } - end.new - mock = Mock.new - mock.responds_like(instance) - assert_equal false, mock.respond_to?(:invoked_method) - end - - def test_should_return_itself_to_allow_method_chaining - mock = Mock.new - assert_same mock.responds_like(Object.new), mock - end - - def test_should_not_raise_no_method_error_if_mock_is_not_restricted_to_respond_like_a_responder - instance = Class.new do - define_method(:respond_to?) { true } - end.new - mock = Mock.new - mock.stubs(:invoked_method) - assert_nothing_raised(NoMethodError) { mock.invoked_method } - end - - def test_should_not_raise_no_method_error_if_responder_does_respond_to_invoked_method - instance = Class.new do - define_method(:respond_to?) { |symbol| true } - end.new - mock = Mock.new - mock.responds_like(instance) - mock.stubs(:invoked_method) - assert_nothing_raised(NoMethodError) { mock.invoked_method } - end - - def test_should_raise_no_method_error_if_responder_does_not_respond_to_invoked_method - instance = Class.new do - define_method(:respond_to?) { |symbol| false } - define_method(:mocha_inspect) { 'mocha_inspect' } - end.new - mock = Mock.new - mock.responds_like(instance) - mock.stubs(:invoked_method) - assert_raises(NoMethodError) { mock.invoked_method } - end - - def test_should_raise_no_method_error_with_message_indicating_that_mock_is_constrained_to_respond_like_responder - instance = Class.new do - define_method(:respond_to?) { |symbol| false } - define_method(:mocha_inspect) { 'mocha_inspect' } - end.new - mock = Mock.new - mock.responds_like(instance) - mock.stubs(:invoked_method) - begin - mock.invoked_method - rescue NoMethodError => e - assert_match(/which responds like mocha_inspect/, e.message) - end - end - - def test_should_handle_respond_to_with_private_methods_param_without_error - mock = Mock.new - assert_nothing_raised{ mock.respond_to?(:object_id, false) } - end - - def test_should_respond_to_any_method_if_stubbing_everything - mock = Mock.new - mock.stub_everything - assert mock.respond_to?(:abc) - assert mock.respond_to?(:xyz) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/mockery_test.rb b/build_lib/mocha/test/unit/mockery_test.rb deleted file mode 100644 index cab0097..0000000 --- a/build_lib/mocha/test/unit/mockery_test.rb +++ /dev/null @@ -1,149 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/mockery' -require 'mocha/state_machine' - -class MockeryTest < Test::Unit::TestCase - - include Mocha - - def test_should_build_instance_of_mockery - mockery = Mockery.instance - assert_not_nil mockery - assert_kind_of Mockery, mockery - end - - def test_should_cache_instance_of_mockery - mockery_1 = Mockery.instance - mockery_2 = Mockery.instance - assert_same mockery_1, mockery_2 - end - - def test_should_expire_mockery_instance_cache - mockery_1 = Mockery.instance - Mockery.reset_instance - mockery_2 = Mockery.instance - assert_not_same mockery_1, mockery_2 - end - - def test_should_raise_expectation_error_because_not_all_expectations_are_satisfied - mockery = Mockery.new - mock_1 = mockery.named_mock('mock-1') { expects(:method_1) } - mock_2 = mockery.named_mock('mock-2') { expects(:method_2) } - 1.times { mock_1.method_1 } - 0.times { mock_2.method_2 } - assert_raises(ExpectationError) { mockery.verify } - end - - def test_should_reset_list_of_mocks_on_teardown - mockery = Mockery.new - mock = mockery.unnamed_mock { expects(:my_method) } - mockery.teardown - assert_nothing_raised(ExpectationError) { mockery.verify } - end - - def test_should_build_instance_of_stubba_on_instantiation - mockery = Mockery.new - assert_not_nil mockery.stubba - assert_kind_of Central, mockery.stubba - end - - def test_should_build_new_instance_of_stubba_on_teardown - mockery = Mockery.new - stubba_1 = mockery.stubba - mockery.teardown - stubba_2 = mockery.stubba - assert_not_same stubba_1, stubba_2 - end - - def test_should_build_and_store_new_state_machine - mockery = Mockery.new - mockery.new_state_machine('state-machine-name') - assert_equal 1, mockery.state_machines.length - assert_kind_of StateMachine, mockery.state_machines[0] - end - - def test_should_reset_list_of_state_machines_on_teardown - mockery = Mockery.new - mockery.new_state_machine('state-machine-name') - mockery.teardown - assert_equal 0, mockery.state_machines.length - end - - class FakeMethod - def stub; end - def unstub; end - end - - def test_should_unstub_all_methods_on_teardown - mockery = Mockery.new - stubba = mockery.stubba - stubba.stub(FakeMethod.new) - mockery.teardown - assert stubba.stubba_methods.empty? - end - - def test_should_display_object_id_for_mocha_inspect_if_mock_has_no_name - mockery = Mockery.new - mock = mockery.unnamed_mock - assert_match Regexp.new("^#$"), mock.mocha_inspect - end - - def test_should_display_object_id_for_inspect_if_mock_has_no_name - mockery = Mockery.new - mock = mockery.unnamed_mock - assert_match Regexp.new("^#$"), mock.inspect - end - - def test_should_display_name_for_mocha_inspect_if_mock_has_string_name - mockery = Mockery.new - mock = mockery.named_mock('named_mock') - assert_equal "#", mock.mocha_inspect - end - - def test_should_display_name_for_mocha_inspect_if_mock_has_symbol_name - mockery = Mockery.new - mock = mockery.named_mock(:named_mock) - assert_equal "#", mock.mocha_inspect - end - - def test_should_display_name_for_inspect_if_mock_has_string_name - mockery = Mockery.new - mock = mockery.named_mock('named_mock') - assert_equal "#", mock.inspect - end - - def test_should_display_name_for_inspect_if_mock_has_symbol_name - mockery = Mockery.new - mock = mockery.named_mock(:named_mock) - assert_equal "#", mock.inspect - end - - def test_should_display_impersonated_object_for_mocha_inspect - mockery = Mockery.new - instance = Object.new - mock = mockery.mock_impersonating(instance) - assert_equal "#{instance.mocha_inspect}", mock.mocha_inspect - end - - def test_should_display_impersonated_object_for_inspect - mockery = Mockery.new - instance = Object.new - mock = mockery.mock_impersonating(instance) - assert_equal "#{instance.mocha_inspect}", mock.inspect - end - - class FakeClass; end - - def test_should_display_any_instance_prefix_followed_by_class_whose_instances_are_being_impersonated_for_mocha_inspect - mockery = Mockery.new - mock = mockery.mock_impersonating_any_instance_of(FakeClass) - assert_equal "#", mock.mocha_inspect - end - - def test_should_display_any_instance_prefix_followed_by_class_whose_instances_are_being_impersonated_for_inspect - mockery = Mockery.new - mock = mockery.mock_impersonating_any_instance_of(FakeClass) - assert_equal "#", mock.inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/multiple_yields_test.rb b/build_lib/mocha/test/unit/multiple_yields_test.rb deleted file mode 100644 index e8bf62c..0000000 --- a/build_lib/mocha/test/unit/multiple_yields_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/multiple_yields' - -class MultipleYieldsTest < Test::Unit::TestCase - - include Mocha - - def test_should_provide_parameters_for_multiple_yields_in_single_invocation - parameter_group = MultipleYields.new([1, 2, 3], [4, 5]) - parameter_groups = [] - parameter_group.each do |parameters| - parameter_groups << parameters - end - assert_equal [[1, 2, 3], [4, 5]], parameter_groups - end - -end diff --git a/build_lib/mocha/test/unit/no_yields_test.rb b/build_lib/mocha/test/unit/no_yields_test.rb deleted file mode 100644 index ee7c59b..0000000 --- a/build_lib/mocha/test/unit/no_yields_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/no_yields' - -class NoYieldsTest < Test::Unit::TestCase - - include Mocha - - def test_should_provide_parameters_for_no_yields_in_single_invocation - parameter_group = NoYields.new - parameter_groups = [] - parameter_group.each do |parameters| - parameter_groups << parameters - end - assert_equal [], parameter_groups - end - -end diff --git a/build_lib/mocha/test/unit/object_inspect_test.rb b/build_lib/mocha/test/unit/object_inspect_test.rb deleted file mode 100644 index 3c16461..0000000 --- a/build_lib/mocha/test/unit/object_inspect_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/inspect' -require 'method_definer' - -class ObjectInspectTest < Test::Unit::TestCase - - def test_should_return_default_string_representation_of_object_not_including_instance_variables - object = Object.new - class << object - attr_accessor :attribute - end - object.attribute = 'instance_variable' - assert_match Regexp.new("^#$"), object.mocha_inspect - assert_no_match(/instance_variable/, object.mocha_inspect) - end - - def test_should_return_customized_string_representation_of_object - object = Object.new - class << object - define_method(:inspect) { 'custom_inspect' } - end - assert_equal 'custom_inspect', object.mocha_inspect - end - - def test_should_use_underscored_id_instead_of_object_id_or_id_so_that_they_can_be_stubbed - calls = [] - object = Object.new - object.replace_instance_method(:id) { calls << :id; return 1 } if RUBY_VERSION < '1.9' - object.replace_instance_method(:object_id) { calls << :object_id; return 1 } - object.replace_instance_method(:__id__) { calls << :__id__; return 1 } - object.replace_instance_method(:inspect) { "object-description" } - - object.mocha_inspect - - assert_equal [:__id__], calls.uniq - end - -end diff --git a/build_lib/mocha/test/unit/object_test.rb b/build_lib/mocha/test/unit/object_test.rb deleted file mode 100644 index 5602e06..0000000 --- a/build_lib/mocha/test/unit/object_test.rb +++ /dev/null @@ -1,82 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/object' -require 'mocha/mockery' -require 'mocha/mock' -require 'method_definer' - -class ObjectTest < Test::Unit::TestCase - - include Mocha - - def test_should_build_mocha_referring_to_self - instance = Object.new - mocha = instance.mocha - assert_not_nil mocha - assert mocha.is_a?(Mock) - assert_equal instance.mocha_inspect, mocha.mocha_inspect - end - - def test_should_reuse_existing_mocha - instance = Object.new - mocha_1 = instance.mocha - mocha_2 = instance.mocha - assert_equal mocha_1, mocha_2 - end - - def test_should_reset_mocha - instance = Object.new - assert_nil instance.reset_mocha - end - - def test_should_build_any_instance_object - klass = Class.new - any_instance = klass.any_instance - assert_not_nil any_instance - assert any_instance.is_a?(Class::AnyInstance) - end - - def test_should_return_same_any_instance_object - klass = Class.new - any_instance_1 = klass.any_instance - any_instance_2 = klass.any_instance - assert_equal any_instance_1, any_instance_2 - end - - def test_should_use_stubba_instance_method_for_object - assert_equal Mocha::InstanceMethod, Object.new.stubba_method - end - - def test_should_use_stubba_module_method_for_module - assert_equal Mocha::ModuleMethod, Module.new.stubba_method - end - - def test_should_use_stubba_class_method_for_class - assert_equal Mocha::ClassMethod, Class.new.stubba_method - end - - def test_should_use_stubba_class_method_for_any_instance - assert_equal Mocha::AnyInstanceMethod, Class::AnyInstance.new(nil).stubba_method - end - - def test_should_stub_self_for_object - object = Object.new - assert_equal object, object.stubba_object - end - - def test_should_stub_self_for_module - mod = Module.new - assert_equal mod, mod.stubba_object - end - - def test_should_stub_self_for_class - klass = Class.new - assert_equal klass, klass.stubba_object - end - - def test_should_stub_relevant_class_for_any_instance - klass = Class.new - any_instance = Class::AnyInstance.new(klass) - assert_equal klass, any_instance.stubba_object - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/all_of_test.rb b/build_lib/mocha/test/unit/parameter_matchers/all_of_test.rb deleted file mode 100644 index cb4aefa..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/all_of_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/all_of' -require 'mocha/inspect' -require 'stub_matcher' - -class AllOfTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_if_all_matchers_match - matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(true), Stub::Matcher.new(true)) - assert matcher.matches?(['any_old_value']) - end - - def test_should_not_match_if_any_matcher_does_not_match - matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(false), Stub::Matcher.new(true)) - assert !matcher.matches?(['any_old_value']) - end - - def test_should_describe_matcher - matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(false), Stub::Matcher.new(true)) - assert_equal 'all_of(matcher(true), matcher(false), matcher(true))', matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/any_of_test.rb b/build_lib/mocha/test/unit/parameter_matchers/any_of_test.rb deleted file mode 100644 index 04af9ef..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/any_of_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/any_of' -require 'mocha/inspect' -require 'stub_matcher' - -class AnyOfTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_if_any_matchers_match - matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(true), Stub::Matcher.new(false)) - assert matcher.matches?(['any_old_value']) - end - - def test_should_not_match_if_no_matchers_match - matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(false), Stub::Matcher.new(false)) - assert !matcher.matches?(['any_old_value']) - end - - def test_should_describe_matcher - matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(true), Stub::Matcher.new(false)) - assert_equal 'any_of(matcher(false), matcher(true), matcher(false))', matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/anything_test.rb b/build_lib/mocha/test/unit/parameter_matchers/anything_test.rb deleted file mode 100644 index f517e0d..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/anything_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/anything' -require 'mocha/inspect' - -class AnythingTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_anything - matcher = anything - assert matcher.matches?([:something]) - assert matcher.matches?([{'x' => 'y'}]) - end - - def test_should_describe_matcher - matcher = anything - assert_equal "anything", matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/equals_test.rb b/build_lib/mocha/test/unit/parameter_matchers/equals_test.rb deleted file mode 100644 index e18df2c..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/equals_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/equals' -require 'mocha/inspect' - -class EqualsTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_object_that_equals_value - matcher = equals('x') - assert matcher.matches?(['x']) - end - - def test_should_not_match_object_that_does_not_equal_value - matcher = equals('x') - assert !matcher.matches?(['y']) - end - - def test_should_describe_matcher - matcher = equals('x') - assert_equal "'x'", matcher.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/parameter_matchers/has_entries_test.rb b/build_lib/mocha/test/unit/parameter_matchers/has_entries_test.rb deleted file mode 100644 index df673c0..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/has_entries_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/has_entries' -require 'mocha/parameter_matchers/object' -require 'mocha/inspect' - -class HasEntriesTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_hash_including_specified_entries - matcher = has_entries(:key_1 => 'value_1', :key_2 => 'value_2') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2', :key_3 => 'value_3' }]) - end - - def test_should_not_match_hash_not_including_specified_entries - matcher = has_entries(:key_1 => 'value_2', :key_2 => 'value_2', :key_3 => 'value_3') - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_describe_matcher - matcher = has_entries(:key_1 => 'value_1', :key_2 => 'value_2') - description = matcher.mocha_inspect - matches = /has_entries\((.*)\)/.match(description) - assert_not_nil matches[0] - entries = eval(matches[1], binding, __FILE__, __LINE__) - assert_equal 'value_1', entries[:key_1] - assert_equal 'value_2', entries[:key_2] - end - - def test_should_match_hash_including_specified_entries_with_nested_key_matchers - matcher = has_entries(equals(:key_1) => 'value_1', equals(:key_2) => 'value_2') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2', :key_3 => 'value_3' }]) - end - - def test_should_not_match_hash_not_including_specified_entries_with_nested_key_matchers - matcher = has_entries(equals(:key_1) => 'value_2', equals(:key_2) => 'value_2', equals(:key_3) => 'value_3') - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_match_hash_including_specified_entries_with_nested_value_matchers - matcher = has_entries(:key_1 => equals('value_1'), :key_2 => equals('value_2')) - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2', :key_3 => 'value_3' }]) - end - - def test_should_not_match_hash_not_including_specified_entries_with_nested_value_matchers - matcher = has_entries(:key_1 => equals('value_2'), :key_2 => equals('value_2'), :key_3 => equals('value_3')) - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/has_entry_test.rb b/build_lib/mocha/test/unit/parameter_matchers/has_entry_test.rb deleted file mode 100644 index 2735c3d..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/has_entry_test.rb +++ /dev/null @@ -1,82 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/has_entry' -require 'mocha/parameter_matchers/object' -require 'mocha/parameter_matchers/equals' -require 'mocha/inspect' - -class HasEntryTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_hash_including_specified_key_value_pair - matcher = has_entry(:key_1, 'value_1') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_key_value_pair - matcher = has_entry(:key_1, 'value_2') - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_match_hash_including_specified_entry - matcher = has_entry(:key_1 => 'value_1') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_entry - matcher = has_entry(:key_1 => 'value_2') - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_describe_matcher_with_key_value_pair - matcher = has_entry(:key_1, 'value_1') - assert_equal "has_entry(:key_1 => 'value_1')", matcher.mocha_inspect - end - - def test_should_describe_matcher_with_entry - matcher = has_entry(:key_1 => 'value_1') - assert_equal "has_entry(:key_1 => 'value_1')", matcher.mocha_inspect - end - - def test_should_match_hash_including_specified_entry_with_nested_key_matcher - matcher = has_entry(equals(:key_1) => 'value_1') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_match_hash_including_specified_entry_with_nested_value_matcher - matcher = has_entry(:key_1 => equals('value_1')) - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_entry_with_nested_key_matcher - matcher = has_entry(equals(:key_1) => 'value_2') - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_entry_with_nested_value_matcher - matcher = has_entry(:key_1 => equals('value_2')) - assert !matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_object_that_doesnt_respond_to_keys - matcher = has_entry(:key_1 => equals('value_2')) - object = Class.new do - def [](key) - 'value_2' - end - end.new - assert !matcher.matches?([object]) - end - - def test_should_not_match_object_that_doesnt_respond_to_square_bracket - matcher = has_entry(:key_1 => equals('value_2')) - object = Class.new do - def keys - [:key_1] - end - end.new - assert !matcher.matches?([object]) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/has_key_test.rb b/build_lib/mocha/test/unit/parameter_matchers/has_key_test.rb deleted file mode 100644 index 90a452a..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/has_key_test.rb +++ /dev/null @@ -1,55 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/has_key' -require 'mocha/parameter_matchers/object' -require 'mocha/inspect' - -class HasKeyTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_hash_including_specified_key - matcher = has_key(:key_1) - assert matcher.matches?([{ :key_1 => 1, :key_2 => 2 }]) - end - - def test_should_not_match_hash_not_including_specified_key - matcher = has_key(:key_1) - assert !matcher.matches?([{ :key_2 => 2 }]) - end - - def test_should_describe_matcher - matcher = has_key(:key) - assert_equal 'has_key(:key)', matcher.mocha_inspect - end - - def test_should_match_hash_including_specified_key_with_nested_key_matcher - matcher = has_key(equals(:key_1)) - assert matcher.matches?([{ :key_1 => 1, :key_2 => 2 }]) - end - - def test_should_not_match_hash_not_including_specified_key_with_nested_key_matcher - matcher = has_key(equals(:key_1)) - assert !matcher.matches?([{ :key_2 => 2 }]) - end - - def test_should_not_raise_error_on_empty_arguments - matcher = has_key(:key) - assert_nothing_raised { matcher.matches?([]) } - end - - def test_should_not_match_on_empty_arguments - matcher = has_key(:key) - assert !matcher.matches?([]) - end - - def test_should_not_raise_error_on_argument_that_does_not_respond_to_keys - matcher = has_key(:key) - assert_nothing_raised { matcher.matches?([:key]) } - end - - def test_should_not_match_on_argument_that_does_not_respond_to_keys - matcher = has_key(:key) - assert !matcher.matches?([:key]) - end -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/has_value_test.rb b/build_lib/mocha/test/unit/parameter_matchers/has_value_test.rb deleted file mode 100644 index d7a9024..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/has_value_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/has_value' -require 'mocha/parameter_matchers/object' -require 'mocha/parameter_matchers/equals' -require 'mocha/inspect' - -class HasValueTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_hash_including_specified_value - matcher = has_value('value_1') - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_value - matcher = has_value('value_1') - assert !matcher.matches?([{ :key_2 => 'value_2' }]) - end - - def test_should_describe_matcher - matcher = has_value('value_1') - assert_equal "has_value('value_1')", matcher.mocha_inspect - end - - def test_should_match_hash_including_specified_value_with_nested_value_matcher - matcher = has_value(equals('value_1')) - assert matcher.matches?([{ :key_1 => 'value_1', :key_2 => 'value_2' }]) - end - - def test_should_not_match_hash_not_including_specified_value_with_nested_value_matcher - matcher = has_value(equals('value_1')) - assert !matcher.matches?([{ :key_2 => 'value_2' }]) - end - - def test_should_not_raise_error_on_empty_arguments - matcher = has_value('value_1') - assert_nothing_raised { matcher.matches?([]) } - end - - def test_should_not_match_empty_arguments - matcher = has_value('value_1') - assert !matcher.matches?([]) - end - - def test_should_not_raise_error_on_argument_that_does_not_respond_to_values - matcher = has_value('value_1') - assert_nothing_raised { matcher.matches?(['value_1']) } - end - - def test_should_not_match_on_argument_that_does_not_respond_to_values - matcher = has_value('value_1') - assert !matcher.matches?(['value_1']) - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/includes_test.rb b/build_lib/mocha/test/unit/parameter_matchers/includes_test.rb deleted file mode 100644 index 2bca34c..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/includes_test.rb +++ /dev/null @@ -1,44 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/includes' -require 'mocha/inspect' - -class IncludesTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_object_including_value - matcher = includes(:x) - assert matcher.matches?([[:x, :y, :z]]) - end - - def test_should_not_match_object_that_does_not_include_value - matcher = includes(:not_included) - assert !matcher.matches?([[:x, :y, :z]]) - end - - def test_should_describe_matcher - matcher = includes(:x) - assert_equal "includes(:x)", matcher.mocha_inspect - end - - def test_should_not_raise_error_on_emtpy_arguments - matcher = includes(:x) - assert_nothing_raised { matcher.matches?([]) } - end - - def test_should_not_match_on_empty_arguments - matcher = includes(:x) - assert !matcher.matches?([]) - end - - def test_should_not_raise_error_on_argument_that_does_not_respond_to_include - matcher = includes(:x) - assert_nothing_raised { matcher.matches?([:x]) } - end - - def test_should_not_match_on_argument_that_does_not_respond_to_include - matcher = includes(:x) - assert !matcher.matches?([:x]) - end -end diff --git a/build_lib/mocha/test/unit/parameter_matchers/instance_of_test.rb b/build_lib/mocha/test/unit/parameter_matchers/instance_of_test.rb deleted file mode 100644 index 861cb85..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/instance_of_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/instance_of' -require 'mocha/inspect' - -class InstanceOfTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_object_that_is_an_instance_of_specified_class - matcher = instance_of(String) - assert matcher.matches?(['string']) - end - - def test_should_not_match_object_that_is_not_an_instance_of_specified_class - matcher = instance_of(String) - assert !matcher.matches?([99]) - end - - def test_should_describe_matcher - matcher = instance_of(String) - assert_equal "instance_of(String)", matcher.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/parameter_matchers/is_a_test.rb b/build_lib/mocha/test/unit/parameter_matchers/is_a_test.rb deleted file mode 100644 index 7904137..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/is_a_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/is_a' -require 'mocha/inspect' - -class IsATest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_object_that_is_a_specified_class - matcher = is_a(Integer) - assert matcher.matches?([99]) - end - - def test_should_not_match_object_that_is_not_a_specified_class - matcher = is_a(Integer) - assert !matcher.matches?(['string']) - end - - def test_should_describe_matcher - matcher = is_a(Integer) - assert_equal "is_a(Integer)", matcher.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/parameter_matchers/kind_of_test.rb b/build_lib/mocha/test/unit/parameter_matchers/kind_of_test.rb deleted file mode 100644 index 1404fa8..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/kind_of_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/kind_of' -require 'mocha/inspect' - -class KindOfTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_object_that_is_a_kind_of_specified_class - matcher = kind_of(Integer) - assert matcher.matches?([99]) - end - - def test_should_not_match_object_that_is_not_a_kind_of_specified_class - matcher = kind_of(Integer) - assert !matcher.matches?(['string']) - end - - def test_should_describe_matcher - matcher = kind_of(Integer) - assert_equal "kind_of(Integer)", matcher.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/parameter_matchers/not_test.rb b/build_lib/mocha/test/unit/parameter_matchers/not_test.rb deleted file mode 100644 index 21f50e2..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/not_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/not' -require 'mocha/inspect' -require 'stub_matcher' - -class NotTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_if_matcher_does_not_match - matcher = Not(Stub::Matcher.new(false)) - assert matcher.matches?(['any_old_value']) - end - - def test_should_not_match_if_matcher_does_match - matcher = Not(Stub::Matcher.new(true)) - assert !matcher.matches?(['any_old_value']) - end - - def test_should_describe_matcher - matcher = Not(Stub::Matcher.new(true)) - assert_equal 'Not(matcher(true))', matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/regexp_matches_test.rb b/build_lib/mocha/test/unit/parameter_matchers/regexp_matches_test.rb deleted file mode 100644 index f33e97d..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/regexp_matches_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/regexp_matches' -require 'mocha/inspect' - -class RegexpMatchesTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_parameter_matching_regular_expression - matcher = regexp_matches(/oo/) - assert matcher.matches?(['foo']) - end - - def test_should_not_match_parameter_not_matching_regular_expression - matcher = regexp_matches(/oo/) - assert !matcher.matches?(['bar']) - end - - def test_should_describe_matcher - matcher = regexp_matches(/oo/) - assert_equal "regexp_matches(/oo/)", matcher.mocha_inspect - end - - def test_should_not_raise_error_on_empty_arguments - matcher = regexp_matches(/oo/) - assert_nothing_raised { matcher.matches?([]) } - end - - def test_should_not_match_on_empty_arguments - matcher = regexp_matches(/oo/) - assert !matcher.matches?([]) - end - - def test_should_not_raise_error_on_argument_that_does_not_respond_to_equals_tilde - object_not_responding_to_equals_tilde = Class.new { undef =~ }.new - matcher = regexp_matches(/oo/) - assert_nothing_raised { matcher.matches?([object_not_responding_to_equals_tilde]) } - end - - def test_should_not_match_on_argument_that_does_not_respond_to_equals_tilde - object_not_responding_to_equals_tilde = Class.new { undef =~ }.new - matcher = regexp_matches(/oo/) - assert !matcher.matches?([object_not_responding_to_equals_tilde]) - end -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/responds_with_test.rb b/build_lib/mocha/test/unit/parameter_matchers/responds_with_test.rb deleted file mode 100644 index 7f5bf4e..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/responds_with_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/responds_with' -require 'mocha/inspect' - -class RespondsWithTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_parameter_responding_with_expected_value - matcher = responds_with(:upcase, 'FOO') - assert matcher.matches?(['foo']) - end - - def test_should_not_match_parameter_responding_with_unexpected_value - matcher = responds_with(:upcase, 'FOO') - assert !matcher.matches?(['bar']) - end - - def test_should_describe_matcher - matcher = responds_with(:foo, :bar) - assert_equal 'responds_with(:foo, :bar)', matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/stub_matcher.rb b/build_lib/mocha/test/unit/parameter_matchers/stub_matcher.rb deleted file mode 100644 index 8bb8172..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/stub_matcher.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Stub - - class Matcher - - attr_accessor :value - - def initialize(matches) - @matches = matches - end - - def matches?(available_parameters) - value = available_parameters.shift - @value = value - @matches - end - - def mocha_inspect - "matcher(#{@matches})" - end - - def to_matcher - self - end - - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameter_matchers/yaml_equivalent_test.rb b/build_lib/mocha/test/unit/parameter_matchers/yaml_equivalent_test.rb deleted file mode 100644 index 8bc66e4..0000000 --- a/build_lib/mocha/test/unit/parameter_matchers/yaml_equivalent_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) - -require 'mocha/parameter_matchers/yaml_equivalent' -require 'mocha/inspect' - -class YamlEquivalentTest < Test::Unit::TestCase - - include Mocha::ParameterMatchers - - def test_should_match_parameter_matching_yaml_representation_of_object - matcher = yaml_equivalent([1, 2, 3]) - assert matcher.matches?(["--- \n- 1\n- 2\n- 3\n"]) - end - - def test_should_not_match_parameter_matching_yaml_representation_of_object - matcher = yaml_equivalent([1, 2, 3]) - assert !matcher.matches?(["--- \n- 4\n- 5\n"]) - end - - def test_should_describe_matcher - matcher = yaml_equivalent([1, 2, 3]) - assert_equal "yaml_equivalent([1, 2, 3])", matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/parameters_matcher_test.rb b/build_lib/mocha/test/unit/parameters_matcher_test.rb deleted file mode 100644 index 3048d30..0000000 --- a/build_lib/mocha/test/unit/parameters_matcher_test.rb +++ /dev/null @@ -1,121 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/parameters_matcher' - -class ParametersMatcherTest < Test::Unit::TestCase - - include Mocha - - def test_should_match_any_actual_parameters_if_no_expected_parameters_specified - parameters_matcher = ParametersMatcher.new - assert parameters_matcher.match?(actual_parameters = [1, 2, 3]) - end - - def test_should_match_if_actual_parameters_are_same_as_expected_parameters - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, 6]) - assert parameters_matcher.match?(actual_parameters = [4, 5, 6]) - end - - def test_should_not_match_if_actual_parameters_are_different_from_expected_parameters - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, 6]) - assert !parameters_matcher.match?(actual_parameters = [1, 2, 3]) - end - - def test_should_not_match_if_there_are_less_actual_parameters_than_expected_parameters - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, 6]) - assert !parameters_matcher.match?(actual_parameters = [4, 5]) - end - - def test_should_not_match_if_there_are_more_actual_parameters_than_expected_parameters - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5]) - assert !parameters_matcher.match?(actual_parameters = [4, 5, 6]) - end - - def test_should_not_match_if_not_all_required_parameters_are_supplied - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert !parameters_matcher.match?(actual_parameters = [4]) - end - - def test_should_match_if_all_required_parameters_match_and_no_optional_parameters_are_supplied - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert parameters_matcher.match?(actual_parameters = [4, 5]) - end - - def test_should_match_if_all_required_and_optional_parameters_match_and_some_optional_parameters_are_supplied - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert parameters_matcher.match?(actual_parameters = [4, 5, 6]) - end - - def test_should_match_if_all_required_and_optional_parameters_match_and_all_optional_parameters_are_supplied - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert parameters_matcher.match?(actual_parameters = [4, 5, 6, 7]) - end - - def test_should_not_match_if_all_required_and_optional_parameters_match_but_too_many_optional_parameters_are_supplied - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert !parameters_matcher.match?(actual_parameters = [4, 5, 6, 7, 8]) - end - - def test_should_not_match_if_all_required_parameters_match_but_some_optional_parameters_do_not_match - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert !parameters_matcher.match?(actual_parameters = [4, 5, 6, 0]) - end - - def test_should_not_match_if_some_required_parameters_do_not_match_although_all_optional_parameters_do_match - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert !parameters_matcher.match?(actual_parameters = [4, 0, 6]) - end - - def test_should_not_match_if_all_required_parameters_match_but_no_optional_parameters_match - optionals = ParameterMatchers::Optionally.new(6, 7) - parameters_matcher = ParametersMatcher.new(expected_parameters = [4, 5, optionals]) - assert !parameters_matcher.match?(actual_parameters = [4, 5, 0, 0]) - end - - def test_should_match_if_actual_parameters_satisfy_matching_block - parameters_matcher = ParametersMatcher.new { |x, y| x + y == 3 } - assert parameters_matcher.match?(actual_parameters = [1, 2]) - end - - def test_should_not_match_if_actual_parameters_do_not_satisfy_matching_block - parameters_matcher = ParametersMatcher.new { |x, y| x + y == 3 } - assert !parameters_matcher.match?(actual_parameters = [2, 3]) - end - - def test_should_remove_outer_array_braces - params = [1, 2, [3, 4]] - parameters_matcher = ParametersMatcher.new(params) - assert_equal '(1, 2, [3, 4])', parameters_matcher.mocha_inspect - end - - def test_should_display_numeric_arguments_as_is - params = [1, 2, 3] - parameters_matcher = ParametersMatcher.new(params) - assert_equal '(1, 2, 3)', parameters_matcher.mocha_inspect - end - - def test_should_remove_curly_braces_if_hash_is_only_argument - params = [{:a => 1, :z => 2}] - parameters_matcher = ParametersMatcher.new(params) - assert_nil parameters_matcher.mocha_inspect.index('{') - assert_nil parameters_matcher.mocha_inspect.index('}') - end - - def test_should_not_remove_curly_braces_if_hash_is_not_the_only_argument - params = [1, {:a => 1}] - parameters_matcher = ParametersMatcher.new(params) - assert_equal '(1, {:a => 1})', parameters_matcher.mocha_inspect - end - - def test_should_indicate_that_matcher_will_match_any_actual_parameters - parameters_matcher = ParametersMatcher.new - assert_equal '(any_parameters)', parameters_matcher.mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/return_values_test.rb b/build_lib/mocha/test/unit/return_values_test.rb deleted file mode 100644 index dc61ca8..0000000 --- a/build_lib/mocha/test/unit/return_values_test.rb +++ /dev/null @@ -1,63 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/return_values' - -class ReturnValuesTest < Test::Unit::TestCase - - include Mocha - - def test_should_return_nil - values = ReturnValues.new - assert_nil values.next - end - - def test_should_keep_returning_nil - values = ReturnValues.new - values.next - assert_nil values.next - assert_nil values.next - end - - def test_should_return_evaluated_single_return_value - values = ReturnValues.new(SingleReturnValue.new('value')) - assert_equal 'value', values.next - end - - def test_should_keep_returning_evaluated_single_return_value - values = ReturnValues.new(SingleReturnValue.new('value')) - values.next - assert_equal 'value', values.next - assert_equal 'value', values.next - end - - def test_should_return_consecutive_evaluated_single_return_values - values = ReturnValues.new(SingleReturnValue.new('value_1'), SingleReturnValue.new('value_2')) - assert_equal 'value_1', values.next - assert_equal 'value_2', values.next - end - - def test_should_keep_returning_last_of_consecutive_evaluated_single_return_values - values = ReturnValues.new(SingleReturnValue.new('value_1'), SingleReturnValue.new('value_2')) - values.next - values.next - assert_equal 'value_2', values.next - assert_equal 'value_2', values.next - end - - def test_should_build_single_return_values_for_each_values - values = ReturnValues.build('value_1', 'value_2', 'value_3').values - assert_equal 'value_1', values[0].evaluate - assert_equal 'value_2', values[1].evaluate - assert_equal 'value_3', values[2].evaluate - end - - def test_should_combine_two_sets_of_return_values - values_1 = ReturnValues.build('value_1') - values_2 = ReturnValues.build('value_2a', 'value_2b') - values = (values_1 + values_2).values - assert_equal 'value_1', values[0].evaluate - assert_equal 'value_2a', values[1].evaluate - assert_equal 'value_2b', values[2].evaluate - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/sequence_test.rb b/build_lib/mocha/test/unit/sequence_test.rb deleted file mode 100644 index 8637b64..0000000 --- a/build_lib/mocha/test/unit/sequence_test.rb +++ /dev/null @@ -1,104 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/sequence' -require 'mocha/expectation' - -class SequenceTest < Test::Unit::TestCase - - include Mocha - - class FakeExpectation - - attr_reader :ordering_constraints - - def initialize(satisfied = false) - @satisfied = satisfied - @ordering_constraints = [] - end - - def add_ordering_constraint(ordering_constraint) - @ordering_constraints << ordering_constraint - end - - def satisfied? - @satisfied - end - - end - - def test_should_be_satisfied_if_no_expectations_added - sequence = Sequence.new('name') - assert sequence.satisfied_to_index?(0) - end - - def test_should_be_satisfied_if_one_unsatisfied_expectations_added_but_it_is_not_included_by_index - sequence = Sequence.new('name') - expectation = FakeExpectation.new(satisfied = false) - sequence.constrain_as_next_in_sequence(expectation) - assert sequence.satisfied_to_index?(0) - end - - def test_should_not_be_satisfied_if_one_unsatisfied_expectations_added_and_it_is_included_by_index - sequence = Sequence.new('name') - expectation = FakeExpectation.new(satisfied = false) - sequence.constrain_as_next_in_sequence(expectation) - assert !sequence.satisfied_to_index?(1) - end - - def test_should_be_satisfied_if_one_satisfied_expectations_added_and_it_is_included_by_index - sequence = Sequence.new('name') - expectation = FakeExpectation.new(satisfied = true) - sequence.constrain_as_next_in_sequence(expectation) - assert sequence.satisfied_to_index?(1) - end - - def test_should_not_be_satisfied_if_one_satisfied_and_one_unsatisfied_expectation_added_and_both_are_included_by_index - sequence = Sequence.new('name') - expectation_one = FakeExpectation.new(satisfied = true) - expectation_two = FakeExpectation.new(satisfied = false) - sequence.constrain_as_next_in_sequence(expectation_one) - sequence.constrain_as_next_in_sequence(expectation_two) - assert !sequence.satisfied_to_index?(2) - end - - def test_should_be_satisfied_if_two_satisfied_expectations_added_and_both_are_included_by_index - sequence = Sequence.new('name') - expectation_one = FakeExpectation.new(satisfied = true) - expectation_two = FakeExpectation.new(satisfied = true) - sequence.constrain_as_next_in_sequence(expectation_one) - sequence.constrain_as_next_in_sequence(expectation_two) - assert sequence.satisfied_to_index?(2) - end - - def test_should_add_ordering_constraint_to_expectation - sequence = Sequence.new('name') - expectation = FakeExpectation.new - sequence.constrain_as_next_in_sequence(expectation) - assert_equal 1, expectation.ordering_constraints.length - end - - def test_should_not_allow_invocation_of_second_method_when_first_n_sequence_has_not_been_invoked - sequence = Sequence.new('name') - expectation_one = FakeExpectation.new(satisfied = false) - expectation_two = FakeExpectation.new(satisfied = false) - sequence.constrain_as_next_in_sequence(expectation_one) - sequence.constrain_as_next_in_sequence(expectation_two) - assert !expectation_two.ordering_constraints[0].allows_invocation_now? - end - - def test_should_allow_invocation_of_second_method_when_first_in_sequence_has_been_invoked - sequence = Sequence.new('name') - expectation_one = FakeExpectation.new(satisfied = true) - expectation_two = FakeExpectation.new(satisfied = false) - sequence.constrain_as_next_in_sequence(expectation_one) - sequence.constrain_as_next_in_sequence(expectation_two) - assert expectation_two.ordering_constraints[0].allows_invocation_now? - end - - def test_should_describe_ordering_constraint_as_being_part_of_named_sequence - sequence = Sequence.new('wibble') - expectation = FakeExpectation.new - sequence.constrain_as_next_in_sequence(expectation) - assert_equal "in sequence 'wibble'", expectation.ordering_constraints[0].mocha_inspect - end - -end \ No newline at end of file diff --git a/build_lib/mocha/test/unit/single_return_value_test.rb b/build_lib/mocha/test/unit/single_return_value_test.rb deleted file mode 100644 index 7b4ff1b..0000000 --- a/build_lib/mocha/test/unit/single_return_value_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/single_return_value' - -class SingleReturnValueTest < Test::Unit::TestCase - - include Mocha - - def test_should_return_value - value = SingleReturnValue.new('value') - assert_equal 'value', value.evaluate - end - -end diff --git a/build_lib/mocha/test/unit/single_yield_test.rb b/build_lib/mocha/test/unit/single_yield_test.rb deleted file mode 100644 index deb08a4..0000000 --- a/build_lib/mocha/test/unit/single_yield_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/single_yield' - -class SingleYieldTest < Test::Unit::TestCase - - include Mocha - - def test_should_provide_parameters_for_single_yield_in_single_invocation - parameter_group = SingleYield.new(1, 2, 3) - parameter_groups = [] - parameter_group.each do |parameters| - parameter_groups << parameters - end - assert_equal [[1, 2, 3]], parameter_groups - end - -end diff --git a/build_lib/mocha/test/unit/state_machine_test.rb b/build_lib/mocha/test/unit/state_machine_test.rb deleted file mode 100644 index c770921..0000000 --- a/build_lib/mocha/test/unit/state_machine_test.rb +++ /dev/null @@ -1,98 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/state_machine' - -class StateMachineTest < Test::Unit::TestCase - - include Mocha - - def test_should_initially_be_in_no_state - state_machine = StateMachine.new('name') - any_state.each do |state| - assert !state_machine.is(state).active? - assert state_machine.is_not(state).active? - end - end - - def test_should_be_able_to_enter_a_state - state_machine = StateMachine.new('name') - state = 'A' - other_states = any_state.reject { |s| s == state } - - state_machine.is(state).activate - - assert state_machine.is(state).active? - assert !state_machine.is_not(state).active? - other_states.each do |s| - assert !state_machine.is(s).active? - assert state_machine.is_not(s).active? - end - end - - def test_should_be_able_to_change_state - state_machine = StateMachine.new('name') - state = 'B' - other_states = any_state.reject { |s| s == state } - - state_machine.is('A').activate - state_machine.is(state).activate - - assert state_machine.is(state).active? - assert !state_machine.is_not(state).active? - other_states.each do |s| - assert !state_machine.is(s).active? - assert state_machine.is_not(s).active? - end - end - - def test_should_be_put_into_an_initial_state - state_machine = StateMachine.new('name') - initial_state = 'A' - other_states = any_state.reject { |s| s == initial_state } - - state_machine.starts_as(initial_state) - - assert state_machine.is(initial_state).active? - assert !state_machine.is_not(initial_state).active? - other_states.each do |state| - assert !state_machine.is(state).active? - assert state_machine.is_not(state).active? - end - end - - def test_should_be_put_into_a_new_state - next_state = 'B' - - other_states = any_state.reject { |s| s == next_state } - state_machine = StateMachine.new('name').starts_as('A') - - state_machine.become(next_state) - - assert state_machine.is(next_state).active? - assert !state_machine.is_not(next_state).active? - other_states.each do |state| - assert !state_machine.is(state).active? - assert state_machine.is_not(state).active? - end - end - - def test_should_describe_itself_as_name_and_current_state - state_machine = StateMachine.new('state_machine_name') - assert_equal 'state_machine_name has no current state', state_machine.mocha_inspect - inspectable_state = Class.new { define_method(:mocha_inspect) { "'inspectable_state'" } }.new - state_machine.is(inspectable_state).activate - assert_equal "state_machine_name is 'inspectable_state'", state_machine.mocha_inspect - end - - def test_should_have_self_describing_states - state_machine = StateMachine.new('state_machine_name') - inspectable_state = Class.new { define_method(:mocha_inspect) { "'inspectable_state'" } }.new - assert_equal "state_machine_name is 'inspectable_state'", state_machine.is(inspectable_state).mocha_inspect - assert_equal "state_machine_name is not 'inspectable_state'", state_machine.is_not(inspectable_state).mocha_inspect - end - - def any_state - %w(A B C D) - end - -end diff --git a/build_lib/mocha/test/unit/string_inspect_test.rb b/build_lib/mocha/test/unit/string_inspect_test.rb deleted file mode 100644 index 6562015..0000000 --- a/build_lib/mocha/test/unit/string_inspect_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) -require 'mocha/inspect' - -class StringInspectTest < Test::Unit::TestCase - - def test_should_replace_escaped_quotes_with_single_quote - string = "my_string" - assert_equal "'my_string'", string.mocha_inspect - end - -end diff --git a/build_lib/mocha/test/unit/yield_parameters_test.rb b/build_lib/mocha/test/unit/yield_parameters_test.rb deleted file mode 100644 index a148058..0000000 --- a/build_lib/mocha/test/unit/yield_parameters_test.rb +++ /dev/null @@ -1,93 +0,0 @@ -require File.expand_path('../../test_helper', __FILE__) - -require 'mocha/yield_parameters' -require 'mocha/no_yields' -require 'mocha/single_yield' -require 'mocha/multiple_yields' - -class YieldParametersTest < Test::Unit::TestCase - - include Mocha - - def test_should_return_null_yield_parameter_group_by_default - yield_parameters = YieldParameters.new - assert yield_parameters.next_invocation.is_a?(NoYields) - end - - def test_should_return_single_yield_parameter_group - yield_parameters = YieldParameters.new - yield_parameters.add(1, 2, 3) - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [1, 2, 3], parameter_group.parameters - end - - def test_should_keep_returning_single_yield_parameter_group - yield_parameters = YieldParameters.new - yield_parameters.add(1, 2, 3) - yield_parameters.next_invocation - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [1, 2, 3], parameter_group.parameters - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [1, 2, 3], parameter_group.parameters - end - - def test_should_return_consecutive_single_yield_parameter_groups - yield_parameters = YieldParameters.new - yield_parameters.add(1, 2, 3) - yield_parameters.add(4, 5) - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [1, 2, 3], parameter_group.parameters - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [4, 5], parameter_group.parameters - end - - def test_should_return_multiple_yield_parameter_group - yield_parameters = YieldParameters.new - yield_parameters.multiple_add([1, 2, 3], [4, 5]) - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[1, 2, 3], [4, 5]], parameter_group.parameter_groups - end - - def test_should_keep_returning_multiple_yield_parameter_group - yield_parameters = YieldParameters.new - yield_parameters.multiple_add([1, 2, 3], [4, 5]) - yield_parameters.next_invocation - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[1, 2, 3], [4, 5]], parameter_group.parameter_groups - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[1, 2, 3], [4, 5]], parameter_group.parameter_groups - end - - def test_should_return_consecutive_multiple_yield_parameter_groups - yield_parameters = YieldParameters.new - yield_parameters.multiple_add([1, 2, 3], [4, 5]) - yield_parameters.multiple_add([6, 7], [8, 9, 0]) - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[1, 2, 3], [4, 5]], parameter_group.parameter_groups - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[6, 7], [8, 9, 0]], parameter_group.parameter_groups - end - - def test_should_return_consecutive_single_and_multiple_yield_parameter_groups - yield_parameters = YieldParameters.new - yield_parameters.add(1, 2, 3) - yield_parameters.multiple_add([4, 5, 6], [7, 8]) - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(SingleYield) - assert_equal [1, 2, 3], parameter_group.parameters - parameter_group = yield_parameters.next_invocation - assert parameter_group.is_a?(MultipleYields) - assert_equal [[4, 5, 6], [7, 8]], parameter_group.parameter_groups - end - -end \ No newline at end of file diff --git a/jruby-openssl.gemspec b/jruby-openssl.gemspec deleted file mode 100644 index 70652e7..0000000 --- a/jruby-openssl.gemspec +++ /dev/null @@ -1,36 +0,0 @@ -# -*- encoding: utf-8 -*- - -Gem::Specification.new do |s| - s.name = "jruby-openssl" - s.version = "0.7.7" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Ola Bini and JRuby contributors"] - s.date = "2012-05-21" - s.description = "JRuby-OpenSSL is an add-on gem for JRuby that emulates the Ruby OpenSSL native library." - s.email = "ola.bini@gmail.com" - s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "License.txt"] - s.files = ["Rakefile", "History.txt", "Manifest.txt", "README.txt", "License.txt", "lib/shared/jopenssl.jar", "lib/1.9", "lib/shared", "lib/1.8", "lib/1.9/openssl.rb", "lib/1.9/openssl", "lib/1.9/openssl/bn.rb", "lib/1.9/openssl/x509-internal.rb", "lib/1.9/openssl/cipher.rb", "lib/1.9/openssl/digest.rb", "lib/1.9/openssl/ssl.rb", "lib/1.9/openssl/buffering.rb", "lib/1.9/openssl/ssl-internal.rb", "lib/1.9/openssl/x509.rb", "lib/1.9/openssl/config.rb", "lib/shared/openssl.rb", "lib/shared/openssl", "lib/shared/jopenssl", "lib/shared/openssl/dummyssl.rb", "lib/shared/openssl/ssl.rb", "lib/shared/openssl/pkcs12.rb", "lib/shared/openssl/x509.rb", "lib/shared/openssl/dummy.rb", "lib/shared/jopenssl/version.rb", "lib/1.8/openssl.rb", "lib/1.8/openssl", "lib/1.8/openssl/bn.rb", "lib/1.8/openssl/pkcs7.rb", "lib/1.8/openssl/x509-internal.rb", "lib/1.8/openssl/cipher.rb", "lib/1.8/openssl/digest.rb", "lib/1.8/openssl/ssl.rb", "lib/1.8/openssl/buffering.rb", "lib/1.8/openssl/ssl-internal.rb", "lib/1.8/openssl/x509.rb", "lib/1.8/openssl/config.rb", "test/1.9", "test/ref", "test/test_all.rb", "test/test_pkey_dsa.rb", "test/fixture", "test/test_integration.rb", "test/ruby", "test/test_ssl.rb", "test/test_parse_certificate.rb", "test/test_openssl.rb", "test/cert_with_ec_pk.cer", "test/java", "test/ut_eof.rb", "test/test_x509store.rb", "test/test_imaps.rb", "test/test_certificate.rb", "test/test_pkcs7.rb", "test/test_cipher.rb", "test/1.8", "test/test_pkey_rsa.rb", "test/test_java.rb", "test/1.9/test_ssl_session.rb", "test/1.9/test_engine.rb", "test/1.9/test_asn1.rb", "test/1.9/test_pkey_dh.rb", "test/1.9/test_pkey_dsa.rb", "test/1.9/test_ocsp.rb", "test/1.9/ssl_server.rb", "test/1.9/test_x509ext.rb", "test/1.9/utils.rb", "test/1.9/test_ssl.rb", "test/1.9/test_buffering.rb", "test/1.9/test_ns_spki.rb", "test/1.9/test_digest.rb", "test/1.9/test_pair.rb", "test/1.9/test_x509crl.rb", "test/1.9/test_x509store.rb", "test/1.9/test_bn.rb", "test/1.9/test_pkey_ec.rb", "test/1.9/test_pkcs7.rb", "test/1.9/test_pkcs12.rb", "test/1.9/test_cipher.rb", "test/1.9/test_pkey_rsa.rb", "test/1.9/test_x509req.rb", "test/1.9/test_x509name.rb", "test/1.9/test_hmac.rb", "test/1.9/test_x509cert.rb", "test/1.9/test_config.rb", "test/ref/a.out", "test/ref/pkcs1", "test/ref/pkcs1.c", "test/ref/compile.rb", "test/fixture/common.pem", "test/fixture/ca_path", "test/fixture/key_then_cert.pem", "test/fixture/imaps", "test/fixture/keypair.pem", "test/fixture/cacert.pem", "test/fixture/verisign.pem", "test/fixture/purpose", "test/fixture/cert_localhost.pem", "test/fixture/selfcert.pem", "test/fixture/max.pem", "test/fixture/localhost_keypair.pem", "test/fixture/ids_in_subject_rdn_set.pem", "test/fixture/ca-bundle.crt", "test/fixture/verisign_c3.pem", "test/fixture/ca_path/72fa7371.0", "test/fixture/ca_path/verisign.pem", "test/fixture/imaps/cacert.pem", "test/fixture/imaps/server.crt", "test/fixture/imaps/server.key", "test/fixture/purpose/ca", "test/fixture/purpose/sslclient", "test/fixture/purpose/scripts", "test/fixture/purpose/sslserver_no_dsig_in_keyUsage.pem", "test/fixture/purpose/cacert.pem", "test/fixture/purpose/sslserver", "test/fixture/purpose/sslserver.pem", "test/fixture/purpose/sslclient.pem", "test/fixture/purpose/b70a5bc1.0", "test/fixture/purpose/ca/serial", "test/fixture/purpose/ca/gen_cert.rb", "test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234", "test/fixture/purpose/ca/ca_config.rb", "test/fixture/purpose/ca/cacert.pem", "test/fixture/purpose/ca/private", "test/fixture/purpose/ca/newcerts", "test/fixture/purpose/ca/private/cakeypair.pem", "test/fixture/purpose/ca/newcerts/4_cert.pem", "test/fixture/purpose/ca/newcerts/3_cert.pem", "test/fixture/purpose/ca/newcerts/2_cert.pem", "test/fixture/purpose/sslclient/csr.pem", "test/fixture/purpose/sslclient/keypair.pem", "test/fixture/purpose/sslclient/sslclient.pem", "test/fixture/purpose/scripts/gen_cert.rb", "test/fixture/purpose/scripts/init_ca.rb", "test/fixture/purpose/scripts/gen_csr.rb", "test/fixture/purpose/sslserver/csr.pem", "test/fixture/purpose/sslserver/keypair.pem", "test/fixture/purpose/sslserver/sslserver.pem", "test/ruby/ut_eof.rb", "test/ruby/envutil.rb", "test/java/pkcs7_mime_enveloped.message", "test/java/test_java_attribute.rb", "test/java/test_java_pkcs7.rb", "test/java/test_java_mime.rb", "test/java/pkcs7_mime_signed.message", "test/java/test_java_smime.rb", "test/java/pkcs7_multipart_signed.message", "test/java/test_java_bio.rb", "test/1.8/test_asn1.rb", "test/1.8/ssl_server.rb", "test/1.8/test_x509ext.rb", "test/1.8/utils.rb", "test/1.8/test_ssl.rb", "test/1.8/test_ec.rb", "test/1.8/test_ns_spki.rb", "test/1.8/test_digest.rb", "test/1.8/test_pair.rb", "test/1.8/test_x509crl.rb", "test/1.8/test_x509store.rb", "test/1.8/test_pkcs7.rb", "test/1.8/test_cipher.rb", "test/1.8/test_pkey_rsa.rb", "test/1.8/test_x509req.rb", "test/1.8/test_x509name.rb", "test/1.8/test_hmac.rb", "test/1.8/test_x509cert.rb", "test/1.8/test_config.rb", ".gemtest"] - s.homepage = "https://github.com/jruby/jruby-ossl" - s.rdoc_options = ["--main", "README.txt"] - s.require_paths = ["lib/shared"] - s.rubyforge_project = "jruby-extras" - s.rubygems_version = "1.8.15" - s.summary = "OpenSSL add-on for JRuby" - s.test_files = ["test/test_all.rb"] - - if s.respond_to? :specification_version then - s.specification_version = 3 - - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 1.5.0146.1"]) - s.add_development_dependency(%q, ["~> 3.10"]) - else - s.add_dependency(%q, [">= 1.5.0146.1"]) - s.add_dependency(%q, ["~> 3.10"]) - end - else - s.add_dependency(%q, [">= 1.5.0146.1"]) - s.add_dependency(%q, ["~> 3.10"]) - end -end diff --git a/lib/1.8/openssl.rb b/lib/1.8/openssl.rb deleted file mode 100644 index d95bba7..0000000 --- a/lib/1.8/openssl.rb +++ /dev/null @@ -1,67 +0,0 @@ -=begin -= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id: openssl.rb 12496 2007-06-08 15:02:04Z technorama $ -=end - -# TODO: remove this chunk after 1.4 support is dropped -require 'digest' -unless defined?(::Digest::Class) - # restricted support for jruby <= 1.4 (1.8.6 Digest compat) - module Digest - class Class - def self.hexdigest(name, data) - digest(name, data).unpack('H*')[0] - end - - def self.digest(data, name) - digester = const_get(name).new - digester.update(data) - digester.finish - end - - def hexdigest - digest.unpack('H*')[0] - end - - def digest - dup.finish - end - - def ==(oth) - digest == oth.digest - end - - def to_s - hexdigest - end - - def size - digest_length - end - - def length - digest_length - end - end - end -end -# end of compat chunk. - -require 'openssl/bn' -require 'openssl/cipher' -require 'openssl/config' -require 'openssl/digest' -require 'openssl/pkcs7' -require 'openssl/ssl-internal' -require 'openssl/x509-internal' diff --git a/lib/1.8/openssl/bn.rb b/lib/1.8/openssl/bn.rb deleted file mode 100644 index 624c137..0000000 --- a/lib/1.8/openssl/bn.rb +++ /dev/null @@ -1,35 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' - -module OpenSSL - class BN - include Comparable - end # BN -end # OpenSSL - -## -# Add double dispatch to Integer -# -class Integer - def to_bn - OpenSSL::BN::new(self.to_s(16), 16) - end -end # Integer - diff --git a/lib/1.8/openssl/buffering.rb b/lib/1.8/openssl/buffering.rb deleted file mode 100644 index c83b92b..0000000 --- a/lib/1.8/openssl/buffering.rb +++ /dev/null @@ -1,241 +0,0 @@ -=begin -= $RCSfile$ -- Buffering mix-in module. - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2001 GOTOU YUUZOU - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -module OpenSSL -module Buffering - include Enumerable - attr_accessor :sync - BLOCK_SIZE = 1024*16 - - def initialize(*args) - @eof = false - @rbuffer = "" - @sync = @io.sync - end - - # - # for reading. - # - private - - def fill_rbuff - begin - @rbuffer << self.sysread(BLOCK_SIZE) - rescue Errno::EAGAIN - retry - rescue EOFError - @eof = true - end - end - - def consume_rbuff(size=nil) - if @rbuffer.empty? - nil - else - size = @rbuffer.size unless size - ret = @rbuffer[0, size] - @rbuffer[0, size] = "" - ret - end - end - - public - - def read(size=nil, buf=nil) - if size == 0 - if buf - buf.clear - else - buf = "" - end - return @eof ? nil : buf - end - until @eof - break if size && size <= @rbuffer.size - fill_rbuff - end - ret = consume_rbuff(size) || "" - if buf - buf.replace(ret) - ret = buf - end - (size && ret.empty?) ? nil : ret - end - - def readpartial(maxlen, buf=nil) - if maxlen == 0 - if buf - buf.clear - else - buf = "" - end - return @eof ? nil : buf - end - if @rbuffer.empty? - begin - return sysread(maxlen, buf) - rescue Errno::EAGAIN - retry - end - end - ret = consume_rbuff(maxlen) - if buf - buf.replace(ret) - ret = buf - end - raise EOFError if ret.empty? - ret - end - - def gets(eol=$/) - idx = @rbuffer.index(eol) - until @eof - break if idx - fill_rbuff - idx = @rbuffer.index(eol) - end - if eol.is_a?(Regexp) - size = idx ? idx+$&.size : nil - else - size = idx ? idx+eol.size : nil - end - consume_rbuff(size) - end - - def each(eol=$/) - while line = self.gets(eol) - yield line - end - end - alias each_line each - - def readlines(eol=$/) - ary = [] - while line = self.gets(eol) - ary << line - end - ary - end - - def readline(eol=$/) - raise EOFError if eof? - gets(eol) - end - - def getc - c = read(1) - c ? c[0] : nil - end - - def each_byte - while c = getc - yield(c) - end - end - - def readchar - raise EOFError if eof? - getc - end - - def ungetc(c) - @rbuffer[0,0] = c.chr - end - - def eof? - fill_rbuff if !@eof && @rbuffer.empty? - @eof && @rbuffer.empty? - end - alias eof eof? - - # - # for writing. - # - private - - def do_write(s) - @wbuffer = "" unless defined? @wbuffer - @wbuffer << s - @sync ||= false - if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) - remain = idx ? idx + $/.size : @wbuffer.length - nwritten = 0 - while remain > 0 - str = @wbuffer[nwritten,remain] - begin - nwrote = syswrite(str) - rescue Errno::EAGAIN - retry - end - remain -= nwrote - nwritten += nwrote - end - @wbuffer[0,nwritten] = "" - end - end - - public - - def write(s) - do_write(s) - s.length - end - - def << (s) - do_write(s) - self - end - - def puts(*args) - s = "" - if args.empty? - s << "\n" - end - args.each{|arg| - s << arg.to_s - if $/ && /\n\z/ !~ s - s << "\n" - end - } - do_write(s) - nil - end - - def print(*args) - s = "" - args.each{ |arg| s << arg.to_s } - do_write(s) - nil - end - - def printf(s, *args) - do_write(s % args) - nil - end - - def flush - osync = @sync - @sync = true - do_write "" - @sync = osync - end - - def close - flush rescue nil - sysclose - end -end -end diff --git a/lib/1.8/openssl/cipher.rb b/lib/1.8/openssl/cipher.rb deleted file mode 100644 index 290e9c1..0000000 --- a/lib/1.8/openssl/cipher.rb +++ /dev/null @@ -1,65 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space predefined Cipher subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' - -module OpenSSL - class Cipher - %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| - klass = Class.new(Cipher){ - define_method(:initialize){|*args| - cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } - super(cipher_name) - } - } - const_set(name, klass) - } - - %w(128 192 256).each{|keylen| - klass = Class.new(Cipher){ - define_method(:initialize){|mode| - mode ||= "CBC" - cipher_name = "AES-#{keylen}-#{mode}" - super(cipher_name) - } - } - const_set("AES#{keylen}", klass) - } - - # Generate, set, and return a random key. - # You must call cipher.encrypt or cipher.decrypt before calling this method. - def random_key - str = OpenSSL::Random.random_bytes(self.key_len) - self.key = str - return str - end - - # Generate, set, and return a random iv. - # You must call cipher.encrypt or cipher.decrypt before calling this method. - def random_iv - str = OpenSSL::Random.random_bytes(self.iv_len) - self.iv = str - return str - end - - # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. - class Cipher < Cipher - # add warning - end - end # Cipher -end # OpenSSL diff --git a/lib/1.8/openssl/config.rb b/lib/1.8/openssl/config.rb deleted file mode 100644 index 21c98b7..0000000 --- a/lib/1.8/openssl/config.rb +++ /dev/null @@ -1,316 +0,0 @@ -=begin -= Ruby-space definitions that completes C-space funcs for Config - -= Info - Copyright (C) 2010 Hiroshi Nakamura - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' -require 'stringio' - -module OpenSSL - class Config - include Enumerable - - class << self - def parse(str) - c = new() - parse_config(StringIO.new(str)).each do |section, hash| - c[section] = hash - end - c - end - - alias load new - - def parse_config(io) - begin - parse_config_lines(io) - rescue ConfigError => e - e.message.replace("error in line #{io.lineno}: " + e.message) - raise - end - end - - def get_key_string(data, section, key) # :nodoc: - if v = data[section] && data[section][key] - return v - elsif section == 'ENV' - if v = ENV[key] - return v - end - end - if v = data['default'] && data['default'][key] - return v - end - end - - private - - def parse_config_lines(io) - section = 'default' - data = {section => {}} - while definition = get_definition(io) - definition = clear_comments(definition) - next if definition.empty? - if definition[0] == ?[ - if /\[([^\]]*)\]/ =~ definition - section = $1.strip - data[section] ||= {} - else - raise ConfigError, "missing close square bracket" - end - else - if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition - if $2 - section = $1 - key = $2 - else - key = $1 - end - value = unescape_value(data, section, $3) - (data[section] ||= {})[key] = value.strip - else - raise ConfigError, "missing equal sign" - end - end - end - data - end - - # escape with backslash - QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ - # escape with backslash and doubled dq - QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ - # escaped char map - ESCAPE_MAP = { - "r" => "\r", - "n" => "\n", - "b" => "\b", - "t" => "\t", - } - - def unescape_value(data, section, value) - scanned = [] - while m = value.match(/['"\\$]/) - scanned << m.pre_match - c = m[0] - value = m.post_match - case c - when "'" - if m = value.match(QUOTE_REGEXP_SQ) - scanned << m[1].gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when '"' - if m = value.match(QUOTE_REGEXP_DQ) - scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when "\\" - c = value.slice!(0, 1) - scanned << (ESCAPE_MAP[c] || c) - when "$" - ref, value = extract_reference(value) - refsec = section - if ref.index('::') - refsec, ref = ref.split('::', 2) - end - if v = get_key_string(data, refsec, ref) - scanned << v - else - raise ConfigError, "variable has no value" - end - else - raise 'must not reaced' - end - end - scanned << value - scanned.join - end - - def extract_reference(value) - rest = '' - if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) - value = m[1] || m[2] - rest = m.post_match - elsif [?(, ?{].include?(value[0]) - raise ConfigError, "no close brace" - end - if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) - return m[0], m.post_match + rest - else - raise - end - end - - def clear_comments(line) - # FCOMMENT - if m = line.match(/\A([\t\n\f ]*);.*\z/) - return m[1] - end - # COMMENT - scanned = [] - while m = line.match(/[#'"\\]/) - scanned << m.pre_match - c = m[0] - line = m.post_match - case c - when '#' - line = nil - break - when "'", '"' - regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ - scanned << c - if m = line.match(regexp) - scanned << m[0] - line = m.post_match - else - scanned << line - line = nil - break - end - when "\\" - scanned << c - scanned << line.slice!(0, 1) - else - raise 'must not reaced' - end - end - scanned << line - scanned.join - end - - def get_definition(io) - if line = get_line(io) - while /[^\\]\\\z/ =~ line - if extra = get_line(io) - line += extra - else - break - end - end - return line.strip - end - end - - def get_line(io) - if line = io.gets - line.gsub(/[\r\n]*/, '') - end - end - end - - def initialize(filename = nil) - @data = {} - if filename - File.open(filename.to_s) do |file| - Config.parse_config(file).each do |section, hash| - self[section] = hash - end - end - end - end - - def get_value(section, key) - if section.nil? - raise TypeError.new('nil not allowed') - end - section = 'default' if section.empty? - get_key_string(section, key) - end - - def value(arg1, arg2 = nil) - warn('Config#value is deprecated; use Config#get_value') - if arg2.nil? - section, key = 'default', arg1 - else - section, key = arg1, arg2 - end - section ||= 'default' - section = 'default' if section.empty? - get_key_string(section, key) - end - - def add_value(section, key, value) - check_modify - (@data[section] ||= {})[key] = value - end - - def [](section) - @data[section] || {} - end - - def section(name) - warn('Config#section is deprecated; use Config#[]') - @data[name] || {} - end - - def []=(section, pairs) - check_modify - @data[section] ||= {} - pairs.each do |key, value| - self.add_value(section, key, value) - end - end - - def sections - @data.keys - end - - def to_s - ary = [] - @data.keys.sort.each do |section| - ary << "[ #{section} ]\n" - @data[section].keys.each do |key| - ary << "#{key}=#{@data[section][key]}\n" - end - ary << "\n" - end - ary.join - end - - def each - @data.each do |section, hash| - hash.each do |key, value| - yield(section, key, value) - end - end - end - - def inspect - "#<#{self.class.name} sections=#{sections.inspect}>" - end - - protected - - def data - @data - end - - private - - def initialize_copy(other) - @data = other.data.dup - end - - def check_modify - raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? - end - - def get_key_string(section, key) - Config.get_key_string(@data, section, key) - end - end -end diff --git a/lib/1.8/openssl/digest.rb b/lib/1.8/openssl/digest.rb deleted file mode 100644 index e603c41..0000000 --- a/lib/1.8/openssl/digest.rb +++ /dev/null @@ -1,61 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space predefined Digest subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -## -# Should we care what if somebody require this file directly? -#require 'openssl' - -module OpenSSL - class Digest - - alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) - if OPENSSL_VERSION_NUMBER > 0x00908000 - alg += %w(SHA224 SHA256 SHA384 SHA512) - end - - def self.digest(name, data) - super(data, name) - end - - alg.each{|name| - klass = Class.new(Digest){ - define_method(:initialize){|*data| - if data.length > 1 - raise ArgumentError, - "wrong number of arguments (#{data.length} for 1)" - end - super(name, data.first) - } - } - singleton = (class << klass; self; end) - singleton.class_eval{ - define_method(:digest){|data| Digest.digest(name, data) } - define_method(:hexdigest){|data| Digest.hexdigest(name, data) } - } - const_set(name, klass) - } - - # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. - class Digest < Digest - def initialize(*args) - # add warning - super(*args) - end - end - - end # Digest -end # OpenSSL - diff --git a/lib/1.8/openssl/dummy.rb b/lib/1.8/openssl/dummy.rb deleted file mode 100644 index af84c03..0000000 --- a/lib/1.8/openssl/dummy.rb +++ /dev/null @@ -1,33 +0,0 @@ -warn "OpenSSL ASN1/PKey/X509/Netscape/PKCS7 implementation unavailable" -warn "gem install bouncy-castle-java for full support." -module OpenSSL - module ASN1 - class ASN1Error < OpenSSLError; end - class ASN1Data; end - class Primitive; end - class Constructive; end - end - module X509 - class Name; end - class Certificate; end - class Extension; end - class CRL; end - class Revoked; end - class Store - def set_default_paths; end - end - class Request; end - class Attribute; end - end - module Netscape - class SPKI; end - end - class PKCS7 - # this definition causes TypeError "superclass mismatch for class PKCS7" - # MRI also crashes following definition; - # class Foo; class Foo < Foo; end; end - # class Foo; class Foo < Foo; end; end - # - # class PKCS7 < PKCS7; end - end -end diff --git a/lib/1.8/openssl/dummyssl.rb b/lib/1.8/openssl/dummyssl.rb deleted file mode 100644 index 6a1d617..0000000 --- a/lib/1.8/openssl/dummyssl.rb +++ /dev/null @@ -1,14 +0,0 @@ -warn "Warning: OpenSSL SSL implementation unavailable" -warn "You must run on JDK 1.5 (Java 5) or higher to use SSL" -module OpenSSL - module SSL - class SSLError < OpenSSLError; end - class SSLContext; end - class SSLSocket; end - VERIFY_NONE = 0 - VERIFY_PEER = 1 - VERIFY_FAIL_IF_NO_PEER_CERT = 2 - VERIFY_CLIENT_ONCE = 4 - OP_ALL = 0x00000FFF - end -end diff --git a/lib/1.8/openssl/pkcs7.rb b/lib/1.8/openssl/pkcs7.rb deleted file mode 100644 index 1f88c1d..0000000 --- a/lib/1.8/openssl/pkcs7.rb +++ /dev/null @@ -1,25 +0,0 @@ -=begin -= $RCSfile$ -- PKCS7 - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id: digest.rb 12148 2007-04-05 05:59:22Z technorama $ -=end - -module OpenSSL - class PKCS7 - # This class is only provided for backwards compatibility. Use OpenSSL::PKCS7 in the future. - class PKCS7 < PKCS7 - def initialize(*args) - super(*args) - - warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead") - end - end - - end # PKCS7 -end # OpenSSL - diff --git a/lib/1.8/openssl/ssl-internal.rb b/lib/1.8/openssl/ssl-internal.rb deleted file mode 100644 index abf0e8d..0000000 --- a/lib/1.8/openssl/ssl-internal.rb +++ /dev/null @@ -1,179 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2001 GOTOU YUUZOU - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -require "openssl/buffering" -require "fcntl" - -module OpenSSL - module SSL - class SSLContext - DEFAULT_PARAMS = { - :ssl_version => "SSLv23", - :verify_mode => OpenSSL::SSL::VERIFY_PEER, - :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", - :options => OpenSSL::SSL::OP_ALL, - } - - DEFAULT_CERT_STORE = OpenSSL::X509::Store.new - DEFAULT_CERT_STORE.set_default_paths - if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) - DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - end - - def set_params(params={}) - params = DEFAULT_PARAMS.merge(params) - # ssl_version need to be set at first. - self.ssl_version = params.delete(:ssl_version) - params.each{|name, value| self.__send__("#{name}=", value) } - if self.verify_mode != OpenSSL::SSL::VERIFY_NONE - unless self.ca_file or self.ca_path or self.cert_store - self.cert_store = DEFAULT_CERT_STORE - end - end - return params - end - end - - module SocketForwarder - def addr - to_io.addr - end - - def peeraddr - to_io.peeraddr - end - - def setsockopt(level, optname, optval) - to_io.setsockopt(level, optname, optval) - end - - def getsockopt(level, optname) - to_io.getsockopt(level, optname) - end - - def fcntl(*args) - to_io.fcntl(*args) - end - - def closed? - to_io.closed? - end - - def do_not_reverse_lookup=(flag) - to_io.do_not_reverse_lookup = flag - end - end - - module Nonblock - def initialize(*args) - flag = File::NONBLOCK - flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) - @io.fcntl(Fcntl::F_SETFL, flag) - super - end - end - - def verify_certificate_identity(cert, hostname) - should_verify_common_name = true - cert.extensions.each{|ext| - next if ext.oid != "subjectAltName" - ext.value.split(/,\s+/).each{|general_name| - if /\ADNS:(.*)/ =~ general_name - should_verify_common_name = false - reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - elsif /\AIP Address:(.*)/ =~ general_name - should_verify_common_name = false - return true if $1 == hostname - end - } - } - if should_verify_common_name - cert.subject.to_a.each{|oid, value| - if oid == "CN" - reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - end - } - end - return false - end - module_function :verify_certificate_identity - - class SSLSocket - include Buffering - include SocketForwarder - include Nonblock - - def post_connection_check(hostname) - unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) - raise SSLError, "hostname was not match with the server certificate" - end - return true - end - - def session - SSL::Session.new(self) - rescue SSL::Session::SessionError - nil - end - end - - class SSLServer - include SocketForwarder - attr_accessor :start_immediately - - def initialize(svr, ctx) - @svr = svr - @ctx = ctx - unless ctx.session_id_context - session_id = OpenSSL::Digest::MD5.hexdigest($0) - @ctx.session_id_context = session_id - end - @start_immediately = true - end - - def to_io - @svr - end - - def listen(backlog=5) - @svr.listen(backlog) - end - - def shutdown(how=Socket::SHUT_RDWR) - @svr.shutdown(how) - end - - def accept - sock = @svr.accept - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) - ssl.sync_close = true - ssl.accept if @start_immediately - ssl - rescue SSLError => ex - sock.close - raise ex - end - end - - def close - @svr.close - end - end - end -end diff --git a/lib/1.8/openssl/ssl.rb b/lib/1.8/openssl/ssl.rb deleted file mode 100644 index 3f17f5a..0000000 --- a/lib/1.8/openssl/ssl.rb +++ /dev/null @@ -1 +0,0 @@ -require 'openssl' diff --git a/lib/1.8/openssl/x509-internal.rb b/lib/1.8/openssl/x509-internal.rb deleted file mode 100644 index 6aff4ca..0000000 --- a/lib/1.8/openssl/x509-internal.rb +++ /dev/null @@ -1,153 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -module OpenSSL - module X509 - class ExtensionFactory - def create_extension(*arg) - if arg.size > 1 - create_ext(*arg) - else - send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) - end - end - - def create_ext_from_array(ary) - raise ExtensionError, "unexpected array form" if ary.size > 3 - create_ext(ary[0], ary[1], ary[2]) - end - - def create_ext_from_string(str) # "oid = critical, value" - oid, value = str.split(/=/, 2) - oid.strip! - value.strip! - create_ext(oid, value) - end - - def create_ext_from_hash(hash) - create_ext(hash["oid"], hash["value"], hash["critical"]) - end - end - - class Extension - def to_s # "oid = critical, value" - str = self.oid - str << " = " - str << "critical, " if self.critical? - str << self.value.gsub(/\n/, ", ") - end - - def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} - {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} - end - - def to_a - [ self.oid, self.value, self.critical? ] - end - end - - class Name - module RFC2253DN - Special = ',=+<>#;' - HexChar = /[0-9a-fA-F]/ - HexPair = /#{HexChar}#{HexChar}/ - HexString = /#{HexPair}+/ - Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ - StringChar = /[^#{Special}\\"]/ - QuoteChar = /[^\\"]/ - AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ - AttributeValue = / - (?!["#])((?:#{StringChar}|#{Pair})*)| - \#(#{HexString})| - "((?:#{QuoteChar}|#{Pair})*)" - /x - TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ - - module_function - - def expand_pair(str) - return nil unless str - return str.gsub(Pair){ - pair = $& - case pair.size - when 2 then pair[1,1] - when 3 then Integer("0x#{pair[1,2]}").chr - else raise OpenSSL::X509::NameError, "invalid pair: #{str}" - end - } - end - - def expand_hexstring(str) - return nil unless str - der = str.gsub(HexPair){$&.to_i(16).chr } - a1 = OpenSSL::ASN1.decode(der) - return a1.value, a1.tag - end - - def expand_value(str1, str2, str3) - value = expand_pair(str1) - value, tag = expand_hexstring(str2) unless value - value = expand_pair(str3) unless value - return value, tag - end - - def scan(dn) - str = dn - ary = [] - while true - if md = TypeAndValue.match(str) - matched = md.to_s - remain = md.post_match - type = md[1] - value, tag = expand_value(md[2], md[3], md[4]) rescue nil - if value - type_and_value = [type, value] - type_and_value.push(tag) if tag - ary.unshift(type_and_value) - if remain.length > 2 && remain[0] == ?, - str = remain[1..-1] - next - elsif remain.length > 2 && remain[0] == ?+ - raise OpenSSL::X509::NameError, - "multi-valued RDN is not supported: #{dn}" - elsif remain.empty? - break - end - end - end - msg_dn = dn[0, dn.length - str.length] + " =>" + str - raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" - end - return ary - end - end - - class <= 0 - size = [size, limit].min - end - consume_rbuff(size) - end - - ## - # Executes the block for every line in the stream where lines are separated - # by +eol+. - # - # See also #gets - - def each(eol=$/) - while line = self.gets(eol) - yield line - end - end - alias each_line each - - ## - # Reads lines from the stream which are separated by +eol+. - # - # See also #gets - - def readlines(eol=$/) - ary = [] - while line = self.gets(eol) - ary << line - end - ary - end - - ## - # Reads a line from the stream which is separated by +eol+. - # - # Raises EOFError if at end of file. - - def readline(eol=$/) - raise EOFError if eof? - gets(eol) - end - - ## - # Reads one character from the stream. Returns nil if called at end of - # file. - - def getc - read(1) - end - - ## - # Calls the given block once for each byte in the stream. - - def each_byte # :yields: byte - while c = getc - yield(c.ord) - end - end - - ## - # Reads a one-character string from the stream. Raises an EOFError at end - # of file. - - def readchar - raise EOFError if eof? - getc - end - - ## - # Pushes character +c+ back onto the stream such that a subsequent buffered - # character read will return it. - # - # Unlike IO#getc multiple bytes may be pushed back onto the stream. - # - # Has no effect on unbuffered reads (such as #sysread). - - def ungetc(c) - @rbuffer[0,0] = c.chr - end - - ## - # Returns true if the stream is at file which means there is no more data to - # be read. - - def eof? - fill_rbuff if !@eof && @rbuffer.empty? - @eof && @rbuffer.empty? - end - alias eof eof? - - # - # for writing. - # - private - - ## - # Writes +s+ to the buffer. When the buffer is full or #sync is true the - # buffer is flushed to the underlying socket. - - def do_write(s) - @wbuffer = "" unless defined? @wbuffer - @wbuffer << s - @wbuffer.force_encoding(Encoding::BINARY) - @sync ||= false - if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/) - remain = idx ? idx + $/.size : @wbuffer.length - nwritten = 0 - while remain > 0 - str = @wbuffer[nwritten,remain] - begin - nwrote = syswrite(str) - rescue Errno::EAGAIN - retry - end - remain -= nwrote - nwritten += nwrote - end - @wbuffer[0,nwritten] = "" - end - end - - public - - ## - # Writes +s+ to the stream. If the argument is not a string it will be - # converted using String#to_s. Returns the number of bytes written. - - def write(s) - do_write(s) - s.bytesize - end - - ## - # Writes +str+ in the non-blocking manner. - # - # If there is buffered data, it is flushed first. This may block. - # - # write_nonblock returns number of bytes written to the SSL connection. - # - # When no data can be written without blocking it raises - # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable. - # - # IO::WaitReadable means SSL needs to read internally so write_nonblock - # should be called again after the underlying IO is readable. - # - # IO::WaitWritable means SSL needs to write internally so write_nonblock - # should be called again after underlying IO is writable. - # - # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows. - # - # # emulates blocking write. - # begin - # result = ssl.write_nonblock(str) - # rescue IO::WaitReadable - # IO.select([io]) - # retry - # rescue IO::WaitWritable - # IO.select(nil, [io]) - # retry - # end - # - # Note that one reason that write_nonblock reads from the underlying IO - # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ - # for more details. http://www.openssl.org/support/faq.html - - def write_nonblock(s) - flush - syswrite_nonblock(s) - end - - ## - # Writes +s+ to the stream. +s+ will be converted to a String using - # String#to_s. - - def << (s) - do_write(s) - self - end - - ## - # Writes +args+ to the stream along with a record separator. - # - # See IO#puts for full details. - - def puts(*args) - s = "" - if args.empty? - s << "\n" - end - args.each{|arg| - s << arg.to_s - if $/ && /\n\z/ !~ s - s << "\n" - end - } - do_write(s) - nil - end - - ## - # Writes +args+ to the stream. - # - # See IO#print for full details. - - def print(*args) - s = "" - args.each{ |arg| s << arg.to_s } - do_write(s) - nil - end - - ## - # Formats and writes to the stream converting parameters under control of - # the format string. - # - # See Kernel#sprintf for format string details. - - def printf(s, *args) - do_write(s % args) - nil - end - - ## - # Flushes buffered data to the SSLSocket. - - def flush - osync = @sync - @sync = true - do_write "" - return self - ensure - @sync = osync - end - - ## - # Closes the SSLSocket and flushes any unwritten data. - - def close - flush rescue nil - sysclose - end -end diff --git a/lib/1.9/openssl/cipher.rb b/lib/1.9/openssl/cipher.rb deleted file mode 100644 index eb146fb..0000000 --- a/lib/1.9/openssl/cipher.rb +++ /dev/null @@ -1,65 +0,0 @@ -#-- -# -# $RCSfile$ -# -# = Ruby-space predefined Cipher subclasses -# -# = Info -# 'OpenSSL for Ruby 2' project -# Copyright (C) 2002 Michal Rokos -# All rights reserved. -# -# = Licence -# This program is licenced under the same licence as Ruby. -# (See the file 'LICENCE'.) -# -# = Version -# $Id$ -# -#++ - -module OpenSSL - class Cipher - %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| - klass = Class.new(Cipher){ - define_method(:initialize){|*args| - cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" } - super(cipher_name) - } - } - const_set(name, klass) - } - - %w(128 192 256).each{|keylen| - klass = Class.new(Cipher){ - define_method(:initialize){|mode| - mode ||= "CBC" - cipher_name = "AES-#{keylen}-#{mode}" - super(cipher_name) - } - } - const_set("AES#{keylen}", klass) - } - - # Generate, set, and return a random key. - # You must call cipher.encrypt or cipher.decrypt before calling this method. - def random_key - str = OpenSSL::Random.random_bytes(self.key_len) - self.key = str - return str - end - - # Generate, set, and return a random iv. - # You must call cipher.encrypt or cipher.decrypt before calling this method. - def random_iv - str = OpenSSL::Random.random_bytes(self.iv_len) - self.iv = str - return str - end - - # This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future. - class Cipher < Cipher - # add warning - end - end # Cipher -end # OpenSSL diff --git a/lib/1.9/openssl/config.rb b/lib/1.9/openssl/config.rb deleted file mode 100644 index 24a54c9..0000000 --- a/lib/1.9/openssl/config.rb +++ /dev/null @@ -1,313 +0,0 @@ -=begin -= Ruby-space definitions that completes C-space funcs for Config - -= Info - Copyright (C) 2010 Hiroshi Nakamura - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -=end - -require 'stringio' - -module OpenSSL - class Config - include Enumerable - - class << self - def parse(str) - c = new() - parse_config(StringIO.new(str)).each do |section, hash| - c[section] = hash - end - c - end - - alias load new - - def parse_config(io) - begin - parse_config_lines(io) - rescue ConfigError => e - e.message.replace("error in line #{io.lineno}: " + e.message) - raise - end - end - - def get_key_string(data, section, key) # :nodoc: - if v = data[section] && data[section][key] - return v - elsif section == 'ENV' - if v = ENV[key] - return v - end - end - if v = data['default'] && data['default'][key] - return v - end - end - - private - - def parse_config_lines(io) - section = 'default' - data = {section => {}} - while definition = get_definition(io) - definition = clear_comments(definition) - next if definition.empty? - if definition[0] == ?[ - if /\[([^\]]*)\]/ =~ definition - section = $1.strip - data[section] ||= {} - else - raise ConfigError, "missing close square bracket" - end - else - if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition - if $2 - section = $1 - key = $2 - else - key = $1 - end - value = unescape_value(data, section, $3) - (data[section] ||= {})[key] = value.strip - else - raise ConfigError, "missing equal sign" - end - end - end - data - end - - # escape with backslash - QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/ - # escape with backslash and doubled dq - QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/ - # escaped char map - ESCAPE_MAP = { - "r" => "\r", - "n" => "\n", - "b" => "\b", - "t" => "\t", - } - - def unescape_value(data, section, value) - scanned = [] - while m = value.match(/['"\\$]/) - scanned << m.pre_match - c = m[0] - value = m.post_match - case c - when "'" - if m = value.match(QUOTE_REGEXP_SQ) - scanned << m[1].gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when '"' - if m = value.match(QUOTE_REGEXP_DQ) - scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1') - value = m.post_match - else - break - end - when "\\" - c = value.slice!(0, 1) - scanned << (ESCAPE_MAP[c] || c) - when "$" - ref, value = extract_reference(value) - refsec = section - if ref.index('::') - refsec, ref = ref.split('::', 2) - end - if v = get_key_string(data, refsec, ref) - scanned << v - else - raise ConfigError, "variable has no value" - end - else - raise 'must not reaced' - end - end - scanned << value - scanned.join - end - - def extract_reference(value) - rest = '' - if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/) - value = m[1] || m[2] - rest = m.post_match - elsif [?(, ?{].include?(value[0]) - raise ConfigError, "no close brace" - end - if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/) - return m[0], m.post_match + rest - else - raise - end - end - - def clear_comments(line) - # FCOMMENT - if m = line.match(/\A([\t\n\f ]*);.*\z/) - return m[1] - end - # COMMENT - scanned = [] - while m = line.match(/[#'"\\]/) - scanned << m.pre_match - c = m[0] - line = m.post_match - case c - when '#' - line = nil - break - when "'", '"' - regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ - scanned << c - if m = line.match(regexp) - scanned << m[0] - line = m.post_match - else - scanned << line - line = nil - break - end - when "\\" - scanned << c - scanned << line.slice!(0, 1) - else - raise 'must not reaced' - end - end - scanned << line - scanned.join - end - - def get_definition(io) - if line = get_line(io) - while /[^\\]\\\z/ =~ line - if extra = get_line(io) - line += extra - else - break - end - end - return line.strip - end - end - - def get_line(io) - if line = io.gets - line.gsub(/[\r\n]*/, '') - end - end - end - - def initialize(filename = nil) - @data = {} - if filename - File.open(filename.to_s) do |file| - Config.parse_config(file).each do |section, hash| - self[section] = hash - end - end - end - end - - def get_value(section, key) - if section.nil? - raise TypeError.new('nil not allowed') - end - section = 'default' if section.empty? - get_key_string(section, key) - end - - def value(arg1, arg2 = nil) - warn('Config#value is deprecated; use Config#get_value') - if arg2.nil? - section, key = 'default', arg1 - else - section, key = arg1, arg2 - end - section ||= 'default' - section = 'default' if section.empty? - get_key_string(section, key) - end - - def add_value(section, key, value) - check_modify - (@data[section] ||= {})[key] = value - end - - def [](section) - @data[section] || {} - end - - def section(name) - warn('Config#section is deprecated; use Config#[]') - @data[name] || {} - end - - def []=(section, pairs) - check_modify - @data[section] ||= {} - pairs.each do |key, value| - self.add_value(section, key, value) - end - end - - def sections - @data.keys - end - - def to_s - ary = [] - @data.keys.sort.each do |section| - ary << "[ #{section} ]\n" - @data[section].keys.each do |key| - ary << "#{key}=#{@data[section][key]}\n" - end - ary << "\n" - end - ary.join - end - - def each - @data.each do |section, hash| - hash.each do |key, value| - yield [section, key, value] - end - end - end - - def inspect - "#<#{self.class.name} sections=#{sections.inspect}>" - end - - protected - - def data - @data - end - - private - - def initialize_copy(other) - @data = other.data.dup - end - - def check_modify - raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen? - end - - def get_key_string(section, key) - Config.get_key_string(@data, section, key) - end - end -end diff --git a/lib/1.9/openssl/digest.rb b/lib/1.9/openssl/digest.rb deleted file mode 100644 index b470071..0000000 --- a/lib/1.9/openssl/digest.rb +++ /dev/null @@ -1,72 +0,0 @@ -#-- -# -# $RCSfile$ -# -# = Ruby-space predefined Digest subclasses -# -# = Info -# 'OpenSSL for Ruby 2' project -# Copyright (C) 2002 Michal Rokos -# All rights reserved. -# -# = Licence -# This program is licenced under the same licence as Ruby. -# (See the file 'LICENCE'.) -# -# = Version -# $Id$ -# -#++ - -module OpenSSL - class Digest - - alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) - if OPENSSL_VERSION_NUMBER > 0x00908000 - alg += %w(SHA224 SHA256 SHA384 SHA512) - end - - # Return the +data+ hash computed with +name+ Digest. +name+ is either the - # long name or short name of a supported digest algorithm. - # - # === Examples - # - # OpenSSL::Digest.digest("SHA256, "abc") - # - # which is equivalent to: - # - # OpenSSL::Digest::SHA256.digest("abc") - - def self.digest(name, data) - super(data, name) - end - - alg.each{|name| - klass = Class.new(Digest){ - define_method(:initialize){|*data| - if data.length > 1 - raise ArgumentError, - "wrong number of arguments (#{data.length} for 1)" - end - super(name, data.first) - } - } - singleton = (class << klass; self; end) - singleton.class_eval{ - define_method(:digest){|data| Digest.digest(name, data) } - define_method(:hexdigest){|data| Digest.hexdigest(name, data) } - } - const_set(name, klass) - } - - # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. - class Digest < Digest - def initialize(*args) - # add warning - super(*args) - end - end - - end # Digest -end # OpenSSL - diff --git a/lib/1.9/openssl/ssl-internal.rb b/lib/1.9/openssl/ssl-internal.rb deleted file mode 100644 index c70b5b8..0000000 --- a/lib/1.9/openssl/ssl-internal.rb +++ /dev/null @@ -1,177 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2001 GOTOU YUUZOU - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -require "openssl/buffering" -require "fcntl" - -module OpenSSL - module SSL - class SSLContext - DEFAULT_PARAMS = { - :ssl_version => "SSLv23", - :verify_mode => OpenSSL::SSL::VERIFY_PEER, - :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW", - :options => OpenSSL::SSL::OP_ALL, - } - - DEFAULT_CERT_STORE = OpenSSL::X509::Store.new - DEFAULT_CERT_STORE.set_default_paths - if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL) - DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - end - - def set_params(params={}) - params = DEFAULT_PARAMS.merge(params) - params.each{|name, value| self.__send__("#{name}=", value) } - if self.verify_mode != OpenSSL::SSL::VERIFY_NONE - unless self.ca_file or self.ca_path or self.cert_store - self.cert_store = DEFAULT_CERT_STORE - end - end - return params - end - end - - module SocketForwarder - def addr - to_io.addr - end - - def peeraddr - to_io.peeraddr - end - - def setsockopt(level, optname, optval) - to_io.setsockopt(level, optname, optval) - end - - def getsockopt(level, optname) - to_io.getsockopt(level, optname) - end - - def fcntl(*args) - to_io.fcntl(*args) - end - - def closed? - to_io.closed? - end - - def do_not_reverse_lookup=(flag) - to_io.do_not_reverse_lookup = flag - end - end - - module Nonblock - def initialize(*args) - flag = File::NONBLOCK - flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) - @io.fcntl(Fcntl::F_SETFL, flag) - super - end - end - - def verify_certificate_identity(cert, hostname) - should_verify_common_name = true - cert.extensions.each{|ext| - next if ext.oid != "subjectAltName" - ext.value.split(/,\s+/).each{|general_name| - if /\ADNS:(.*)/ =~ general_name - should_verify_common_name = false - reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - elsif /\AIP Address:(.*)/ =~ general_name - should_verify_common_name = false - return true if $1 == hostname - end - } - } - if should_verify_common_name - cert.subject.to_a.each{|oid, value| - if oid == "CN" - reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") - return true if /\A#{reg}\z/i =~ hostname - end - } - end - return false - end - module_function :verify_certificate_identity - - class SSLSocket - include Buffering - include SocketForwarder - include Nonblock - - def post_connection_check(hostname) - unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname) - raise SSLError, "hostname does not match the server certificate" - end - return true - end - - def session - SSL::Session.new(self) - rescue SSL::Session::SessionError - nil - end - end - - class SSLServer - include SocketForwarder - attr_accessor :start_immediately - - def initialize(svr, ctx) - @svr = svr - @ctx = ctx - unless ctx.session_id_context - session_id = OpenSSL::Digest::MD5.hexdigest($0) - @ctx.session_id_context = session_id - end - @start_immediately = true - end - - def to_io - @svr - end - - def listen(backlog=5) - @svr.listen(backlog) - end - - def shutdown(how=Socket::SHUT_RDWR) - @svr.shutdown(how) - end - - def accept - sock = @svr.accept - begin - ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) - ssl.sync_close = true - ssl.accept if @start_immediately - ssl - rescue SSLError => ex - sock.close - raise ex - end - end - - def close - @svr.close - end - end - end -end diff --git a/lib/1.9/openssl/ssl.rb b/lib/1.9/openssl/ssl.rb deleted file mode 100644 index 15f42d6..0000000 --- a/lib/1.9/openssl/ssl.rb +++ /dev/null @@ -1,2 +0,0 @@ -warn 'deprecated openssl/ssl use: require "openssl" instead of "openssl/ssl"' -require 'openssl' diff --git a/lib/1.9/openssl/x509-internal.rb b/lib/1.9/openssl/x509-internal.rb deleted file mode 100644 index 47e3a6f..0000000 --- a/lib/1.9/openssl/x509-internal.rb +++ /dev/null @@ -1,158 +0,0 @@ -=begin -= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses - -= Info - 'OpenSSL for Ruby 2' project - Copyright (C) 2002 Michal Rokos - All rights reserved. - -= Licence - This program is licenced under the same licence as Ruby. - (See the file 'LICENCE'.) - -= Version - $Id$ -=end - -module OpenSSL - module X509 - class ExtensionFactory - def create_extension(*arg) - if arg.size > 1 - create_ext(*arg) - else - send("create_ext_from_"+arg[0].class.name.downcase, arg[0]) - end - end - - def create_ext_from_array(ary) - raise ExtensionError, "unexpected array form" if ary.size > 3 - create_ext(ary[0], ary[1], ary[2]) - end - - def create_ext_from_string(str) # "oid = critical, value" - oid, value = str.split(/=/, 2) - oid.strip! - value.strip! - create_ext(oid, value) - end - - def create_ext_from_hash(hash) - create_ext(hash["oid"], hash["value"], hash["critical"]) - end - end - - class Extension - def to_s # "oid = critical, value" - str = self.oid - str << " = " - str << "critical, " if self.critical? - str << self.value.gsub(/\n/, ", ") - end - - def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false} - {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?} - end - - def to_a - [ self.oid, self.value, self.critical? ] - end - end - - class Name - module RFC2253DN - Special = ',=+<>#;' - HexChar = /[0-9a-fA-F]/ - HexPair = /#{HexChar}#{HexChar}/ - HexString = /#{HexPair}+/ - Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/ - StringChar = /[^#{Special}\\"]/ - QuoteChar = /[^\\"]/ - AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/ - AttributeValue = / - (?!["#])((?:#{StringChar}|#{Pair})*)| - \#(#{HexString})| - "((?:#{QuoteChar}|#{Pair})*)" - /x - TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/ - - module_function - - def expand_pair(str) - return nil unless str - return str.gsub(Pair){ - pair = $& - case pair.size - when 2 then pair[1,1] - when 3 then Integer("0x#{pair[1,2]}").chr - else raise OpenSSL::X509::NameError, "invalid pair: #{str}" - end - } - end - - def expand_hexstring(str) - return nil unless str - der = str.gsub(HexPair){$&.to_i(16).chr } - a1 = OpenSSL::ASN1.decode(der) - return a1.value, a1.tag - end - - def expand_value(str1, str2, str3) - value = expand_pair(str1) - value, tag = expand_hexstring(str2) unless value - value = expand_pair(str3) unless value - return value, tag - end - - def scan(dn) - str = dn - ary = [] - while true - if md = TypeAndValue.match(str) - remain = md.post_match - type = md[1] - value, tag = expand_value(md[2], md[3], md[4]) rescue nil - if value - type_and_value = [type, value] - type_and_value.push(tag) if tag - ary.unshift(type_and_value) - if remain.length > 2 && remain[0] == ?, - str = remain[1..-1] - next - elsif remain.length > 2 && remain[0] == ?+ - raise OpenSSL::X509::NameError, - "multi-valued RDN is not supported: #{dn}" - elsif remain.empty? - break - end - end - end - msg_dn = dn[0, dn.length - str.length] + " =>" + str - raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}" - end - return ary - end - end - - class << self - def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE) - ary = OpenSSL::X509::Name::RFC2253DN.scan(str) - self.new(ary, template) - end - - def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE) - ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) } - self.new(ary, template) - end - - alias parse parse_openssl - end - end - - class StoreContext - def cleanup - warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE - end - end - end -end diff --git a/lib/1.9/openssl/x509.rb b/lib/1.9/openssl/x509.rb deleted file mode 100644 index f1777cd..0000000 --- a/lib/1.9/openssl/x509.rb +++ /dev/null @@ -1,2 +0,0 @@ -warn 'deprecated openssl/x509 use: require "openssl" instead of "openssl/x509"' -require 'openssl' diff --git a/lib/shared/jopenssl/version.rb b/lib/shared/jopenssl/version.rb deleted file mode 100644 index beadba2..0000000 --- a/lib/shared/jopenssl/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Jopenssl - module Version - VERSION = "0.8.0.pre1" - end -end diff --git a/lib/shared/jruby-openssl.rb b/lib/shared/jruby-openssl.rb deleted file mode 100644 index b0cab18..0000000 --- a/lib/shared/jruby-openssl.rb +++ /dev/null @@ -1,26 +0,0 @@ -unless defined? JRUBY_VERSION - warn 'Loading jruby-openssl in a non-JRuby interpreter' -end - -# Load bouncy-castle gem if available -begin - require 'bouncy-castle-java' -rescue LoadError - # runs under restricted mode or uses builtin BC -end - -# Load extension -require 'jruby' -require 'jopenssl.jar' -org.jruby.ext.openssl.OSSLLibrary.new.load(JRuby.runtime, false) - -# Add version-appropriate library path to LOAD_PATH -if RUBY_VERSION >= '1.9.0' - $LOAD_PATH.unshift(File.expand_path('../../1.9', __FILE__)) - load(File.expand_path('../../1.9/openssl.rb', __FILE__)) -else - $LOAD_PATH.unshift(File.expand_path('../../1.8', __FILE__)) - load(File.expand_path('../../1.8/openssl.rb', __FILE__)) -end - -require 'openssl/pkcs12' diff --git a/lib/shared/openssl.rb b/lib/shared/openssl.rb deleted file mode 100644 index b0cab18..0000000 --- a/lib/shared/openssl.rb +++ /dev/null @@ -1,26 +0,0 @@ -unless defined? JRUBY_VERSION - warn 'Loading jruby-openssl in a non-JRuby interpreter' -end - -# Load bouncy-castle gem if available -begin - require 'bouncy-castle-java' -rescue LoadError - # runs under restricted mode or uses builtin BC -end - -# Load extension -require 'jruby' -require 'jopenssl.jar' -org.jruby.ext.openssl.OSSLLibrary.new.load(JRuby.runtime, false) - -# Add version-appropriate library path to LOAD_PATH -if RUBY_VERSION >= '1.9.0' - $LOAD_PATH.unshift(File.expand_path('../../1.9', __FILE__)) - load(File.expand_path('../../1.9/openssl.rb', __FILE__)) -else - $LOAD_PATH.unshift(File.expand_path('../../1.8', __FILE__)) - load(File.expand_path('../../1.8/openssl.rb', __FILE__)) -end - -require 'openssl/pkcs12' diff --git a/lib/shared/openssl/dummy.rb b/lib/shared/openssl/dummy.rb deleted file mode 100644 index af84c03..0000000 --- a/lib/shared/openssl/dummy.rb +++ /dev/null @@ -1,33 +0,0 @@ -warn "OpenSSL ASN1/PKey/X509/Netscape/PKCS7 implementation unavailable" -warn "gem install bouncy-castle-java for full support." -module OpenSSL - module ASN1 - class ASN1Error < OpenSSLError; end - class ASN1Data; end - class Primitive; end - class Constructive; end - end - module X509 - class Name; end - class Certificate; end - class Extension; end - class CRL; end - class Revoked; end - class Store - def set_default_paths; end - end - class Request; end - class Attribute; end - end - module Netscape - class SPKI; end - end - class PKCS7 - # this definition causes TypeError "superclass mismatch for class PKCS7" - # MRI also crashes following definition; - # class Foo; class Foo < Foo; end; end - # class Foo; class Foo < Foo; end; end - # - # class PKCS7 < PKCS7; end - end -end diff --git a/lib/shared/openssl/dummyssl.rb b/lib/shared/openssl/dummyssl.rb deleted file mode 100644 index 6a1d617..0000000 --- a/lib/shared/openssl/dummyssl.rb +++ /dev/null @@ -1,14 +0,0 @@ -warn "Warning: OpenSSL SSL implementation unavailable" -warn "You must run on JDK 1.5 (Java 5) or higher to use SSL" -module OpenSSL - module SSL - class SSLError < OpenSSLError; end - class SSLContext; end - class SSLSocket; end - VERIFY_NONE = 0 - VERIFY_PEER = 1 - VERIFY_FAIL_IF_NO_PEER_CERT = 2 - VERIFY_CLIENT_ONCE = 4 - OP_ALL = 0x00000FFF - end -end diff --git a/lib/shared/openssl/pkcs12.rb b/lib/shared/openssl/pkcs12.rb deleted file mode 100644 index 268aa10..0000000 --- a/lib/shared/openssl/pkcs12.rb +++ /dev/null @@ -1,50 +0,0 @@ -require 'java' - -module OpenSSL - class PKCS12 - java_import java.io.StringReader - java_import java.io.StringBufferInputStream - java_import java.security.cert.CertificateFactory - java_import java.security.KeyStore - java_import java.io.ByteArrayOutputStream - java_import org.bouncycastle.openssl.PEMReader - - java.security.Security.add_provider(org.bouncycastle.jce.provider.BouncyCastleProvider.new) - - def self.create(pass, name, key, cert) - pkcs12 = self.new(pass, name, key, cert) - pkcs12.generate - pkcs12 - end - - attr_reader :key, :certificate - - def initialize(pass, name, key, cert) - @pass = pass - @name = name - @key = key - @certificate = cert - end - - def generate - key_reader = StringReader.new(key.to_pem) - key_pair = PEMReader.new(key_reader).read_object - - cert_input_stream = StringBufferInputStream.new(certificate.to_pem) - certs = CertificateFactory.get_instance("X.509").generate_certificates(cert_input_stream) - - store = KeyStore.get_instance("PKCS12", "BC") - store.load(nil, nil) - store.set_key_entry(@name, key_pair.get_private, nil, certs.to_array(Java::java.security.cert.Certificate[certs.size].new)) - - pkcs12_output_stream = ByteArrayOutputStream.new - store.store(pkcs12_output_stream, @pass.to_java.to_char_array) - - @der = String.from_java_bytes(pkcs12_output_stream.to_byte_array) - end - - def to_der - @der - end - end -end diff --git a/lib/shared/openssl/ssl.rb b/lib/shared/openssl/ssl.rb deleted file mode 100644 index 3f17f5a..0000000 --- a/lib/shared/openssl/ssl.rb +++ /dev/null @@ -1 +0,0 @@ -require 'openssl' diff --git a/lib/shared/openssl/x509.rb b/lib/shared/openssl/x509.rb deleted file mode 100644 index 3f17f5a..0000000 --- a/lib/shared/openssl/x509.rb +++ /dev/null @@ -1 +0,0 @@ -require 'openssl' diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties deleted file mode 100644 index 218838b..0000000 --- a/nbproject/genfiles.properties +++ /dev/null @@ -1,5 +0,0 @@ -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/jdk.xml.data.CRC32=0988335f -nbproject/jdk.xml.script.CRC32=5342cb35 -nbproject/jdk.xml.stylesheet.CRC32=c45af3dc diff --git a/nbproject/jdk.xml b/nbproject/jdk.xml deleted file mode 100644 index a886978..0000000 --- a/nbproject/jdk.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Permits selection of a JDK to use when building and running project. - See: http://www.netbeans.org/issues/show_bug.cgi?id=64160 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - nbjdk.active=${nbjdk.active} nbjdk.home=${nbjdk.home} nbjdk.java=${nbjdk.java} nbjdk.javac=${nbjdk.javac} nbjdk.javadoc=${nbjdk.javadoc} nbjdk.bootclasspath=${nbjdk.bootclasspath} nbjdk.valid=${nbjdk.valid} have-jdk-1.4=${have-jdk-1.4} have-jdk-1.5=${have-jdk-1.5} - - - - - Warning: nbjdk.active=${nbjdk.active} or nbjdk.home=${nbjdk.home} is an invalid Java platform; ignoring and using ${jdkhome.presumed} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/nbproject/nbjdk.properties b/nbproject/nbjdk.properties deleted file mode 100644 index 50ca3f8..0000000 --- a/nbproject/nbjdk.properties +++ /dev/null @@ -1 +0,0 @@ -nbjdk.active=JDK_1.5 diff --git a/nbproject/nbjdk.xml b/nbproject/nbjdk.xml deleted file mode 100644 index cf31751..0000000 --- a/nbproject/nbjdk.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/nbproject/project.xml b/nbproject/project.xml deleted file mode 100644 index 0c41bc7..0000000 --- a/nbproject/project.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - org.netbeans.modules.ant.freeform - - - JRuby-OpenSSL - - - - JRuby-OpenSSL - - - - - . - UTF-8 - - - - java - lib/jopenssl - UTF-8 - - - - java - lib/openssl - UTF-8 - - - - java - test - UTF-8 - - - - java - src/java - UTF-8 - - - - - - build - - - - clean - - - - test - - - - clean - build - - - - - - - lib/jopenssl - - - - lib/openssl - - - - test - - - - src/java - - - build.xml - - - - - - - - - - - - - - lib/jopenssl - 1.5 - - - lib/openssl - 1.5 - - - test - - 1.5 - - - src/java - build_lib/bcmail-jdk15-146.jar:build_lib/bcprov-jdk15-146.jar:../jruby/lib/jruby.jar:../jruby/build_lib/bytelist.jar - 1.5 - - - - - - - diff --git a/src/java/org/jruby/ext/openssl/ASN1.java b/src/java/org/jruby/ext/openssl/ASN1.java deleted file mode 100644 index f1a7a5e..0000000 --- a/src/java/org/jruby/ext/openssl/ASN1.java +++ /dev/null @@ -1,938 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.math.BigInteger; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERString; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.DERUTCTime; -import org.bouncycastle.asn1.DERUTF8String; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyBignum; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.RubySymbol; -import org.jruby.RubyTime; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class ASN1 { - private static Map> SYM_TO_OID = new IdentityHashMap>(); - private static Map> OID_TO_SYM = new IdentityHashMap>(); - private static Map> OID_TO_NID = new IdentityHashMap>(); - private static Map> NID_TO_OID = new IdentityHashMap>(); - private static Map> NID_TO_SN = new IdentityHashMap>(); - private static Map> NID_TO_LN = new IdentityHashMap>(); - - - static void addObject(Ruby runtime, int nid, String sn, String ln, String oid) { - Map s2o = SYM_TO_OID.get(runtime); - Map o2s = OID_TO_SYM.get(runtime); - Map o2n = OID_TO_NID.get(runtime); - Map n2o = NID_TO_OID.get(runtime); - Map n2s = NID_TO_SN.get(runtime); - Map n2l = NID_TO_LN.get(runtime); - if(null != oid && (null != sn || null != ln)) { - DERObjectIdentifier ident = new DERObjectIdentifier(oid); - if(sn != null) { - s2o.put(sn.toLowerCase(),ident); - } - if(ln != null) { - s2o.put(ln.toLowerCase(),ident); - } - o2s.put(ident,sn == null ? ln : sn); - o2n.put(ident,nid); - n2o.put(nid,ident); - n2s.put(nid,sn); - n2l.put(nid,ln); - } - } - - @SuppressWarnings("unchecked") - private synchronized static void initMaps(Ruby runtime) { - Map val = new HashMap(org.bouncycastle.asn1.x509.X509Name.DefaultLookUp); - Map val2 = new HashMap(org.bouncycastle.asn1.x509.X509Name.DefaultSymbols); - SYM_TO_OID.put(runtime,val); - OID_TO_SYM.put(runtime,val2); - OID_TO_NID.put(runtime,new HashMap()); - NID_TO_OID.put(runtime,new HashMap()); - NID_TO_SN.put(runtime,new HashMap()); - NID_TO_LN.put(runtime,new HashMap()); - OpenSSLImpl.defaultObjects(runtime); - } - - synchronized static Integer obj2nid(Ruby runtime, String oid) { - return obj2nid(runtime, new DERObjectIdentifier(oid)); - } - - synchronized static String ln2oid(Ruby runtime, String ln) { - Map val = SYM_TO_OID.get(runtime); - if(null == val) { - initMaps(runtime); - val = SYM_TO_OID.get(runtime); - } - return val.get(ln).getId(); - } - - synchronized static Integer obj2nid(Ruby runtime, DERObjectIdentifier oid) { - Map o2n = OID_TO_NID.get(runtime); - if(null == o2n) { - initMaps(runtime); - o2n = OID_TO_NID.get(runtime); - } - return o2n.get(oid); - } - - synchronized static String o2a(Ruby runtime, DERObjectIdentifier obj) { - Integer nid = obj2nid(runtime,obj); - Map n2l = NID_TO_LN.get(runtime); - Map n2s = NID_TO_SN.get(runtime); - String one = n2l.get(nid); - if(one == null) { - one = n2s.get(nid); - } - return one; - } - - synchronized static String nid2ln(Ruby runtime, int nid) { - return nid2ln(runtime, new Integer(nid)); - } - - synchronized static String nid2ln(Ruby runtime, Integer nid) { - Map n2l = NID_TO_LN.get(runtime); - if(null == n2l) { - initMaps(runtime); - n2l = NID_TO_LN.get(runtime); - } - return n2l.get(nid); - } - - synchronized static Map getOIDLookup(Ruby runtime) { - Map val = SYM_TO_OID.get(runtime); - if(null == val) { - initMaps(runtime); - val = SYM_TO_OID.get(runtime); - } - return val; - } - - synchronized static Map getSymLookup(Ruby runtime) { - Map val = OID_TO_SYM.get(runtime); - if(null == val) { - initMaps(runtime); - val = OID_TO_SYM.get(runtime); - } - return val; - } - - private final static Object[][] ASN1_INFO = { - {"EOC", null, null }, - {"BOOLEAN", org.bouncycastle.asn1.DERBoolean.class, "Boolean" }, - {"INTEGER", org.bouncycastle.asn1.DERInteger.class, "Integer" }, - {"BIT_STRING", org.bouncycastle.asn1.DERBitString.class, "BitString" }, - {"OCTET_STRING", org.bouncycastle.asn1.DEROctetString.class, "OctetString" }, - {"NULL", org.bouncycastle.asn1.DERNull.class, "Null" }, - {"OBJECT", org.bouncycastle.asn1.DERObjectIdentifier.class, "ObjectId" }, - {"OBJECT_DESCRIPTOR", null, null }, - {"EXTERNAL", null, null }, - {"REAL", null, null }, - {"ENUMERATED", org.bouncycastle.asn1.DEREnumerated.class, "Enumerated" }, - {"EMBEDDED_PDV", null, null }, - {"UTF8STRING", org.bouncycastle.asn1.DERUTF8String.class, "UTF8String" }, - {"RELATIVE_OID", null, null }, - {"[UNIVERSAL 14]", null, null }, - {"[UNIVERSAL 15]", null, null }, - {"SEQUENCE", org.bouncycastle.asn1.DERSequence.class, "Sequence" }, - {"SET", org.bouncycastle.asn1.DERSet.class, "Set" }, - {"NUMERICSTRING", org.bouncycastle.asn1.DERNumericString.class, "NumericString" }, - {"PRINTABLESTRING", org.bouncycastle.asn1.DERPrintableString.class, "PrintableString" }, - {"T61STRING", org.bouncycastle.asn1.DERT61String.class, "T61String" }, - {"VIDEOTEXSTRING", null, null }, - {"IA5STRING", org.bouncycastle.asn1.DERIA5String.class, "IA5String" }, - {"UTCTIME", org.bouncycastle.asn1.DERUTCTime.class, "UTCTime" }, - {"GENERALIZEDTIME", org.bouncycastle.asn1.DERGeneralizedTime.class, "GeneralizedTime" }, - {"GRAPHICSTRING", null, null }, - {"ISO64STRING", null, null }, - {"GENERALSTRING", org.bouncycastle.asn1.DERGeneralString.class, "GeneralString" }, - {"UNIVERSALSTRING", org.bouncycastle.asn1.DERUniversalString.class, "UniversalString" }, - {"CHARACTER_STRING", null, null }, - {"BMPSTRING", org.bouncycastle.asn1.DERBMPString.class, "BMPString" }}; - - private final static Map CLASS_TO_ID = new HashMap(); - private final static Map RUBYNAME_TO_ID = new HashMap(); - - static { - for(int i=0;i classForId(int id) { - @SuppressWarnings("unchecked") - Class result = (Class)(ASN1_INFO[id][1]); - return result; - } - - public static void createASN1(Ruby runtime, RubyModule ossl) { - RubyModule mASN1 = ossl.defineModuleUnder("ASN1"); - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - mASN1.defineClassUnder("ASN1Error",openSSLError, openSSLError.getAllocator()); - - mASN1.defineAnnotatedMethods(ASN1.class); - - List ary = new ArrayList(); - mASN1.setConstant("UNIVERSAL_TAG_NAME",runtime.newArray(ary)); - for(int i=0;i em = getOIDLookup(runtime); - String name = null; - for(Iterator iter = em.keySet().iterator();iter.hasNext();) { - String key = iter.next(); - if(oid.equals(em.get(key))) { - if(name == null || key.length() < name.length()) { - name = key; - } - } - } - return name; - } - - private static String getLongNameFor(Ruby runtime, String nameOrOid) { - DERObjectIdentifier oid = getObjectIdentifier(runtime,nameOrOid); - Map em = getOIDLookup(runtime); - String name = null; - for(Iterator iter = em.keySet().iterator();iter.hasNext();) { - String key = iter.next(); - if(oid.equals(em.get(key))) { - if(name == null || key.length() > name.length()) { - name = key; - } - } - } - return name; - } - - private static DERObjectIdentifier getObjectIdentifier(Ruby runtime, String nameOrOid) { - Object val1 = ASN1.getOIDLookup(runtime).get(nameOrOid.toLowerCase()); - if(null != val1) { - return (DERObjectIdentifier)val1; - } - DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid); - return val2; - } - - @JRubyMethod(name="Boolean", module=true, rest=true) - public static IRubyObject fact_Boolean(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Boolean").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="Integer", module=true, rest=true) - public static IRubyObject fact_Integer(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Integer").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="Enumerated", module=true, rest=true) - public static IRubyObject fact_Enumerated(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Enumerated").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="BitString", module=true, rest=true) - public static IRubyObject fact_BitString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("BitString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="OctetString", module=true, rest=true) - public static IRubyObject fact_OctetString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("OctetString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="UTF8String", module=true, rest=true) - public static IRubyObject fact_UTF8String(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("UTF8String").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="NumericString", module=true, rest=true) - public static IRubyObject fact_NumericString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("NumericString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="PrintableString", module=true, rest=true) - public static IRubyObject fact_PrintableString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("PrintableString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="T61String", module=true, rest=true) - public static IRubyObject fact_T61String(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("T61String").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="VideotexString", module=true, rest=true) - public static IRubyObject fact_VideotexString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("VideotexString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="IA5String", module=true, rest=true) - public static IRubyObject fact_IA5String(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("IA5String").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="GraphicString", module=true, rest=true) - public static IRubyObject fact_GraphicString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("GraphicString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="ISO64String", module=true, rest=true) - public static IRubyObject fact_ISO64String(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("ISO64String").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="GeneralString", module=true, rest=true) - public static IRubyObject fact_GeneralString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("GeneralString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="UniversalString", module=true, rest=true) - public static IRubyObject fact_UniversalString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("UniversalString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="BMPString", module=true, rest=true) - public static IRubyObject fact_BMPString(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("BMPString").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="Nul", module=true, rest=true) - public static IRubyObject fact_Null(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Null").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="ObjectId", module=true, rest=true) - public static IRubyObject fact_ObjectId(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("ObjectId").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="UTCTime", module=true, rest=true) - public static IRubyObject fact_UTCTime(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("UTCTime").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="GeneralizedTime", module=true, rest=true) - public static IRubyObject fact_GeneralizedTime(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("GeneralizedTime").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="Sequence", module=true, rest=true) - public static IRubyObject fact_Sequence(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Sequence").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(name="Set", module=true, rest=true) - public static IRubyObject fact_Set(IRubyObject recv, IRubyObject[] args) { - return ((RubyModule)recv).getClass("Set").callMethod(recv.getRuntime().getCurrentContext(),"new",args); - } - - @JRubyMethod(meta=true, required=1) - public static IRubyObject traverse(IRubyObject recv, IRubyObject a) { - System.err.println("WARNING: unimplemented method called: traverse"); - return null; - } - - public static class ObjectId { - @JRubyMethod(meta=true, rest=true) - public static IRubyObject register(IRubyObject recv, IRubyObject[] args) { - DERObjectIdentifier deroi = new DERObjectIdentifier(args[0].toString()); - getOIDLookup(recv.getRuntime()).put(args[1].toString().toLowerCase(),deroi); - getOIDLookup(recv.getRuntime()).put(args[2].toString().toLowerCase(),deroi); - getSymLookup(recv.getRuntime()).put(deroi,args[1].toString()); - return recv.getRuntime().getTrue(); - } - - @JRubyMethod(name={"sn","short_name"}) - public static IRubyObject sn(IRubyObject self) { - return self.getRuntime().newString(getShortNameFor(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString())); - } - - @JRubyMethod(name={"ln","long_name"}) - public static IRubyObject ln(IRubyObject self) { - return self.getRuntime().newString(getLongNameFor(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString())); - } - - @JRubyMethod - public static IRubyObject oid(IRubyObject self) { - return self.getRuntime().newString(getObjectIdentifier(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString()).getId()); - } - } - - private final static DateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); - private static IRubyObject decodeObj(RubyModule asnM,Object v) throws IOException, java.text.ParseException { - int ix = idForClass(v.getClass()); - String v_name = ix == -1 ? null : (String)(ASN1_INFO[ix][2]); - ThreadContext tc = asnM.getRuntime().getCurrentContext(); - if(null != v_name) { - RubyClass c = asnM.getClass(v_name); - if(v instanceof DERBitString) { - ByteList bl = new ByteList(((DERBitString)v).getBytes(), false); - IRubyObject bString = c.callMethod(tc,"new",asnM.getRuntime().newString(bl)); - bString.callMethod(tc,"unused_bits=",asnM.getRuntime().newFixnum(((DERBitString)v).getPadBits())); - return bString; - } else if(v instanceof DERString) { - ByteList val; - if (v instanceof DERUTF8String) { - val = new ByteList(((DERUTF8String) v).getString().getBytes("UTF-8")); - } else { - val = ByteList.create(((DERString)v).getString()); - } - return c.callMethod(tc,"new",asnM.getRuntime().newString(val)); - } else if(v instanceof ASN1Sequence) { - List l = new ArrayList(); - for(Enumeration enm = ((ASN1Sequence)v).getObjects(); enm.hasMoreElements(); ) { - l.add(decodeObj(asnM,enm.nextElement())); - } - return c.callMethod(tc,"new",asnM.getRuntime().newArray(l)); - } else if(v instanceof DERSet) { - List l = new ArrayList(); - for(Enumeration enm = ((DERSet)v).getObjects(); enm.hasMoreElements(); ) { - l.add(decodeObj(asnM,enm.nextElement())); - } - return c.callMethod(tc,"new",asnM.getRuntime().newArray(l)); - } else if(v instanceof DERNull) { - return c.callMethod(tc,"new",asnM.getRuntime().getNil()); - } else if(v instanceof DERInteger) { - return c.callMethod(tc, "new", BN.newBN(asnM.getRuntime(), ((DERInteger) v).getValue())); - } else if(v instanceof DERUTCTime) { - Date d = dateF.parse(((DERUTCTime)v).getAdjustedTime()); - Calendar cal = Calendar.getInstance(); - cal.setTime(d); - IRubyObject[] argv = new IRubyObject[6]; - argv[0] = asnM.getRuntime().newFixnum(cal.get(Calendar.YEAR)); - argv[1] = asnM.getRuntime().newFixnum(cal.get(Calendar.MONTH)+1); - argv[2] = asnM.getRuntime().newFixnum(cal.get(Calendar.DAY_OF_MONTH)); - argv[3] = asnM.getRuntime().newFixnum(cal.get(Calendar.HOUR_OF_DAY)); - argv[4] = asnM.getRuntime().newFixnum(cal.get(Calendar.MINUTE)); - argv[5] = asnM.getRuntime().newFixnum(cal.get(Calendar.SECOND)); - return c.callMethod(tc,"new",asnM.getRuntime().getClass("Time").callMethod(tc,"local",argv)); - } else if(v instanceof DERObjectIdentifier) { - String av = ((DERObjectIdentifier)v).getId(); - return c.callMethod(tc,"new",asnM.getRuntime().newString(av)); - } else if(v instanceof DEROctetString) { - ByteList bl = new ByteList(((DEROctetString)v).getOctets(), false); - return c.callMethod(tc,"new",asnM.getRuntime().newString(bl)); - } else if(v instanceof DERBoolean) { - return c.callMethod(tc,"new",((DERBoolean)v).isTrue() ? asnM.getRuntime().getTrue() : asnM.getRuntime().getFalse()); - } else { - System.out.println("Should handle: " + v.getClass().getName()); - } - } else if(v instanceof DERTaggedObject) { - RubyClass c = asnM.getClass("ASN1Data"); - IRubyObject val = decodeObj(asnM, ((DERTaggedObject)v).getObject()); - IRubyObject tag = asnM.getRuntime().newFixnum(((DERTaggedObject)v).getTagNo()); - IRubyObject tag_class = asnM.getRuntime().newSymbol("CONTEXT_SPECIFIC"); - return c.callMethod(tc,"new",new IRubyObject[]{asnM.getRuntime().newArray(val),tag,tag_class}); - } - - // System.err.println("v: " + v + "[" + v.getClass().getName() + "]"); - return null; - } - - @JRubyMethod(meta = true) - public static IRubyObject decode(IRubyObject recv, IRubyObject obj) { - try { - IRubyObject obj2 = OpenSSLImpl.to_der_if_possible(obj); - RubyModule asnM = (RubyModule)recv; - ASN1InputStream asis = new ASN1InputStream(obj2.convertToString().getBytes()); - IRubyObject ret = decodeObj(asnM, asis.readObject()); - return ret; - } catch(IOException e) { - throw recv.getRuntime().newIOErrorFromException(e); - } catch(Exception e) { - throw recv.getRuntime().newArgumentError(e.getMessage()); - } - } - - @JRubyMethod(meta=true, required=1) - public static IRubyObject decode_all(IRubyObject recv, IRubyObject a) { - System.err.println("WARNING: unimplemented method called: decode_all"); - return null; - } - - public static class ASN1Data extends RubyObject { - private static final long serialVersionUID = 6117598347932209839L; - - public static ObjectAllocator ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new ASN1Data(runtime, klass); - } - }; - public ASN1Data(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - protected void asn1Error() { - asn1Error(null); - } - - protected void asn1Error(String msg) { - throw Utils.newError(getRuntime(), "OpenSSL::ASN1::ASN1Error", msg); - } - - @JRubyMethod - public IRubyObject initialize(IRubyObject value, IRubyObject tag, IRubyObject tag_class) { - if(!(tag_class instanceof RubySymbol)) { - asn1Error("invalid tag class"); - } - if(tag_class.toString().equals(":UNIVERSAL") && RubyNumeric.fix2int(tag) > 31) { - asn1Error("tag number for Universal too large"); - } - ThreadContext tc = getRuntime().getCurrentContext(); - this.callMethod(tc,"tag=", tag); - this.callMethod(tc,"value=", value); - this.callMethod(tc,"tag_class=", tag_class); - - return this; - } - - ASN1Encodable toASN1() { - ThreadContext tc = getRuntime().getCurrentContext(); - int tag = RubyNumeric.fix2int(callMethod(tc,"tag")); - IRubyObject val = callMethod(tc,"value"); - if(val instanceof RubyArray) { - RubyArray arr = (RubyArray)callMethod(tc,"value"); - if(arr.size() > 1) { - ASN1EncodableVector vec = new ASN1EncodableVector(); - for (IRubyObject obj : arr.toJavaArray()) { - vec.add(((ASN1Data)obj).toASN1()); - } - return new DERTaggedObject(tag, new DERSequence(vec)); - } else { - return new DERTaggedObject(tag,((ASN1Data)(arr.getList().get(0))).toASN1()); - } - } else { - return new DERTaggedObject(tag, ((ASN1Data)val).toASN1()); - } - } - - @JRubyMethod - public IRubyObject to_der() { - return getRuntime().newString(new ByteList(toASN1().getDEREncoded(),false)); - } - - protected IRubyObject defaultTag() { - int i = idForRubyName(getMetaClass().getRealClass().getBaseName()); - if(i != -1) { - return getRuntime().newFixnum(i); - } else { - return getRuntime().getNil(); - } - } - - protected void print() { - print(0); - } - - protected void printIndent(int indent) { - for(int i=0;i1) { - tag = args[1]; - if(args.length>2) { - tagging = args[2]; - if(args.length>3) { - tag_class = args[3]; - } - } - if(tag.isNil()) { - asn1Error("must specify tag number"); - } - if(tagging.isNil()) { - tagging = getRuntime().newSymbol("EXPLICIT"); - } - if(!(tagging instanceof RubySymbol)) { - asn1Error("invalid tag default"); - } - if(tag_class.isNil()) { - tag_class = getRuntime().newSymbol("CONTEXT_SPECIFIC"); - } - if(!(tag_class instanceof RubySymbol)) { - asn1Error("invalid tag class"); - } - if(tagging.toString().equals(":IMPLICIT") && RubyNumeric.fix2int(tag) > 31) { - asn1Error("tag number for Universal too large"); - } - } else { - tag = defaultTag(); - tagging = getRuntime().getNil(); - tag_class = getRuntime().newSymbol("UNIVERSAL"); - } - if("ObjectId".equals(getMetaClass().getRealClass().getBaseName())) { - String v = getSymLookup(getRuntime()).get(getObjectIdentifier(value.toString())); - if(v != null) { - value = getRuntime().newString(v); - } - } - ThreadContext tc = getRuntime().getCurrentContext(); - this.callMethod(tc,"tag=",tag); - this.callMethod(tc,"value=",value); - this.callMethod(tc,"tagging=",tagging); - this.callMethod(tc,"tag_class=",tag_class); - - return this; - } - - private DERObjectIdentifier getObjectIdentifier(String nameOrOid) { - Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase()); - if(null != val1) { - return (DERObjectIdentifier)val1; - } - DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid); - return val2; - } - - ASN1Encodable toASN1() { - // System.err.println(getMetaClass().getRealClass().getBaseName()+"#toASN1"); - int tag = idForRubyName(getMetaClass().getRealClass().getBaseName()); - @SuppressWarnings("unchecked") Class imp = (Class)ASN1_INFO[tag][1]; - IRubyObject val = callMethod(getRuntime().getCurrentContext(),"value"); - if(imp == DERObjectIdentifier.class) { - return getObjectIdentifier(val.toString()); - } else if(imp == DERNull.class) { - return new DERNull(); - } else if(imp == DERBoolean.class) { - return new DERBoolean(val.isTrue()); - } else if(imp == DERUTCTime.class) { - return new DERUTCTime(((RubyTime)val).getJavaDate()); - } else if(imp == DERInteger.class && val instanceof RubyBignum) { - return new DERInteger(((RubyBignum)val).getValue()); - } else if(imp == DERInteger.class) { - return new DERInteger(new BigInteger(val.toString())); - } else if(imp == DEROctetString.class) { - return new DEROctetString(val.convertToString().getBytes()); - } else if(imp == DERBitString.class) { - byte[] bs = val.convertToString().getBytes(); - int unused = 0; - for(int i = (bs.length-1); i>-1; i--) { - if(bs[i] == 0) { - unused += 8; - } else { - byte v2 = bs[i]; - int x = 8; - while(v2 != 0) { - v2 <<= 1; - x--; - } - unused += x; - break; - } - } - return new DERBitString(bs,unused); - } else if(val instanceof RubyString) { - try { - return imp.getConstructor(String.class).newInstance(val.toString()); - } catch (Exception ex) { - throw RaiseException.createNativeRaiseException(getRuntime(), ex); - } - } - - System.err.println("object with tag: " + tag + " and value: " + val + " and val.class: " + val.getClass().getName() + " and impl: " + imp.getName()); - System.err.println("WARNING: unimplemented method called: asn1data#toASN1"); - return null; - } - - protected void print(int indent) { - printIndent(indent); - System.out.println(getMetaClass().getRealClass().getBaseName() + ": " + callMethod(getRuntime().getCurrentContext(),"value").callMethod(getRuntime().getCurrentContext(),"inspect").toString()); - } - } - - public static class ASN1Constructive extends ASN1Data { - private static final long serialVersionUID = -7166662655104776828L; - - public static ObjectAllocator ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new ASN1Constructive(runtime, klass); - } - }; - public ASN1Constructive(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - @JRubyMethod - public IRubyObject to_der() { - return super.to_der(); - } - - @JRubyMethod(required=1, optional=3) - public IRubyObject initialize(IRubyObject[] args) { - IRubyObject value = args[0]; - IRubyObject tag = getRuntime().getNil(); - IRubyObject tagging = getRuntime().getNil(); - IRubyObject tag_class = getRuntime().getNil(); - if(args.length>1) { - tag = args[1]; - if(args.length>2) { - tagging = args[2]; - if(args.length>3) { - tag_class = args[3]; - } - } - if(tag.isNil()) { - asn1Error("must specify tag number"); - } - if(tagging.isNil()) { - tagging = getRuntime().newSymbol("EXPLICIT"); - } - if(!(tagging instanceof RubySymbol)) { - asn1Error("invalid tag default"); - } - if(tag_class.isNil()) { - tag_class = getRuntime().newSymbol("CONTEXT_SPECIFIC"); - } - if(!(tag_class instanceof RubySymbol)) { - asn1Error("invalid tag class"); - } - if(tagging.toString().equals(":IMPLICIT") && RubyNumeric.fix2int(tag) > 31) { - asn1Error("tag number for Universal too large"); - } - } else { - tag = defaultTag(); - tagging = getRuntime().getNil(); - tag_class = getRuntime().newSymbol("UNIVERSAL"); - } - ThreadContext tc = getRuntime().getCurrentContext(); - this.callMethod(tc,"tag=",tag); - this.callMethod(tc,"value=",value); - this.callMethod(tc,"tagging=",tagging); - this.callMethod(tc,"tag_class=",tag_class); - - return this; - } - - ASN1Encodable toASN1() { - // System.err.println(getMetaClass().getRealClass().getBaseName()+"#toASN1"); - int id = idForRubyName(getMetaClass().getRealClass().getBaseName()); - if(id != -1) { - ASN1EncodableVector vec = new ASN1EncodableVector(); - RubyArray arr = (RubyArray)callMethod(getRuntime().getCurrentContext(),"value"); - for (IRubyObject obj : arr.toJavaArray()) { - if(obj instanceof ASN1Data) { - vec.add(((ASN1Data)obj).toASN1()); - } else { - vec.add(((ASN1Data) ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), OpenSSLImpl.to_der_if_possible(obj))).toASN1()); - } - } - try { - @SuppressWarnings("unchecked") - ASN1Encodable result = ((Class) (ASN1_INFO[id][1])).getConstructor(new Class[] { ASN1EncodableVector.class }) - .newInstance(new Object[] { vec }); - return result; - } catch (Exception e) { - // TODO: deprecated - throw RaiseException.createNativeRaiseException(getRuntime(), e); - } - } - return null; - } - - @JRubyMethod(frame=true) - public IRubyObject each(Block block) { - RubyArray arr = (RubyArray) callMethod(getRuntime().getCurrentContext(), "value"); - for (IRubyObject obj : arr.toJavaArray()) { - block.yield(getRuntime().getCurrentContext(), obj); - } - return getRuntime().getNil(); - } - - protected void print(int indent) { - printIndent(indent); - System.out.println(getMetaClass().getRealClass().getBaseName() + ": "); - RubyArray arr = (RubyArray)callMethod(getRuntime().getCurrentContext(),"value"); - for (IRubyObject obj : arr.toJavaArray()) { - ((ASN1Data)obj).print(indent+1); - } - } - } -}// ASN1 diff --git a/src/java/org/jruby/ext/openssl/Attribute.java b/src/java/org/jruby/ext/openssl/Attribute.java deleted file mode 100644 index e915f50..0000000 --- a/src/java/org/jruby/ext/openssl/Attribute.java +++ /dev/null @@ -1,133 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.anno.JRubyMethod; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class Attribute extends RubyObject { - private static final long serialVersionUID = 5569940260019783275L; - - private static ObjectAllocator ATTRIBUTE_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new Attribute(runtime, klass); - } - }; - - public static void createAttribute(Ruby runtime, RubyModule mX509) { - RubyClass cAttribute = mX509.defineClassUnder("Attribute",runtime.getObject(), ATTRIBUTE_ALLOCATOR); - - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("AttributeError",openSSLError, openSSLError.getAllocator()); - - cAttribute.defineAnnotatedMethods(Attribute.class); - } - - public Attribute(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private IRubyObject oid; - private IRubyObject value; - - private DERObjectIdentifier getObjectIdentifier(String nameOrOid) { - Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase()); - if(null != val1) { - return (DERObjectIdentifier)val1; - } - DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid); - return val2; - } - - DERObject toASN1() { - ASN1EncodableVector v1 = new ASN1EncodableVector(); - v1.add(getObjectIdentifier(oid.toString())); - if(value instanceof ASN1.ASN1Constructive) { - v1.add(((ASN1.ASN1Constructive)value).toASN1()); - } else { - ASN1EncodableVector v2 = new ASN1EncodableVector(); - v2.add(((ASN1.ASN1Data)value).toASN1()); - v1.add(new DERSet(v2)); - } - return new DERSequence(v1); - } - - @JRubyMethod(name="initialize", required=1, optional=1) - public IRubyObject _initialize(IRubyObject[] str) { - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),str,1,2) == 1) { - IRubyObject _oid = OpenSSLImpl.to_der_if_possible(str[0]); - set_oid(_oid); - return this; - } - set_oid(str[0]); - set_value(str[1]); - return this; - } - - @JRubyMethod - public IRubyObject to_der() { - System.err.println("WARNING: unimplemented method called: attr#to_der"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject oid() { - return oid; - } - - @JRubyMethod(name="oid=") - public IRubyObject set_oid(IRubyObject val) { - this.oid = val; - return val; - } - - @JRubyMethod - public IRubyObject value() { - return value; - } - - @JRubyMethod(name="value=") - public IRubyObject set_value(IRubyObject val) { - IRubyObject tmp = OpenSSLImpl.to_der_if_possible(val); - this.value = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), tmp); - return val; - } -}// Attribute diff --git a/src/java/org/jruby/ext/openssl/BN.java b/src/java/org/jruby/ext/openssl/BN.java deleted file mode 100644 index 18a77e3..0000000 --- a/src/java/org/jruby/ext/openssl/BN.java +++ /dev/null @@ -1,766 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2007 William N Dortch - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Random; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyFixnum; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.Arity; -import org.jruby.runtime.ClassIndex; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * OpenSSL::BN implementation. Wraps java.math.BigInteger, which provides - * most functionality directly; the rest is easily derived. - * - * Beware that BN's are mutable -- I don't agree with this approach, but - * must conform for compatibility with MRI's implementation. The offending methods - * are set_bit!, clear_bit!, mask_bits! and copy.

    - * - * I've included a few operations (& | ^ ~) that aren't defined by MRI/OpenSSL. - * These are non-portable (i.e., won't work in C-Ruby), so use at your own risk.

    - * - * @author Bill Dortch - */ -public class BN extends RubyObject { - private static final long serialVersionUID = -5660938062191525498L; - - private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); - private static final BigInteger TWO = BigInteger.valueOf(2); - private static final int DEFAULT_CERTAINTY = 100; - private static Random _random; - private static SecureRandom _secureRandom; - - private static ObjectAllocator BN_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new BN(runtime, klass, BigInteger.ZERO); - } - }; - - public static BN newBN(Ruby runtime, BigInteger value) { - return new BN(runtime, value != null ? value : BigInteger.ZERO); - } - - public static void createBN(Ruby runtime, RubyModule ossl) { - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - ossl.defineClassUnder("BNError", openSSLError, openSSLError.getAllocator()); - - RubyClass bn = ossl.defineClassUnder("BN", runtime.getObject(), BN_ALLOCATOR); - - bn.defineAnnotatedMethods(BN.class); - } - - private volatile BigInteger value; - - private BN(Ruby runtime, RubyClass clazz, BigInteger value) { - super(runtime, clazz); - this.value = value; - } - - private BN(Ruby runtime, BigInteger value) { - super(runtime, runtime.getModule("OpenSSL").getClass("BN")); - this.value = value; - } - - public BigInteger getValue() { - return value; - } - - // TODO: check whether this is really needed for JRuby 1.0x (not used in 1.1x) - public IRubyObject doClone() { - return newBN(getRuntime(), this.value); - } - - public IRubyObject initialize_copy(IRubyObject original) { - super.initialize_copy(original); - if (this != original) { - this.value = ((BN)original).value; - } - return this; - } - - @JRubyMethod(name="initialize", required=1, optional=1) - public synchronized IRubyObject bn_initialize(IRubyObject[] args) { - Ruby runtime = getRuntime(); - if (this.value != BigInteger.ZERO) { // already initialized - throw newBNError(runtime, "illegal initialization"); - } - int argc = Arity.checkArgumentCount(runtime, args, 1, 2); - int base = argc == 2 ? RubyNumeric.num2int(args[1]) : 10; - RubyString str = RubyString.stringValue(args[0]); - switch (base) { - case 2: - // this seems wrong to me, but is the behavior of the - // MRI implementation. rather than interpreting the string - // as ASCII-encoded binary digits, the raw binary value of - // the string is used instead. the value is always interpreted - // as positive, hence the use of the signum version of the BI - // constructor here: - this.value = new BigInteger(1, str.getBytes()); - break; - case 10: - case 16: - // here, the ASCII-encoded decimal or hex string is used - try { - this.value = new BigInteger(str.toString(), base); - break; - } catch (NumberFormatException e) { - throw runtime.newArgumentError("value " + str + " is not legal for radix " + base); - } - case 0: // FIXME: not currently supporting BN_mpi2bn - throw runtime.newArgumentError("unsupported radix: " + base); - default: - throw runtime.newArgumentError("illegal radix: " + base); - } - return this; - } - - @JRubyMethod(name="copy") - public synchronized IRubyObject bn_copy(IRubyObject other) { - if (this != other) { - this.value = getBigInteger(other); - } - return this; - } - - @JRubyMethod(name="to_s", rest=true) - public IRubyObject bn_to_s(IRubyObject[] args) { - Ruby runtime = getRuntime(); - int argc = Arity.checkArgumentCount(runtime, args, 0, 1); - int base = argc == 1 ? RubyNumeric.num2int(args[0]) : 10; - switch (base) { - case 2: - // again, following MRI implementation, wherein base 2 deals - // with strings as byte arrays rather than ASCII-encoded binary - // digits. note that negative values are returned as though positive: - - byte[] bytes = this.value.abs().toByteArray(); - - // suppress leading 0 byte to conform to MRI behavior - if (bytes[0] == 0) { - return runtime.newString(new ByteList(bytes, 1, bytes.length - 1)); - } - return runtime.newString(new ByteList(bytes, false)); - case 10: - case 16: - return runtime.newString(value.toString(base).toUpperCase()); - case 0: // FIXME: not currently supporting BN_mpi2bn - throw runtime.newArgumentError("unsupported radix: " + base); - default: - throw runtime.newArgumentError("illegal radix: " + base); - } - } - - @JRubyMethod(name="to_i") - public IRubyObject bn_to_i() { - Ruby runtime = getRuntime(); - // FIXME: s/b faster way to convert than going through RubyString - return RubyNumeric.str2inum(runtime, runtime.newString(value.toString()), 10, true); - } - - @JRubyMethod(name="to_bn") - public IRubyObject bn_to_bn() { - return this; - } - - @JRubyMethod(name="coerce") - // FIXME: is this right? don't see how it would be useful... - public IRubyObject bn_coerce(IRubyObject other) { - Ruby runtime = getRuntime(); - IRubyObject self; - switch (other.getMetaClass().index) { - case ClassIndex.STRING: - self = runtime.newString(value.toString()); - break; - case ClassIndex.FIXNUM: - case ClassIndex.BIGNUM: - // FIXME: s/b faster way to convert than going through RubyString - self = RubyNumeric.str2inum(runtime, runtime.newString(value.toString()), 10, true); - break; - default: - if (other instanceof BN) { - self = this; - } else { - throw runtime.newTypeError("Don't know how to coerce"); - } - } - return runtime.newArray(other, self); - } - - @JRubyMethod(name="zero?") - public IRubyObject bn_is_zero() { - return getRuntime().newBoolean(value.equals(BigInteger.ZERO)); - } - - @JRubyMethod(name="one?") - public IRubyObject bn_is_one() { - return getRuntime().newBoolean(value.equals(BigInteger.ONE)); - } - - @JRubyMethod(name="odd?") - public IRubyObject bn_is_odd() { - return getRuntime().newBoolean(value.testBit(0)); - } - - @JRubyMethod(name={"cmp", "<=>"}) - public IRubyObject bn_cmp(IRubyObject other) { - return getRuntime().newFixnum(value.compareTo(getBigInteger(other))); - } - - @JRubyMethod(name="ucmp") - public IRubyObject bn_ucmp(IRubyObject other) { - return getRuntime().newFixnum(value.abs().compareTo(getBigInteger(other).abs())); - } - - @JRubyMethod(name={"eql?", "==", "==="}) - public IRubyObject bn_eql(IRubyObject other) { - return getRuntime().newBoolean(value.equals(getBigInteger(other))); - } - - @JRubyMethod(name="sqr") - public IRubyObject bn_sqr() { - // TODO: check whether mult n * n is faster - return newBN(getRuntime(), value.pow(2)); - } - - @JRubyMethod(name="~") - public IRubyObject bn_not() { - return newBN(getRuntime(), value.not()); - } - - @JRubyMethod(name="+") - public IRubyObject bn_add(IRubyObject other) { - return newBN(getRuntime(), value.add(getBigInteger(other))); - } - - @JRubyMethod(name="-") - public IRubyObject bn_sub(IRubyObject other) { - return newBN(getRuntime(), value.subtract(getBigInteger(other))); - } - - @JRubyMethod(name="*") - public IRubyObject bn_mul(IRubyObject other) { - return newBN(getRuntime(), value.multiply(getBigInteger(other))); - } - - @JRubyMethod(name="%") - public IRubyObject bn_mod(IRubyObject other) { - try { - return newBN(getRuntime(), value.mod(getBigInteger(other))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="/") - public IRubyObject bn_div(IRubyObject other) { - Ruby runtime = getRuntime(); - try { - BigInteger[] result = value.divideAndRemainder(getBigInteger(other)); - return runtime.newArray(newBN(runtime, result[0]), newBN(runtime, result[1])); - } catch (ArithmeticException e) { - throw runtime.newZeroDivisionError(); - } - } - - @JRubyMethod(name="&") - public IRubyObject bn_and(IRubyObject other) { - return newBN(getRuntime(), value.and(getBigInteger(other))); - } - - @JRubyMethod(name="|") - public IRubyObject bn_or(IRubyObject other) { - return newBN(getRuntime(), value.or(getBigInteger(other))); - } - - @JRubyMethod(name="^") - public IRubyObject bn_xor(IRubyObject other) { - return newBN(getRuntime(), value.xor(getBigInteger(other))); - } - - @JRubyMethod(name="**") - public IRubyObject bn_exp(IRubyObject other) { - // somewhat strangely, BigInteger takes int rather than BigInteger - // as the argument to pow. so we'll have to narrow the value, and - // raise an exception if data would be lost. (on the other hand, an - // exponent even approaching Integer.MAX_VALUE would be silly big, and - // the value would take a very, very long time to calculate.) - // we'll check for values < 0 (illegal) while we're at it - int exp; - switch(other.getMetaClass().index) { - case ClassIndex.FIXNUM: { - long val = ((RubyFixnum)other).getLongValue(); - if (val >= 0 && val <= Integer.MAX_VALUE) { - exp = (int)val; - break; - } - } - case ClassIndex.BIGNUM: - // Bignum is inherently too big - throw newBNError(getRuntime(), "invalid exponent"); - default: { - if (!(other instanceof BN)) { - throw getRuntime().newTypeError("Cannot convert into OpenSSL::BN"); - } - BigInteger val = ((BN)other).value; - if (val.compareTo(BigInteger.ZERO) < 0 || val.compareTo(MAX_INT) > 0) { - throw newBNError(getRuntime(), "invalid exponent"); - } - exp = val.intValue(); - break; - } - } - try { - return newBN(getRuntime(), value.pow(exp)); - } catch (ArithmeticException e) { - // shouldn't happen, we've already checked for < 0 - throw newBNError(getRuntime(), "invalid exponent"); - } - } - - @JRubyMethod(name="gcd") - public IRubyObject bn_gcd(IRubyObject other) { - return newBN(getRuntime(), value.gcd(getBigInteger(other))); - } - - @JRubyMethod(name="mod_sqr") - public IRubyObject bn_mod_sqr(IRubyObject other) { - try { - return newBN(getRuntime(), value.modPow(TWO, getBigInteger(other))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="mod_inverse") - public IRubyObject bn_mod_inverse(IRubyObject other) { - try { - return newBN(getRuntime(), value.modInverse(getBigInteger(other))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="mod_add") - public IRubyObject bn_mod_add(IRubyObject other, IRubyObject mod) { - try { - return newBN(getRuntime(), value.add(getBigInteger(other)).mod(getBigInteger(mod))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="mod_sub") - public IRubyObject bn_mod_sub(IRubyObject other, IRubyObject mod) { - try { - return newBN(getRuntime(), value.subtract(getBigInteger(other)).mod(getBigInteger(mod))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="mod_mul") - public IRubyObject bn_mod_mul(IRubyObject other, IRubyObject mod) { - try { - return newBN(getRuntime(), value.multiply(getBigInteger(other)).mod(getBigInteger(mod))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="mod_exp") - public IRubyObject bn_mod_exp(IRubyObject other, IRubyObject mod) { - try { - return newBN(getRuntime(), value.modPow(getBigInteger(other), getBigInteger(mod))); - } catch (ArithmeticException e) { - throw getRuntime().newZeroDivisionError(); - } - } - - @JRubyMethod(name="set_bit!") - public synchronized IRubyObject bn_set_bit(IRubyObject n) { - // evil mutable BN - int pos = RubyNumeric.num2int(n); - BigInteger oldValue = this.value; - // FIXME? in MRI/OSSL-BIGNUM, the original sign of a BN is remembered, so if - // you set the value of an (originally) negative number to zero (through some - // combination of clear_bit! and/or mask_bits! calls), and later call set_bit!, - // the resulting value will be negative. this seems unintuitive and, frankly, - // wrong, not to mention expensive to carry the extra sign field. - // I'm not duplicating this behavior here at this time. -BD - try { - if (oldValue.signum() >= 0) { - this.value = oldValue.setBit(pos); - } else { - this.value = oldValue.abs().setBit(pos).negate(); - } - } catch (ArithmeticException e) { - throw newBNError(getRuntime(), "invalid pos"); - } - return this; - } - - @JRubyMethod(name="clear_bit!") - public synchronized IRubyObject bn_clear_bit(IRubyObject n) { - // evil mutable BN - int pos = RubyNumeric.num2int(n); - BigInteger oldValue = this.value; - try { - if (oldValue.signum() >= 0) { - this.value = oldValue.clearBit(pos); - } else { - this.value = oldValue.abs().clearBit(pos).negate(); - } - } catch (ArithmeticException e) { - throw newBNError(getRuntime(), "invalid pos"); - } - return this; - } - - /** - * Truncates value to n bits - */ - @JRubyMethod(name="mask_bits!") - public synchronized IRubyObject bn_mask_bits(IRubyObject n) { - // evil mutable BN - - int pos = RubyNumeric.num2int(n); - if (pos < 0) throw newBNError(getRuntime(), "invalid pos"); - - BigInteger oldValue = this.value; - - // TODO: cache 2 ** n values? - if (oldValue.signum() >= 0) { - if (oldValue.bitLength() < pos) throw newBNError(getRuntime(), "invalid pos"); - this.value = oldValue.mod(TWO.pow(pos)); - } else { - BigInteger absValue = oldValue.abs(); - if (absValue.bitLength() < pos) throw newBNError(getRuntime(), "invalid pos"); - this.value = absValue.mod(TWO.pow(pos)).negate(); - } - - return this; - } - - @JRubyMethod(name="bit_set?") - public IRubyObject bn_is_bit_set(IRubyObject n) { - int pos = RubyNumeric.num2int(n); - BigInteger val = this.value; - try { - if (val.signum() >= 0) { - return getRuntime().newBoolean(val.testBit(pos)); - } else { - return getRuntime().newBoolean(val.abs().testBit(pos)); - } - } catch (ArithmeticException e) { - throw newBNError(getRuntime(), "invalid pos"); - } - } - - @JRubyMethod(name="<<") - public IRubyObject bn_lshift(IRubyObject n) { - int nbits = RubyNumeric.num2int(n); - BigInteger val = this.value; - if (val.signum() >= 0) { - return newBN(getRuntime(), val.shiftLeft(nbits)); - } else { - return newBN(getRuntime(), val.abs().shiftLeft(nbits).negate()); - } - } - - @JRubyMethod(name=">>") - public IRubyObject bn_rshift(IRubyObject n) { - int nbits = RubyNumeric.num2int(n); - BigInteger val = this.value; - if (val.signum() >= 0) { - return newBN(getRuntime(), val.shiftRight(nbits)); - } else { - return newBN(getRuntime(), val.abs().shiftRight(nbits).negate()); - } - } - - @JRubyMethod(name="num_bits") - public IRubyObject bn_num_bits() { - return getRuntime().newFixnum(this.value.abs().bitLength()); - } - - @JRubyMethod(name="num_bytes") - public IRubyObject bn_num_bytes() { - return getRuntime().newFixnum((this.value.abs().bitLength() + 7) / 8); - } - - @JRubyMethod(name="num_bits_set") - public IRubyObject bn_num_bits_set() { - return getRuntime().newFixnum(this.value.abs().bitCount()); - } - - // note that there is a bug in the MRI version, in argument handling, - // so apparently no one ever calls this... - @JRubyMethod(name="prime?", rest=true) - public IRubyObject bn_is_prime(IRubyObject[] args) { - Ruby runtime = getRuntime(); - int argc = Arity.checkArgumentCount(runtime, args, 0, 1); - // BigInteger#isProbablePrime will actually limit checks to a maximum of 50, - // depending on bit count. - int certainty = argc == 0 ? DEFAULT_CERTAINTY : RubyNumeric.fix2int(args[0]); - return runtime.newBoolean(this.value.isProbablePrime(certainty)); - } - - // FIXME? BigInteger doesn't supply this, so right now this is (essentially) - // the same as bn_is_prime - @JRubyMethod(name="prime_fasttest?", rest=true) - public IRubyObject bn_is_prime_fasttest(IRubyObject[] args) { - Ruby runtime = getRuntime(); - int argc = Arity.checkArgumentCount(runtime, args, 0, 2); - // BigInteger#isProbablePrime will actually limit checks to a maximum of 50, - // depending on bit count. - int certainty = argc == 0 ? DEFAULT_CERTAINTY : RubyNumeric.fix2int(args[0]); - return runtime.newBoolean(this.value.isProbablePrime(certainty)); - } - - @JRubyMethod(name="generate_prime", meta=true, rest=true) - public static IRubyObject bn_generate_prime(IRubyObject recv, IRubyObject[] args) { - Ruby runtime = recv.getRuntime(); - int argc = Arity.checkArgumentCount(runtime, args, 1, 4); - int bits = RubyNumeric.num2int(args[0]); - boolean safe = argc > 1 ? args[1] != runtime.getFalse() : true; - BigInteger add = argc > 2 ? getBigInteger(args[2]) : null; - BigInteger rem = argc > 3 ? getBigInteger(args[3]) : null; - if (bits < 3) { - if (safe) throw runtime.newArgumentError("bits < 3"); - if (bits < 2) throw runtime.newArgumentError("bits < 2"); - } - return newBN(runtime, generatePrime(bits, safe, add, rem)); - } - - public static BigInteger generatePrime(int bits, boolean safe, BigInteger add, BigInteger rem) { - // From OpenSSL man page BN_generate_prime(3): - // - // "If add is not NULL, the prime will fulfill the condition p % add == rem - // (p % add == 1 if rem == NULL) in order to suit a given generator." - // - // "If safe is true, it will be a safe prime (i.e. a prime p so that - // (p-1)/2 is also prime)." - // - // see [ossl]/crypto/bn/bn_prime.c #BN_generate_prime_ex - // - - if (add != null && rem == null) { - rem = BigInteger.ONE; - } - - // borrowing technique from org.bouncycastle.crypto.generators.DHParametersHelper - // (unfortunately the code has package visibility), wherein for safe primes, - // we'll use the lowest useful certainty (2) for generation of q, then if - // p ( = 2q + 1) is prime to our required certainty (100), we'll verify that q - // is as well. - // - // for typical bit lengths ( >= 1024), this should speed things up by reducing - // initial Miller-Rabin iterations from 2 to 1 for candidate values of q. - // - // it's still painfully slow... - // - BigInteger p, q; - int qbits = bits - 1; - SecureRandom secureRandom = getSecureRandom(); - do { - if (safe) { - do { - q = new BigInteger(qbits, 2, secureRandom); - p = q.shiftLeft(1).setBit(0); - } while (!(p.isProbablePrime(DEFAULT_CERTAINTY) && q.isProbablePrime(DEFAULT_CERTAINTY))); - } else { - p = BigInteger.probablePrime(bits, secureRandom); - } - } while (add != null && !p.mod(add).equals(rem)); - return p; - } - - public static BigInteger generatePrime(int bits, boolean safe) { - return generatePrime(bits, safe, null, null); - } - - @JRubyMethod(name="rand", meta=true, rest=true) - public static IRubyObject bn_rand(IRubyObject recv, IRubyObject[] args) { - return getRandomBN(recv.getRuntime(), args, getSecureRandom()); - } - - @JRubyMethod(name="pseudo_rand", meta=true, rest=true) - public static IRubyObject bn_pseudo_rand(IRubyObject recv, IRubyObject[] args) { - return getRandomBN(recv.getRuntime(), args, getRandom()); - } - - public static BN getRandomBN(Ruby runtime, IRubyObject[] args, Random random) { - int argc = Arity.checkArgumentCount(runtime, args, 1, 3); - int bits = RubyNumeric.num2int(args[0]); - int top; - boolean bottom; - if (argc > 1) { - top = RubyNumeric.fix2int(args[1]); - bottom = argc == 3 ? args[2].isTrue() : false; - } else { - top = 0; - bottom = false; - } - - BigInteger value; - try { - value = getRandomBI(bits, top, bottom, random); - } catch (IllegalArgumentException e) { - throw runtime.newArgumentError(e.getMessage()); - } - return newBN(runtime, value); - } - - public static BigInteger getRandomBI(int bits, int top, boolean bottom, Random random) { - // From OpenSSL man page BN_rand(3): - // - // "If top is -1, the most significant bit of the random number can be zero. - // If top is 0, it is set to 1, and if top is 1, the two most significant bits - // of the number will be set to 1, so that the product of two such random numbers - // will always have 2*bits length." - // - // "If bottom is true, the number will be odd." - // - if (bits <= 0) { - if (bits == 0) return BigInteger.ZERO; - throw new IllegalArgumentException("Illegal bit length"); - } - if (top < -1 || top > 1) { - throw new IllegalArgumentException("Illegal top value"); - } - - // top/bottom handling adapted from OpenSSL's crypto/bn/bn_rand.c - int bytes = (bits + 7) / 8; - int bit = (bits - 1) % 8; - int mask = 0xff << (bit + 1); - - byte[] buf; - random.nextBytes(buf = new byte[bytes]); - if (top >= 0) { - if (top == 0) { - buf[0] |= (1 << bit); - } else { - if (bit == 0) { - buf[0] = 1; - buf[1] |= 0x80; - } - else { - buf[0] |= (3 << (bit - 1)); - } - } - } - buf[0] &= ~mask; - if (bottom) { - buf[bytes-1] |= 1; - } - - // treating result as unsigned - return new BigInteger(1, buf); - } - - @JRubyMethod(name="rand_range", meta=true) - public static IRubyObject bn_rand_range(IRubyObject recv, IRubyObject arg) { - return getRandomBNInRange(recv.getRuntime(), getBigInteger(arg), getSecureRandom()); - } - - @JRubyMethod(name="pseudo_rand_range", meta=true) - public static IRubyObject bn_pseudo_rand_range(IRubyObject recv, IRubyObject arg) { - return getRandomBNInRange(recv.getRuntime(), getBigInteger(arg), getRandom()); - } - - private static BN getRandomBNInRange(Ruby runtime, BigInteger limit, Random random) { - BigInteger value; - try { - value = getRandomBIInRange(limit, random); - } catch (IllegalArgumentException e) { - throw newBNError(runtime, "illegal range"); - } - return newBN(runtime, value); - } - - public static BigInteger getRandomBIInRange(BigInteger limit, Random random) { - if (limit.signum() < 0) { - throw new IllegalArgumentException("illegal range"); - } - int bits = limit.bitLength(); - BigInteger value; - do { - value = new BigInteger(bits, random); - } while (value.compareTo(limit) >= 0); - return value; - } - - private static Random getRandom() { - Random rand; - if ((rand = _random) != null) { - return rand; - } - return _random = new Random(); - } - - private static SecureRandom getSecureRandom() { - SecureRandom rand; - if ((rand = _secureRandom) != null) { - return rand; - } - // FIXME: do we want a particular algorithm / provider? BC? - return _secureRandom = new SecureRandom(); - } - - public static RaiseException newBNError(Ruby runtime, String message) { - return new RaiseException(runtime, runtime.getModule("OpenSSL").getClass("BNError"), message, true); - } - - public static BigInteger getBigInteger(IRubyObject arg) { - if (arg.isNil()) return null; - switch(arg.getMetaClass().index) { - case ClassIndex.FIXNUM: - case ClassIndex.BIGNUM: - return new BigInteger(arg.toString()); - default: - if (arg instanceof BN) { - return ((BN)arg).value; - } - throw arg.getRuntime().newTypeError("Cannot convert into OpenSSL::BN"); - } - } - -} diff --git a/src/java/org/jruby/ext/openssl/BouncyCastlePEMHandler.java b/src/java/org/jruby/ext/openssl/BouncyCastlePEMHandler.java deleted file mode 100644 index 0babf5e..0000000 --- a/src/java/org/jruby/ext/openssl/BouncyCastlePEMHandler.java +++ /dev/null @@ -1,69 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.Reader; -import java.io.Writer; - -import org.bouncycastle.openssl.PEMReader; -import org.bouncycastle.openssl.PEMWriter; -import org.bouncycastle.openssl.PasswordFinder; - -/** - * @author Ola Bini - */ -public class BouncyCastlePEMHandler implements PEMHandler { - public Object readPEM(Reader read, String password) throws Exception { - return new PEMReader(read,new BasicPasswordFinder(password)).readObject(); - } - - public void writePEM(Writer writ, Object obj, String algorithm, char[] password) throws Exception { - PEMWriter p = new PEMWriter(writ); - p.writeObject(obj,algorithm,password,null); - p.flush(); - } - - public void writePEM(Writer writ, Object obj) throws Exception { - PEMWriter p = new PEMWriter(writ); - p.writeObject(obj); - p.flush(); - } - - private static class BasicPasswordFinder implements PasswordFinder { - private char[] pwd; - BasicPasswordFinder(String pwd) { - if(pwd != null) { - this.pwd = pwd.toCharArray(); - } - } - - public char[] getPassword() { - return pwd; - } - } -}// BouncyCastlePEMHandler diff --git a/src/java/org/jruby/ext/openssl/Cipher.java b/src/java/org/jruby/ext/openssl/Cipher.java deleted file mode 100644 index dafe964..0000000 --- a/src/java/org/jruby/ext/openssl/Cipher.java +++ /dev/null @@ -1,806 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.crypto.spec.IvParameterSpec; - -import javax.crypto.spec.RC2ParameterSpec; -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.common.IRubyWarnings; -import org.jruby.common.IRubyWarnings.ID; -import org.jruby.anno.JRubyMethod; -import org.jruby.anno.JRubyModule; -import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class Cipher extends RubyObject { - private static final long serialVersionUID = 7727377435222646536L; - - // set to enable debug output - private static final boolean DEBUG = false; - private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() { - - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new Cipher(runtime, klass); - } - }; - - public static void createCipher(Ruby runtime, RubyModule mOSSL) { - RubyClass cCipher = mOSSL.defineClassUnder("Cipher", runtime.getObject(), CIPHER_ALLOCATOR); - cCipher.defineAnnotatedMethods(Cipher.class); - cCipher.defineAnnotatedMethods(CipherModule.class); - RubyClass openSSLError = mOSSL.getClass("OpenSSLError"); - cCipher.defineClassUnder("CipherError", openSSLError, openSSLError.getAllocator()); - } - - @JRubyModule(name = "OpenSSL::Cipher") - public static class CipherModule { - - @JRubyMethod(meta = true) - public static IRubyObject ciphers(IRubyObject recv) { - initializeCiphers(); - List result = new ArrayList(); - for (String cipher : CIPHERS) { - result.add(recv.getRuntime().newString(cipher)); - result.add(recv.getRuntime().newString(cipher.toLowerCase())); - } - return recv.getRuntime().newArray(result); - } - - public static boolean isSupportedCipher(String name) { - initializeCiphers(); - return CIPHERS.indexOf(name.toUpperCase()) != -1; - } - private static boolean initialized = false; - private static final List CIPHERS = new ArrayList(); - - private static void initializeCiphers() { - synchronized (CIPHERS) { - if (initialized) { - return; - } - String[] other = {"AES128", "AES192", "AES256", "BLOWFISH", "RC2-40-CBC", "RC2-64-CBC", "RC4", "RC4-40", "CAST", "CAST-CBC"}; - String[] bases = {"AES-128", "AES-192", "AES-256", "BF", "DES", "DES-EDE", "DES-EDE3", "RC2", "CAST5"}; - String[] suffixes = {"", "-CBC", "-CFB", "-CFB1", "-CFB8", "-ECB", "-OFB"}; - for (int i = 0, j = bases.length; i < j; i++) { - for (int k = 0, l = suffixes.length; k < l; k++) { - String val = bases[i] + suffixes[k]; - if (tryCipher(val)) { - CIPHERS.add(val.toUpperCase()); - } - } - } - for (int i = 0, j = other.length; i < j; i++) { - if (tryCipher(other[i])) { - CIPHERS.add(other[i].toUpperCase()); - } - } - initialized = true; - } - } - } - - public static class Algorithm { - - private static final Set BLOCK_MODES; - - static { - BLOCK_MODES = new HashSet(); - - BLOCK_MODES.add("CBC"); - BLOCK_MODES.add("CFB"); - BLOCK_MODES.add("CFB1"); - BLOCK_MODES.add("CFB8"); - BLOCK_MODES.add("ECB"); - BLOCK_MODES.add("OFB"); - } - - public static String jsseToOssl(String inName, int keyLen) { - String cryptoBase = null; - String cryptoVersion = null; - String cryptoMode = null; - String[] parts = inName.split("/"); - if (parts.length != 1 && parts.length != 3) { - return null; - } - cryptoBase = parts[0]; - if (parts.length > 2) { - cryptoMode = parts[1]; - // padding: parts[2] is not used - } - if (!BLOCK_MODES.contains(cryptoMode)) { - cryptoVersion = cryptoMode; - cryptoMode = "CBC"; - } - if (cryptoMode == null) { - cryptoMode = "CBC"; - } - if (cryptoBase.equals("DESede")) { - cryptoBase = "DES"; - cryptoVersion = "EDE3"; - } else if (cryptoBase.equals("Blowfish")) { - cryptoBase = "BF"; - } - if (cryptoVersion == null) { - cryptoVersion = String.valueOf(keyLen); - } - return cryptoBase + "-" + cryptoVersion + "-" + cryptoMode; - } - - public static String getAlgorithmBase(javax.crypto.Cipher cipher) { - String algoBase = cipher.getAlgorithm(); - if (algoBase.indexOf('/') != -1) { - algoBase = algoBase.split("/")[0]; - } - return algoBase; - } - - public static String[] osslToJsse(String inName) { - // assume PKCS5Padding - return osslToJsse(inName, null); - } - - public static String[] osslToJsse(String inName, String padding) { - String[] split = inName.split("-"); - String cryptoBase = split[0]; - String cryptoVersion = null; - String cryptoMode = null; - String realName = null; - - String paddingType; - if (padding == null || padding.equalsIgnoreCase("PKCS5Padding")) { - paddingType = "PKCS5Padding"; - } else if (padding.equals("0") || padding.equalsIgnoreCase("NoPadding")) { - paddingType = "NoPadding"; - } else if (padding.equalsIgnoreCase("ISO10126Padding")) { - paddingType = "ISO10126Padding"; - } else { - paddingType = "PKCS5Padding"; - } - - if ("bf".equalsIgnoreCase(cryptoBase)) { - cryptoBase = "Blowfish"; - } - - if (split.length == 3) { - cryptoVersion = split[1]; - cryptoMode = split[2]; - } else if (split.length == 2) { - cryptoMode = split[1]; - } else { - cryptoMode = "CBC"; - } - - if (cryptoBase.equalsIgnoreCase("CAST")) { - realName = "CAST5"; - } else if (cryptoBase.equalsIgnoreCase("DES") && "EDE3".equalsIgnoreCase(cryptoVersion)) { - realName = "DESede"; - } else { - realName = cryptoBase; - } - - if (!BLOCK_MODES.contains(cryptoMode.toUpperCase())) { - cryptoVersion = cryptoMode; - cryptoMode = "CBC"; - } else if (cryptoMode.equalsIgnoreCase("CFB1")) { - // uglish SunJCE cryptoMode normalization. - cryptoMode = "CFB"; - } - - if (realName.equalsIgnoreCase("RC4")) { - realName = "RC4"; - cryptoMode = "NONE"; - paddingType = "NoPadding"; - } else { - realName = realName + "/" + cryptoMode + "/" + paddingType; - } - - return new String[]{cryptoBase, cryptoVersion, cryptoMode, realName, paddingType}; - } - - public static int[] osslKeyIvLength(String name) { - String[] values = Algorithm.osslToJsse(name); - String cryptoBase = values[0]; - String cryptoVersion = values[1]; - String cryptoMode = values[2]; - String realName = values[3]; - - int keyLen = -1; - int ivLen = -1; - - if (hasLen(cryptoBase) && null != cryptoVersion) { - try { - keyLen = Integer.parseInt(cryptoVersion) / 8; - } catch (NumberFormatException e) { - keyLen = -1; - } - } - if (keyLen == -1) { - if ("DES".equalsIgnoreCase(cryptoBase)) { - ivLen = 8; - if ("EDE3".equalsIgnoreCase(cryptoVersion)) { - keyLen = 24; - } else { - keyLen = 8; - } - } else if ("RC4".equalsIgnoreCase(cryptoBase)) { - ivLen = 0; - keyLen = 16; - } else { - keyLen = 16; - try { - if ((javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8) < keyLen) { - keyLen = javax.crypto.Cipher.getMaxAllowedKeyLength(name) / 8; - } - } catch (Exception e) { - // I hate checked exceptions - } - } - } - - if (ivLen == -1) { - if ("AES".equalsIgnoreCase(cryptoBase)) { - ivLen = 16; - } else { - ivLen = 8; - } - } - return new int[] { keyLen, ivLen }; - } - - public static boolean hasLen(String cryptoBase) { - return "AES".equalsIgnoreCase(cryptoBase) || "RC2".equalsIgnoreCase(cryptoBase) || "RC4".equalsIgnoreCase(cryptoBase); - } - } - - private static boolean tryCipher(final String rubyName) { - String cryptoMode = Algorithm.osslToJsse(rubyName, null)[3]; - try { - javax.crypto.Cipher.getInstance(cryptoMode); - return true; - } catch (NoSuchAlgorithmException nsae) { - try { - OpenSSLReal.getCipherBC(cryptoMode); - return true; - } catch (GeneralSecurityException gse) { - return false; - } - } catch (Exception e) { - return false; - } - } - - public Cipher(Ruby runtime, RubyClass type) { - super(runtime, type); - } - - private javax.crypto.Cipher ciph; - private String name; - private String cryptoBase; - private String cryptoVersion; - private String cryptoMode; - private String padding_type; - private String realName; - private int keyLen = -1; - private int generateKeyLen = -1; - private int ivLen = -1; - private boolean encryptMode = true; - //private IRubyObject[] modeParams; - private boolean ciphInited = false; - private byte[] key; - private byte[] realIV; - private byte[] orgIV; - private String padding; - - void dumpVars() { - System.out.println("***** Cipher instance vars ****"); - System.out.println("name = " + name); - System.out.println("cryptoBase = " + cryptoBase); - System.out.println("cryptoVersion = " + cryptoVersion); - System.out.println("cryptoMode = " + cryptoMode); - System.out.println("padding_type = " + padding_type); - System.out.println("realName = " + realName); - System.out.println("keyLen = " + keyLen); - System.out.println("ivLen = " + ivLen); - System.out.println("ciph block size = " + ciph.getBlockSize()); - System.out.println("encryptMode = " + encryptMode); - System.out.println("ciphInited = " + ciphInited); - System.out.println("key.length = " + (key == null ? 0 : key.length)); - System.out.println("iv.length = " + (this.realIV == null ? 0 : this.realIV.length)); - System.out.println("padding = " + padding); - System.out.println("ciphAlgo = " + ciph.getAlgorithm()); - System.out.println("*******************************"); - } - - @JRubyMethod(required = 1) - public IRubyObject initialize(IRubyObject str) { - name = str.toString(); - if (!CipherModule.isSupportedCipher(name)) { - throw newCipherError(getRuntime(), String.format("unsupported cipher algorithm (%s)", name)); - } - if (ciph != null) { - throw getRuntime().newRuntimeError("Cipher already inititalized!"); - } - updateCipher(name, padding); - return this; - } - - @Override - @JRubyMethod(required = 1) - public IRubyObject initialize_copy(IRubyObject obj) { - if (this == obj) { - return this; - } - - checkFrozen(); - - cryptoBase = ((Cipher) obj).cryptoBase; - cryptoVersion = ((Cipher) obj).cryptoVersion; - cryptoMode = ((Cipher) obj).cryptoMode; - padding_type = ((Cipher) obj).padding_type; - realName = ((Cipher) obj).realName; - name = ((Cipher) obj).name; - keyLen = ((Cipher) obj).keyLen; - ivLen = ((Cipher) obj).ivLen; - encryptMode = ((Cipher) obj).encryptMode; - ciphInited = false; - if (((Cipher) obj).key != null) { - key = new byte[((Cipher) obj).key.length]; - System.arraycopy(((Cipher) obj).key, 0, key, 0, key.length); - } else { - key = null; - } - if (((Cipher) obj).realIV != null) { - this.realIV = new byte[((Cipher) obj).realIV.length]; - System.arraycopy(((Cipher) obj).realIV, 0, this.realIV, 0, this.realIV.length); - } else { - this.realIV = null; - } - this.orgIV = this.realIV; - padding = ((Cipher) obj).padding; - - ciph = getCipher(); - - return this; - } - - @JRubyMethod - public IRubyObject name() { - return getRuntime().newString(name); - } - - @JRubyMethod - public IRubyObject key_len() { - return getRuntime().newFixnum(keyLen); - } - - @JRubyMethod - public IRubyObject iv_len() { - return getRuntime().newFixnum(ivLen); - } - - @JRubyMethod(name = "key_len=", required = 1) - public IRubyObject set_key_len(IRubyObject len) { - this.keyLen = RubyNumeric.fix2int(len); - return len; - } - - @JRubyMethod(name = "key=", required = 1) - public IRubyObject set_key(IRubyObject key) { - byte[] keyBytes; - try { - keyBytes = key.convertToString().getBytes(); - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - } - throw newCipherError(getRuntime(), e.getMessage()); - } - if (keyBytes.length < keyLen) { - throw newCipherError(getRuntime(), "key length to short"); - } - - if (keyBytes.length > keyLen) { - byte[] keys = new byte[keyLen]; - System.arraycopy(keyBytes, 0, keys, 0, keyLen); - keyBytes = keys; - } - - this.key = keyBytes; - return key; - } - - @JRubyMethod(name = "iv=", required = 1) - public IRubyObject set_iv(IRubyObject iv) { - byte[] ivBytes; - try { - ivBytes = iv.convertToString().getBytes(); - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - } - throw newCipherError(getRuntime(), e.getMessage()); - } - if (ivBytes.length < ivLen) { - throw newCipherError(getRuntime(), "iv length to short"); - } else { - // EVP_CipherInit_ex uses leading IV length of given sequence. - byte[] iv2 = new byte[ivLen]; - System.arraycopy(ivBytes, 0, iv2, 0, ivLen); - this.realIV = iv2; - } - this.orgIV = this.realIV; - if (!isStreamCipher()) { - ciphInited = false; - } - return iv; - } - - @JRubyMethod - public IRubyObject block_size() { - checkInitialized(); - if (isStreamCipher()) { - // getBlockSize() returns 0 for stream cipher in JCE. OpenSSL returns 1 for RC4. - return getRuntime().newFixnum(1); - } - return getRuntime().newFixnum(ciph.getBlockSize()); - } - - protected void init(IRubyObject[] args, boolean encrypt) { - org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); - - encryptMode = encrypt; - ciphInited = false; - - if (args.length > 0) { - /* - * oops. this code mistakes salt for IV. - * We deprecated the arguments for this method, but we decided - * keeping this behaviour for backward compatibility. - */ - byte[] pass = args[0].convertToString().getBytes(); - byte[] iv = null; - try { - iv = "OpenSSL for Ruby rulez!".getBytes("ISO8859-1"); - byte[] iv2 = new byte[this.ivLen]; - System.arraycopy(iv, 0, iv2, 0, this.ivLen); - iv = iv2; - } catch (Exception e) { - } - - if (args.length > 1 && !args[1].isNil()) { - getRuntime().getWarnings().warning(ID.MISCELLANEOUS, "key derivation by " + getMetaClass().getRealClass().getName() + "#encrypt is deprecated; use " + getMetaClass().getRealClass().getName() + "::pkcs5_keyivgen instead"); - iv = args[1].convertToString().getBytes(); - if (iv.length > this.ivLen) { - byte[] iv2 = new byte[this.ivLen]; - System.arraycopy(iv, 0, iv2, 0, this.ivLen); - iv = iv2; - } - } - - MessageDigest digest = Digest.getDigest("MD5", getRuntime()); - OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen, ivLen, digest, iv, pass, 2048); - this.key = result.getKey(); - this.realIV = iv; - this.orgIV = this.realIV; - } - } - - @JRubyMethod(optional = 2) - public IRubyObject encrypt(IRubyObject[] args) { - this.realIV = orgIV; - init(args, true); - return this; - } - - @JRubyMethod(optional = 2) - public IRubyObject decrypt(IRubyObject[] args) { - this.realIV = orgIV; - init(args, false); - return this; - } - - @JRubyMethod - public IRubyObject reset() { - checkInitialized(); - if (!isStreamCipher()) { - this.realIV = orgIV; - doInitialize(); - } - return this; - } - - private void updateCipher(String name, String padding) { - // given 'rc4' must be 'RC4' here. OpenSSL checks it as a LN of object - // ID and set SN. We don't check 'name' is allowed as a LN in ASN.1 for - // the possibility of JCE specific algorithm so just do upperCase here - // for OpenSSL compatibility. - this.name = name.toUpperCase(); - this.padding = padding; - - String[] values = Algorithm.osslToJsse(name, padding); - cryptoBase = values[0]; - cryptoVersion = values[1]; - cryptoMode = values[2]; - realName = values[3]; - padding_type = values[4]; - - int[] lengths = Algorithm.osslKeyIvLength(name); - keyLen = lengths[0]; - ivLen = lengths[1]; - if ("DES".equalsIgnoreCase(cryptoBase)) { - generateKeyLen = keyLen / 8 * 7; - } - - ciph = getCipher(); - } - - javax.crypto.Cipher getCipher() { - try { - return javax.crypto.Cipher.getInstance(realName); - } catch (NoSuchAlgorithmException e) { - try { - return OpenSSLReal.getCipherBC(realName); - } catch (GeneralSecurityException ignore) { - } - throw newCipherError(getRuntime(), "unsupported cipher algorithm (" + realName + ")"); - } catch (javax.crypto.NoSuchPaddingException e) { - throw newCipherError(getRuntime(), "unsupported cipher padding (" + realName + ")"); - } - } - - @JRubyMethod(required = 1, optional = 3) - public IRubyObject pkcs5_keyivgen(IRubyObject[] args) { - org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 4); - byte[] pass = args[0].convertToString().getBytes(); - byte[] salt = null; - int iter = 2048; - IRubyObject vdigest = getRuntime().getNil(); - if (args.length > 1) { - if (!args[1].isNil()) { - salt = args[1].convertToString().getBytes(); - } - if (args.length > 2) { - if (!args[2].isNil()) { - iter = RubyNumeric.fix2int(args[2]); - } - if (args.length > 3) { - vdigest = args[3]; - } - } - } - if (null != salt) { - if (salt.length != 8) { - throw newCipherError(getRuntime(), "salt must be an 8-octet string"); - } - } - - final String algorithm = vdigest.isNil() ? "MD5" : ((Digest) vdigest).getAlgorithm(); - MessageDigest digest = Digest.getDigest(algorithm, getRuntime()); - OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen, ivLen, digest, salt, pass, iter); - this.key = result.getKey(); - this.realIV = result.getIv(); - this.orgIV = this.realIV; - - doInitialize(); - - return getRuntime().getNil(); - } - - private void doInitialize() { - if (DEBUG) { - System.out.println("*** doInitialize"); - dumpVars(); - } - checkInitialized(); - if (key == null) { - throw newCipherError(getRuntime(), "key not specified"); - } - try { - if (!"ECB".equalsIgnoreCase(cryptoMode)) { - if (this.realIV == null) { - this.realIV = new byte[ivLen]; - System.arraycopy("OpenSSL for JRuby rulez".getBytes(), 0, - this.realIV, 0, ivLen); - } - if ("RC2".equalsIgnoreCase(cryptoBase)) { - this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey("RC2", this.key), new RC2ParameterSpec(this.key.length * 8, this.realIV)); - } else if ("RC4".equalsIgnoreCase(cryptoBase)) { - this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey("RC4", this.key)); - } else { - this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(realName.split("/")[0], this.key), new IvParameterSpec(this.realIV)); - } - } else { - this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(realName.split("/")[0], this.key)); - } - } catch (java.security.InvalidKeyException ike) { - throw newCipherError(getRuntime(), ike.getMessage() + ": possibly you need to install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for your JRE"); - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - } - throw newCipherError(getRuntime(), e.getMessage()); - } - ciphInited = true; - } - private byte[] lastIv = null; - - @JRubyMethod - public IRubyObject update(IRubyObject data) { - if (DEBUG) { - System.out.println("*** update [" + data + "]"); - } - checkInitialized(); - byte[] val = data.convertToString().getBytes(); - if (val.length == 0) { - throw getRuntime().newArgumentError("data must not be empty"); - } - - if (!ciphInited) { - if (DEBUG) { - System.out.println("BEFORE INITING"); - } - doInitialize(); - if (DEBUG) { - System.out.println("AFTER INITING"); - } - } - - byte[] str = new byte[0]; - try { - byte[] out = ciph.update(val); - if (out != null) { - str = out; - - if (this.realIV != null) { - if (lastIv == null) { - lastIv = new byte[ivLen]; - } - byte[] tmpIv = encryptMode ? out : val; - if (tmpIv.length >= ivLen) { - System.arraycopy(tmpIv, tmpIv.length - ivLen, lastIv, 0, ivLen); - } - } - } - } catch (Exception e) { - if (DEBUG) { - e.printStackTrace(); - } - throw newCipherError(getRuntime(), e.getMessage()); - } - - return getRuntime().newString(new ByteList(str, false)); - } - - @JRubyMethod(name = "<<") - public IRubyObject update_deprecated(IRubyObject data) { - getRuntime().getWarnings().warn(IRubyWarnings.ID.DEPRECATED_METHOD, "" + this.getMetaClass().getRealClass().getName() + "#<< is deprecated; use " + this.getMetaClass().getRealClass().getName() + "#update instead"); - return update(data); - } - - @JRubyMethod(name = "final") - public IRubyObject _final() { - checkInitialized(); - if (!ciphInited) { - doInitialize(); - } - // trying to allow update after final like cruby-openssl. Bad idea. - if ("RC4".equalsIgnoreCase(cryptoBase)) { - return getRuntime().newString(""); - } - ByteList str = new ByteList(ByteList.NULL_ARRAY); - try { - byte[] out = ciph.doFinal(); - if (out != null) { - str = new ByteList(out, false); - // TODO: Modifying this line appears to fix the issue, but I do - // not have a good reason for why. Best I can tell, lastIv needs - // to be set regardless of encryptMode, so we'll go with this - // for now. JRUBY-3335. - //if(this.realIV != null && encryptMode) { - if (this.realIV != null) { - if (lastIv == null) { - lastIv = new byte[ivLen]; - } - byte[] tmpIv = out; - if (tmpIv.length >= ivLen) { - System.arraycopy(tmpIv, tmpIv.length - ivLen, lastIv, 0, ivLen); - } - } - } - if (this.realIV != null) { - this.realIV = lastIv; - doInitialize(); - } - } catch (Exception e) { - throw newCipherError(getRuntime(), e.getMessage()); - } - return getRuntime().newString(str); - } - - @JRubyMethod(name = "padding=") - public IRubyObject set_padding(IRubyObject padding) { - updateCipher(name, padding.toString()); - return padding; - } - - String getAlgorithm() { - return this.ciph.getAlgorithm(); - } - - String getName() { - return this.name; - } - - String getCryptoBase() { - return this.cryptoBase; - } - - String getCryptoMode() { - return this.cryptoMode; - } - - int getKeyLen() { - return keyLen; - } - - int getGenerateKeyLen() { - return (generateKeyLen == -1) ? keyLen : generateKeyLen; - } - - private void checkInitialized() { - if (ciph == null) { - throw getRuntime().newRuntimeError("Cipher not inititalized!"); - } - } - - private boolean isStreamCipher() { - return ciph.getBlockSize() == 0; - } - - private static RaiseException newCipherError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::Cipher::CipherError", message); - } -} diff --git a/src/java/org/jruby/ext/openssl/CipherStrings.java b/src/java/org/jruby/ext/openssl/CipherStrings.java deleted file mode 100644 index 15cb992..0000000 --- a/src/java/org/jruby/ext/openssl/CipherStrings.java +++ /dev/null @@ -1,1856 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * - * @author Ola Bini - */ -public class CipherStrings { - public final static String SSL2_TXT_DES_64_CFB64_WITH_MD5_1 = "DES-CFB-M1"; - public final static String SSL2_TXT_NULL_WITH_MD5 = "NULL-MD5"; - public final static String SSL2_TXT_RC4_128_WITH_MD5 = "RC4-MD5"; - public final static String SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 = "EXP-RC4-MD5"; - public final static String SSL2_TXT_RC2_128_CBC_WITH_MD5 = "RC2-CBC-MD5"; - public final static String SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 = "EXP-RC2-CBC-MD5"; - public final static String SSL2_TXT_IDEA_128_CBC_WITH_MD5 = "IDEA-CBC-MD5"; - public final static String SSL2_TXT_DES_64_CBC_WITH_MD5 = "DES-CBC-MD5"; - public final static String SSL2_TXT_DES_64_CBC_WITH_SHA = "DES-CBC-SHA"; - public final static String SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 = "DES-CBC3-MD5"; - public final static String SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA = "DES-CBC3-SHA"; - public final static String SSL2_TXT_RC4_64_WITH_MD5 = "RC4-64-MD5"; - public final static String SSL2_TXT_NULL = "NULL"; - - public final static String SSL3_TXT_RSA_NULL_MD5 = "NULL-MD5"; - public final static String SSL3_TXT_RSA_NULL_SHA = "NULL-SHA"; - public final static String SSL3_TXT_RSA_RC4_40_MD5 = "EXP-RC4-MD5"; - public final static String SSL3_TXT_RSA_RC4_128_MD5 = "RC4-MD5"; - public final static String SSL3_TXT_RSA_RC4_128_SHA = "RC4-SHA"; - public final static String SSL3_TXT_RSA_RC2_40_MD5 = "EXP-RC2-CBC-MD5"; - public final static String SSL3_TXT_RSA_IDEA_128_SHA = "IDEA-CBC-SHA"; - public final static String SSL3_TXT_RSA_DES_40_CBC_SHA = "EXP-DES-CBC-SHA"; - public final static String SSL3_TXT_RSA_DES_64_CBC_SHA = "DES-CBC-SHA"; - public final static String SSL3_TXT_RSA_DES_192_CBC3_SHA = "DES-CBC3-SHA"; - public final static String SSL3_TXT_DH_DSS_DES_40_CBC_SHA = "EXP-DH-DSS-DES-CBC-SHA"; - public final static String SSL3_TXT_DH_DSS_DES_64_CBC_SHA = "DH-DSS-DES-CBC-SHA"; - public final static String SSL3_TXT_DH_DSS_DES_192_CBC3_SHA = "DH-DSS-DES-CBC3-SHA"; - public final static String SSL3_TXT_DH_RSA_DES_40_CBC_SHA = "EXP-DH-RSA-DES-CBC-SHA"; - public final static String SSL3_TXT_DH_RSA_DES_64_CBC_SHA = "DH-RSA-DES-CBC-SHA"; - public final static String SSL3_TXT_DH_RSA_DES_192_CBC3_SHA = "DH-RSA-DES-CBC3-SHA"; - public final static String SSL3_TXT_EDH_DSS_DES_40_CBC_SHA = "EXP-EDH-DSS-DES-CBC-SHA"; - public final static String SSL3_TXT_EDH_DSS_DES_64_CBC_SHA = "EDH-DSS-DES-CBC-SHA"; - public final static String SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA = "EDH-DSS-DES-CBC3-SHA"; - public final static String SSL3_TXT_EDH_RSA_DES_40_CBC_SHA = "EXP-EDH-RSA-DES-CBC-SHA"; - public final static String SSL3_TXT_EDH_RSA_DES_64_CBC_SHA = "EDH-RSA-DES-CBC-SHA"; - public final static String SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA = "EDH-RSA-DES-CBC3-SHA"; - public final static String SSL3_TXT_ADH_RC4_40_MD5 = "EXP-ADH-RC4-MD5"; - public final static String SSL3_TXT_ADH_RC4_128_MD5 = "ADH-RC4-MD5"; - public final static String SSL3_TXT_ADH_DES_40_CBC_SHA = "EXP-ADH-DES-CBC-SHA"; - public final static String SSL3_TXT_ADH_DES_64_CBC_SHA = "ADH-DES-CBC-SHA"; - public final static String SSL3_TXT_ADH_DES_192_CBC_SHA = "ADH-DES-CBC3-SHA"; - public final static String SSL3_TXT_FZA_DMS_NULL_SHA = "FZA-NULL-SHA"; - public final static String SSL3_TXT_FZA_DMS_FZA_SHA = "FZA-FZA-CBC-SHA"; - public final static String SSL3_TXT_FZA_DMS_RC4_SHA = "FZA-RC4-SHA"; - public final static String SSL3_TXT_KRB5_DES_64_CBC_SHA = "KRB5-DES-CBC-SHA"; - public final static String SSL3_TXT_KRB5_DES_192_CBC3_SHA = "KRB5-DES-CBC3-SHA"; - public final static String SSL3_TXT_KRB5_RC4_128_SHA = "KRB5-RC4-SHA"; - public final static String SSL3_TXT_KRB5_IDEA_128_CBC_SHA = "KRB5-IDEA-CBC-SHA"; - public final static String SSL3_TXT_KRB5_DES_64_CBC_MD5 = "KRB5-DES-CBC-MD5"; - public final static String SSL3_TXT_KRB5_DES_192_CBC3_MD5 = "KRB5-DES-CBC3-MD5"; - public final static String SSL3_TXT_KRB5_RC4_128_MD5 = "KRB5-RC4-MD5"; - public final static String SSL3_TXT_KRB5_IDEA_128_CBC_MD5 = "KRB5-IDEA-CBC-MD5"; - public final static String SSL3_TXT_KRB5_DES_40_CBC_SHA = "EXP-KRB5-DES-CBC-SHA"; - public final static String SSL3_TXT_KRB5_RC2_40_CBC_SHA = "EXP-KRB5-RC2-CBC-SHA"; - public final static String SSL3_TXT_KRB5_RC4_40_SHA = "EXP-KRB5-RC4-SHA"; - public final static String SSL3_TXT_KRB5_DES_40_CBC_MD5 = "EXP-KRB5-DES-CBC-MD5"; - public final static String SSL3_TXT_KRB5_RC2_40_CBC_MD5 = "EXP-KRB5-RC2-CBC-MD5"; - public final static String SSL3_TXT_KRB5_RC4_40_MD5 = "EXP-KRB5-RC4-MD5"; - - public final static String SSL_TXT_NULL_WITH_MD5 = SSL2_TXT_NULL_WITH_MD5; - public final static String SSL_TXT_RC4_128_WITH_MD5 = SSL2_TXT_RC4_128_WITH_MD5; - public final static String SSL_TXT_RC4_128_EXPORT40_WITH_MD5 = SSL2_TXT_RC4_128_EXPORT40_WITH_MD5; - public final static String SSL_TXT_RC2_128_CBC_WITH_MD5 = SSL2_TXT_RC2_128_CBC_WITH_MD5; - public final static String SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 = SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5; - public final static String SSL_TXT_IDEA_128_CBC_WITH_MD5 = SSL2_TXT_IDEA_128_CBC_WITH_MD5; - public final static String SSL_TXT_DES_64_CBC_WITH_MD5 = SSL2_TXT_DES_64_CBC_WITH_MD5; - public final static String SSL_TXT_DES_64_CBC_WITH_SHA = SSL2_TXT_DES_64_CBC_WITH_SHA; - public final static String SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 = SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5; - public final static String SSL_TXT_DES_192_EDE3_CBC_WITH_SHA = SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA; - - public final static String SSL_TXT_KRB5_DES_64_CBC_SHA = SSL3_TXT_KRB5_DES_64_CBC_SHA; - public final static String SSL_TXT_KRB5_DES_192_CBC3_SHA = SSL3_TXT_KRB5_DES_192_CBC3_SHA; - public final static String SSL_TXT_KRB5_RC4_128_SHA = SSL3_TXT_KRB5_RC4_128_SHA; - public final static String SSL_TXT_KRB5_IDEA_128_CBC_SHA = SSL3_TXT_KRB5_IDEA_128_CBC_SHA; - public final static String SSL_TXT_KRB5_DES_64_CBC_MD5 = SSL3_TXT_KRB5_DES_64_CBC_MD5; - public final static String SSL_TXT_KRB5_DES_192_CBC3_MD5 = SSL3_TXT_KRB5_DES_192_CBC3_MD5; - public final static String SSL_TXT_KRB5_RC4_128_MD5 = SSL3_TXT_KRB5_RC4_128_MD5; - public final static String SSL_TXT_KRB5_IDEA_128_CBC_MD5 = SSL3_TXT_KRB5_IDEA_128_CBC_MD5; - - public final static String SSL_TXT_KRB5_DES_40_CBC_SHA = SSL3_TXT_KRB5_DES_40_CBC_SHA; - public final static String SSL_TXT_KRB5_RC2_40_CBC_SHA = SSL3_TXT_KRB5_RC2_40_CBC_SHA; - public final static String SSL_TXT_KRB5_RC4_40_SHA = SSL3_TXT_KRB5_RC4_40_SHA; - public final static String SSL_TXT_KRB5_DES_40_CBC_MD5 = SSL3_TXT_KRB5_DES_40_CBC_MD5; - public final static String SSL_TXT_KRB5_RC2_40_CBC_MD5 = SSL3_TXT_KRB5_RC2_40_CBC_MD5; - public final static String SSL_TXT_KRB5_RC4_40_MD5 = SSL3_TXT_KRB5_RC4_40_MD5; - - public final static String SSL_TXT_LOW = "LOW"; - public final static String SSL_TXT_MEDIUM = "MEDIUM"; - public final static String SSL_TXT_HIGH = "HIGH"; - public final static String SSL_TXT_kFZA = "kFZA"; - public final static String SSL_TXT_aFZA = "aFZA"; - public final static String SSL_TXT_eFZA = "eFZA"; - public final static String SSL_TXT_FZA = "FZA"; - - public final static String SSL_TXT_aNULL = "aNULL"; - public final static String SSL_TXT_eNULL = "eNULL"; - public final static String SSL_TXT_NULL = "NULL"; - - public final static String SSL_TXT_kKRB5 = "kKRB5"; - public final static String SSL_TXT_aKRB5 = "aKRB5"; - public final static String SSL_TXT_KRB5 = "KRB5"; - - public final static String SSL_TXT_kRSA = "kRSA"; - public final static String SSL_TXT_kDHr = "kDHr"; - public final static String SSL_TXT_kDHd = "kDHd"; - public final static String SSL_TXT_kEDH = "kEDH"; - public final static String SSL_TXT_aRSA = "aRSA"; - public final static String SSL_TXT_aDSS = "aDSS"; - public final static String SSL_TXT_aDH = "aDH"; - public final static String SSL_TXT_DSS = "DSS"; - public final static String SSL_TXT_DH = "DH"; - public final static String SSL_TXT_EDH = "EDH"; - public final static String SSL_TXT_ADH = "ADH"; - public final static String SSL_TXT_RSA = "RSA"; - public final static String SSL_TXT_DES = "DES"; - public final static String SSL_TXT_3DES = "3DES"; - public final static String SSL_TXT_RC4 = "RC4"; - public final static String SSL_TXT_RC2 = "RC2"; - public final static String SSL_TXT_IDEA = "IDEA"; - public final static String SSL_TXT_AES = "AES"; - public final static String SSL_TXT_MD5 = "MD5"; - public final static String SSL_TXT_SHA1 = "SHA1"; - public final static String SSL_TXT_SHA = "SHA"; - public final static String SSL_TXT_EXP = "EXP"; - public final static String SSL_TXT_EXPORT = "EXPORT"; - public final static String SSL_TXT_EXP40 = "EXPORT40"; - public final static String SSL_TXT_EXP56 = "EXPORT56"; - public final static String SSL_TXT_SSLV2 = "SSLv2"; - public final static String SSL_TXT_SSLV3 = "SSLv3"; - public final static String SSL_TXT_TLSV1 = "TLSv1"; - public final static String SSL_TXT_ALL = "ALL"; - public final static String SSL_TXT_ECC = "ECCdraft"; - - public final static String SSL_TXT_CMPALL = "COMPLEMENTOFALL"; - public final static String SSL_TXT_CMPDEF = "COMPLEMENTOFDEFAULT"; - - // "ALL:!aNULL:!eNULL:!SSLv2" is for OpenSSL 1.0.0 GA - public final static String SSL_DEFAULT_CIPHER_LIST = "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH"; - - public final static long SSL_MKEY_MASK = 0x000000FFL; - public final static long SSL_kRSA = 0x00000001L; - public final static long SSL_kDHr = 0x00000002L; - public final static long SSL_kDHd = 0x00000004L; - public final static long SSL_kFZA = 0x00000008L; - public final static long SSL_kEDH = 0x00000010L; - public final static long SSL_kKRB5 = 0x00000020L; - public final static long SSL_kECDH = 0x00000040L; - public final static long SSL_kECDHE = 0x00000080L; - public final static long SSL_aNULL = 0x00000800L; - public final static long SSL_AUTH_MASK = 0x00007F00L; - public final static long SSL_EDH = (SSL_kEDH|(SSL_AUTH_MASK^SSL_aNULL)); - public final static long SSL_aRSA = 0x00000100L; - public final static long SSL_aDSS = 0x00000200L; - public final static long SSL_DSS = SSL_aDSS; - public final static long SSL_aFZA = 0x00000400L; - public final static long SSL_aDH = 0x00001000L; - public final static long SSL_aKRB5 = 0x00002000L; - public final static long SSL_aECDSA = 0x00004000L; - public final static long SSL_eNULL = 0x00200000L; - public final static long SSL_eFZA = 0x00100000L; - public final static long SSL_NULL = (SSL_eNULL); - public final static long SSL_ADH = (SSL_kEDH|SSL_aNULL); - public final static long SSL_RSA = (SSL_kRSA|SSL_aRSA); - public final static long SSL_DH = (SSL_kDHr|SSL_kDHd|SSL_kEDH); - public final static long SSL_ECDH = (SSL_kECDH|SSL_kECDHE); - public final static long SSL_FZA = (SSL_aFZA|SSL_kFZA|SSL_eFZA); - public final static long SSL_KRB5 = (SSL_kKRB5|SSL_aKRB5); - public final static long SSL_ENC_MASK = 0x043F8000L; - public final static long SSL_DES = 0x00008000L; - public final static long SSL_3DES = 0x00010000L; - public final static long SSL_RC4 = 0x00020000L; - public final static long SSL_RC2 = 0x00040000L; - public final static long SSL_IDEA = 0x00080000L; - public final static long SSL_AES = 0x04000000L; - public final static long SSL_MAC_MASK = 0x00c00000L; - public final static long SSL_MD5 = 0x00400000L; - public final static long SSL_SHA1 = 0x00800000L; - public final static long SSL_SHA = (SSL_SHA1); - public final static long SSL_SSL_MASK = 0x03000000L; - public final static long SSL_SSLV2 = 0x01000000L; - public final static long SSL_SSLV3 = 0x02000000L; - public final static long SSL_TLSV1 = SSL_SSLV3; - public final static long SSL_EXP_MASK = 0x00000003L; - public final static long SSL_NOT_EXP = 0x00000001L; - public final static long SSL_EXPORT = 0x00000002L; - public final static long SSL_STRONG_MASK = 0x000000fcL; - public final static long SSL_STRONG_NONE = 0x00000004L; - public final static long SSL_EXP40 = 0x00000008L; - public final static long SSL_MICRO = (SSL_EXP40); - public final static long SSL_EXP56 = 0x00000010L; - public final static long SSL_MINI = (SSL_EXP56); - public final static long SSL_LOW = 0x00000020L; - public final static long SSL_MEDIUM = 0x00000040L; - public final static long SSL_HIGH = 0x00000080L; - public final static long SSL_ALL = 0xffffffffL; - public final static long SSL_ALL_CIPHERS = (SSL_MKEY_MASK|SSL_AUTH_MASK|SSL_ENC_MASK|SSL_MAC_MASK); - public final static long SSL_ALL_STRENGTHS = (SSL_EXP_MASK|SSL_STRONG_MASK); - public final static long SSL_PKEY_RSA_ENC = 0; - public final static long SSL_PKEY_RSA_SIGN = 1; - public final static long SSL_PKEY_DSA_SIGN = 2; - public final static long SSL_PKEY_DH_RSA = 3; - public final static long SSL_PKEY_DH_DSA = 4; - public final static long SSL_PKEY_ECC = 5; - public final static long SSL_PKEY_NUM = 6; - - public final static long SSL3_CK_RSA_NULL_MD5 = 0x03000001; - public final static long SSL3_CK_RSA_NULL_SHA = 0x03000002; - public final static long SSL3_CK_RSA_RC4_40_MD5 = 0x03000003; - public final static long SSL3_CK_RSA_RC4_128_MD5 = 0x03000004; - public final static long SSL3_CK_RSA_RC4_128_SHA = 0x03000005; - public final static long SSL3_CK_RSA_RC2_40_MD5 = 0x03000006; - public final static long SSL3_CK_RSA_IDEA_128_SHA = 0x03000007; - public final static long SSL3_CK_RSA_DES_40_CBC_SHA = 0x03000008; - public final static long SSL3_CK_RSA_DES_64_CBC_SHA = 0x03000009; - public final static long SSL3_CK_RSA_DES_192_CBC3_SHA = 0x0300000A; - public final static long SSL3_CK_DH_DSS_DES_40_CBC_SHA = 0x0300000B; - public final static long SSL3_CK_DH_DSS_DES_64_CBC_SHA = 0x0300000C; - public final static long SSL3_CK_DH_DSS_DES_192_CBC3_SHA = 0x0300000D; - public final static long SSL3_CK_DH_RSA_DES_40_CBC_SHA = 0x0300000E; - public final static long SSL3_CK_DH_RSA_DES_64_CBC_SHA = 0x0300000F; - public final static long SSL3_CK_DH_RSA_DES_192_CBC3_SHA = 0x03000010; - public final static long SSL3_CK_EDH_DSS_DES_40_CBC_SHA = 0x03000011; - public final static long SSL3_CK_EDH_DSS_DES_64_CBC_SHA = 0x03000012; - public final static long SSL3_CK_EDH_DSS_DES_192_CBC3_SHA = 0x03000013; - public final static long SSL3_CK_EDH_RSA_DES_40_CBC_SHA = 0x03000014; - public final static long SSL3_CK_EDH_RSA_DES_64_CBC_SHA = 0x03000015; - public final static long SSL3_CK_EDH_RSA_DES_192_CBC3_SHA = 0x03000016; - public final static long SSL3_CK_ADH_RC4_40_MD5 = 0x03000017; - public final static long SSL3_CK_ADH_RC4_128_MD5 = 0x03000018; - public final static long SSL3_CK_ADH_DES_40_CBC_SHA = 0x03000019; - public final static long SSL3_CK_ADH_DES_64_CBC_SHA = 0x0300001A; - public final static long SSL3_CK_ADH_DES_192_CBC_SHA = 0x0300001B; - public final static long SSL3_CK_FZA_DMS_NULL_SHA = 0x0300001C; - public final static long SSL3_CK_FZA_DMS_FZA_SHA = 0x0300001D; - public final static long SSL3_CK_KRB5_DES_64_CBC_SHA = 0x0300001E; - public final static long SSL3_CK_KRB5_DES_192_CBC3_SHA = 0x0300001F; - public final static long SSL3_CK_KRB5_RC4_128_SHA = 0x03000020; - public final static long SSL3_CK_KRB5_IDEA_128_CBC_SHA = 0x03000021; - public final static long SSL3_CK_KRB5_DES_64_CBC_MD5 = 0x03000022; - public final static long SSL3_CK_KRB5_DES_192_CBC3_MD5 = 0x03000023; - public final static long SSL3_CK_KRB5_RC4_128_MD5 = 0x03000024; - public final static long SSL3_CK_KRB5_IDEA_128_CBC_MD5 = 0x03000025; - public final static long SSL3_CK_KRB5_DES_40_CBC_SHA = 0x03000026; - public final static long SSL3_CK_KRB5_RC2_40_CBC_SHA = 0x03000027; - public final static long SSL3_CK_KRB5_RC4_40_SHA = 0x03000028; - public final static long SSL3_CK_KRB5_DES_40_CBC_MD5 = 0x03000029; - public final static long SSL3_CK_KRB5_RC2_40_CBC_MD5 = 0x0300002A; - public final static long SSL3_CK_KRB5_RC4_40_MD5 = 0x0300002B; - - - public final static long TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 = 0x03000060; - public final static long TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 = 0x03000061; - public final static long TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA = 0x03000062; - public final static long TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = 0x03000063; - public final static long TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA = 0x03000064; - public final static long TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA = 0x03000065; - public final static long TLS1_CK_DHE_DSS_WITH_RC4_128_SHA = 0x03000066; - public final static long TLS1_CK_RSA_WITH_AES_128_SHA = 0x0300002F; - public final static long TLS1_CK_DH_DSS_WITH_AES_128_SHA = 0x03000030; - public final static long TLS1_CK_DH_RSA_WITH_AES_128_SHA = 0x03000031; - public final static long TLS1_CK_DHE_DSS_WITH_AES_128_SHA = 0x03000032; - public final static long TLS1_CK_DHE_RSA_WITH_AES_128_SHA = 0x03000033; - public final static long TLS1_CK_ADH_WITH_AES_128_SHA = 0x03000034; - public final static long TLS1_CK_RSA_WITH_AES_256_SHA = 0x03000035; - public final static long TLS1_CK_DH_DSS_WITH_AES_256_SHA = 0x03000036; - public final static long TLS1_CK_DH_RSA_WITH_AES_256_SHA = 0x03000037; - public final static long TLS1_CK_DHE_DSS_WITH_AES_256_SHA = 0x03000038; - public final static long TLS1_CK_DHE_RSA_WITH_AES_256_SHA = 0x03000039; - public final static long TLS1_CK_ADH_WITH_AES_256_SHA = 0x0300003A; - public final static long TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA = 0x0300C001; - public final static long TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA = 0x0300C002; - public final static long TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA = 0x0300C003; - public final static long TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0x0300C004; - public final static long TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0x0300C005; - public final static long TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA = 0x0300C006; - public final static long TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA = 0x0300C007; - public final static long TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA = 0x0300C008; - public final static long TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0x0300C009; - public final static long TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0x0300C00A; - public final static long TLS1_CK_ECDH_RSA_WITH_NULL_SHA = 0x0300C00B; - public final static long TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA = 0x0300C00C; - public final static long TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA = 0x0300C00D; - public final static long TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA = 0x0300C00E; - public final static long TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA = 0x0300C00F; - public final static long TLS1_CK_ECDHE_RSA_WITH_NULL_SHA = 0x0300C010; - public final static long TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA = 0x0300C011; - public final static long TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA = 0x0300C012; - public final static long TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0x0300C013; - public final static long TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0x0300C014; - public final static long TLS1_CK_ECDH_anon_WITH_NULL_SHA = 0x0300C015; - public final static long TLS1_CK_ECDH_anon_WITH_RC4_128_SHA = 0x0300C016; - public final static long TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA = 0x0300C017; - public final static long TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA = 0x0300C018; - public final static long TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA = 0x0300C019; - - public final static String TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 = "EXP1024-RC4-MD5"; - public final static String TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 = "EXP1024-RC2-CBC-MD5"; - public final static String TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA = "EXP1024-DES-CBC-SHA"; - public final static String TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = "EXP1024-DHE-DSS-DES-CBC-SHA"; - public final static String TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA = "EXP1024-RC4-SHA"; - public final static String TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA = "EXP1024-DHE-DSS-RC4-SHA"; - public final static String TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA = "DHE-DSS-RC4-SHA"; - public final static String TLS1_TXT_RSA_WITH_AES_128_SHA = "AES128-SHA"; - public final static String TLS1_TXT_DH_DSS_WITH_AES_128_SHA = "DH-DSS-AES128-SHA"; - public final static String TLS1_TXT_DH_RSA_WITH_AES_128_SHA = "DH-RSA-AES128-SHA"; - public final static String TLS1_TXT_DHE_DSS_WITH_AES_128_SHA = "DHE-DSS-AES128-SHA"; - public final static String TLS1_TXT_DHE_RSA_WITH_AES_128_SHA = "DHE-RSA-AES128-SHA"; - public final static String TLS1_TXT_ADH_WITH_AES_128_SHA = "ADH-AES128-SHA"; - public final static String TLS1_TXT_RSA_WITH_AES_256_SHA = "AES256-SHA"; - public final static String TLS1_TXT_DH_DSS_WITH_AES_256_SHA = "DH-DSS-AES256-SHA"; - public final static String TLS1_TXT_DH_RSA_WITH_AES_256_SHA = "DH-RSA-AES256-SHA"; - public final static String TLS1_TXT_DHE_DSS_WITH_AES_256_SHA = "DHE-DSS-AES256-SHA"; - public final static String TLS1_TXT_DHE_RSA_WITH_AES_256_SHA = "DHE-RSA-AES256-SHA"; - public final static String TLS1_TXT_ADH_WITH_AES_256_SHA = "ADH-AES256-SHA"; - public final static String TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA = "ECDH-ECDSA-NULL-SHA"; - public final static String TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA = "ECDH-ECDSA-RC4-SHA"; - public final static String TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA = "ECDH-ECDSA-DES-CBC3-SHA"; - public final static String TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA = "ECDH-ECDSA-AES128-SHA"; - public final static String TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA = "ECDH-ECDSA-AES256-SHA"; - public final static String TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA = "ECDHE-ECDSA-NULL-SHA"; - public final static String TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA = "ECDHE-ECDSA-RC4-SHA"; - public final static String TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA = "ECDHE-ECDSA-DES-CBC3-SHA"; - public final static String TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = "ECDHE-ECDSA-AES128-SHA"; - public final static String TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = "ECDHE-ECDSA-AES256-SHA"; - public final static String TLS1_TXT_ECDH_RSA_WITH_NULL_SHA = "ECDH-RSA-NULL-SHA"; - public final static String TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA = "ECDH-RSA-RC4-SHA"; - public final static String TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA = "ECDH-RSA-DES-CBC3-SHA"; - public final static String TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA = "ECDH-RSA-AES128-SHA"; - public final static String TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA = "ECDH-RSA-AES256-SHA"; - public final static String TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA = "ECDHE-RSA-NULL-SHA"; - public final static String TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA = "ECDHE-RSA-RC4-SHA"; - public final static String TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA = "ECDHE-RSA-DES-CBC3-SHA"; - public final static String TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA = "ECDHE-RSA-AES128-SHA"; - public final static String TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA = "ECDHE-RSA-AES256-SHA"; - public final static String TLS1_TXT_ECDH_anon_WITH_NULL_SHA = "AECDH-NULL-SHA"; - public final static String TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA = "AECDH-RC4-SHA"; - public final static String TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA = "AECDH-DES-CBC3-SHA"; - public final static String TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA = "AECDH-AES128-SHA"; - public final static String TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA = "AECDH-AES256-SHA"; - - public static class Def { - public final int valid; - public final String name; - public final long id; - public final long algorithms; - public final long algo_strength; - public final long algorithm2; - public final int strength_bits; - public final int alg_bits; - public final long mask; - public final long mask_strength; - public String cipherSuite; - public Def(int valid, String name, long id, long algorithms, long algo_strength, long algorithm2, int strength_bits, int alg_bits, long mask, long mask_strength) { - this.valid = valid; - this.name = name; - this.id = id; - this.algorithms = algorithms; - this.algo_strength = algo_strength; - this.algorithm2 = algorithm2; - this.strength_bits = strength_bits; - this.alg_bits = alg_bits; - this.mask = mask; - this.mask_strength = mask_strength; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object other) { - boolean ret = this == other; - if(!ret && (other instanceof Def)) { - ret = this.name.equals(((Def)other).name); - } - return ret; - } - - @Override - public String toString() { - return "Cipher<" + name + ">"; - } - - // from ssl_cipher_apply_rule - public boolean matches(Def current) { -// ma = mask & cp->algorithms; -// ma_s = mask_strength & cp->algo_strength; -// -// // Select: if none of the mask bit was met from the -// // cipher or not all of the bits were met, the -// // selection does not apply. -// if (((ma == 0) && (ma_s == 0)) || -// ((ma & algorithms) != ma) || -// ((ma_s & algo_strength) != ma_s)) -// continue; // does not apply -// } - long ma = mask & current.algorithms; - long ma_s = mask_strength & current.algo_strength; - if (((ma == 0) && (ma_s == 0)) || - ((ma & algorithms) != ma) || - ((ma_s & algo_strength) != ma_s)) { - return false; - } - return true; - } - } - - public final static Map Definitions = new HashMap(); - public final static List Ciphers = new ArrayList(); - public final static Map CipherNames = new HashMap(); - public final static Map SuiteToOSSL = new HashMap(); - - public static List getMatchingCiphers(String str, String[] all) { - String[] parts = str.split("[:, ]+"); - List currentList = new ArrayList(); - Set removed = new HashSet(); - - for (String part : parts) { - if (part.equals("@STRENGTH")) { - Collections.sort(currentList, new Comparator() { - - public int compare(Def first, Def second) { - return second.strength_bits - first.strength_bits; - } - }); - continue; - } - int index = 0; - switch (part.charAt(0)) { - case '!': - index++; - break; - case '+': - index++; - break; - case '-': - index++; - break; - } - List matching = getMatching(part.substring(index), all); - if (matching != null) { - if (index > 0) { - switch (part.charAt(0)) { - case '!': - currentList.removeAll(matching); - removed.addAll(matching); - break; - case '+': // '+' is for moving entry in the list. - for (Def ele : matching) { - if (!removed.contains(ele) && currentList.contains(ele)) { - currentList.remove(ele); - currentList.add(ele); - } - } - break; - case '-': - currentList.removeAll(matching); - break; - } - } else { - for (Def ele : matching) { - if (!removed.contains(ele) && !currentList.contains(ele)) { - currentList.add(ele); - } - } - } - } - } - return currentList; - } - - private static List getMatching(String definition, String[] all) { - List matching = null; - for (String name : definition.split("[+]")) { - Def pattern = Definitions.get(name); - if (pattern != null) { - if (matching == null) { - matching = getMatchingPattern(pattern, all); - } else { - List updated = new ArrayList(); - for (Def ele : getMatchingPattern(pattern, all)) { - if (matching.contains(ele)) { - updated.add(ele); - } - } - matching = updated; - } - } - } - return matching; - } - - private static List getMatchingPattern(Def pattern, String[] all) { - List matching = new ArrayList(); - for (String entry : all) { - String ossl = SuiteToOSSL.get(entry); - if (ossl != null) { - Def def = CipherNames.get(ossl); - if (def != null) { - def.cipherSuite = entry; - if (pattern.matches(def)) { - matching.add(def); - } - } - } - } - return matching; - } - - private static void addAlias(String cipherSuite, String ossl) { - SuiteToOSSL.put(cipherSuite, ossl); - } - - static { - Definitions.put(SSL_TXT_ALL,new Def(0,SSL_TXT_ALL, 0,SSL_ALL & ~SSL_eNULL & ~SSL_kECDH & ~SSL_kECDHE, SSL_ALL ,0,0,0,SSL_ALL,SSL_ALL)); - Definitions.put(SSL_TXT_CMPALL,new Def(0,SSL_TXT_CMPALL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_CMPDEF,new Def(0,SSL_TXT_CMPDEF,0,SSL_ADH, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_kKRB5,new Def(0,SSL_TXT_kKRB5,0,SSL_kKRB5,0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_kRSA,new Def(0,SSL_TXT_kRSA,0,SSL_kRSA, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_kDHr,new Def(0,SSL_TXT_kDHr,0,SSL_kDHr, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_kDHd,new Def(0,SSL_TXT_kDHd,0,SSL_kDHd, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_kEDH,new Def(0,SSL_TXT_kEDH,0,SSL_kEDH, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_kFZA,new Def(0,SSL_TXT_kFZA,0,SSL_kFZA, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_DH,new Def(0,SSL_TXT_DH, 0,SSL_DH, 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_ECC,new Def(0,SSL_TXT_ECC, 0,(SSL_kECDH|SSL_kECDHE), 0,0,0,0,SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_EDH,new Def(0,SSL_TXT_EDH, 0,SSL_EDH, 0,0,0,0,SSL_MKEY_MASK|SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aKRB5,new Def(0,SSL_TXT_aKRB5,0,SSL_aKRB5,0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aRSA,new Def(0,SSL_TXT_aRSA,0,SSL_aRSA, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aDSS,new Def(0,SSL_TXT_aDSS,0,SSL_aDSS, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aFZA,new Def(0,SSL_TXT_aFZA,0,SSL_aFZA, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aNULL,new Def(0,SSL_TXT_aNULL,0,SSL_aNULL,0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_aDH,new Def(0,SSL_TXT_aDH, 0,SSL_aDH, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_DSS,new Def(0,SSL_TXT_DSS, 0,SSL_DSS, 0,0,0,0,SSL_AUTH_MASK,0)); - Definitions.put(SSL_TXT_DES,new Def(0,SSL_TXT_DES, 0,SSL_DES, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_3DES,new Def(0,SSL_TXT_3DES,0,SSL_3DES, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_RC4,new Def(0,SSL_TXT_RC4, 0,SSL_RC4, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_RC2,new Def(0,SSL_TXT_RC2, 0,SSL_RC2, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_IDEA,new Def(0,SSL_TXT_IDEA,0,SSL_IDEA, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_eNULL,new Def(0,SSL_TXT_eNULL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_eFZA,new Def(0,SSL_TXT_eFZA,0,SSL_eFZA, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_AES,new Def(0,SSL_TXT_AES, 0,SSL_AES, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_MD5,new Def(0,SSL_TXT_MD5, 0,SSL_MD5, 0,0,0,0,SSL_MAC_MASK,0)); - Definitions.put(SSL_TXT_SHA1,new Def(0,SSL_TXT_SHA1,0,SSL_SHA1, 0,0,0,0,SSL_MAC_MASK,0)); - Definitions.put(SSL_TXT_SHA,new Def(0,SSL_TXT_SHA, 0,SSL_SHA, 0,0,0,0,SSL_MAC_MASK,0)); - Definitions.put(SSL_TXT_NULL,new Def(0,SSL_TXT_NULL,0,SSL_NULL, 0,0,0,0,SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_KRB5,new Def(0,SSL_TXT_KRB5,0,SSL_KRB5, 0,0,0,0,SSL_AUTH_MASK|SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_RSA,new Def(0,SSL_TXT_RSA, 0,SSL_RSA, 0,0,0,0,SSL_AUTH_MASK|SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_ADH,new Def(0,SSL_TXT_ADH, 0,SSL_ADH, 0,0,0,0,SSL_AUTH_MASK|SSL_MKEY_MASK,0)); - Definitions.put(SSL_TXT_FZA,new Def(0,SSL_TXT_FZA, 0,SSL_FZA, 0,0,0,0,SSL_AUTH_MASK|SSL_MKEY_MASK|SSL_ENC_MASK,0)); - Definitions.put(SSL_TXT_SSLV2,new Def(0,SSL_TXT_SSLV2, 0,SSL_SSLV2, 0,0,0,0,SSL_SSL_MASK,0)); - Definitions.put(SSL_TXT_SSLV3,new Def(0,SSL_TXT_SSLV3, 0,SSL_SSLV3, 0,0,0,0,SSL_SSL_MASK,0)); - Definitions.put(SSL_TXT_TLSV1,new Def(0,SSL_TXT_TLSV1, 0,SSL_TLSV1, 0,0,0,0,SSL_SSL_MASK,0)); - Definitions.put(SSL_TXT_EXP,new Def(0,SSL_TXT_EXP ,0, 0,SSL_EXPORT, 0,0,0,0,SSL_EXP_MASK)); - Definitions.put(SSL_TXT_EXPORT,new Def(0,SSL_TXT_EXPORT,0, 0,SSL_EXPORT, 0,0,0,0,SSL_EXP_MASK)); - Definitions.put(SSL_TXT_EXP40,new Def(0,SSL_TXT_EXP40, 0, 0, SSL_EXP40, 0,0,0,0,SSL_STRONG_MASK)); - Definitions.put(SSL_TXT_EXP56,new Def(0,SSL_TXT_EXP56, 0, 0, SSL_EXP56, 0,0,0,0,SSL_STRONG_MASK)); - Definitions.put(SSL_TXT_LOW,new Def(0,SSL_TXT_LOW, 0, 0, SSL_LOW, 0,0,0,0,SSL_STRONG_MASK)); - Definitions.put(SSL_TXT_MEDIUM,new Def(0,SSL_TXT_MEDIUM,0, 0,SSL_MEDIUM, 0,0,0,0,SSL_STRONG_MASK)); - Definitions.put(SSL_TXT_HIGH,new Def(0,SSL_TXT_HIGH, 0, 0, SSL_HIGH, 0,0,0,0,SSL_STRONG_MASK)); - - /* Cipher 01 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_NULL_MD5, - SSL3_CK_RSA_NULL_MD5, - SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_MD5|SSL_SSLV3, - SSL_NOT_EXP|SSL_STRONG_NONE, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 02 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_NULL_SHA, - SSL3_CK_RSA_NULL_SHA, - SSL_kRSA|SSL_aRSA|SSL_eNULL |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_STRONG_NONE, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 03 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_RC4_40_MD5, - SSL3_CK_RSA_RC4_40_MD5, - SSL_kRSA|SSL_aRSA|SSL_RC4 |SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 04 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_RC4_128_MD5, - SSL3_CK_RSA_RC4_128_MD5, - SSL_kRSA|SSL_aRSA|SSL_RC4 |SSL_MD5|SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 05 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_RC4_128_SHA, - SSL3_CK_RSA_RC4_128_SHA, - SSL_kRSA|SSL_aRSA|SSL_RC4 |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 06 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_RC2_40_MD5, - SSL3_CK_RSA_RC2_40_MD5, - SSL_kRSA|SSL_aRSA|SSL_RC2 |SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 07 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_IDEA_128_SHA, - SSL3_CK_RSA_IDEA_128_SHA, - SSL_kRSA|SSL_aRSA|SSL_IDEA |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 08 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_DES_40_CBC_SHA, - SSL3_CK_RSA_DES_40_CBC_SHA, - SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 09 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_DES_64_CBC_SHA, - SSL3_CK_RSA_DES_64_CBC_SHA, - SSL_kRSA|SSL_aRSA|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 0A */ - Ciphers.add(new Def( - 1, - SSL3_TXT_RSA_DES_192_CBC3_SHA, - SSL3_CK_RSA_DES_192_CBC3_SHA, - SSL_kRSA|SSL_aRSA|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* The DH ciphers */ - /* Cipher 0B */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_DSS_DES_40_CBC_SHA, - SSL3_CK_DH_DSS_DES_40_CBC_SHA, - SSL_kDHd |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 0C */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_DSS_DES_64_CBC_SHA, - SSL3_CK_DH_DSS_DES_64_CBC_SHA, - SSL_kDHd |SSL_aDH|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 0D */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_DSS_DES_192_CBC3_SHA, - SSL3_CK_DH_DSS_DES_192_CBC3_SHA, - SSL_kDHd |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 0E */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_RSA_DES_40_CBC_SHA, - SSL3_CK_DH_RSA_DES_40_CBC_SHA, - SSL_kDHr |SSL_aDH|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 0F */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_RSA_DES_64_CBC_SHA, - SSL3_CK_DH_RSA_DES_64_CBC_SHA, - SSL_kDHr |SSL_aDH|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 10 */ - Ciphers.add(new Def( - 0, - SSL3_TXT_DH_RSA_DES_192_CBC3_SHA, - SSL3_CK_DH_RSA_DES_192_CBC3_SHA, - SSL_kDHr |SSL_aDH|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* The Ephemeral DH ciphers */ - /* Cipher 11 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_DSS_DES_40_CBC_SHA, - SSL3_CK_EDH_DSS_DES_40_CBC_SHA, - SSL_kEDH|SSL_aDSS|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 12 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_DSS_DES_64_CBC_SHA, - SSL3_CK_EDH_DSS_DES_64_CBC_SHA, - SSL_kEDH|SSL_aDSS|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 13 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA, - SSL3_CK_EDH_DSS_DES_192_CBC3_SHA, - SSL_kEDH|SSL_aDSS|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 14 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_RSA_DES_40_CBC_SHA, - SSL3_CK_EDH_RSA_DES_40_CBC_SHA, - SSL_kEDH|SSL_aRSA|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 15 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_RSA_DES_64_CBC_SHA, - SSL3_CK_EDH_RSA_DES_64_CBC_SHA, - SSL_kEDH|SSL_aRSA|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 16 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA, - SSL3_CK_EDH_RSA_DES_192_CBC3_SHA, - SSL_kEDH|SSL_aRSA|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 17 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_ADH_RC4_40_MD5, - SSL3_CK_ADH_RC4_40_MD5, - SSL_kEDH |SSL_aNULL|SSL_RC4 |SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 18 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_ADH_RC4_128_MD5, - SSL3_CK_ADH_RC4_128_MD5, - SSL_kEDH |SSL_aNULL|SSL_RC4 |SSL_MD5 |SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 19 */ - Ciphers.add(new Def( - 1, - SSL3_TXT_ADH_DES_40_CBC_SHA, - SSL3_CK_ADH_DES_40_CBC_SHA, - SSL_kEDH |SSL_aNULL|SSL_DES|SSL_SHA1|SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 1A */ - Ciphers.add(new Def( - 1, - SSL3_TXT_ADH_DES_64_CBC_SHA, - SSL3_CK_ADH_DES_64_CBC_SHA, - SSL_kEDH |SSL_aNULL|SSL_DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 1B */ - Ciphers.add(new Def( - 1, - SSL3_TXT_ADH_DES_192_CBC_SHA, - SSL3_CK_ADH_DES_192_CBC_SHA, - SSL_kEDH |SSL_aNULL|SSL_3DES |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Fortezza */ - /* Cipher 1C */ - Ciphers.add(new Def( - 0, - SSL3_TXT_FZA_DMS_NULL_SHA, - SSL3_CK_FZA_DMS_NULL_SHA, - SSL_kFZA|SSL_aFZA |SSL_eNULL |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_STRONG_NONE, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 1D */ - Ciphers.add(new Def( - 0, - SSL3_TXT_FZA_DMS_FZA_SHA, - SSL3_CK_FZA_DMS_FZA_SHA, - SSL_kFZA|SSL_aFZA |SSL_eFZA |SSL_SHA1|SSL_SSLV3, - SSL_NOT_EXP|SSL_STRONG_NONE, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 1E VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_64_CBC_SHA, - SSL3_CK_KRB5_DES_64_CBC_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_DES|SSL_SHA1 |SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 1F VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_192_CBC3_SHA, - SSL3_CK_KRB5_DES_192_CBC3_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_3DES|SSL_SHA1 |SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 112, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 20 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC4_128_SHA, - SSL3_CK_KRB5_RC4_128_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_RC4|SSL_SHA1 |SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 21 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_IDEA_128_CBC_SHA, - SSL3_CK_KRB5_IDEA_128_CBC_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_IDEA|SSL_SHA1 |SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 22 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_64_CBC_MD5, - SSL3_CK_KRB5_DES_64_CBC_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_DES|SSL_MD5 |SSL_SSLV3, - SSL_NOT_EXP|SSL_LOW, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 23 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_192_CBC3_MD5, - SSL3_CK_KRB5_DES_192_CBC3_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_3DES|SSL_MD5 |SSL_SSLV3, - SSL_NOT_EXP|SSL_HIGH, - 0, - 112, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 24 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC4_128_MD5, - SSL3_CK_KRB5_RC4_128_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_RC4|SSL_MD5 |SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 25 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_IDEA_128_CBC_MD5, - SSL3_CK_KRB5_IDEA_128_CBC_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_IDEA|SSL_MD5 |SSL_SSLV3, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 26 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_40_CBC_SHA, - SSL3_CK_KRB5_DES_40_CBC_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_DES|SSL_SHA1 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 27 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC2_40_CBC_SHA, - SSL3_CK_KRB5_RC2_40_CBC_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_RC2|SSL_SHA1 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 28 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC4_40_SHA, - SSL3_CK_KRB5_RC4_40_SHA, - SSL_kKRB5|SSL_aKRB5| SSL_RC4|SSL_SHA1 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 29 VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_DES_40_CBC_MD5, - SSL3_CK_KRB5_DES_40_CBC_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_DES|SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 2A VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC2_40_CBC_MD5, - SSL3_CK_KRB5_RC2_40_CBC_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_RC2|SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 40, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 2B VRS */ - Ciphers.add(new Def( - 1, - SSL3_TXT_KRB5_RC4_40_MD5, - SSL3_CK_KRB5_RC4_40_MD5, - SSL_kKRB5|SSL_aKRB5| SSL_RC4|SSL_MD5 |SSL_SSLV3, - SSL_EXPORT|SSL_EXP40, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 2F */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_WITH_AES_128_SHA, - TLS1_CK_RSA_WITH_AES_128_SHA, - SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA |SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 30 */ - Ciphers.add(new Def( - 0, - TLS1_TXT_DH_DSS_WITH_AES_128_SHA, - TLS1_CK_DH_DSS_WITH_AES_128_SHA, - SSL_kDHd|SSL_aDH|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 31 */ - Ciphers.add(new Def( - 0, - TLS1_TXT_DH_RSA_WITH_AES_128_SHA, - TLS1_CK_DH_RSA_WITH_AES_128_SHA, - SSL_kDHr|SSL_aDH|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 32 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_DSS_WITH_AES_128_SHA, - TLS1_CK_DHE_DSS_WITH_AES_128_SHA, - SSL_kEDH|SSL_aDSS|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 33 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, - TLS1_CK_DHE_RSA_WITH_AES_128_SHA, - SSL_kEDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 34 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ADH_WITH_AES_128_SHA, - TLS1_CK_ADH_WITH_AES_128_SHA, - SSL_kEDH|SSL_aNULL|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher 35 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_WITH_AES_256_SHA, - TLS1_CK_RSA_WITH_AES_256_SHA, - SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA |SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 36 */ - Ciphers.add(new Def( - 0, - TLS1_TXT_DH_DSS_WITH_AES_256_SHA, - TLS1_CK_DH_DSS_WITH_AES_256_SHA, - SSL_kDHd|SSL_aDH|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 37 */ - Ciphers.add(new Def( - 0, - TLS1_TXT_DH_RSA_WITH_AES_256_SHA, - TLS1_CK_DH_RSA_WITH_AES_256_SHA, - SSL_kDHr|SSL_aDH|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 38 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_DSS_WITH_AES_256_SHA, - TLS1_CK_DHE_DSS_WITH_AES_256_SHA, - SSL_kEDH|SSL_aDSS|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 39 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, - TLS1_CK_DHE_RSA_WITH_AES_256_SHA, - SSL_kEDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 3A */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ADH_WITH_AES_256_SHA, - TLS1_CK_ADH_WITH_AES_256_SHA, - SSL_kEDH|SSL_aNULL|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* New TLS Export CipherSuites */ - /* Cipher 60 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5, - TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5, - SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 61 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, - TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, - SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 62 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA, - TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA, - SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 63 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - SSL_kEDH|SSL_aDSS|SSL_DES|SSL_SHA|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 56, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 64 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA, - TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA, - SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 65 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, - TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, - SSL_kEDH|SSL_aDSS|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_EXPORT|SSL_EXP56, - 0, - 56, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher 66 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA, - TLS1_CK_DHE_DSS_WITH_RC4_128_SHA, - SSL_kEDH|SSL_aDSS|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_MEDIUM, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - /* Cipher C001 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA, - TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA, - SSL_kECDH|SSL_aECDSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C002 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA, - TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA, - SSL_kECDH|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C003 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, - TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, - SSL_kECDH|SSL_aECDSA|SSL_3DES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C004 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C005 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - SSL_kECDH|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C006 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA, - SSL_kECDHE|SSL_aECDSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C007 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, - SSL_kECDHE|SSL_aECDSA|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C008 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA, - SSL_kECDHE|SSL_aECDSA|SSL_3DES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C009 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - SSL_kECDHE|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00A */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - SSL_kECDHE|SSL_aECDSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00B */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_RSA_WITH_NULL_SHA, - TLS1_CK_ECDH_RSA_WITH_NULL_SHA, - SSL_kECDH|SSL_aRSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00C */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA, - TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA, - SSL_kECDH|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00D */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA, - TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA, - SSL_kECDH|SSL_aRSA|SSL_3DES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00E */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA, - SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C00F */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA, - SSL_kECDH|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C010 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA, - TLS1_CK_ECDHE_RSA_WITH_NULL_SHA, - SSL_kECDHE|SSL_aRSA|SSL_eNULL|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C011 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, - TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, - SSL_kECDHE|SSL_aRSA|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C012 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA, - TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA, - SSL_kECDHE|SSL_aRSA|SSL_3DES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C013 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, - SSL_kECDHE|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C014 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, - SSL_kECDHE|SSL_aRSA|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C015 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_anon_WITH_NULL_SHA, - TLS1_CK_ECDH_anon_WITH_NULL_SHA, - SSL_kECDHE|SSL_aNULL|SSL_eNULL|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 0, - 0, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C016 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA, - TLS1_CK_ECDH_anon_WITH_RC4_128_SHA, - SSL_kECDHE|SSL_aNULL|SSL_RC4|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C017 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA, - TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA, - SSL_kECDHE|SSL_aNULL|SSL_3DES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 168, - 168, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C018 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA, - TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA, - SSL_kECDHE|SSL_aNULL|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 128, - 128, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - /* Cipher C019 */ - Ciphers.add(new Def( - 1, - TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA, - TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA, - SSL_kECDHE|SSL_aNULL|SSL_AES|SSL_SHA|SSL_TLSV1, - SSL_NOT_EXP|SSL_HIGH, - 0, - 256, - 256, - SSL_ALL_CIPHERS, - SSL_ALL_STRENGTHS - )); - - for(Def def : Ciphers) { - CipherNames.put(def.name, def); - } - - addAlias("SSL_RSA_WITH_NULL_MD5","NULL-MD5"); - addAlias("SSL_RSA_WITH_NULL_SHA","NULL-SHA"); - addAlias("SSL_RSA_EXPORT_WITH_RC4_40_MD5","EXP-RC4-MD5"); - addAlias("SSL_RSA_WITH_RC4_128_MD5","RC4-MD5"); - addAlias("SSL_RSA_WITH_RC4_128_SHA","RC4-SHA"); - addAlias("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5","EXP-RC2-CBC-MD5"); - addAlias("SSL_RSA_WITH_IDEA_CBC_SHA","IDEA-CBC-SHA"); - addAlias("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA","EXP-DES-CBC-SHA"); - addAlias("SSL_RSA_WITH_DES_CBC_SHA","DES-CBC-SHA"); - addAlias("SSL_RSA_WITH_3DES_EDE_CBC_SHA","DES-CBC3-SHA"); - addAlias("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA","EXP-EDH-DSS-DES-CBC-SHA"); - addAlias("SSL_DHE_DSS_WITH_DES_CBC_SHA","EDH-DSS-CBC-SHA"); - addAlias("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA","EDH-DSS-DES-CBC3-SHA"); - addAlias("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA","EXP-EDH-RSA-DES-CBC-SHA"); - addAlias("SSL_DHE_RSA_WITH_DES_CBC_SHA","EDH-RSA-DES-CBC-SHA"); - addAlias("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA","EDH-RSA-DES-CBC3-SHA"); - addAlias("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5","EXP-ADH-RC4-MD5"); - addAlias("SSL_DH_anon_WITH_RC4_128_MD5","ADH-RC4-MD5"); - addAlias("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA","EXP-ADH-DES-CBC-SHA"); - addAlias("SSL_DH_anon_WITH_DES_CBC_SHA","ADH-DES-CBC-SHA"); - addAlias("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA","ADH-DES-CBC3-SHA"); - addAlias("TLS_RSA_WITH_NULL_MD5","NULL-MD5"); - addAlias("TLS_RSA_WITH_NULL_SHA","NULL-SHA"); - addAlias("TLS_RSA_EXPORT_WITH_RC4_40_MD5","EXP-RC4-MD5"); - addAlias("TLS_RSA_WITH_RC4_128_MD5","RC4-MD5"); - addAlias("TLS_RSA_WITH_RC4_128_SHA","RC4-SHA"); - addAlias("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5","EXP-RC2-CBC-MD5"); - addAlias("TLS_RSA_WITH_IDEA_CBC_SHA","IDEA-CBC-SHA"); - addAlias("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA","EXP-DES-CBC-SHA"); - addAlias("TLS_RSA_WITH_DES_CBC_SHA","DES-CBC-SHA"); - addAlias("TLS_RSA_WITH_3DES_EDE_CBC_SHA","DES-CBC3-SHA"); - addAlias("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA","EXP-EDH-DSS-DES-CBC-SHA"); - addAlias("TLS_DHE_DSS_WITH_DES_CBC_SHA","EDH-DSS-CBC-SHA"); - addAlias("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA","EDH-DSS-DES-CBC3-SHA"); - addAlias("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA","EXP-EDH-RSA-DES-CBC-SHA"); - addAlias("TLS_DHE_RSA_WITH_DES_CBC_SHA","EDH-RSA-DES-CBC-SHA"); - addAlias("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA","EDH-RSA-DES-CBC3-SHA"); - addAlias("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5","EXP-ADH-RC4-MD5"); - addAlias("TLS_DH_anon_WITH_RC4_128_MD5","ADH-RC4-MD5"); - addAlias("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA","EXP-ADH-DES-CBC-SHA"); - addAlias("TLS_DH_anon_WITH_DES_CBC_SHA","ADH-DES-CBC-SHA"); - addAlias("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA","ADH-DES-CBC3-SHA"); - addAlias("TLS_RSA_WITH_AES_128_CBC_SHA","AES128-SHA"); - addAlias("TLS_RSA_WITH_AES_256_CBC_SHA","AES256-SHA"); - addAlias("TLS_DH_DSS_WITH_AES_128_CBC_SHA","DH-DSS-AES128-SHA"); - addAlias("TLS_DH_DSS_WITH_AES_256_CBC_SHA","DH-DSS-AES256-SHA"); - addAlias("TLS_DH_RSA_WITH_AES_128_CBC_SHA","DH-RSA-AES128-SHA"); - addAlias("TLS_DH_RSA_WITH_AES_256_CBC_SHA","DH-RSA-AES256-SHA"); - addAlias("TLS_DHE_DSS_WITH_AES_128_CBC_SHA","DHE-DSS-AES128-SHA"); - addAlias("TLS_DHE_DSS_WITH_AES_256_CBC_SHA","DHE-DSS-AES256-SHA"); - addAlias("TLS_DHE_RSA_WITH_AES_128_CBC_SHA","DHE-RSA-AES128-SHA"); - addAlias("TLS_DHE_RSA_WITH_AES_256_CBC_SHA","DHE-RSA-AES256-SHA"); - addAlias("TLS_DH_anon_WITH_AES_128_CBC_SHA","ADH-AES128-SHA"); - addAlias("TLS_DH_anon_WITH_AES_256_CBC_SHA","ADH-AES256-SHA"); - addAlias("TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA","EXP1024-DES-CBC-SHA"); - addAlias("TLS_RSA_EXPORT1024_WITH_RC4_56_SHA","EXP1024-RC4-SHA"); - addAlias("TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA","EXP1024-DHE-DSS-DES-CBC-SHA"); - addAlias("TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA","EXP1024-DHE-DSS-RC4-SHA"); - addAlias("TLS_DHE_DSS_WITH_RC4_128_SHA","DHE-DSS-RC4-SHA"); - addAlias("SSL_CK_RC4_128_WITH_MD5","RC4-MD5"); - addAlias("SSL_CK_RC4_128_EXPORT40_WITH_MD5","EXP-RC4-MD5"); - addAlias("SSL_CK_RC2_128_CBC_WITH_MD5","RC2-MD5"); - addAlias("SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5","EXP-RC2-MD5"); - addAlias("SSL_CK_IDEA_128_CBC_WITH_MD5","IDEA-CBC-MD5"); - addAlias("SSL_CK_DES_64_CBC_WITH_MD5","DES-CBC-MD5"); - addAlias("SSL_CK_DES_192_EDE3_CBC_WITH_MD5","DES-CBC3-MD5"); - } -}// CipherStrings diff --git a/src/java/org/jruby/ext/openssl/Config.java b/src/java/org/jruby/ext/openssl/Config.java deleted file mode 100644 index dd8fd30..0000000 --- a/src/java/org/jruby/ext/openssl/Config.java +++ /dev/null @@ -1,49 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; - -/** - * @author Ola Bini - */ -public class Config { - // TODO: we cannot detect OS's default config file. ignore? - public static final String DEFAULT_CONFIG_FILE = "./openssl.cnf"; - - public static void createConfig(Ruby runtime, RubyModule mOSSL) { - RubyClass cConfig = mOSSL.defineClassUnder("Config", runtime.getObject(), runtime.getObject().getAllocator()); - cConfig.defineAnnotatedMethods(Config.class); - RubyClass openSSLError = mOSSL.getClass("OpenSSLError"); - mOSSL.defineClassUnder("ConfigError", openSSLError, openSSLError.getAllocator()); - // TODO: we should define this constant with proper path. (see above) - //cConfig.setConstant("DEFAULT_CONFIG_FILE", runtime.newString(DEFAULT_CONFIG_FILE)); - } -}// Config diff --git a/src/java/org/jruby/ext/openssl/DefaultPEMHandler.java b/src/java/org/jruby/ext/openssl/DefaultPEMHandler.java deleted file mode 100644 index d47337c..0000000 --- a/src/java/org/jruby/ext/openssl/DefaultPEMHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.Reader; -import java.io.Writer; - -/** - * @author Ola Bini - */ -public class DefaultPEMHandler implements PEMHandler { - public Object readPEM(Reader read, String password) { - return null; - } - public void writePEM(Writer writ, Object obj, String algorithm, char[] password) { - } - public void writePEM(Writer writ, Object obj) { - } -}// DefaultPEMHandler diff --git a/src/java/org/jruby/ext/openssl/Digest.java b/src/java/org/jruby/ext/openssl/Digest.java deleted file mode 100644 index 4e53d51..0000000 --- a/src/java/org/jruby/ext/openssl/Digest.java +++ /dev/null @@ -1,191 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyFixnum; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class Digest extends RubyObject { - private static final long serialVersionUID = 1L; - - private static ObjectAllocator DIGEST_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new Digest(runtime, klass); - } - }; - - public static void createDigest(Ruby runtime, RubyModule mOSSL) { - runtime.getLoadService().require("digest"); - RubyModule mDigest = runtime.getModule("Digest"); - RubyClass cDigestClass = mDigest.getClass("Class"); - RubyClass cDigest = mOSSL.defineClassUnder("Digest", cDigestClass, DIGEST_ALLOCATOR); - cDigest.defineAnnotatedMethods(Digest.class); - RubyClass openSSLError = mOSSL.getClass("OpenSSLError"); - mOSSL.defineClassUnder("DigestError", openSSLError, openSSLError.getAllocator()); - } - - static MessageDigest getDigest(final String name, final Ruby runtime) { - String algorithm = transformDigest(name); - try { - return MessageDigest.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - try { - return OpenSSLReal.getMessageDigestBC(algorithm); - } catch (GeneralSecurityException ignore) { - } - throw runtime.newNotImplementedError("Unsupported digest algorithm (" + name + ")"); - } - } - - // name mapping for openssl -> JCE - private static String transformDigest(String inp) { - String[] sp = inp.split("::"); - if (sp.length > 1) { // We only want Digest names from the last part of class name - inp = sp[sp.length - 1]; - } - // MessageDigest algorithm name normalization. - // BC accepts "SHA1" but it should be "SHA-1" per spec. - if ("DSS".equalsIgnoreCase(inp)) { - return "SHA"; // why? - } else if ("DSS1".equalsIgnoreCase(inp)) { - return "SHA-1"; - } else if (inp.toUpperCase().startsWith("SHA") && inp.length() > 3 && inp.charAt(3) != '-') { - inp = "SHA-" + inp.substring(3); - } - return inp; - } - - public Digest(Ruby runtime, RubyClass type) { - super(runtime,type); - // do not initialize MessageDigest at allocation time (same as the ruby-openssl) - name = null; - algo = null; - } - private MessageDigest algo; - private String name; - - public String getRealName() { - return transformDigest(name); - } - - public String getName() { - return name; - } - - @JRubyMethod(required = 1, optional = 1) - public IRubyObject initialize(IRubyObject[] args) { - IRubyObject type = args[0]; - IRubyObject data = getRuntime().getNil(); - if (args.length > 1) { - data = args[1]; - } - name = type.toString(); - algo = getDigest(name, getRuntime()); - if (!data.isNil()) { - update(data.convertToString()); - } - return this; - } - - @Override - @JRubyMethod - public IRubyObject initialize_copy(IRubyObject obj) { - checkFrozen(); - if(this == obj) { - return this; - } - name = ((Digest)obj).algo.getAlgorithm(); - try { - algo = (MessageDigest)((Digest)obj).algo.clone(); - } catch(CloneNotSupportedException e) { - throw getRuntime().newTypeError("Could not initialize copy of digest (" + name + ")"); - } - return this; - } - - @JRubyMethod(name={"update","<<"}) - public IRubyObject update(IRubyObject obj) { - ByteList bytes = obj.convertToString().getByteList(); - algo.update(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize()); - return this; - } - - @JRubyMethod - public IRubyObject reset() { - algo.reset(); - return this; - } - - @JRubyMethod - public IRubyObject finish() { - IRubyObject digest = RubyString.newStringNoCopy(getRuntime(), algo.digest()); - algo.reset(); - return digest; - } - - @JRubyMethod - public IRubyObject name() { - return getRuntime().newString(name); - } - - @JRubyMethod() - public IRubyObject digest_length() { - return RubyFixnum.newFixnum(getRuntime(), algo.getDigestLength()); - } - - @JRubyMethod() - public IRubyObject block_length() { - // TODO: ruby-openssl supports it. - throw getRuntime().newRuntimeError( - this.getMetaClass() + " doesn't implement block_length()"); - } - - String getAlgorithm() { - return this.algo.getAlgorithm(); - } - - String getShortAlgorithm() { - return getAlgorithm().replace("-", ""); - } -} - diff --git a/src/java/org/jruby/ext/openssl/HMAC.java b/src/java/org/jruby/ext/openssl/HMAC.java deleted file mode 100644 index 5bb63dc..0000000 --- a/src/java/org/jruby/ext/openssl/HMAC.java +++ /dev/null @@ -1,184 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.NoSuchAlgorithmException; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class HMAC extends RubyObject { - private static final long serialVersionUID = 7602535792884680307L; - - private static ObjectAllocator HMAC_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new HMAC(runtime, klass); - } - }; - - public static void createHMAC(Ruby runtime, RubyModule ossl) { - RubyClass cHMAC = ossl.defineClassUnder("HMAC",runtime.getObject(),HMAC_ALLOCATOR); - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - ossl.defineClassUnder("HMACError",openSSLError,openSSLError.getAllocator()); - - cHMAC.defineAnnotatedMethods(HMAC.class); - } - - static Mac getMac(String algoName) throws NoSuchAlgorithmException { - // some algorithms need the - removed; this is ugly, I know. - try { - return Mac.getInstance("HMAC" + algoName.replaceAll("-", "")); - } catch (NoSuchAlgorithmException nsae) { - return Mac.getInstance("HMAC-" + algoName.replaceAll("-", "")); - } - } - - @JRubyMethod(name = "digest", meta = true) - public static IRubyObject s_digest(IRubyObject recv, IRubyObject digest, IRubyObject kay, IRubyObject data) { - String algoName = getDigestAlgorithmName(digest); - try { - Mac mac = getMac(algoName); - byte[] key = kay.convertToString().getBytes(); - SecretKey keysp = new SecretKeySpec(key, mac.getAlgorithm()); - mac.init(keysp); - return RubyString.newString(recv.getRuntime(), mac.doFinal(data.convertToString().getBytes())); - } catch (Exception e) { - e.printStackTrace(); - throw recv.getRuntime().newNotImplementedError(e.getMessage()); - } - } - - @JRubyMethod(name = "hexdigest", meta = true) - public static IRubyObject s_hexdigest(IRubyObject recv, IRubyObject digest, IRubyObject kay, IRubyObject data) { - String algoName = getDigestAlgorithmName(digest); - try { - Mac mac = getMac(algoName); - byte[] key = kay.convertToString().getBytes(); - SecretKey keysp = new SecretKeySpec(key, mac.getAlgorithm()); - mac.init(keysp); - return RubyString.newString(recv.getRuntime(), ByteList.plain(Utils.toHex(mac.doFinal(data.convertToString().getBytes())))); - } catch (Exception e) { - throw recv.getRuntime().newNotImplementedError(e.getMessage()); - } - } - - public HMAC(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private Mac mac; - private byte[] key; - private StringBuffer data = new StringBuffer(); - - @JRubyMethod - public IRubyObject initialize(IRubyObject kay, IRubyObject digest) { - String algoName = getDigestAlgorithmName(digest); - try { - mac = getMac(algoName); - key = kay.convertToString().getBytes(); - SecretKey keysp = new SecretKeySpec(key, mac.getAlgorithm()); - mac.init(keysp); - } catch (Exception e) { - throw getRuntime().newNotImplementedError(e.getMessage()); - } - return this; - } - - @Override - @JRubyMethod - public IRubyObject initialize_copy(IRubyObject obj) { - if(this == obj) { - return this; - } - checkFrozen(); - String name = ((HMAC)obj).mac.getAlgorithm(); - try { - mac = Mac.getInstance(name); - key = ((HMAC)obj).key; - SecretKey keysp = new SecretKeySpec(key,name); - mac.init(keysp); - } catch(Exception e) { - throw getRuntime().newNotImplementedError("Unsupported MAC algorithm (" + name + ")"); - } - - data = new StringBuffer(((HMAC)obj).data.toString()); - - return this; - } - - @JRubyMethod(name={"update", "<<"}) - public IRubyObject update(IRubyObject obj) { - data.append(obj); - return this; - } - - @JRubyMethod - public IRubyObject digest() { - mac.reset(); - return RubyString.newString(getRuntime(), mac.doFinal(ByteList.plain(data))); - } - - @JRubyMethod - public IRubyObject reset() { - data.setLength(0); - return this; - } - - @JRubyMethod(name={"hexdigest","inspect","to_s"}) - public IRubyObject hexdigest() { - mac.reset(); - return RubyString.newString(getRuntime(), ByteList.plain(Utils.toHex(mac.doFinal(ByteList.plain(data))))); - } - - String getAlgorithm() { - return this.mac.getAlgorithm(); - } - - private static String getDigestAlgorithmName(IRubyObject digest) { - String algoName = null; - if (digest instanceof Digest) { - algoName = ((Digest) digest).getShortAlgorithm(); - } else { - algoName = digest.asString().toString(); - } - return algoName; - } -}// HMAC diff --git a/src/java/org/jruby/ext/openssl/NetscapeSPKI.java b/src/java/org/jruby/ext/openssl/NetscapeSPKI.java deleted file mode 100644 index 7c88d22..0000000 --- a/src/java/org/jruby/ext/openssl/NetscapeSPKI.java +++ /dev/null @@ -1,253 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.PublicKey; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jce.netscape.NetscapeCertRequest; -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.Base64; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class NetscapeSPKI extends RubyObject { - private static final long serialVersionUID = 3211242351810109432L; - - private static ObjectAllocator NETSCAPESPKI_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new NetscapeSPKI(runtime, klass); - } - }; - - public static void createNetscapeSPKI(Ruby runtime, RubyModule ossl) { - RubyModule mNetscape = ossl.defineModuleUnder("Netscape"); - RubyClass cSPKI = mNetscape.defineClassUnder("SPKI",runtime.getObject(),NETSCAPESPKI_ALLOCATOR); - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - mNetscape.defineClassUnder("SPKIError",openSSLError,openSSLError.getAllocator()); - - cSPKI.defineAnnotatedMethods(NetscapeSPKI.class); - } - - public NetscapeSPKI(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private IRubyObject public_key; - private IRubyObject challenge; - - private NetscapeCertRequest cert; - - @JRubyMethod(name = "initialize", rest = true) - public IRubyObject _initialize(IRubyObject[] args) { - if (args.length > 0) { - byte[] b = args[0].convertToString().getBytes(); - b = tryBase64Decode(b); - final byte[] b2 = b; - String algo = null; - byte[] enc = null; - try { - // NetscapeCertRequest requires "BC" provider. - PublicKey pkey = (PublicKey) OpenSSLReal.getWithBCProvider(new OpenSSLReal.Callable() { - - public Object call() throws GeneralSecurityException { - try { - // NetscapeCertRequest throws java.lang.IllegalArgumentException - // when no BC provider allowed, with a message - // "java.security.NoSuchProviderException: no such provider: BC" - // instead of NoSuchProviderException. - cert = new NetscapeCertRequest(b2); - challenge = getRuntime().newString(cert.getChallenge()); - return cert.getPublicKey(); - } catch (IOException ioe) { - throw new GeneralSecurityException(ioe.getMessage(), ioe); - } - } - }); - algo = pkey.getAlgorithm(); - enc = pkey.getEncoded(); - } catch (GeneralSecurityException gse) { - throw newSPKIError(getRuntime(), gse.getMessage()); - } - - if ("RSA".equalsIgnoreCase(algo)) { - this.public_key = Utils.newRubyInstance(getRuntime(), "OpenSSL::PKey::RSA", RubyString.newString(getRuntime(), enc)); - } else if ("DSA".equalsIgnoreCase(algo)) { - this.public_key = Utils.newRubyInstance(getRuntime(), "OpenSSL::PKey::DSA", RubyString.newString(getRuntime(), enc)); - } else { - throw getRuntime().newLoadError("not implemented algo for public key: " + algo); - } - } - return this; - } - - // just try to decode for the time when the given bytes are base64 encoded. - private byte[] tryBase64Decode(byte[] b) { - try { - b = Base64.decode(b, 0, b.length, Base64.NO_OPTIONS); - } catch (Exception ignored) { - } - return b; - } - - @JRubyMethod - public IRubyObject to_der() { - try { - return RubyString.newString(getRuntime(), internalToDer()); - } catch (IOException ioe) { - throw newSPKIError(getRuntime(), ioe.getMessage()); - } - } - - @JRubyMethod(name={"to_pem","to_s"}) - public IRubyObject to_pem() { - try { - byte[] source = internalToDer(); - // no Base64.DO_BREAK_LINES option needed for NSPKI. - return getRuntime().newString(Base64.encodeBytes(source, 0, source.length, Base64.NO_OPTIONS)); - } catch (IOException ioe) { - throw newSPKIError(getRuntime(), ioe.getMessage()); - } - } - - private byte[] internalToDer() throws IOException { - DERSequence b = (DERSequence)cert.toASN1Object(); - DERObjectIdentifier encType = null; - DERBitString publicKey = new DERBitString(((PKey)public_key).to_der().convertToString().getBytes()); - DERIA5String encodedChallenge = new DERIA5String(this.challenge.toString()); - DERObjectIdentifier sigAlg = null; - DERBitString sig = null; - encType = (DERObjectIdentifier)((DERSequence)((DERSequence)((DERSequence)b.getObjectAt(0)).getObjectAt(0)).getObjectAt(0)).getObjectAt(0); - sigAlg = ((AlgorithmIdentifier)b.getObjectAt(1)).getObjectId(); - sig = (DERBitString)b.getObjectAt(2); - - ASN1EncodableVector v1 = new ASN1EncodableVector(); - ASN1EncodableVector v1_2 = new ASN1EncodableVector(); - ASN1EncodableVector v2 = new ASN1EncodableVector(); - ASN1EncodableVector v3 = new ASN1EncodableVector(); - ASN1EncodableVector v4 = new ASN1EncodableVector(); - v4.add(encType); - v4.add(new DERNull()); - v3.add(new DERSequence(v4)); - v3.add(publicKey); - v2.add(new DERSequence(v3)); - v2.add(encodedChallenge); - v1.add(new DERSequence(v2)); - v1_2.add(sigAlg); - v1_2.add(new DERNull()); - v1.add(new DERSequence(v1_2)); - v1.add(sig); - return new DERSequence(v1).getEncoded(); - } - - @JRubyMethod - public IRubyObject to_text() { - System.err.println("WARNING: calling unimplemented method: to_text"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject public_key() { - return this.public_key; - } - - @JRubyMethod(name="public_key=") - public IRubyObject set_public_key(IRubyObject arg) { - this.public_key = arg; - return arg; - } - - @JRubyMethod - public IRubyObject sign(final IRubyObject key, IRubyObject digest) { - String keyAlg = ((PKey) key).getAlgorithm(); - String digAlg = ((Digest) digest).getShortAlgorithm(); - final DERObjectIdentifier alg = ASN1.getOIDLookup(getRuntime()).get(keyAlg.toLowerCase() + "-" + digAlg.toLowerCase()); - try { - // NetscapeCertRequest requires "BC" provider. - OpenSSLReal.doWithBCProvider(new OpenSSLReal.Runnable() { - - public void run() throws GeneralSecurityException { - cert = new NetscapeCertRequest(challenge.toString(), new AlgorithmIdentifier(alg), ((PKey) public_key).getPublicKey()); - cert.sign(((PKey) key).getPrivateKey()); - } - }); - } catch (GeneralSecurityException gse) { - throw newSPKIError(getRuntime(), gse.getMessage()); - } - return this; - } - - @JRubyMethod - public IRubyObject verify(final IRubyObject pkey) { - cert.setPublicKey(((PKey) pkey).getPublicKey()); - try { - // NetscapeCertRequest requires "BC" provider. - Boolean result = (Boolean) OpenSSLReal.getWithBCProvider(new OpenSSLReal.Callable() { - - public Boolean call() throws GeneralSecurityException { - return cert.verify(challenge.toString()); - } - }); - return result.booleanValue() ? getRuntime().getTrue() : getRuntime().getFalse(); - } catch (GeneralSecurityException gse) { - throw newSPKIError(getRuntime(), gse.getMessage()); - } - } - - @JRubyMethod - public IRubyObject challenge() { - return this.challenge; - } - - @JRubyMethod(name="challenge=") - public IRubyObject set_challenge(IRubyObject arg) { - this.challenge = arg; - return arg; - } - - private static RaiseException newSPKIError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::Netscape::SPKIError", message); - } -}// NetscapeSPKI diff --git a/src/java/org/jruby/ext/openssl/OSSLLibrary.java b/src/java/org/jruby/ext/openssl/OSSLLibrary.java deleted file mode 100644 index a1846bc..0000000 --- a/src/java/org/jruby/ext/openssl/OSSLLibrary.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.ext.nkf.RubyNKF; -import org.jruby.ext.openssl.OpenSSLReal; -import org.jruby.runtime.load.Library; - -import java.io.IOException; - -public class OSSLLibrary implements Library { - public void load(Ruby runtime, boolean wrap) throws IOException { - OpenSSLReal.createOpenSSL(runtime); - } -} \ No newline at end of file diff --git a/src/java/org/jruby/ext/openssl/OpenSSLImpl.java b/src/java/org/jruby/ext/openssl/OpenSSLImpl.java deleted file mode 100644 index 7363dd8..0000000 --- a/src/java/org/jruby/ext/openssl/OpenSSLImpl.java +++ /dev/null @@ -1,357 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.StringReader; -import java.security.MessageDigest; - -import org.jruby.Ruby; -import org.jruby.RubyString; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * Static class that holds various OpenSSL methods that aren't - * really easy to do any other way. - * - * @author Ola Bini - */ -public class OpenSSLImpl { - /** - * No instantiating this class... - */ - private OpenSSLImpl() {} - - public static IRubyObject to_der(IRubyObject obj) { - return obj.callMethod(obj.getRuntime().getCurrentContext(),"to_der"); - } - - public static IRubyObject to_der_if_possible(IRubyObject obj) { - if(obj.respondsTo("to_der")) { - return to_der(obj); - } else { - return obj; - } - } - - public static byte[] readX509PEM(IRubyObject arg) { - arg = to_der_if_possible(arg); - // TODO: should handle RubyFile - RubyString str = arg.convertToString(); - StringReader in = null; - try { - in = new StringReader(str.getUnicodeValue()); - byte[] bytes = PEMInputOutput.readX509PEM(in); - if (bytes != null) { - return bytes; - } - } catch (Exception e) { - // this is not PEM encoded, let's use the default argument - if (in != null) { - in.close(); - } - } - return str.getBytes(); - } - - public static void defaultObjects(Ruby runtime) { -ASN1.addObject(runtime, 0, null, null,"1.2.840.113549.1.12.1"); -ASN1.addObject(runtime, 1, null, "rsadsi","1.2.840.113549"); -ASN1.addObject(runtime, 2, null, "pkcs","1.2.840.113549.1"); -ASN1.addObject(runtime, 3, "MD2", "md2","1.2.840.113549.2.2"); -ASN1.addObject(runtime, 4, "MD5", "md5","1.2.840.113549.2.5"); -ASN1.addObject(runtime, 5, "RC4", "rc4","1.2.840.113549.3.4"); -ASN1.addObject(runtime, 6, null, "rsaEncryption","1.2.840.113549.1.1.1"); -ASN1.addObject(runtime, 7, "RSA-MD2", "md2WithRSAEncryption","1.2.840.113549.1.1.2"); -ASN1.addObject(runtime, 8, "RSA-MD5", "md5WithRSAEncryption","1.2.840.113549.1.1.4"); -ASN1.addObject(runtime, 9, "PBE-MD2-DES", "pbeWithMD2AndDES-CBC","1.2.840.113549.1.5.1"); -ASN1.addObject(runtime, 10, "PBE-MD5-DES", "pbeWithMD5AndDES-CBC","1.2.840.113549.1.5.3"); -ASN1.addObject(runtime, 11, null, "X500","2.5"); -ASN1.addObject(runtime, 12, null, "X509","2.5.4"); -ASN1.addObject(runtime, 13, "CN", "commonName","2.5.4.3"); -ASN1.addObject(runtime, 14, "C", "countryName","2.5.4.6"); -ASN1.addObject(runtime, 15, "L", "localityName","2.5.4.7"); -ASN1.addObject(runtime, 16, "ST", "stateOrProvinceName","2.5.4.8"); -ASN1.addObject(runtime, 17, "O", "organizationName","2.5.4.10"); -ASN1.addObject(runtime, 18, "OU", "organizationalUnitName","2.5.4.11"); -ASN1.addObject(runtime, 19, "RSA", "rsa","2.5.8.1.1"); -ASN1.addObject(runtime, 20, null, "pkcs7","1.2.840.113549.1.7"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_data, null, "pkcs7-data","1.2.840.113549.1.7.1"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_signed, null, "pkcs7-signedData","1.2.840.113549.1.7.2"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_enveloped, null, "pkcs7-envelopedData","1.2.840.113549.1.7.3"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_signedAndEnveloped, null, "pkcs7-signedAndEnvelopedData","1.2.840.113549.1.7.4"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_digest, null, "pkcs7-digestData","1.2.840.113549.1.7.5"); -ASN1.addObject(runtime, org.jruby.ext.openssl.impl.ASN1Registry.NID_pkcs7_encrypted, null, "pkcs7-encryptedData","1.2.840.113549.1.7.6"); -ASN1.addObject(runtime, 27, null, "pkcs3","1.2.840.113549.1.3"); -ASN1.addObject(runtime, 28, null, "dhKeyAgreement","1.2.840.113549.1.3.1"); -ASN1.addObject(runtime, 29, "DES-ECB", "des-ecb","1.3.14.3.2.6"); -ASN1.addObject(runtime, 30, "DES-CFB", "des-cfb","1.3.14.3.2.9"); -ASN1.addObject(runtime, 31, "DES-CBC", "des-cbc","1.3.14.3.2.7"); -ASN1.addObject(runtime, 32, "DES-EDE", "des-ede","1.3.14.3.2.17"); -ASN1.addObject(runtime, 33, "DES-EDE3", "des-ede3",null); -ASN1.addObject(runtime, 34, "IDEA-CBC", "idea-cbc","1.3.6.1.4.1.188.7.1.1.2"); -ASN1.addObject(runtime, 35, "IDEA-CFB", "idea-cfb",null); -ASN1.addObject(runtime, 36, "IDEA-ECB", "idea-ecb",null); -ASN1.addObject(runtime, 37, "RC2-CBC", "rc2-cbc","1.2.840.113549.3.2"); -ASN1.addObject(runtime, 38, "RC2-ECB", "rc2-ecb",null); -ASN1.addObject(runtime, 39, "RC2-CFB", "rc2-cfb",null); -ASN1.addObject(runtime, 40, "RC2-OFB", "rc2-ofb",null); -ASN1.addObject(runtime, 41, "SHA", "sha","1.3.14.3.2.18"); -ASN1.addObject(runtime, 42, "RSA-SHA", "shaWithRSAEncryption","1.3.14.3.2.15"); -ASN1.addObject(runtime, 43, "DES-EDE-CBC", "des-ede-cbc",null); -ASN1.addObject(runtime, 44, "DES-EDE3-CBC", "des-ede3-cbc","1.2.840.113549.3.7"); -ASN1.addObject(runtime, 45, "DES-OFB", "des-ofb","1.3.14.3.2.8"); -ASN1.addObject(runtime, 46, "IDEA-OFB", "idea-ofb",null); -ASN1.addObject(runtime, 47, null, "pkcs9","1.2.840.113549.1.9"); -ASN1.addObject(runtime, 48, "Email", "emailAddress","1.2.840.113549.1.9.1"); -ASN1.addObject(runtime, 49, null, "unstructuredName","1.2.840.113549.1.9.2"); -ASN1.addObject(runtime, 50, null, "contentType","1.2.840.113549.1.9.3"); -ASN1.addObject(runtime, 51, null, "messageDigest","1.2.840.113549.1.9.4"); -ASN1.addObject(runtime, 52, null, "signingTime","1.2.840.113549.1.9.5"); -ASN1.addObject(runtime, 53, null, "countersignature","1.2.840.113549.1.9.6"); -ASN1.addObject(runtime, 54, null, "challengePassword","1.2.840.113549.1.9.7"); -ASN1.addObject(runtime, 55, null, "unstructuredAddress","1.2.840.113549.1.9.8"); -ASN1.addObject(runtime, 56, null, "extendedCertificateAttributes","1.2.840.113549.1.9.9"); -ASN1.addObject(runtime, 57, "Netscape", "Netscape Communications Corp.","2.16.840.1.113730"); -ASN1.addObject(runtime, 58, "nsCertExt", "Netscape Certificate Extension","2.16.840.1.113730.1"); -ASN1.addObject(runtime, 59, "nsDataType", "Netscape Data Type","2.16.840.1.113730.2"); -ASN1.addObject(runtime, 60, "DES-EDE-CFB", "des-ede-cfb",null); -ASN1.addObject(runtime, 61, "DES-EDE3-CFB", "des-ede3-cfb",null); -ASN1.addObject(runtime, 62, "DES-EDE-OFB", "des-ede-ofb",null); -ASN1.addObject(runtime, 63, "DES-EDE3-OFB", "des-ede3-ofb",null); -ASN1.addObject(runtime, 64, "SHA1", "sha1","1.3.14.3.2.26"); -ASN1.addObject(runtime, 65, "RSA-SHA1", "sha1WithRSAEncryption","1.2.840.113549.1.1.5"); -ASN1.addObject(runtime, 66, "DSA-SHA", "dsaWithSHA","1.3.14.3.2.13"); -ASN1.addObject(runtime, 67, "DSA-old", "dsaEncryption-old","1.3.14.3.2.12"); -ASN1.addObject(runtime, 68, "PBE-SHA1-RC2-64", "pbeWithSHA1AndRC2-CBC","1.2.840.113549.1.5.11"); -ASN1.addObject(runtime, 69, null, "PBKDF2","1.2.840.113549.1.5.12"); -ASN1.addObject(runtime, 70, "DSA-SHA1-old", "dsaWithSHA1-old","1.3.14.3.2.27"); -ASN1.addObject(runtime, 71, "nsCertType", "Netscape Cert Type","2.16.840.1.113730.1.1"); -ASN1.addObject(runtime, 72, "nsBaseUrl", "Netscape Base Url","2.16.840.1.113730.1.2"); -ASN1.addObject(runtime, 73, "nsRevocationUrl", "Netscape Revocation Url","2.16.840.1.113730.1.3"); -ASN1.addObject(runtime, 74, "nsCaRevocationUrl", "Netscape CA Revocation Url","2.16.840.1.113730.1.4"); -ASN1.addObject(runtime, 75, "nsRenewalUrl", "Netscape Renewal Url","2.16.840.1.113730.1.7"); -ASN1.addObject(runtime, 76, "nsCaPolicyUrl", "Netscape CA Policy Url","2.16.840.1.113730.1.8"); -ASN1.addObject(runtime, 77, "nsSslServerName", "Netscape SSL Server Name","2.16.840.1.113730.1.12"); -ASN1.addObject(runtime, 78, "nsComment", "Netscape Comment","2.16.840.1.113730.1.13"); -ASN1.addObject(runtime, 79, "nsCertSequence", "Netscape Certificate Sequence","2.16.840.1.113730.2.5"); -ASN1.addObject(runtime, 80, "DESX-CBC", "desx-cbc",null); -ASN1.addObject(runtime, 81, "id-ce", null,"2.5.29"); -ASN1.addObject(runtime, 82, "subjectKeyIdentifier", "X509v3 Subject Key Identifier","2.5.29.14"); -ASN1.addObject(runtime, 83, "keyUsage", "X509v3 Key Usage","2.5.29.15"); -ASN1.addObject(runtime, 84, "privateKeyUsagePeriod", "X509v3 Private Key Usage Period","2.5.29.16"); -ASN1.addObject(runtime, 85, "subjectAltName", "X509v3 Subject Alternative Name","2.5.29.17"); -ASN1.addObject(runtime, 86, "issuerAltName", "X509v3 Issuer Alternative Name","2.5.29.18"); -ASN1.addObject(runtime, 87, "basicConstraints", "X509v3 Basic Constraints","2.5.29.19"); -ASN1.addObject(runtime, 88, "crlNumber", "X509v3 CRL Number","2.5.29.20"); -ASN1.addObject(runtime, 89, "certificatePolicies", "X509v3 Certificate Policies","2.5.29.32"); -ASN1.addObject(runtime, 90, "authorityKeyIdentifier", "X509v3 Authority Key Identifier","2.5.29.35"); -ASN1.addObject(runtime, 91, "BF-CBC", "bf-cbc","1.3.6.1.4.1.3029.1.2"); -ASN1.addObject(runtime, 92, "BF-ECB", "bf-ecb",null); -ASN1.addObject(runtime, 93, "BF-CFB", "bf-cfb",null); -ASN1.addObject(runtime, 94, "BF-OFB", "bf-ofb",null); -ASN1.addObject(runtime, 95, "MDC2", "mdc2","2.5.8.3.101"); -ASN1.addObject(runtime, 96, "RSA-MDC2", "mdc2withRSA","2.5.8.3.100"); -ASN1.addObject(runtime, 97, "RC4-40", "rc4-40",null); -ASN1.addObject(runtime, 98, "RC2-40-CBC", "rc2-40-cbc",null); -ASN1.addObject(runtime, 99, "G", "givenName","2.5.4.42"); -ASN1.addObject(runtime, 100, "S", "surname","2.5.4.4"); -ASN1.addObject(runtime, 101, "I", "initials","2.5.4.43"); -ASN1.addObject(runtime, 102, "UID", "uniqueIdentifier","2.5.4.45"); -ASN1.addObject(runtime, 103, "crlDistributionPoints", "X509v3 CRL Distribution Points","2.5.29.31"); -ASN1.addObject(runtime, 104, "RSA-NP-MD5", "md5WithRSA","1.3.14.3.2.3"); -ASN1.addObject(runtime, 105, "SN", "serialNumber","2.5.4.5"); -ASN1.addObject(runtime, 106, "T", "title","2.5.4.12"); -ASN1.addObject(runtime, 107, "D", "description","2.5.4.13"); -ASN1.addObject(runtime, 108, "CAST5-CBC", "cast5-cbc","1.2.840.113533.7.66.10"); -ASN1.addObject(runtime, 109, "CAST5-ECB", "cast5-ecb",null); -ASN1.addObject(runtime, 110, "CAST5-CFB", "cast5-cfb",null); -ASN1.addObject(runtime, 111, "CAST5-OFB", "cast5-ofb",null); -ASN1.addObject(runtime, 112, null, "pbeWithMD5AndCast5CBC","1.2.840.113533.7.66.12"); -ASN1.addObject(runtime, 113, "DSA-SHA1", "dsaWithSHA1","1.2.840.10040.4.3"); -ASN1.addObject(runtime, 114, "MD5-SHA1", "md5-sha1",null); -ASN1.addObject(runtime, 115, "RSA-SHA1-2", "sha1WithRSA","1.3.14.3.2.29"); -ASN1.addObject(runtime, 116, "DSA", "dsaEncryption","1.2.840.10040.4.1"); -ASN1.addObject(runtime, 117, "RIPEMD160", "ripemd160","1.3.36.3.2.1"); -ASN1.addObject(runtime, 118, "RSA-RIPEMD160", "ripemd160WithRSA","1.3.36.3.3.1.2"); -ASN1.addObject(runtime, 119, "RC5-CBC", "rc5-cbc","1.2.840.113549.3.8"); -ASN1.addObject(runtime, 120, "RC5-ECB", "rc5-ecb",null); -ASN1.addObject(runtime, 121, "RC5-CFB", "rc5-cfb",null); -ASN1.addObject(runtime, 122, "RC5-OFB", "rc5-ofb",null); -ASN1.addObject(runtime, 123, "RLE", "run length compression","1.1.1.1.666.1"); -ASN1.addObject(runtime, 124, "ZLIB", "zlib compression","1.1.1.1.666.2"); -ASN1.addObject(runtime, 125, "extendedKeyUsage", "X509v3 Extended Key Usage","2.5.29.37"); -ASN1.addObject(runtime, 126, "PKIX", null,"1.3.6.1.5.5.7"); -ASN1.addObject(runtime, 127, "id-kp", null,"1.3.6.1.5.5.7.3"); -ASN1.addObject(runtime, 128, "serverAuth", "TLS Web Server Authentication","1.3.6.1.5.5.7.3.1"); -ASN1.addObject(runtime, 129, "clientAuth", "TLS Web Client Authentication","1.3.6.1.5.5.7.3.2"); -ASN1.addObject(runtime, 130, "codeSigning", "Code Signing","1.3.6.1.5.5.7.3.3"); -ASN1.addObject(runtime, 131, "emailProtection", "E-mail Protection","1.3.6.1.5.5.7.3.4"); -ASN1.addObject(runtime, 132, "timeStamping", "Time Stamping","1.3.6.1.5.5.7.3.8"); -ASN1.addObject(runtime, 133, "msCodeInd", "Microsoft Individual Code Signing","1.3.6.1.4.1.311.2.1.21"); -ASN1.addObject(runtime, 134, "msCodeCom", "Microsoft Commercial Code Signing","1.3.6.1.4.1.311.2.1.22"); -ASN1.addObject(runtime, 135, "msCTLSign", "Microsoft Trust List Signing","1.3.6.1.4.1.311.10.3.1"); -ASN1.addObject(runtime, 136, "msSGC", "Microsoft Server Gated Crypto","1.3.6.1.4.1.311.10.3.3"); -ASN1.addObject(runtime, 137, "msEFS", "Microsoft Encrypted File System","1.3.6.1.4.1.311.10.3.4"); -ASN1.addObject(runtime, 138, "nsSGC", "Netscape Server Gated Crypto","2.16.840.1.113730.4.1"); -ASN1.addObject(runtime, 139, "deltaCRL", "X509v3 Delta CRL Indicator","2.5.29.27"); -ASN1.addObject(runtime, 140, "CRLReason", "CRL Reason Code","2.5.29.21"); -ASN1.addObject(runtime, 141, "invalidityDate", "Invalidity Date","2.5.29.24"); -ASN1.addObject(runtime, 142, "SXNetID", "Strong Extranet ID","1.3.101.1.4.1"); -ASN1.addObject(runtime, 143, "PBE-SHA1-RC4-128", "pbeWithSHA1And128BitRC4","1.2.840.113549.1.12.1.1"); -ASN1.addObject(runtime, 144, "PBE-SHA1-RC4-40", "pbeWithSHA1And40BitRC4","1.2.840.113549.1.12.1.2"); -ASN1.addObject(runtime, 145, "PBE-SHA1-3DES", "pbeWithSHA1And3-KeyTripleDES-CBC","1.2.840.113549.1.12.1.3"); -ASN1.addObject(runtime, 146, "PBE-SHA1-2DES", "pbeWithSHA1And2-KeyTripleDES-CBC","1.2.840.113549.1.12.1.4"); -ASN1.addObject(runtime, 147, "PBE-SHA1-RC2-128", "pbeWithSHA1And128BitRC2-CBC","1.2.840.113549.1.12.1.5"); -ASN1.addObject(runtime, 148, "PBE-SHA1-RC2-40", "pbeWithSHA1And40BitRC2-CBC","1.2.840.113549.1.12.1.6"); -ASN1.addObject(runtime, 149, null, "keyBag","1.2.840.113549.1.12.10.1.1"); -ASN1.addObject(runtime, 150, null, "pkcs8ShroudedKeyBag","1.2.840.113549.1.12.10.1.2"); -ASN1.addObject(runtime, 151, null, "certBag","1.2.840.113549.1.12.10.1.3"); -ASN1.addObject(runtime, 152, null, "crlBag","1.2.840.113549.1.12.10.1.4"); -ASN1.addObject(runtime, 153, null, "secretBag","1.2.840.113549.1.12.10.1.5"); -ASN1.addObject(runtime, 154, null, "safeContentsBag","1.2.840.113549.1.12.10.1.6"); -ASN1.addObject(runtime, 155, null, "PBES2","1.2.840.113549.1.5.13"); -ASN1.addObject(runtime, 156, null, "PBMAC1","1.2.840.113549.1.5.14"); -ASN1.addObject(runtime, 157, null, "hmacWithSHA1","1.2.840.113549.2.7"); -ASN1.addObject(runtime, 158, "id-qt-cps", "Policy Qualifier CPS","1.3.6.1.5.5.7.2.1"); -ASN1.addObject(runtime, 159, "id-qt-unotice", "Policy Qualifier User Notice","1.3.6.1.5.5.7.2.2"); -ASN1.addObject(runtime, 160, "RC2-64-CBC", "rc2-64-cbc",null); -ASN1.addObject(runtime, 161, "SMIME-CAPS", "S/MIME Capabilities","1.2.840.113549.1.9.15"); -ASN1.addObject(runtime, 162, "PBE-MD2-RC2-64", "pbeWithMD2AndRC2-CBC","1.2.840.113549.1.5.4"); -ASN1.addObject(runtime, 163, "PBE-MD5-RC2-64", "pbeWithMD5AndRC2-CBC","1.2.840.113549.1.5.6"); -ASN1.addObject(runtime, 164, "PBE-SHA1-DES", "pbeWithSHA1AndDES-CBC","1.2.840.113549.1.5.10"); -ASN1.addObject(runtime, 165, "msExtReq", "Microsoft Extension Request","1.3.6.1.4.1.311.2.1.14"); -ASN1.addObject(runtime, 166, "extReq", "Extension Request","1.2.840.113549.1.9.14"); -ASN1.addObject(runtime, 167, "name", "name","2.5.4.41"); -ASN1.addObject(runtime, 168, "dnQualifier", "dnQualifier","2.5.4.46"); -ASN1.addObject(runtime, 169, "id-pe", null,"1.3.6.1.5.5.7.1"); -ASN1.addObject(runtime, 170, "id-ad", null,"1.3.6.1.5.5.7.48"); -ASN1.addObject(runtime, 171, "authorityInfoAccess", "Authority Information Access","1.3.6.1.5.5.7.1.1"); -ASN1.addObject(runtime, 172, "OCSP", "OCSP","1.3.6.1.5.5.7.48.1"); -ASN1.addObject(runtime, 173, "caIssuers", "CA Issuers","1.3.6.1.5.5.7.48.2"); -ASN1.addObject(runtime, 174, "OCSPSigning", "OCSP Signing","1.3.6.1.5.5.7.3.9"); -ASN1.addObject(runtime, 175, "AES-128-EBC", "aes-128-ebc","2.16.840.1.101.3.4.1.1"); -ASN1.addObject(runtime, 176, "AES-128-CBC", "aes-128-cbc","2.16.840.1.101.3.4.1.2"); -ASN1.addObject(runtime, 177, "AES-128-OFB", "aes-128-ofb","2.16.840.1.101.3.4.1.3"); -ASN1.addObject(runtime, 178, "AES-128-CFB", "aes-128-cfb","2.16.840.1.101.3.4.1.4"); -ASN1.addObject(runtime, 179, "AES-192-EBC", "aes-192-ebc","2.16.840.1.101.3.4.1.21"); -ASN1.addObject(runtime, 180, "AES-192-CBC", "aes-192-cbc","2.16.840.1.101.3.4.1.22"); -ASN1.addObject(runtime, 181, "AES-192-OFB", "aes-192-ofb","2.16.840.1.101.3.4.1.23"); -ASN1.addObject(runtime, 182, "AES-192-CFB", "aes-192-cfb","2.16.840.1.101.3.4.1.24"); -ASN1.addObject(runtime, 183, "AES-256-EBC", "aes-256-ebc","2.16.840.1.101.3.4.1.41"); -ASN1.addObject(runtime, 184, "AES-256-CBC", "aes-256-cbc","2.16.840.1.101.3.4.1.42"); -ASN1.addObject(runtime, 185, "AES-256-OFB", "aes-256-ofb","2.16.840.1.101.3.4.1.43"); -ASN1.addObject(runtime, 186, "AES-256-CFB", "aes-256-cfb","2.16.840.1.101.3.4.1.44"); - } - - public static interface KeyAndIv { - byte[] getKey(); - byte[] getIv(); - } - - private static class KeyAndIvImpl implements KeyAndIv { - private final byte[] key; - private final byte[] iv; - public KeyAndIvImpl(byte[] key, byte[] iv) { - this.key = key; - this.iv = iv; - } - public byte[] getKey() { - return key; - } - public byte[] getIv() { - return iv; - } - } - - public static PEMHandler getPEMHandler() { - try { - return new org.jruby.ext.openssl.BouncyCastlePEMHandler(); - } catch (Exception e) { - // fallback to... - } - return new DefaultPEMHandler(); - } - - public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) { - byte[] key = new byte[key_len]; - byte[] iv = new byte[iv_len]; - int key_ix = 0; - int iv_ix = 0; - byte[] md_buf = null; - int nkey = key_len; - int niv = iv_len; - int i = 0; - if(data == null) { - return new KeyAndIvImpl(key,iv); - } - int addmd = 0; - for(;;) { - md.reset(); - if(addmd++ > 0) { - md.update(md_buf); - } - md.update(data); - if(null != salt) { - md.update(salt,0,8); - } - md_buf = md.digest(); - for(i=1;i 0) { - for(;;) { - if(nkey == 0) break; - if(i == md_buf.length) break; - key[key_ix++] = md_buf[i]; - nkey--; - i++; - } - } - if(niv > 0 && i != md_buf.length) { - for(;;) { - if(niv == 0) break; - if(i == md_buf.length) break; - iv[iv_ix++] = md_buf[i]; - niv--; - i++; - } - } - if(nkey == 0 && niv == 0) { - break; - } - } - for(i=0;i - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateFactory; -import java.util.ArrayList; -import java.util.List; - -import javax.crypto.SecretKeyFactory; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.anno.JRubyMethod; -import org.jruby.anno.JRubyModule; -import org.jruby.ext.openssl.Cipher.CipherModule; -import org.jruby.ext.openssl.x509store.X509Error; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class OpenSSLReal { - private static java.security.Provider BC_PROVIDER = null; - - static { - try { - BC_PROVIDER = (java.security.Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance(); - } catch (Throwable ignored) { - // no bouncy castle available - } - } - - public interface Runnable { - public void run() throws GeneralSecurityException; - } - - public interface Callable { - public Object call() throws GeneralSecurityException; - } - - public static void doWithBCProvider(final Runnable toRun) throws GeneralSecurityException { - getWithBCProvider(new Callable() { - - public Object call() throws GeneralSecurityException { - toRun.run(); - return null; - } - }); - } - - // This method just adds BouncyCastleProvider if it's allowed. Removing - // "BC" can remove pre-installed or runtime-added BC provider by elsewhere - // and it causes unknown runtime error anywhere. We avoid this. To use - // part of jruby-openssl feature (X.509 and PKCS), users must be aware of - // dynamic BC provider adding. - public static Object getWithBCProvider(Callable toCall) throws GeneralSecurityException { - try { - if (BC_PROVIDER != null && java.security.Security.getProvider("BC") == null) { - java.security.Security.addProvider(BC_PROVIDER); - } - return toCall.call(); - } catch (NoSuchProviderException nspe) { - throw new GeneralSecurityException(bcExceptionMessage(nspe), nspe); - } catch (Exception e) { - throw new GeneralSecurityException(e.getMessage(), e); - } - } - - public static String bcExceptionMessage(NoSuchProviderException nspe) { - return "You need to configure JVM/classpath to enable BouncyCastle Security Provider: " + nspe.getMessage(); - } - - public static String bcExceptionMessage(NoClassDefFoundError ncdfe) { - return "You need to configure JVM/classpath to enable BouncyCastle Security Provider: NoClassDefFoundError: " + ncdfe.getMessage(); - } - - public static void createOpenSSL(Ruby runtime) { - RubyModule ossl = runtime.getOrCreateModule("OpenSSL"); - RubyClass standardError = runtime.getClass("StandardError"); - ossl.defineClassUnder("OpenSSLError", standardError, standardError.getAllocator()); - ossl.defineAnnotatedMethods(OpenSSLModule.class); - - // those are BC provider free (uses BC class but does not use BC provider) - PKey.createPKey(runtime, ossl); - BN.createBN(runtime, ossl); - Digest.createDigest(runtime, ossl); - Cipher.createCipher(runtime, ossl); - Random.createRandom(runtime, ossl); - HMAC.createHMAC(runtime, ossl); - Config.createConfig(runtime, ossl); - - // these classes depends on BC provider now. - try { - ASN1.createASN1(runtime, ossl); - X509.createX509(runtime, ossl); - NetscapeSPKI.createNetscapeSPKI(runtime, ossl); - PKCS7.createPKCS7(runtime, ossl); - } catch (SecurityException ignore) { - // some class might be prohibited to use. - runtime.getLoadService().require("openssl/dummy"); - } catch (Error ignore) { - // mainly for rescuing NoClassDefFoundError: no bc*.jar - runtime.getLoadService().require("openssl/dummy"); - } - try { - SSL.createSSL(runtime, ossl); - } catch (SecurityException ignore) { - // some class might be prohibited to use. ex. SSL* on GAE/J. - runtime.getLoadService().require("openssl/dummyssl"); - } catch (Error ignore) { - // mainly for rescuing NoClassDefFoundError: no bc*.jar - runtime.getLoadService().require("openssl/dummyssl"); - } - - runtime.getLoadService().require("jopenssl/version"); - String jopensslVersion = runtime.getClassFromPath("Jopenssl::Version").getConstant("VERSION").toString(); - ossl.setConstant("VERSION", runtime.newString("1.0.0")); - ossl.setConstant("OPENSSL_VERSION", - runtime.newString("jruby-ossl " + jopensslVersion)); - ossl.setConstant("OPENSSL_VERSION_NUMBER", runtime.newFixnum(9469999)); - OpenSSLModule.setDebug(ossl, runtime.getFalse()); - } - - @JRubyModule(name = "OpenSSL") - public static class OpenSSLModule { - - @JRubyMethod(name = "errors", meta = true) - public static IRubyObject errors(IRubyObject recv) { - Ruby runtime = recv.getRuntime(); - RubyArray result = runtime.newArray(); - for (X509Error.ErrorException e : X509Error.getErrors()) { - result.add(runtime.newString(e.getMessage())); - } - return result; - } - - @JRubyMethod(name = "debug", meta = true) - public static IRubyObject getDebug(IRubyObject recv) { - return (IRubyObject)((RubyModule) recv).getInternalVariable("debug"); - } - - @JRubyMethod(name = "debug=", meta = true) - public static IRubyObject setDebug(IRubyObject recv, IRubyObject debug) { - ((RubyModule) recv).setInternalVariable("debug", debug); - return debug; - } - } - - public static javax.crypto.Cipher getCipherBC(final String algorithm) throws GeneralSecurityException { - return (javax.crypto.Cipher) getWithBCProvider(new Callable() { - - public Object call() throws GeneralSecurityException { - return javax.crypto.Cipher.getInstance(algorithm, "BC"); - } - }); - } - - public static SecretKeyFactory getSecretKeyFactoryBC(final String algorithm) throws GeneralSecurityException { - return (SecretKeyFactory) getWithBCProvider(new Callable() { - - public Object call() throws GeneralSecurityException { - return SecretKeyFactory.getInstance(algorithm, "BC"); - } - }); - } - - public static MessageDigest getMessageDigestBC(final String algorithm) throws GeneralSecurityException { - return (MessageDigest) getWithBCProvider(new Callable() { - - public Object call() throws GeneralSecurityException { - return MessageDigest.getInstance(algorithm, "BC"); - } - }); - } - - public static CertificateFactory getX509CertificateFactoryBC() throws GeneralSecurityException { - return (CertificateFactory) getWithBCProvider(new Callable() { - - public Object call() throws GeneralSecurityException { - return CertificateFactory.getInstance("X.509", "BC"); - } - }); - } -}// OpenSSLReal - diff --git a/src/java/org/jruby/ext/openssl/PEMHandler.java b/src/java/org/jruby/ext/openssl/PEMHandler.java deleted file mode 100644 index 9e523f2..0000000 --- a/src/java/org/jruby/ext/openssl/PEMHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.Reader; -import java.io.Writer; - -/** - * @author Ola Bini - */ -public interface PEMHandler { - Object readPEM(Reader read, String password) throws Exception; - void writePEM(Writer writ, Object obj, String algorithm, char[] password) throws Exception; - void writePEM(Writer writ, Object obj) throws Exception; -}// PEMHandler diff --git a/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java b/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java deleted file mode 100644 index b1c6d66..0000000 --- a/src/java/org/jruby/ext/openssl/PKCS10CertificationRequestExt.java +++ /dev/null @@ -1,159 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.ByteArrayOutputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; -import org.bouncycastle.jce.PKCS10CertificationRequest; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class PKCS10CertificationRequestExt extends PKCS10CertificationRequest { - public PKCS10CertificationRequestExt(byte[] bytes) { - super(bytes); - } - - public PKCS10CertificationRequestExt(ASN1Sequence sequence) { - super(sequence); - } - - public PKCS10CertificationRequestExt( - String signatureAlgorithm, - org.bouncycastle.asn1.x509.X509Name subject, - PublicKey key, - ASN1Set attributes, - PrivateKey signingKey) - throws NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException, SignatureException - { - super(signatureAlgorithm,subject,key,attributes,signingKey); - } - - public PKCS10CertificationRequestExt( - String signatureAlgorithm, - X500Principal subject, - PublicKey key, - ASN1Set attributes, - PrivateKey signingKey) - throws NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException, SignatureException - { - super(signatureAlgorithm,subject,key,attributes,signingKey); - } - - public PKCS10CertificationRequestExt( - String signatureAlgorithm, - X500Principal subject, - PublicKey key, - ASN1Set attributes, - PrivateKey signingKey, - String provider) - throws NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException, SignatureException - { - super(signatureAlgorithm,subject,key,attributes,signingKey,provider); - } - - public PKCS10CertificationRequestExt( - String signatureAlgorithm, - org.bouncycastle.asn1.x509.X509Name subject, - PublicKey key, - ASN1Set attributes, - PrivateKey signingKey, - String provider) - throws NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException, SignatureException - { - super(signatureAlgorithm,subject,key,attributes,signingKey,provider); - } - - public void setAttributes(DERSet attrs) { - ASN1Sequence seq = (ASN1Sequence)this.reqInfo.toASN1Object(); - ASN1EncodableVector v1 = new ASN1EncodableVector(); - for(int i=0;i<(seq.size()-1);i++) { - v1.add(seq.getObjectAt(i)); - } - v1.add(new DERTaggedObject(0,attrs)); - this.reqInfo = new CertificationRequestInfo(new DERSequence(v1)); - } - - public void setVersion(int v) { - DERInteger nVersion = new DERInteger(v); - ASN1Sequence seq = (ASN1Sequence)this.reqInfo.toASN1Object(); - ASN1EncodableVector v1 = new ASN1EncodableVector(); - v1.add(nVersion); - for(int i=1;i - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.io.StringWriter; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.cert.CertificateEncodingException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; - -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyBignum; -import org.jruby.RubyClass; -import org.jruby.RubyFile; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.ASN1Registry; -import org.jruby.ext.openssl.impl.BIO; -import org.jruby.ext.openssl.impl.CipherSpec; -import org.jruby.ext.openssl.impl.MemBIO; -import org.jruby.ext.openssl.impl.Mime; -import org.jruby.ext.openssl.impl.NotVerifiedPKCS7Exception; -import org.jruby.ext.openssl.impl.PKCS7Exception; -import org.jruby.ext.openssl.impl.RecipInfo; -import org.jruby.ext.openssl.impl.SMIME; -import org.jruby.ext.openssl.impl.SignerInfoWithPkey; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.ext.openssl.x509store.Store; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.runtime.Arity; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class PKCS7 extends RubyObject { - private static final long serialVersionUID = -3925104500966826973L; - - private static ObjectAllocator PKCS7_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new PKCS7(runtime, klass); - } - }; - - public static void createPKCS7(Ruby runtime, RubyModule mOSSL) { - RubyClass cPKCS7 = mOSSL.defineClassUnder("PKCS7",runtime.getObject(),PKCS7_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - cPKCS7.defineClassUnder("PKCS7Error",openSSLError,openSSLError.getAllocator()); - cPKCS7.addReadWriteAttribute(runtime.getCurrentContext(), "data"); - cPKCS7.addReadWriteAttribute(runtime.getCurrentContext(), "error_string"); - cPKCS7.defineAnnotatedMethods(PKCS7.class); - cPKCS7.defineAnnotatedMethods(ModuleMethods.class); - - SignerInfo.createSignerInfo(runtime,cPKCS7); - RecipientInfo.createRecipientInfo(runtime,cPKCS7); - - cPKCS7.setConstant("TEXT",runtime.newFixnum(1)); - cPKCS7.setConstant("NOCERTS",runtime.newFixnum(2)); - cPKCS7.setConstant("NOSIGS",runtime.newFixnum(4)); - cPKCS7.setConstant("NOCHAIN",runtime.newFixnum(8)); - cPKCS7.setConstant("NOINTERN",runtime.newFixnum(16)); - cPKCS7.setConstant("NOVERIFY",runtime.newFixnum(32)); - cPKCS7.setConstant("DETACHED",runtime.newFixnum(64)); - cPKCS7.setConstant("BINARY",runtime.newFixnum(128)); - cPKCS7.setConstant("NOATTR",runtime.newFixnum(256)); - cPKCS7.setConstant("NOSMIMECAP",runtime.newFixnum(512)); - } - - public static BIO obj2bio(IRubyObject obj) { - if(obj instanceof RubyFile) { - throw new IllegalArgumentException("TODO: handle RubyFile correctly"); -// if (TYPE(obj) == T_FILE) { -// OpenFile *fptr; -// GetOpenFile(obj, fptr); -// rb_io_check_readable(fptr); -// bio = BIO_new_fp(fptr->f, BIO_NOCLOSE); - } else { - RubyString str = obj.convertToString(); - ByteList bl = str.getByteList(); - return BIO.memBuf(bl.getUnsafeBytes(), bl.getBegin(), bl.getRealSize()); - } - } - - public static PKCS7 wrap(RubyClass klass, org.jruby.ext.openssl.impl.PKCS7 p7) { - PKCS7 wrapped = new PKCS7(klass.getRuntime(), klass); - wrapped.p7 = p7; - return wrapped; - } - - public static IRubyObject membio2str(Ruby runtime, BIO bio) { - return runtime.newString(new ByteList(((MemBIO)bio).getMemCopy(), false)); - } - - private static List x509_ary2sk(IRubyObject ary) { - List certs = new ArrayList(); - RubyArray arr = (RubyArray)ary; - for(int i = 0; i x509s = certs.isNil() - ? null - : x509_ary2sk(certs); - - try { - org.jruby.ext.openssl.impl.PKCS7 p7 = org.jruby.ext.openssl.impl.PKCS7.sign(x509, pkey, x509s, in, flg); - PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7"), p7); - ret.setData(data); - return ret; - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(recv.getRuntime(), pkcs7e); - } - } - - /** ossl_pkcs7_s_encrypt - * - */ - @JRubyMethod(meta=true, rest=true) - public static IRubyObject encrypt(IRubyObject recv, IRubyObject[] args) { - IRubyObject certs, data, cipher = recv.getRuntime().getNil(), flags = recv.getRuntime().getNil(); - switch(Arity.checkArgumentCount(recv.getRuntime(), args, 2, 4)) { - case 4: - flags = args[3]; - case 3: - cipher = args[2]; - } - data = args[1]; - certs = args[0]; - CipherSpec ciph = null; - if (cipher.isNil()) { - try { - ciph = new CipherSpec(javax.crypto.Cipher.getInstance("RC2/CBC/PKCS5Padding"), Cipher.Algorithm.jsseToOssl("RC2/CBC/PKCS5Padding", 40), 40); - } catch (GeneralSecurityException gse) { - throw newPKCS7Error(recv.getRuntime(), gse.getMessage()); - } - } else { - Cipher c = ((Cipher) cipher); - ciph = new CipherSpec(c.getCipher(), c.getName(), c.getGenerateKeyLen() * 8); - } - int flg = flags.isNil() ? 0 : RubyNumeric.fix2int(flags); - byte[] in = data.convertToString().getBytes(); - List x509s = x509_ary2sk(certs); - try { - org.jruby.ext.openssl.impl.PKCS7 p7 = org.jruby.ext.openssl.impl.PKCS7.encrypt(x509s, in, ciph, flg); - PKCS7 ret = wrap(Utils.getClassFromPath(recv.getRuntime(), "OpenSSL::PKCS7"), p7); - ret.setData(data); - return ret; - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(recv.getRuntime(), pkcs7e); - } - } - } - - public PKCS7(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private org.jruby.ext.openssl.impl.PKCS7 p7; - - public void setData(IRubyObject object) { - setInstanceVariable("@data", object); - } - - public IRubyObject getData() { - return getInstanceVariable("@data"); - } - - @JRubyMethod(name="initialize", rest=true) - public IRubyObject _initialize(IRubyObject[] args) { - IRubyObject arg = null; - if(Arity.checkArgumentCount(getRuntime(), args, 0, 1) == 0) { - p7 = new org.jruby.ext.openssl.impl.PKCS7(); - try { - p7.setType(ASN1Registry.NID_undef); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - return this; - } - arg = args[0]; - arg = OpenSSLImpl.to_der_if_possible(arg); - BIO input = obj2bio(arg); - try { - p7 = org.jruby.ext.openssl.impl.PKCS7.readPEM(input); - if (p7 == null) { - input.reset(); - p7 = org.jruby.ext.openssl.impl.PKCS7.fromASN1(input); - } - } catch (IOException ioe) { - throw newPKCS7Error(getRuntime(), ioe.getMessage()); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - setData(getRuntime().getNil()); - return this; - } - - @Override - @JRubyMethod - public IRubyObject initialize_copy(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#init_copy"); - return this; - } - - @JRubyMethod(name="type=") - public IRubyObject set_type(IRubyObject obj) { - int typeId = ASN1Registry.NID_undef; - - String type = obj.convertToString().asJavaString(); - - if ("signed".equals(type)) { - typeId = ASN1Registry.NID_pkcs7_signed; - } else if ("data".equals(type)) { - typeId = ASN1Registry.NID_pkcs7_data; - } else if ("signedAndEnveloped".equals(type)) { - typeId = ASN1Registry.NID_pkcs7_signedAndEnveloped; - } else if ("enveloped".equals(type)) { - typeId = ASN1Registry.NID_pkcs7_enveloped; - } else if ("encrypted".equals(type)) { - typeId = ASN1Registry.NID_pkcs7_encrypted; - } - - try { - p7.setType(typeId); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - - return obj; - } - - @JRubyMethod(name="type") - public IRubyObject get_type() { - if(p7.isSigned()) { - return getRuntime().newSymbol("signed"); - } - if(p7.isEncrypted()) { - return getRuntime().newSymbol("encrypted"); - } - if(p7.isEnveloped()) { - return getRuntime().newSymbol("enveloped"); - } - if(p7.isSignedAndEnveloped()) { - return getRuntime().newSymbol("signedAndEnveloped"); - } - if(p7.isData()) { - return getRuntime().newSymbol("data"); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="detached=") - public IRubyObject set_detached(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#detached="); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject detached() { - System.err.println("WARNING: unimplemented method called PKCS7#detached"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="detached?") - public IRubyObject detached_p() { - System.err.println("WARNING: unimplemented method called PKCS7#detached?"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="cipher=") - public IRubyObject set_cipher(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#cipher="); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject add_signer(IRubyObject obj) { - SignerInfoWithPkey p7si = ((SignerInfo)obj).getSignerInfo().dup(); - - try { - p7.addSigner(p7si); - } catch (PKCS7Exception pkcse) { - throw newPKCS7Exception(getRuntime(), pkcse); - } - // TODO: Handle exception here - - if(p7.isSigned()) { - p7si.addSignedAttribute(ASN1Registry.NID_pkcs9_contentType, ASN1Registry.nid2obj(ASN1Registry.NID_pkcs7_data)); - } - - return this; - } - - /** ossl_pkcs7_get_signer - * - * This seems to return a list of SignerInfo objects. - * - */ - @JRubyMethod - public IRubyObject signers() { - Collection sk = p7.getSignerInfo(); - RubyArray ary = getRuntime().newArray(sk.size()); - for(SignerInfoWithPkey si : sk) { - ary.append(SignerInfo.create(getRuntime(), si)); - } - return ary; - } - - @JRubyMethod - public IRubyObject add_recipient(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#add_recipient"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject recipients() { - Collection sk = null; - - if(p7.isEnveloped()) { - sk = p7.getEnveloped().getRecipientInfo(); - } else if(p7.isSignedAndEnveloped()) { - sk = p7.getSignedAndEnveloped().getRecipientInfo(); - } else { - sk = null; - } - if(sk == null) { - return getRuntime().newArray(); - } - - RubyArray ary = getRuntime().newArray(sk.size()); - for(RecipInfo ri : sk) { - ary.append(RecipientInfo.create(getRuntime(), ri)); - } - return ary; - } - - @JRubyMethod - public IRubyObject add_certificate(IRubyObject obj) { - try { - p7.addCertificate(((X509Cert)obj).getAuxCert()); - } catch (PKCS7Exception pkcse) { - throw newPKCS7Exception(getRuntime(), pkcse); - } - return this; - } - - @JRubyMethod(name="certificates=") - public IRubyObject set_certificates(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#certificates="); - return getRuntime().getNil(); - } - - private Collection getCertificates() { - Collection certs; - int i = p7.getType(); - switch(i) { - case ASN1Registry.NID_pkcs7_signed: - certs = p7.getSign().getCert(); - break; - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - certs = p7.getSignedAndEnveloped().getCert(); - break; - default: - certs = new HashSet(); - break; - } - return certs; - } - - private RubyArray certsToArray(Collection certs) throws CertificateEncodingException { - RubyArray ary = getRuntime().newArray(certs.size()); - for(X509AuxCertificate x509 : certs) { - ary.append(X509Cert.wrap(getRuntime(), x509)); - } - return ary; - } - - @JRubyMethod - public IRubyObject certificates() { - try { - return certsToArray(getCertificates()); - } catch (CertificateEncodingException cee) { - throw newPKCS7Error(getRuntime(), cee.getMessage()); - } - } - - @JRubyMethod - public IRubyObject add_crl(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#add_crl"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="crls=") - public IRubyObject set_crls(IRubyObject obj) { - System.err.println("WARNING: unimplemented method called PKCS7#crls="); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject crls() { - System.err.println("WARNING: unimplemented method called PKCS7#crls"); - return getRuntime().getNil(); - } - - @JRubyMethod(name={"add_data", "data="}) - public IRubyObject add_data(IRubyObject obj) { - if (p7.isSigned()) { - try { - p7.contentNew(ASN1Registry.NID_pkcs7_data); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - } - - BIO in = obj2bio(obj); - BIO out = null; - try { - out = p7.dataInit(null); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - byte[] buf = new byte[4096]; - for(;;) { - try { - int i = in.read(buf, 0, buf.length); - if(i <= 0) { - break; - } - if(out != null) { - out.write(buf, 0, i); - } - } catch(IOException e) { - throw getRuntime().newIOErrorFromException(e); - } - } - - try { - p7.dataFinal(out); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - setData(getRuntime().getNil()); - - return obj; - } - - @JRubyMethod(rest=true) - public IRubyObject verify(IRubyObject[] args) { - IRubyObject certs = null; - IRubyObject store = null; - IRubyObject indata = getRuntime().getNil(); - IRubyObject vflags = getRuntime().getNil(); - - switch(Arity.checkArgumentCount(getRuntime(), args, 2, 4)) { - case 4: - vflags = args[3]; - case 3: - indata = args[2]; - default: - store = args[1]; - certs = args[0]; - } - int flg = vflags.isNil() ? 0 : RubyNumeric.fix2int(vflags); - - if(indata.isNil()) { - indata = getData(); - } - - BIO in = indata.isNil() ? null : obj2bio(indata); - - List x509s = certs.isNil() - ? null - : x509_ary2sk(certs); - - Store x509st = ((X509Store)store).getStore(); - BIO out = BIO.mem(); - - boolean result = false; - try { - p7.verify(x509s, x509st, in, out, flg); - result = true; - } catch(NotVerifiedPKCS7Exception e) { - result = false; - } catch(PKCS7Exception pkcs7e) { - if (getRuntime().isDebug()) { - System.err.println(pkcs7e.toString()); - pkcs7e.printStackTrace(System.err); - } - result = false; - } - - IRubyObject data = membio2str(getRuntime(), out); - setData(data); - - return result ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod(rest=true) - public IRubyObject decrypt(IRubyObject[] args) { - IRubyObject dflags = getRuntime().getNil(); - if(Arity.checkArgumentCount(getRuntime(), args, 2, 3) == 3) { - dflags = args[2]; - } - IRubyObject pkey = args[0]; - IRubyObject cert = args[1]; - PrivateKey key = ((PKey)pkey).getPrivateKey(); - X509AuxCertificate x509 = ((X509Cert)cert).getAuxCert(); - int flg = dflags.isNil() ? 0 : RubyNumeric.fix2int(dflags); - - BIO out = BIO.mem(); - try { - p7.decrypt(key, x509, out, flg); - } catch (PKCS7Exception pkcs7e) { - throw newPKCS7Exception(getRuntime(), pkcs7e); - } - - return membio2str(getRuntime(), out); - } - - public static RaiseException newPKCS7Exception(Ruby ruby, PKCS7Exception pkcs7e) { - if (ruby.isDebug()) { - System.err.println(pkcs7e.toString()); - pkcs7e.printStackTrace(System.err); - } - return Utils.newError(ruby, "OpenSSL::PKCS7::PKCS7Error", pkcs7e.getMessage()); - } - - @JRubyMethod(name = {"to_pem", "to_s"}) - public IRubyObject to_pem() { - try { - StringWriter w = new StringWriter(); - PEMInputOutput.writePKCS7(w, p7.toASN1()); - w.close(); - return getRuntime().newString(w.toString()); - } catch (IOException ex) { - throw getRuntime().newIOErrorFromException(ex); - } - } - - @JRubyMethod - public IRubyObject to_der() { - try { - return getRuntime().newString(new ByteList(p7.toASN1(), false)); - } catch (IOException ioe) { - throw newPKCS7Error(getRuntime(), ioe.getMessage()); - } - } - - public static class SignerInfo extends RubyObject { - private static final long serialVersionUID = -3799397032272738848L; - - private static ObjectAllocator SIGNERINFO_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new SignerInfo(runtime, klass); - } - }; - - public static void createSignerInfo(Ruby runtime, RubyModule cPKCS7) { - RubyClass cPKCS7Signer = cPKCS7.defineClassUnder("SignerInfo",runtime.getObject(),SIGNERINFO_ALLOCATOR); - cPKCS7.defineConstant("Signer",cPKCS7Signer); - - cPKCS7Signer.defineAnnotatedMethods(SignerInfo.class); - } - - public static SignerInfo create(Ruby runtime, SignerInfoWithPkey info) { - SignerInfo sinfo = new SignerInfo(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKCS7::SignerInfo")); - sinfo.initWithSignerInformation(info); - return sinfo; - } - - public SignerInfo(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private SignerInfoWithPkey info; - - private void initWithSignerInformation(SignerInfoWithPkey info) { - this.info = info; - } - - SignerInfoWithPkey getSignerInfo() { - return info; - } - - @JRubyMethod - public IRubyObject initialize(IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) { - System.err.println("WARNING: unimplemented method called SignerInfo#initialize"); - return this; - } - - - @JRubyMethod(name={"issuer","name"}) - public IRubyObject issuer() { - return X509Name.create(getRuntime(), info.getIssuerAndSerialNumber().getName()); - } - - @JRubyMethod - public IRubyObject serial() { - return RubyBignum.bignorm(getRuntime(), info.getIssuerAndSerialNumber().getCertificateSerialNumber().getValue()); - } - - @JRubyMethod - public IRubyObject signed_time() { - System.err.println("WARNING: unimplemented method called SignerInfo#signed_time"); - return getRuntime().getNil(); - } - } - - public static class RecipientInfo extends RubyObject { - private static final long serialVersionUID = 6977793206950149902L; - - private static ObjectAllocator RECIPIENTINFO_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new RecipientInfo(runtime, klass); - } - }; - - public static void createRecipientInfo(Ruby runtime, RubyModule cPKCS7) { - RubyClass cPKCS7Recipient = cPKCS7.defineClassUnder("RecipientInfo",runtime.getObject(),RECIPIENTINFO_ALLOCATOR); - - cPKCS7Recipient.defineAnnotatedMethods(RecipientInfo.class); - } - - public RecipientInfo(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - - public static RecipientInfo create(Ruby runtime, RecipInfo info) { - RecipientInfo rinfo = new RecipientInfo(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKCS7::RecipientInfo")); - rinfo.initWithRecipientInformation(info); - return rinfo; - } - - private RecipInfo info; - - private void initWithRecipientInformation(RecipInfo info) { - this.info = info; - } - - @JRubyMethod - public IRubyObject initialize(IRubyObject arg) { - System.err.println("WARNING: unimplemented method called RecipientInfo#initialize"); - return this; - } - - @JRubyMethod - public IRubyObject issuer() { - return X509Name.create(getRuntime(), info.getIssuerAndSerial().getName()); - } - - @JRubyMethod - public IRubyObject serial() { - return RubyBignum.bignorm(getRuntime(), info.getIssuerAndSerial().getCertificateSerialNumber().getValue()); - } - - @JRubyMethod - public IRubyObject enc_key() { - System.err.println("WARNING: unimplemented method called RecipientInfo#enc_key"); - return getRuntime().getNil(); - } - } - - private static RaiseException newPKCS7Error(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::PKCS7::PKCS7Error", message); - } -}// PKCS7 diff --git a/src/java/org/jruby/ext/openssl/PKey.java b/src/java/org/jruby/ext/openssl/PKey.java deleted file mode 100644 index fd8945f..0000000 --- a/src/java/org/jruby/ext/openssl/PKey.java +++ /dev/null @@ -1,264 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPublicKey; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.Arity; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public abstract class PKey extends RubyObject { - private static final long serialVersionUID = 6114668087816965720L; - - public static void createPKey(Ruby runtime, RubyModule ossl) { - RubyModule mPKey = ossl.defineModuleUnder("PKey"); - mPKey.defineAnnotatedMethods(PKeyModule.class); - // PKey is abstract - RubyClass cPKey = mPKey.defineClassUnder("PKey",runtime.getObject(),ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - mPKey.defineClassUnder("PKeyError",openSSLError,openSSLError.getAllocator()); - - cPKey.defineAnnotatedMethods(PKey.class); - - PKeyRSA.createPKeyRSA(runtime,mPKey); - PKeyDSA.createPKeyDSA(runtime,mPKey); - PKeyDH.createPKeyDH(runtime, mPKey, cPKey); - } - - public static RaiseException newPKeyError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::PKey::PKeyError", message); - } - - public static class PKeyModule { - - @JRubyMethod(name = "read", meta = true, required = 1, optional = 1) - public static IRubyObject read(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) { - Ruby runtime = ctx.runtime; - IRubyObject data; - char[] pass; - switch (args.length) { - case 1: - data = args[0]; - pass = null; - break; - default: - data = args[0]; - pass = args[1].isNil() ? null : args[1].toString().toCharArray(); - } - byte[] input = OpenSSLImpl.readX509PEM(data); - KeyPair key = null; - // d2i_PrivateKey_bio - try { - key = org.jruby.ext.openssl.impl.PKey.readPrivateKey(input); - } catch (IOException ioe) { - // ignore - } catch (GeneralSecurityException gse) { - // ignore - } - // PEM_read_bio_PrivateKey - if (key == null) { - try { - key = PEMInputOutput.readPrivateKey(new InputStreamReader(new ByteArrayInputStream(input)), pass); - } catch (IOException ioe) { - // ignore - } - } - if (key != null) { - if (key.getPublic().getAlgorithm().equals("RSA")) { - return new PKeyRSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::RSA"), (RSAPrivateCrtKey) key.getPrivate(), - (RSAPublicKey) key.getPublic()); - } else if (key.getPublic().getAlgorithm().equals("DSA")) { - return new PKeyDSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::DSA"), (DSAPrivateKey) key.getPrivate(), - (DSAPublicKey) key.getPublic()); - } - } - - PublicKey pubKey = null; - // d2i_PUBKEY_bio - try { - pubKey = org.jruby.ext.openssl.impl.PKey.readPublicKey(input); - } catch (IOException ioe) { - // ignore - } catch (GeneralSecurityException gse) { - // ignore - } - // PEM_read_bio_PUBKEY - if (pubKey == null) { - try { - pubKey = PEMInputOutput.readPubKey(new InputStreamReader(new ByteArrayInputStream(input))); - } catch (IOException ioe) { - // ignore - } - } - - if (pubKey != null) { - if (pubKey.getAlgorithm().equals("RSA")) { - return new PKeyRSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::RSA"), (RSAPublicKey) pubKey); - } else if (key.getPublic().getAlgorithm().equals("DSA")) { - return new PKeyDSA(runtime, Utils.getClassFromPath(runtime, "OpenSSL::PKey::DSA"), (DSAPublicKey) pubKey); - } - } - - throw runtime.newArgumentError("Could not parse PKey"); - } - } - - public PKey(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - @Override - @JRubyMethod - public IRubyObject initialize(ThreadContext context) { - return this; - } - - PublicKey getPublicKey() { - return null; - } - - PrivateKey getPrivateKey() { - return null; - } - - String getAlgorithm() { - return "NONE"; - } - - // NetscapeSPKI uses it. - public abstract IRubyObject to_der(); - - @JRubyMethod(name = "sign") - public IRubyObject sign(IRubyObject digest, IRubyObject data) { - if (!this.callMethod(getRuntime().getCurrentContext(), "private?").isTrue()) { - throw getRuntime().newArgumentError("Private key is needed."); - } - String digAlg = ((Digest) digest).getShortAlgorithm(); - try { - Signature sig = Signature.getInstance(digAlg + "WITH" + getAlgorithm()); - sig.initSign(getPrivateKey()); - byte[] inp = data.convertToString().getBytes(); - sig.update(inp); - byte[] sigge = sig.sign(); - return RubyString.newString(getRuntime(), sigge); - } catch (GeneralSecurityException gse) { - throw newPKeyError(getRuntime(), gse.getMessage()); - } - /* - GetPKey(self, pkey); - EVP_SignInit(&ctx, GetDigestPtr(digest)); - StringValue(data); - EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len); - str = rb_str_new(0, EVP_PKEY_size(pkey)+16); - if (!EVP_SignFinal(&ctx, RSTRING(str)->ptr, &buf_len, pkey)) - ossl_raise(ePKeyError, NULL); - assert(buf_len <= RSTRING(str)->len); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; - - return str; - */ - } - - @JRubyMethod(name = "verify") - public IRubyObject verify(IRubyObject digest, IRubyObject sig, IRubyObject data) { - if (!(digest instanceof Digest)) { - throw newPKeyError(getRuntime(), "invalid digest"); - } - if (!(sig instanceof RubyString)) { - throw newPKeyError(getRuntime(), "invalid signature"); - } - if (!(data instanceof RubyString)) { - throw newPKeyError(getRuntime(), "invalid data"); - } - byte[] sigBytes = ((RubyString)sig).getBytes(); - byte[] dataBytes = ((RubyString)data).getBytes(); - String algorithm = ((Digest)digest).getShortAlgorithm() + "WITH" + getAlgorithm(); - boolean valid; - try { - Signature signature = Signature.getInstance(algorithm); - signature.initVerify(getPublicKey()); - signature.update(dataBytes); - valid = signature.verify(sigBytes); - } catch (NoSuchAlgorithmException e) { - throw newPKeyError(getRuntime(), "unsupported algorithm: " + algorithm); - } catch (SignatureException e) { - throw newPKeyError(getRuntime(), "invalid signature"); - } catch (InvalidKeyException e) { - throw newPKeyError(getRuntime(), "invalid key"); - } - return getRuntime().newBoolean(valid); - } - - protected static void addSplittedAndFormatted(StringBuilder result, BigInteger value) { - String v = value.toString(16); - if ((v.length() % 2) != 0) { - v = "0" + v; - } - String sep = ""; - for (int i = 0; i < v.length(); i += 2) { - result.append(sep); - if ((i % 30) == 0) { - result.append("\n "); - } - result.append(v.substring(i, i + 2)); - sep = ":"; - } - result.append("\n"); - } -}// PKey diff --git a/src/java/org/jruby/ext/openssl/PKeyDH.java b/src/java/org/jruby/ext/openssl/PKeyDH.java deleted file mode 100644 index 3587f51..0000000 --- a/src/java/org/jruby/ext/openssl/PKeyDH.java +++ /dev/null @@ -1,398 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2007 William N Dortch - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.SecureRandom; -import java.security.spec.InvalidParameterSpecException; -import java.util.HashMap; - -import javax.crypto.spec.DHParameterSpec; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyHash; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.Arity; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * OpenSSL::PKey::DH implementation. - * - * @author Bill Dortch - */ -public class PKeyDH extends PKey { - private static final long serialVersionUID = 293266329939132250L; - - // parameters used in generating 'p'; see [ossl]/crypto/dh/dh_gen.c #dh_builtin_genparams - private static final BigInteger GEN_2_ADD_PARAM = BigInteger.valueOf(24); - private static final BigInteger GEN_2_REM_PARAM = BigInteger.valueOf(11); - private static final BigInteger GEN_5_ADD_PARAM = BigInteger.valueOf(10); - private static final BigInteger GEN_5_REM_PARAM = BigInteger.valueOf(3); - private static final BigInteger DEFAULT_ADD_PARAM = BigInteger.valueOf(2); - private static final BigInteger DEFAULT_REM_PARAM = BigInteger.ONE; - - private static final BigInteger TWO = BigInteger.valueOf(2); - - // from [ossl]/crypto/dh/dh.h - private static final int OPENSSL_DH_MAX_MODULUS_BITS = 10000; - - private static ObjectAllocator PKEYDH_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new PKeyDH(runtime, klass); - } - }; - - public static void createPKeyDH(Ruby runtime, RubyModule pkeyModule, RubyClass pkeyClass) { - RubyClass dh = pkeyModule.defineClassUnder("DH", pkeyClass, PKEYDH_ALLOCATOR); - - RubyClass pkeyError = pkeyModule.getClass("PKeyError"); - pkeyModule.defineClassUnder("DHError",pkeyError,pkeyError.getAllocator()); - - dh.defineAnnotatedMethods(PKeyDH.class); - } - - public static RaiseException newDHError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::PKey::DHError", message); - } - - private static SecureRandom _secureRandom; - - private static SecureRandom getSecureRandom() { - SecureRandom rand; - if ((rand = _secureRandom) != null) { - return rand; - } - // FIXME: do we want a particular algorithm / provider? BC? - return _secureRandom = new SecureRandom(); - } - - // transient because: we do not want these value serialized (insecure) - // volatile because: permits unsynchronized reads in some cases - private transient volatile BigInteger dh_p; - private transient volatile BigInteger dh_g; - private transient volatile BigInteger dh_pub_key; - private transient volatile BigInteger dh_priv_key; - - // FIXME! need to figure out what it means in MRI/OSSL code to - // claim a DH is(/has) private if an engine is present -- doesn't really - // map to Java implementation. - - //private volatile boolean haveEngine; - - public PKeyDH(Ruby runtime, RubyClass clazz) { - super(runtime, clazz); - } - - @JRubyMethod(name="initialize", rest=true) - public synchronized IRubyObject dh_initialize(IRubyObject[] args) { - Ruby runtime = getRuntime(); - if (this.dh_p != null || this.dh_g != null || this.dh_pub_key != null || this.dh_priv_key != null) { - throw newDHError(runtime, "illegal initialization"); - } - int argc = Arity.checkArgumentCount(runtime, args, 0, 2); - if (argc > 0) { - IRubyObject arg0 = args[0]; - if (argc == 1 && arg0 instanceof RubyString) { - try { - DHParameterSpec spec = PEMInputOutput.readDHParameters(new StringReader(arg0.toString())); - if (spec == null) { - spec = org.jruby.ext.openssl.impl.PKey.readDHParameter(arg0.asString().getByteList().bytes()); - } - if (spec == null) { - throw runtime.newArgumentError("invalid DH PARAMETERS"); - } - this.dh_p = spec.getP(); - this.dh_g = spec.getG(); - } catch (NoClassDefFoundError ncdfe) { - throw newDHError(runtime, OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException e) { - throw runtime.newIOErrorFromException(e); - } - } else { - int bits = RubyNumeric.fix2int(arg0); - // g defaults to 2 - int gval = argc == 2 ? RubyNumeric.fix2int(args[1]) : 2; - BigInteger p; - try { - p = generateP(bits, gval); - } catch(IllegalArgumentException e) { - throw runtime.newArgumentError(e.getMessage()); - } - BigInteger g = BigInteger.valueOf(gval); - BigInteger x = generateX(p); - BigInteger y = generateY(p, g, x); - this.dh_p = p; - this.dh_g = g; - this.dh_priv_key = x; - this.dh_pub_key = y; - } - } - return this; - } - - public static BigInteger generateP(int bits, int g) { - - // FIXME? I'm following algorithms used in OpenSSL, could use JCE provider instead. - // (Note that I tried that, but got mystifying values of g returned by the param generator. - // In any case, in OpenSSL/MRI-OpenSSL, the caller supplies g, or it defaults to 2.) - - // see [ossl]/crypto/dh/dh_gen.c #dh_builtin_genparams - - if (bits < 2) throw new IllegalArgumentException("invalid bit length"); - if (g < 2) throw new IllegalArgumentException("invalid generator"); - - // generate safe prime meeting appropriate add/rem (mod) criteria - - switch(g) { - case 2: - // add = 24, rem = 11 - return BN.generatePrime(bits, true, GEN_2_ADD_PARAM, GEN_2_REM_PARAM); - case 5: - // add = 10, rem = 3 - return BN.generatePrime(bits, true, GEN_5_ADD_PARAM, GEN_5_REM_PARAM); - default: - // add = 2, rem = 1 - return BN.generatePrime(bits, true, DEFAULT_ADD_PARAM, DEFAULT_REM_PARAM); - } - } - - public static BigInteger generateX(BigInteger p, int limit) { - if (limit < 0) throw new IllegalArgumentException("invalid limit"); - - BigInteger x; - SecureRandom secureRandom = getSecureRandom(); - // adapting algorithm from org.bouncycastle.crypto.generators.DHKeyGeneratorHelper, - // which seems a little stronger (?) than OpenSSL's (OSSL just generates a random, - // while BC generates a random potential prime [for limit > 0], though it's not - // subject to Miller-Rabin [certainty = 0], but is subject to other constraints) - // see also [ossl]/crypto/dh/dh_key.c #generate_key - if (limit == 0) { - BigInteger pSub2 = p.subtract(TWO); - do { - x = BN.getRandomBIInRange(pSub2, secureRandom); - } while (x.equals(BigInteger.ZERO)); - } else { - do { - // generate potential prime, though with 0 certainty (no Miller-Rabin tests) - x = new BigInteger(limit, 0, secureRandom); - } while (x.equals(BigInteger.ZERO)); - } - return x; - } - - public static BigInteger generateX(BigInteger p) { - // OpenSSL default l(imit) is p bits - 1 -- see [ossl]/crypto/dh/dh_key.c #generate_key - return generateX(p, p.bitLength() - 1); - } - - public static BigInteger generateY(BigInteger p, BigInteger g, BigInteger x) { - return g.modPow(x, p); - } - - public static BigInteger generateY(BigInteger p, int g, BigInteger x) { - return generateY(p, BigInteger.valueOf(g), x); - } - - @JRubyMethod(name="generate_key!") - public synchronized IRubyObject dh_generate_key() { - BigInteger p, g, x, y; - if ((p = this.dh_p) == null || (g = this.dh_g) == null) { - throw newDHError(getRuntime(), "can't generate key"); - } - if ((x = this.dh_priv_key) == null) { - x = generateX(p); - } - y = generateY(p, g, x); - this.dh_priv_key = x; - this.dh_pub_key = y; - return this; - } - - @JRubyMethod(name="compute_key") - public synchronized IRubyObject dh_compute_key(IRubyObject other_pub_key) { - BigInteger x, y, p; - if ((y = BN.getBigInteger(other_pub_key)) == null) { - throw getRuntime().newArgumentError("invalid public key"); - } - if ((x = this.dh_priv_key) == null || (p = this.dh_p) == null) { - throw newDHError(getRuntime(), "can't compute key"); - } - int plen; - if ((plen = p.bitLength()) == 0 || plen > OPENSSL_DH_MAX_MODULUS_BITS) { - throw newDHError(getRuntime(), "can't compute key"); - } - return getRuntime().newString(new ByteList(computeKey(y, x, p), false)); - } - - public static byte[] computeKey(BigInteger y, BigInteger x, BigInteger p) { - return y.modPow(x, p).toByteArray(); - } - - @JRubyMethod(name="public?") - public IRubyObject dh_is_public() { - return getRuntime().newBoolean(dh_pub_key != null); - } - - @JRubyMethod(name="private?") - public IRubyObject dh_is_private() { - // FIXME! need to figure out what it means in MRI/OSSL code to - // claim a DH is private if an engine is present -- doesn't really - // map to Java implementation. - return getRuntime().newBoolean(dh_priv_key != null /* || haveEngine */); - } - - @JRubyMethod(name={"export", "to_pem", "to_s"}) - public IRubyObject dh_export() { - BigInteger p, g; - synchronized(this) { - p = this.dh_p; - g = this.dh_g; - } - StringWriter w = new StringWriter(); - try { - PEMInputOutput.writeDHParameters(w, new DHParameterSpec(p, g)); - w.flush(); - w.close(); - } catch (NoClassDefFoundError ncdfe) { - throw newDHError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException e) { - // shouldn't happen (string/buffer io only) - throw getRuntime().newIOErrorFromException(e); - } - return getRuntime().newString(w.toString()); - } - - @JRubyMethod(name = "to_der") - public IRubyObject dh_to_der() { - BigInteger p, g; - synchronized (this) { - p = this.dh_p; - g = this.dh_g; - } - try { - byte[] bytes = org.jruby.ext.openssl.impl.PKey.toDerDHKey(p, g); - return RubyString.newString(getRuntime(), bytes); - } catch (NoClassDefFoundError ncdfe) { - throw newDHError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException ioe) { - throw newDHError(getRuntime(), ioe.getMessage()); - } - } - - @JRubyMethod(name="params") - public IRubyObject dh_get_params() { - BigInteger p, g, x, y; - synchronized(this) { - p = this.dh_p; - g = this.dh_g; - x = this.dh_priv_key; - y = this.dh_pub_key; - } - Ruby runtime = getRuntime(); - HashMap params = new HashMap(); - - params.put(runtime.newString("p"), BN.newBN(runtime, p)); - params.put(runtime.newString("g"), BN.newBN(runtime, g)); - params.put(runtime.newString("pub_key"), BN.newBN(runtime, x)); - params.put(runtime.newString("priv_key"), BN.newBN(runtime, y)); - - return RubyHash.newHash(runtime, params, runtime.getNil()); - } - - // don't need synchronized as value is volatile - @JRubyMethod(name="p") - public IRubyObject dh_get_p() { - return getBN(dh_p); - } - - @JRubyMethod(name="p=") - public synchronized IRubyObject dh_set_p(IRubyObject arg) { - this.dh_p = BN.getBigInteger(arg); - return arg; - } - - // don't need synchronized as value is volatile - @JRubyMethod(name="g") - public IRubyObject dh_get_g() { - return getBN(dh_g); - } - - @JRubyMethod(name="g=") - public synchronized IRubyObject dh_set_g(IRubyObject arg) { - this.dh_g = BN.getBigInteger(arg); - return arg; - } - - // don't need synchronized as value is volatile - @JRubyMethod(name="pub_key") - public IRubyObject dh_get_pub_key() { - return getBN(dh_pub_key); - } - - @JRubyMethod(name="pub_key=") - public synchronized IRubyObject dh_set_pub_key(IRubyObject arg) { - this.dh_pub_key = BN.getBigInteger(arg); - return arg; - } - - // don't need synchronized as value is volatile - @JRubyMethod(name="priv_key") - public IRubyObject dh_get_priv_key() { - return getBN(dh_priv_key); - } - - @JRubyMethod(name="priv_key=") - public synchronized IRubyObject dh_set_priv_key(IRubyObject arg) { - this.dh_priv_key = BN.getBigInteger(arg); - return arg; - } - - private IRubyObject getBN(BigInteger value) { - if (value != null) { - return BN.newBN(getRuntime(), value); - } - return getRuntime().getNil(); - } - - // override differently-named abstract method from PKey - public IRubyObject to_der() { - return dh_to_der(); - } - -} diff --git a/src/java/org/jruby/ext/openssl/PKeyDSA.java b/src/java/org/jruby/ext/openssl/PKeyDSA.java deleted file mode 100644 index c6e5cb8..0000000 --- a/src/java/org/jruby/ext/openssl/PKeyDSA.java +++ /dev/null @@ -1,502 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * Copyright (C) 2007 Wiliam N Dortch - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAKey; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyFixnum; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.CipherSpec; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class PKeyDSA extends PKey { - private static final long serialVersionUID = 2359742219218350277L; - - private static ObjectAllocator PKEYDSA_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new PKeyDSA(runtime, klass); - } - }; - - public static void createPKeyDSA(Ruby runtime, RubyModule mPKey) { - RubyClass cDSA = mPKey.defineClassUnder("DSA",mPKey.getClass("PKey"),PKEYDSA_ALLOCATOR); - RubyClass pkeyError = mPKey.getClass("PKeyError"); - mPKey.defineClassUnder("DSAError",pkeyError,pkeyError.getAllocator()); - - - cDSA.defineAnnotatedMethods(PKeyDSA.class); - } - - public static RaiseException newDSAError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::PKey::DSAError", message); - } - - public PKeyDSA(Ruby runtime, RubyClass type) { - super(runtime, type); - } - - public PKeyDSA(Ruby runtime, RubyClass type, DSAPrivateKey privKey, DSAPublicKey pubKey) { - super(runtime, type); - this.privKey = privKey; - this.pubKey = pubKey; - } - - public PKeyDSA(Ruby runtime, RubyClass type, DSAPublicKey pubKey) { - this(runtime, type, null, pubKey); - } - - private DSAPrivateKey privKey; - private DSAPublicKey pubKey; - - // specValues holds individual DSAPublicKeySpec components. this allows - // a public key to be constructed incrementally, as required by the - // current implementation of Net::SSH. - // (see net-ssh-1.1.2/lib/net/ssh/transport/ossl/buffer.rb #read_keyblob) - private BigInteger[] specValues; - - private static final int SPEC_Y = 0; - private static final int SPEC_P = 1; - private static final int SPEC_Q = 2; - private static final int SPEC_G = 3; - - @Override - PublicKey getPublicKey() { - return pubKey; - } - - @Override - PrivateKey getPrivateKey() { - return privKey; - } - - @Override - String getAlgorithm() { - return "DSA"; - } - - @JRubyMethod(name = "generate", meta = true) - public static IRubyObject generate(IRubyObject recv, IRubyObject arg) { - int keysize = RubyNumeric.fix2int(arg); - PKeyDSA dsa = new PKeyDSA(recv.getRuntime(), (RubyClass) recv); - dsaGenerate(dsa, keysize); - return dsa; - } - - /* - * c: dsa_generate - */ - private static void dsaGenerate(PKeyDSA dsa, int keysize) throws RaiseException { - try { - KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA"); - gen.initialize(keysize, new SecureRandom()); - KeyPair pair = gen.generateKeyPair(); - dsa.privKey = (DSAPrivateKey) (pair.getPrivate()); - dsa.pubKey = (DSAPublicKey) (pair.getPublic()); - } catch (Exception e) { - throw newDSAError(dsa.getRuntime(), e.getMessage()); - } - } - - @JRubyMethod(rest = true) - public IRubyObject initialize(IRubyObject[] args) { - IRubyObject arg; - IRubyObject pass = null; - char[] passwd = null; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2) == 0) { - privKey = null; - pubKey = null; - } else { - arg = args[0]; - if (args.length > 1) { - pass = args[1]; - } - if (arg instanceof RubyFixnum) { - int keysize = RubyNumeric.fix2int(arg); - dsaGenerate(this, keysize); - } else { - if (pass != null && !pass.isNil()) { - passwd = pass.toString().toCharArray(); - } - arg = OpenSSLImpl.to_der_if_possible(arg); - RubyString str = arg.convertToString(); - - Object val = null; - KeyFactory fact = null; - try { - fact = KeyFactory.getInstance("DSA"); - } catch (NoSuchAlgorithmException e) { - throw getRuntime().newLoadError("unsupported key algorithm (DSA)"); - } - // TODO: ugly NoClassDefFoundError catching for no BC env. How can we remove this? - if (null == val) { - // PEM_read_bio_DSAPrivateKey - try { - val = PEMInputOutput.readDSAPrivateKey(new StringReader(str.toString()), passwd); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // PEM_read_bio_DSAPublicKey - try { - val = PEMInputOutput.readDSAPublicKey(new StringReader(str.toString()), passwd); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // PEM_read_bio_DSA_PUBKEY - try { - val = PEMInputOutput.readDSAPubKey(new StringReader(str.toString())); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // d2i_DSAPrivateKey_bio - try { - val = org.jruby.ext.openssl.impl.PKey.readDSAPrivateKey(str.getBytes()); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // d2i_DSA_PUBKEY_bio - try { - val = org.jruby.ext.openssl.impl.PKey.readDSAPublicKey(str.getBytes()); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - try { - val = fact.generatePrivate(new PKCS8EncodedKeySpec(str.getBytes())); - } catch (Exception e) { - val = null; - } - } - if (null == val) { - try { - val = fact.generatePublic(new X509EncodedKeySpec(str.getBytes())); - } catch (Exception e) { - val = null; - } - } - if (null == val) { - throw newDSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - - if (val instanceof KeyPair) { - PrivateKey privateKey = ((KeyPair) val).getPrivate(); - PublicKey publicKey = ((KeyPair) val).getPublic(); - if (privateKey instanceof DSAPrivateKey) { - privKey = (DSAPrivateKey) privateKey; - pubKey = (DSAPublicKey) publicKey; - } else { - throw newDSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - } else if (val instanceof DSAPrivateKey) { - privKey = (DSAPrivateKey) val; - } else if (val instanceof DSAPublicKey) { - pubKey = (DSAPublicKey) val; - privKey = null; - } else { - throw newDSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - } - } - return this; - } - - @JRubyMethod(name="public?") - public IRubyObject public_p() { - return pubKey != null ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod(name="private?") - public IRubyObject private_p() { - return privKey != null ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod - public IRubyObject to_der() { - try { - byte[] bytes = org.jruby.ext.openssl.impl.PKey.toDerDSAKey(pubKey, privKey); - return RubyString.newString(getRuntime(), bytes); - } catch (NoClassDefFoundError ncdfe) { - throw newDSAError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException ioe) { - throw newDSAError(getRuntime(), ioe.getMessage()); - } - } - - @JRubyMethod - public IRubyObject to_text() { - StringBuilder result = new StringBuilder(); - if (privKey != null) { - int len = privKey.getParams().getP().bitLength(); - result.append("Private-Key: (").append(len).append(" bit)").append("\n"); - result.append("priv:"); - addSplittedAndFormatted(result, privKey.getX()); - } - result.append("pub:"); - addSplittedAndFormatted(result, pubKey.getY()); - result.append("P:"); - addSplittedAndFormatted(result, pubKey.getParams().getP()); - result.append("Q:"); - addSplittedAndFormatted(result, pubKey.getParams().getQ()); - result.append("G:"); - addSplittedAndFormatted(result, pubKey.getParams().getG()); - return getRuntime().newString(result.toString()); - } - - @JRubyMethod - public IRubyObject public_key() { - PKeyDSA val = new PKeyDSA(getRuntime(),getMetaClass().getRealClass()); - val.privKey = null; - val.pubKey = this.pubKey; - return val; - } - - @JRubyMethod(name = { "export", "to_pem", "to_s" }, rest = true) - public IRubyObject export(IRubyObject[] args) { - StringWriter w = new StringWriter(); - org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); - CipherSpec ciph = null; - char[] passwd = null; - if (args.length > 0 && !args[0].isNil()) { - org.jruby.ext.openssl.Cipher c = (org.jruby.ext.openssl.Cipher) args[0]; - ciph = new CipherSpec(c.getCipher(), c.getName(), c.getKeyLen() * 8); - if (args.length > 1 && !args[1].isNil()) { - passwd = args[1].toString().toCharArray(); - } - } - try { - if (privKey != null) { - PEMInputOutput.writeDSAPrivateKey(w, privKey, ciph, passwd); - } else { - PEMInputOutput.writeDSAPublicKey(w, pubKey); - } - w.close(); - return getRuntime().newString(w.toString()); - } catch (NoClassDefFoundError ncdfe) { - throw newDSAError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException ioe) { - throw newDSAError(getRuntime(), ioe.getMessage()); - } - } - - @JRubyMethod - public IRubyObject syssign(IRubyObject arg) { - // TODO - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject sysverify(IRubyObject arg, IRubyObject arg2) { - // TODO - return getRuntime().getNil(); - } - - @JRubyMethod(name="p") - public synchronized IRubyObject get_p() { - // FIXME: return only for public? - DSAKey key; - BigInteger param; - if ((key = this.pubKey) != null || (key = this.privKey) != null) { - if ((param = key.getParams().getP()) != null) { - return BN.newBN(getRuntime(), param); - } - } else if (specValues != null) { - if ((param = specValues[SPEC_P]) != null) { - return BN.newBN(getRuntime(), param); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="p=") - public synchronized IRubyObject set_p(IRubyObject p) { - return setKeySpecComponent(SPEC_P, p); - } - - @JRubyMethod(name="q") - public synchronized IRubyObject get_q() { - // FIXME: return only for public? - DSAKey key; - BigInteger param; - if ((key = this.pubKey) != null || (key = this.privKey) != null) { - if ((param = key.getParams().getQ()) != null) { - return BN.newBN(getRuntime(), param); - } - } else if (specValues != null) { - if ((param = specValues[SPEC_Q]) != null) { - return BN.newBN(getRuntime(), param); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="q=") - public synchronized IRubyObject set_q(IRubyObject q) { - return setKeySpecComponent(SPEC_Q, q); - } - - @JRubyMethod(name="g") - public synchronized IRubyObject get_g() { - // FIXME: return only for public? - DSAKey key; - BigInteger param; - if ((key = this.pubKey) != null || (key = this.privKey) != null) { - if ((param = key.getParams().getG()) != null) { - return BN.newBN(getRuntime(), param); - } - } else if (specValues != null) { - if ((param = specValues[SPEC_G]) != null) { - return BN.newBN(getRuntime(), param); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="g=") - public synchronized IRubyObject set_g(IRubyObject g) { - return setKeySpecComponent(SPEC_G, g); - } - - @JRubyMethod(name="pub_key") - public synchronized IRubyObject get_pub_key() { - DSAPublicKey key; - BigInteger param; - if ((key = this.pubKey) != null) { - return BN.newBN(getRuntime(), key.getY()); - } else if (specValues != null) { - if ((param = specValues[SPEC_Y]) != null) { - return BN.newBN(getRuntime(), param); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="priv_key") - public synchronized IRubyObject get_priv_key() { - DSAPrivateKey key; - BigInteger param; - if ((key = this.privKey) != null) { - return BN.newBN(getRuntime(), key.getX()); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="pub_key=") - public synchronized IRubyObject set_pub_key(IRubyObject pub_key) { - return setKeySpecComponent(SPEC_Y, pub_key); - } - - private IRubyObject setKeySpecComponent(int index, IRubyObject value) { - BigInteger[] vals; - // illegal to set if we already have a key for this component - // FIXME: allow changes after keys are created? MRI doesn't prevent it... - if (this.pubKey != null || this.privKey != null || - (vals = this.specValues) != null && vals[index] != null) { - throw newDSAError(getRuntime(), "illegal modification"); - } - // get the BigInteger value - BigInteger bival = BN.getBigInteger(value); - - if (vals != null) { - // we already have some vals stored, store this one, too - vals[index] = bival; - // check to see if we have all values yet - for (int i = vals.length; --i >= 0; ) { - if (vals[i] == null) { - // still missing components, return - return value; - } - } - // we now have all components. create the key. - DSAPublicKeySpec spec = new DSAPublicKeySpec(vals[SPEC_Y], vals[SPEC_P], vals[SPEC_Q], vals[SPEC_G]); - try { - this.pubKey = (DSAPublicKey)KeyFactory.getInstance("DSA").generatePublic(spec); - } catch (InvalidKeySpecException e) { - throw newDSAError(getRuntime(), "invalid keyspec"); - } catch (NoSuchAlgorithmException e) { - throw newDSAError(getRuntime(), "unsupported key algorithm (DSA)"); - } - // clear out the specValues - this.specValues = null; - - } else { - - // first value received, save - this.specValues = new BigInteger[4]; - this.specValues[index] = bival; - } - return value; - } - -}// PKeyDSA diff --git a/src/java/org/jruby/ext/openssl/PKeyRSA.java b/src/java/org/jruby/ext/openssl/PKeyRSA.java deleted file mode 100644 index 900782d..0000000 --- a/src/java/org/jruby/ext/openssl/PKeyRSA.java +++ /dev/null @@ -1,769 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAKeyGenParameterSpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import javax.crypto.Cipher; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyBignum; -import org.jruby.RubyFixnum; -import org.jruby.RubyHash; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.CipherSpec; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.Arity; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class PKeyRSA extends PKey { - private static final long serialVersionUID = 3675324750727019454L; - - private static ObjectAllocator PKEYRSA_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new PKeyRSA(runtime, klass); - } - }; - - public static void createPKeyRSA(Ruby runtime, RubyModule mPKey) { - RubyClass cRSA = mPKey.defineClassUnder("RSA",mPKey.getClass("PKey"),PKEYRSA_ALLOCATOR); - RubyClass pkeyError = mPKey.getClass("PKeyError"); - mPKey.defineClassUnder("RSAError",pkeyError,pkeyError.getAllocator()); - - cRSA.defineAnnotatedMethods(PKeyRSA.class); - - cRSA.setConstant("PKCS1_PADDING",runtime.newFixnum(1)); - cRSA.setConstant("SSLV23_PADDING",runtime.newFixnum(2)); - cRSA.setConstant("NO_PADDING",runtime.newFixnum(3)); - cRSA.setConstant("PKCS1_OAEP_PADDING",runtime.newFixnum(4)); - } - - public static RaiseException newRSAError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::PKey::RSAError", message); - } - - public PKeyRSA(Ruby runtime, RubyClass type) { - super(runtime, type); - } - - public PKeyRSA(Ruby runtime, RubyClass type, RSAPrivateCrtKey privKey, RSAPublicKey pubKey) { - super(runtime, type); - this.privKey = privKey; - this.pubKey = pubKey; - } - - public PKeyRSA(Ruby runtime, RubyClass type, RSAPublicKey pubKey) { - this(runtime, type, null, pubKey); - } - - private transient volatile RSAPrivateCrtKey privKey; - private transient volatile RSAPublicKey pubKey; - - // fields to hold individual RSAPublicKeySpec components. this allows - // a public key to be constructed incrementally, as required by the - // current implementation of Net::SSH. - // (see net-ssh-1.1.2/lib/net/ssh/transport/ossl/buffer.rb #read_keyblob) - private transient volatile BigInteger rsa_e; - private transient volatile BigInteger rsa_n; - - private transient volatile BigInteger rsa_d; - private transient volatile BigInteger rsa_p; - private transient volatile BigInteger rsa_q; - private transient volatile BigInteger rsa_dmp1; - private transient volatile BigInteger rsa_dmq1; - private transient volatile BigInteger rsa_iqmp; - - @Override - PublicKey getPublicKey() { - return pubKey; - } - - @Override - PrivateKey getPrivateKey() { - return privKey; - } - - @Override - String getAlgorithm() { - return "RSA"; - } - - @JRubyMethod(name = "generate", meta = true, rest = true) - public static IRubyObject generate(IRubyObject recv, IRubyObject[] args) { - BigInteger exp = RSAKeyGenParameterSpec.F4; - if (Arity.checkArgumentCount(recv.getRuntime(), args, 1, 2) == 2) { - if (args[1] instanceof RubyFixnum) { - exp = BigInteger.valueOf(RubyNumeric.num2long(args[1])); - } else { - exp = ((RubyBignum) args[1]).getValue(); - } - } - int keysize = RubyNumeric.fix2int(args[0]); - PKeyRSA rsa = new PKeyRSA(recv.getRuntime(), (RubyClass) recv); - rsaGenerate(rsa, keysize, exp); - return rsa; - } - - /* - * c: rsa_generate - */ - private static void rsaGenerate(PKeyRSA rsa, int keysize, BigInteger exp) throws RaiseException { - try { - KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); - gen.initialize(new RSAKeyGenParameterSpec(keysize, exp), new SecureRandom()); - KeyPair pair = gen.generateKeyPair(); - rsa.privKey = (RSAPrivateCrtKey) (pair.getPrivate()); - rsa.pubKey = (RSAPublicKey) (pair.getPublic()); - } catch (Exception e) { - throw newRSAError(rsa.getRuntime(), e.getMessage()); - } - } - - @JRubyMethod(frame = true, rest = true) - public IRubyObject initialize(IRubyObject[] args, Block block) { - IRubyObject arg; - IRubyObject pass = null; - char[] passwd = null; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2) == 0) { - privKey = null; - pubKey = null; - } else { - arg = args[0]; - if (args.length > 1) { - pass = args[1]; - } - if (arg instanceof RubyFixnum) { - int keysize = RubyNumeric.fix2int(arg); - BigInteger exp = RSAKeyGenParameterSpec.F4; - if (null != pass && !pass.isNil()) { - exp = BigInteger.valueOf(RubyNumeric.num2long(pass)); - } - rsaGenerate(this, keysize, exp); - } else { - if (pass != null && !pass.isNil()) { - passwd = pass.toString().toCharArray(); - } - arg = OpenSSLImpl.to_der_if_possible(arg); - RubyString str = arg.convertToString(); - - Object val = null; - KeyFactory fact = null; - try { - fact = KeyFactory.getInstance("RSA"); - } catch (Exception e) { - throw getRuntime().newRuntimeError("unsupported key algorithm (RSA)"); - } - // TODO: ugly NoClassDefFoundError catching for no BC env. How can we remove this? - if (null == val) { - // PEM_read_bio_RSAPrivateKey - try { - val = PEMInputOutput.readPrivateKey(new StringReader(str.toString()), passwd); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // PEM_read_bio_RSAPublicKey - try { - val = PEMInputOutput.readRSAPublicKey(new StringReader(str.toString()), passwd); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // PEM_read_bio_RSA_PUBKEY - try { - val = PEMInputOutput.readRSAPubKey(new StringReader(str.toString())); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // d2i_RSAPrivateKey_bio - try { - val = org.jruby.ext.openssl.impl.PKey.readRSAPrivateKey(str.getBytes()); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // d2i_RSAPublicKey_bio - try { - val = org.jruby.ext.openssl.impl.PKey.readRSAPublicKey(str.getBytes()); - } catch (NoClassDefFoundError e) { - val = null; - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // try to read PrivateKeyInfo. - try { - val = fact.generatePrivate(new PKCS8EncodedKeySpec(str.getBytes())); - } catch (Exception e) { - val = null; - } - } - if (null == val) { - // try to read SubjectPublicKeyInfo. - try { - val = fact.generatePublic(new X509EncodedKeySpec(str.getBytes())); - } catch (Exception e) { - val = null; - } - } - if (null == val) { - throw newRSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - - if (val instanceof KeyPair) { - PrivateKey privateKey = ((KeyPair) val).getPrivate(); - PublicKey publicKey = ((KeyPair) val).getPublic(); - if (privateKey instanceof RSAPrivateCrtKey) { - privKey = (RSAPrivateCrtKey) privateKey; - pubKey = (RSAPublicKey) publicKey; - } else { - throw newRSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - } else if (val instanceof RSAPrivateCrtKey) { - privKey = (RSAPrivateCrtKey) val; - try { - pubKey = (RSAPublicKey) (fact.generatePublic(new RSAPublicKeySpec(privKey.getModulus(), privKey.getPublicExponent()))); - } catch (Exception e) { - throw newRSAError(getRuntime(), "Something rotten with private key"); - } - } else if (val instanceof RSAPublicKey) { - pubKey = (RSAPublicKey) val; - privKey = null; - } else { - throw newRSAError(getRuntime(), "Neither PUB key nor PRIV key:"); - } - } - } - return this; - } - - @JRubyMethod(name="public?") - public IRubyObject public_p() { - return pubKey != null ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod(name="private?") - public IRubyObject private_p() { - return privKey != null ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod - public IRubyObject to_der() { - try { - byte[] bytes = org.jruby.ext.openssl.impl.PKey.toDerRSAKey(pubKey, privKey); - return RubyString.newString(getRuntime(), bytes); - } catch (NoClassDefFoundError ncdfe) { - throw newRSAError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException ioe) { - throw newRSAError(getRuntime(), ioe.getMessage()); - } - } - - @JRubyMethod - public IRubyObject public_key() { - PKeyRSA val = new PKeyRSA(getRuntime(),getMetaClass().getRealClass()); - val.privKey = null; - val.pubKey = this.pubKey; - return val; - } - - @JRubyMethod - public IRubyObject params() { - ThreadContext ctx = getRuntime().getCurrentContext(); - RubyHash hash = RubyHash.newHash(getRuntime()); - if(privKey != null) { - hash.op_aset(ctx, getRuntime().newString("iqmp"), BN.newBN(getRuntime(), privKey.getCrtCoefficient())); - hash.op_aset(ctx, getRuntime().newString("n"), BN.newBN(getRuntime(), privKey.getModulus())); - hash.op_aset(ctx, getRuntime().newString("d"), BN.newBN(getRuntime(), privKey.getPrivateExponent())); - hash.op_aset(ctx, getRuntime().newString("p"), BN.newBN(getRuntime(), privKey.getPrimeP())); - hash.op_aset(ctx, getRuntime().newString("e"), BN.newBN(getRuntime(), privKey.getPublicExponent())); - hash.op_aset(ctx, getRuntime().newString("q"), BN.newBN(getRuntime(), privKey.getPrimeQ())); - hash.op_aset(ctx, getRuntime().newString("dmq1"), BN.newBN(getRuntime(), privKey.getPrimeExponentQ())); - hash.op_aset(ctx, getRuntime().newString("dmp1"), BN.newBN(getRuntime(), privKey.getPrimeExponentP())); - - } else { - hash.op_aset(ctx, getRuntime().newString("iqmp"), BN.newBN(getRuntime(), BigInteger.ZERO)); - hash.op_aset(ctx, getRuntime().newString("n"), BN.newBN(getRuntime(), pubKey.getModulus())); - hash.op_aset(ctx, getRuntime().newString("d"), BN.newBN(getRuntime(), BigInteger.ZERO)); - hash.op_aset(ctx, getRuntime().newString("p"), BN.newBN(getRuntime(), BigInteger.ZERO)); - hash.op_aset(ctx, getRuntime().newString("e"), BN.newBN(getRuntime(), pubKey.getPublicExponent())); - hash.op_aset(ctx, getRuntime().newString("q"), BN.newBN(getRuntime(), BigInteger.ZERO)); - hash.op_aset(ctx, getRuntime().newString("dmq1"), BN.newBN(getRuntime(), BigInteger.ZERO)); - hash.op_aset(ctx, getRuntime().newString("dmp1"), BN.newBN(getRuntime(), BigInteger.ZERO)); - } - return hash; - } - - @JRubyMethod - public IRubyObject to_text() { - StringBuilder result = new StringBuilder(); - if (privKey != null) { - int len = privKey.getModulus().bitLength(); - result.append("Private-Key: (").append(len).append(" bit)").append("\n"); - result.append("modulus:"); - addSplittedAndFormatted(result, privKey.getModulus()); - result.append("publicExponent: ").append(privKey.getPublicExponent()).append(" (0x").append(privKey.getPublicExponent().toString(16)).append(")\n"); - result.append("privateExponent:"); - addSplittedAndFormatted(result, privKey.getPrivateExponent()); - result.append("prime1:"); - addSplittedAndFormatted(result, privKey.getPrimeP()); - result.append("prime2:"); - addSplittedAndFormatted(result, privKey.getPrimeQ()); - result.append("exponent1:"); - addSplittedAndFormatted(result, privKey.getPrimeExponentP()); - result.append("exponent2:"); - addSplittedAndFormatted(result, privKey.getPrimeExponentQ()); - result.append("coefficient:"); - addSplittedAndFormatted(result, privKey.getCrtCoefficient()); - } else { - int len = pubKey.getModulus().bitLength(); - result.append("Modulus (").append(len).append(" bit):"); - addSplittedAndFormatted(result, pubKey.getModulus()); - result.append("Exponent: ").append(pubKey.getPublicExponent()).append(" (0x").append(pubKey.getPublicExponent().toString(16)).append(")\n"); - } - return getRuntime().newString(result.toString()); - } - - @JRubyMethod(name = { "export", "to_pem", "to_s" }, rest = true) - public IRubyObject export(IRubyObject[] args) { - StringWriter w = new StringWriter(); - org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 0, 2); - CipherSpec ciph = null; - char[] passwd = null; - if (args.length > 0 && !args[0].isNil()) { - org.jruby.ext.openssl.Cipher c = (org.jruby.ext.openssl.Cipher) args[0]; - ciph = new CipherSpec(c.getCipher(), c.getName(), c.getKeyLen() * 8); - if (args.length > 1 && !args[1].isNil()) { - passwd = args[1].toString().toCharArray(); - } - } - try { - if (privKey != null) { - PEMInputOutput.writeRSAPrivateKey(w, privKey, ciph, passwd); - } else { - PEMInputOutput.writeRSAPublicKey(w, pubKey); - } - w.close(); - return getRuntime().newString(w.toString()); - } catch (NoClassDefFoundError ncdfe) { - throw newRSAError(getRuntime(), OpenSSLReal.bcExceptionMessage(ncdfe)); - } catch (IOException ioe) { - throw newRSAError(getRuntime(), ioe.getMessage()); - } - } - - private String getPadding(int padding) { - if(padding < 1 || padding > 4) { - throw newRSAError(getRuntime(), null); - } - // BC accepts "/NONE/*" but SunJCE doesn't. use "/ECB/*" - String p = "/ECB/PKCS1Padding"; - if(padding == 3) { - p = "/ECB/NoPadding"; - } else if(padding == 4) { - p = "/ECB/OAEPWithMD5AndMGF1Padding"; - } else if(padding == 2) { - p = "/ECB/ISO9796-1Padding"; - } - return p; - } - - @JRubyMethod(rest = true) - public IRubyObject private_encrypt(IRubyObject[] args) { - int padding = 1; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2 && !args[1].isNil()) { - padding = RubyNumeric.fix2int(args[1]); - } - String p = getPadding(padding); - RubyString buffer = args[0].convertToString(); - if (privKey == null) { - throw newRSAError(getRuntime(), "private key needed."); - } - try { - Cipher engine = Cipher.getInstance("RSA" + p); - engine.init(Cipher.ENCRYPT_MODE, privKey); - byte[] outp = engine.doFinal(buffer.getBytes()); - return RubyString.newString(getRuntime(), outp); - } catch (GeneralSecurityException gse) { - throw newRSAError(getRuntime(), gse.getMessage()); - } - } - - @JRubyMethod(rest = true) - public IRubyObject private_decrypt(IRubyObject[] args) { - int padding = 1; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2 && !args[1].isNil()) { - padding = RubyNumeric.fix2int(args[1]); - } - String p = getPadding(padding); - RubyString buffer = args[0].convertToString(); - if (privKey == null) { - throw newRSAError(getRuntime(), "private key needed."); - } - try { - Cipher engine = Cipher.getInstance("RSA" + p); - engine.init(Cipher.DECRYPT_MODE, privKey); - byte[] outp = engine.doFinal(buffer.getBytes()); - return RubyString.newString(getRuntime(), outp); - } catch (GeneralSecurityException gse) { - throw newRSAError(getRuntime(), gse.getMessage()); - } - } - - @JRubyMethod(rest = true) - public IRubyObject public_encrypt(IRubyObject[] args) { - int padding = 1; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2 && !args[1].isNil()) { - padding = RubyNumeric.fix2int(args[1]); - } - String p = getPadding(padding); - RubyString buffer = args[0].convertToString(); - try { - Cipher engine = Cipher.getInstance("RSA" + p); - engine.init(Cipher.ENCRYPT_MODE, pubKey); - byte[] outp = engine.doFinal(buffer.getBytes()); - return RubyString.newString(getRuntime(), outp); - } catch (GeneralSecurityException gse) { - throw newRSAError(getRuntime(), gse.getMessage()); - } - } - - @JRubyMethod(rest = true) - public IRubyObject public_decrypt(IRubyObject[] args) { - int padding = 1; - if (org.jruby.runtime.Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 2 && !args[1].isNil()) { - padding = RubyNumeric.fix2int(args[1]); - } - String p = getPadding(padding); - RubyString buffer = args[0].convertToString(); - try { - Cipher engine = Cipher.getInstance("RSA" + p); - engine.init(Cipher.DECRYPT_MODE, pubKey); - byte[] outp = engine.doFinal(buffer.getBytes()); - return RubyString.newString(getRuntime(), outp); - } catch (GeneralSecurityException gse) { - throw newRSAError(getRuntime(), gse.getMessage()); - } - } - - @JRubyMethod(name="d=") - public synchronized IRubyObject set_d(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_d = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="p=") - public synchronized IRubyObject set_p(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_p = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="q=") - public synchronized IRubyObject set_q(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_q = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="dmp1=") - public synchronized IRubyObject set_dmp1(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_dmp1 = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="dmq1=") - public synchronized IRubyObject set_dmq1(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_dmq1 = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="iqmp=") - public synchronized IRubyObject set_iqmp(IRubyObject value) { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - rsa_iqmp = BN.getBigInteger(value); - generatePrivateKeyIfParams(); - return value; - } - - @JRubyMethod(name="iqmp") - public synchronized IRubyObject get_iqmp() { - BigInteger iqmp = null; - if (privKey != null) { - iqmp = privKey.getCrtCoefficient(); - } else { - iqmp = rsa_iqmp; - } - if (iqmp != null) { - return BN.newBN(getRuntime(), iqmp); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="dmp1") - public synchronized IRubyObject get_dmp1() { - BigInteger dmp1 = null; - if (privKey != null) { - dmp1 = privKey.getPrimeExponentP(); - } else { - dmp1 = rsa_dmp1; - } - if (dmp1 != null) { - return BN.newBN(getRuntime(), dmp1); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="dmq1") - public synchronized IRubyObject get_dmq1() { - BigInteger dmq1 = null; - if (privKey != null) { - dmq1 = privKey.getPrimeExponentQ(); - } else { - dmq1 = rsa_dmq1; - } - if (dmq1 != null) { - return BN.newBN(getRuntime(), dmq1); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="d") - public synchronized IRubyObject get_d() { - BigInteger d = null; - if (privKey != null) { - d = privKey.getPrivateExponent(); - } else { - d = rsa_d; - } - if (d != null) { - return BN.newBN(getRuntime(), d); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="p") - public synchronized IRubyObject get_p() { - BigInteger p = null; - if (privKey != null) { - p = privKey.getPrimeP(); - } else { - p = rsa_p; - } - if (p != null) { - return BN.newBN(getRuntime(), p); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="q") - public synchronized IRubyObject get_q() { - BigInteger q = null; - if (privKey != null) { - q = privKey.getPrimeQ(); - } else { - q = rsa_q; - } - if (q != null) { - return BN.newBN(getRuntime(), q); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="e") - public synchronized IRubyObject get_e() { - RSAPublicKey key; - BigInteger e; - if ((key = pubKey) != null) { - e = key.getPublicExponent(); - } else if(privKey != null) { - e = privKey.getPublicExponent(); - } else { - e = rsa_e; - } - if (e != null) { - return BN.newBN(getRuntime(), e); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="e=") - public synchronized IRubyObject set_e(IRubyObject value) { - rsa_e = BN.getBigInteger(value); - - if(privKey == null) { - generatePrivateKeyIfParams(); - } - if(pubKey == null) { - generatePublicKeyIfParams(); - } - return value; - } - - @JRubyMethod(name="n") - public synchronized IRubyObject get_n() { - RSAPublicKey key; - BigInteger n; - if ((key = pubKey) != null) { - n = key.getModulus(); - } else if(privKey != null) { - n = privKey.getModulus(); - } else { - n = rsa_n; - } - if (n != null) { - return BN.newBN(getRuntime(), n); - } - return getRuntime().getNil(); - } - - @JRubyMethod(name="n=") - public synchronized IRubyObject set_n(IRubyObject value) { - rsa_n = BN.getBigInteger(value); - - if(privKey == null) { - generatePrivateKeyIfParams(); - } - if(pubKey == null) { - generatePublicKeyIfParams(); - } - return value; - } - - private void generatePublicKeyIfParams() { - if (pubKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - BigInteger e, n; - if ((e = rsa_e) != null && (n = rsa_n) != null) { - KeyFactory fact; - try { - fact = KeyFactory.getInstance("RSA"); - } catch(Exception ex) { - throw getRuntime().newLoadError("unsupported key algorithm (RSA)"); - } - try { - pubKey = (RSAPublicKey)fact.generatePublic(new RSAPublicKeySpec(n, e)); - } catch (InvalidKeySpecException ex) { - throw newRSAError(getRuntime(), "invalid parameters"); - } - rsa_e = null; - rsa_n = null; - } - } - - private void generatePrivateKeyIfParams() { - if (privKey != null) { - throw newRSAError(getRuntime(), "illegal modification"); - } - if (rsa_e != null && rsa_n != null && rsa_p != null && rsa_q != null && rsa_d != null && rsa_dmp1 != null && rsa_dmq1 != null && rsa_iqmp != null) { - KeyFactory fact; - try { - fact = KeyFactory.getInstance("RSA"); - } catch(Exception ex) { - throw getRuntime().newLoadError("unsupported key algorithm (RSA)"); - } - try { - privKey = (RSAPrivateCrtKey)fact.generatePrivate(new RSAPrivateCrtKeySpec(rsa_n, rsa_e, rsa_d, rsa_p, rsa_q, rsa_dmp1, rsa_dmq1, rsa_iqmp)); - } catch (InvalidKeySpecException ex) { - throw newRSAError(getRuntime(), "invalid parameters"); - } - rsa_n = null; - rsa_e = null; - rsa_d = null; - rsa_p = null; - rsa_q = null; - rsa_dmp1 = null; - rsa_dmq1 = null; - rsa_iqmp = null; - } - } -}// PKeyRSA diff --git a/src/java/org/jruby/ext/openssl/Random.java b/src/java/org/jruby/ext/openssl/Random.java deleted file mode 100644 index 66e9d55..0000000 --- a/src/java/org/jruby/ext/openssl/Random.java +++ /dev/null @@ -1,103 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.SecureRandom; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class Random { - private final static class RandomHolder { - public java.util.Random[] randomizers; - } - public static void createRandom(Ruby runtime, RubyModule ossl) { - RubyModule rand = ossl.defineModuleUnder("Random"); - - RubyClass osslError = (RubyClass)ossl.getConstant("OpenSSLError"); - rand.defineClassUnder("RandomError",osslError,osslError.getAllocator()); - - rand.defineAnnotatedMethods(Random.class); - - RandomHolder holder = new RandomHolder(); - holder.randomizers = new java.util.Random[]{new java.util.Random(), new SecureRandom()}; - rand.dataWrapStruct(holder); - } - - @JRubyMethod(meta=true) - public static IRubyObject seed(IRubyObject recv, IRubyObject arg) { - return recv.getRuntime().getNil(); - } - @JRubyMethod(meta=true) - public static IRubyObject load_random_file(IRubyObject recv, IRubyObject arg) { - return recv.getRuntime().getNil(); - } - @JRubyMethod(meta=true) - public static IRubyObject write_random_file(IRubyObject recv, IRubyObject arg) { - return recv.getRuntime().getNil(); - } - - @JRubyMethod(meta=true) - public static IRubyObject random_bytes(IRubyObject recv, IRubyObject arg) { - return generate(recv, arg, 1); - } - - @JRubyMethod(meta=true) - public static IRubyObject pseudo_bytes(IRubyObject recv, IRubyObject arg) { - return generate(recv, arg, 0); - } - - private static RubyString generate(IRubyObject recv, IRubyObject arg, int ix) { - RandomHolder holder = (RandomHolder)recv.dataGetStruct(); - int len = RubyNumeric.fix2int(arg); - if (len < 0 || len > Integer.MAX_VALUE) { - throw recv.getRuntime().newArgumentError("negative string size (or size too big)"); - } - byte[] buf = new byte[len]; - holder.randomizers[ix].nextBytes(buf); - return RubyString.newString(recv.getRuntime(), new ByteList(buf,false)); - } - - @JRubyMethod(meta=true) - public static IRubyObject egd(IRubyObject recv, IRubyObject arg) { - return recv.getRuntime().getNil(); - } - @JRubyMethod(meta=true) - public static IRubyObject egd_bytes(IRubyObject recv, IRubyObject arg1, IRubyObject arg2) { - return recv.getRuntime().getNil(); - } -} diff --git a/src/java/org/jruby/ext/openssl/Request.java b/src/java/org/jruby/ext/openssl/Request.java deleted file mode 100644 index 381f89d..0000000 --- a/src/java/org/jruby/ext/openssl/Request.java +++ /dev/null @@ -1,328 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.io.IOException; -import java.io.StringWriter; -import java.security.GeneralSecurityException; -import java.security.PublicKey; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERString; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class Request extends RubyObject { - private static final long serialVersionUID = -5551557929791764918L; - - private static ObjectAllocator REQUEST_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new Request(runtime, klass); - } - }; - - public static void createRequest(Ruby runtime, RubyModule mX509) { - RubyClass cRequest = mX509.defineClassUnder("Request",runtime.getObject(),REQUEST_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("RequestError",openSSLError,openSSLError.getAllocator()); - - cRequest.defineAnnotatedMethods(Request.class); - } - - private IRubyObject version; - private IRubyObject subject; - private IRubyObject public_key; - private boolean valid = false; - - private List attrs; - - private PKCS10CertificationRequestExt req; - - public Request(Ruby runtime, RubyClass type) { - super(runtime,type); - attrs = new ArrayList(); - } - - @JRubyMethod(name="initialize", frame=true, rest=true) - public IRubyObject _initialize(IRubyObject[] args, Block block) { - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,0,1) == 0) { - return this; - } - - byte[] req_bytes = OpenSSLImpl.readX509PEM(args[0]); - req = new PKCS10CertificationRequestExt(req_bytes); - version = getRuntime().newFixnum(req.getVersion()); - - String algo = null; - byte[] enc = null; - try { - PublicKey pkey = (PublicKey) OpenSSLReal.getWithBCProvider(new OpenSSLReal.Callable() { - - public Object call() throws GeneralSecurityException { - return req.getPublicKey("BC"); - } - }); - algo = pkey.getAlgorithm(); - enc = pkey.getEncoded(); - } catch (GeneralSecurityException gse) { - throw newX509ReqError(getRuntime(), gse.getMessage()); - } - - if("RSA".equalsIgnoreCase(algo)) { - this.public_key = Utils.newRubyInstance(getRuntime(), "OpenSSL::PKey::RSA", RubyString.newString(getRuntime(), enc)); - } else if("DSA".equalsIgnoreCase(algo)) { - this.public_key = Utils.newRubyInstance(getRuntime(), "OpenSSL::PKey::DSA", RubyString.newString(getRuntime(), enc)); - } else { - throw getRuntime().newLoadError("not implemented algo for public key: " + algo); - } - org.bouncycastle.asn1.x509.X509Name subName = req.getCertificationRequestInfo().getSubject(); - subject = Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Name"); - DERSequence subNameD = (DERSequence)subName.toASN1Object(); - for(int i=0;i iter = attrs.iterator();iter.hasNext();) { - v1.add(((Attribute)iter.next()).toASN1()); - } - try { - // PKCS10CertificationRequestExt depends BC. - OpenSSLReal.doWithBCProvider(new OpenSSLReal.Runnable() { - - public void run() throws GeneralSecurityException { - req = new PKCS10CertificationRequestExt(digAlg + "WITH" + keyAlg, - ((X509Name) subject).getRealName(), - ((PKey) public_key).getPublicKey(), - new DERSet(v1), - ((PKey) key).getPrivateKey(), - "BC"); - } - }); - } catch (GeneralSecurityException gse) { - throw newX509ReqError(getRuntime(), gse.getMessage()); - } - req.setVersion(RubyNumeric.fix2int(version)); - valid = true; - return this; - } - - @JRubyMethod - public IRubyObject verify(IRubyObject key) { - try { - return valid && req.verify(((PKey)(key.callMethod(getRuntime().getCurrentContext(),"public_key"))).getPublicKey()) ? getRuntime().getTrue() : getRuntime().getFalse(); - } catch(Exception e) { - return getRuntime().getFalse(); - } - } - - @JRubyMethod - public IRubyObject attributes() { - return getRuntime().newArray(attrs); - } - - @SuppressWarnings("unchecked") - @JRubyMethod(name="attributes=") - public IRubyObject set_attributes(IRubyObject val) { - valid = false; - attrs.clear(); - attrs.addAll(((RubyArray)val).getList()); - if(req != null) { - ASN1EncodableVector v1 = new ASN1EncodableVector(); - for(Iterator iter = attrs.iterator();iter.hasNext();) { - v1.add(((Attribute)iter.next()).toASN1()); - } - req.setAttributes(new DERSet(v1)); - } - return val; - } - - @JRubyMethod - public IRubyObject add_attribute(IRubyObject val) { - valid = false; - attrs.add(val); - if(req != null) { - ASN1EncodableVector v1 = new ASN1EncodableVector(); - for(Iterator iter = attrs.iterator();iter.hasNext();) { - v1.add(((Attribute)iter.next()).toASN1()); - } - req.setAttributes(new DERSet(v1)); - } - return getRuntime().getNil(); - } - - private static RaiseException newX509ReqError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::X509::RequestError", message); - } -}// Request diff --git a/src/java/org/jruby/ext/openssl/SSL.java b/src/java/org/jruby/ext/openssl/SSL.java deleted file mode 100644 index 46cd504..0000000 --- a/src/java/org/jruby/ext/openssl/SSL.java +++ /dev/null @@ -1,94 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.exceptions.RaiseException; - -/** - * @author Ola Bini - */ -public class SSL { - - public static final int VERIFY_NONE = 0x00; - public static final int VERIFY_PEER = 0x01; - public static final int VERIFY_FAIL_IF_NO_PEER_CERT = 0x02; - public static final int VERIFY_CLIENT_ONCE = 0x04; - - public static final long OP_ALL = 0x00000FFFL; - public static final long OP_NO_TICKET = 0x00004000L; - public static final long OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000L; - public static final long OP_SINGLE_ECDH_USE = 0x00080000L; - public static final long OP_SINGLE_DH_USE = 0x00100000L; - public static final long OP_EPHEMERAL_RSA = 0x00200000L; - public static final long OP_CIPHER_SERVER_PREFERENCE = 0x00400000L; - public static final long OP_TLS_ROLLBACK_BUG = 0x00800000L; - public static final long OP_NO_SSLv2 = 0x01000000L; // supported - public static final long OP_NO_SSLv3 = 0x02000000L; // supported - public static final long OP_NO_TLSv1 = 0x04000000L; // supported - public static final long OP_PKCS1_CHECK_1 = 0x08000000L; - public static final long OP_PKCS1_CHECK_2 = 0x10000000L; - public static final long OP_NETSCAPE_CA_DN_BUG = 0x20000000L; - public static final long OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 0x40000000L; - - public static void createSSL(Ruby runtime, RubyModule ossl) { - RubyModule mSSL = ossl.defineModuleUnder("SSL"); - RubyClass openSSLError = ossl.getClass("OpenSSLError"); - mSSL.defineClassUnder("SSLError",openSSLError,openSSLError.getAllocator()); - - SSLContext.createSSLContext(runtime,mSSL); - SSLSocket.createSSLSocket(runtime,mSSL); - - mSSL.setConstant("VERIFY_NONE", runtime.newFixnum(VERIFY_NONE)); - mSSL.setConstant("VERIFY_PEER", runtime.newFixnum(VERIFY_PEER)); - mSSL.setConstant("VERIFY_FAIL_IF_NO_PEER_CERT", runtime.newFixnum(VERIFY_FAIL_IF_NO_PEER_CERT)); - mSSL.setConstant("VERIFY_CLIENT_ONCE", runtime.newFixnum(VERIFY_CLIENT_ONCE)); - - mSSL.setConstant("OP_ALL", runtime.newFixnum(OP_ALL)); - mSSL.setConstant("OP_NO_TICKET", runtime.newFixnum(OP_NO_TICKET)); - mSSL.setConstant("OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION", runtime.newFixnum(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)); - mSSL.setConstant("OP_SINGLE_ECDH_USE", runtime.newFixnum(OP_SINGLE_ECDH_USE)); - mSSL.setConstant("OP_SINGLE_DH_USE", runtime.newFixnum(OP_SINGLE_DH_USE)); - mSSL.setConstant("OP_EPHEMERAL_RSA", runtime.newFixnum(OP_EPHEMERAL_RSA)); - mSSL.setConstant("OP_CIPHER_SERVER_PREFERENCE", runtime.newFixnum(OP_CIPHER_SERVER_PREFERENCE)); - mSSL.setConstant("OP_TLS_ROLLBACK_BUG", runtime.newFixnum(OP_TLS_ROLLBACK_BUG)); - mSSL.setConstant("OP_NO_SSLv2", runtime.newFixnum(OP_NO_SSLv2)); - mSSL.setConstant("OP_NO_SSLv3", runtime.newFixnum(OP_NO_SSLv3)); - mSSL.setConstant("OP_NO_TLSv1", runtime.newFixnum(OP_NO_TLSv1)); - mSSL.setConstant("OP_PKCS1_CHECK_1", runtime.newFixnum(OP_PKCS1_CHECK_1)); - mSSL.setConstant("OP_PKCS1_CHECK_2", runtime.newFixnum(OP_PKCS1_CHECK_2)); - mSSL.setConstant("OP_NETSCAPE_CA_DN_BUG", runtime.newFixnum(OP_NETSCAPE_CA_DN_BUG)); - mSSL.setConstant("OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", runtime.newFixnum(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG)); - } - - public static RaiseException newSSLError(Ruby runtime, Throwable t) { - throw Utils.newError(runtime, "OpenSSL::SSL::SSLError", t.getMessage()); - } -}// SSL diff --git a/src/java/org/jruby/ext/openssl/SSLContext.java b/src/java/org/jruby/ext/openssl/SSLContext.java deleted file mode 100644 index c6c1e97..0000000 --- a/src/java/org/jruby/ext/openssl/SSLContext.java +++ /dev/null @@ -1,747 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.net.ssl.SSLEngine; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.RubySymbol; -import org.jruby.anno.JRubyMethod; -import org.jruby.common.IRubyWarnings.ID; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.Certificate; -import org.jruby.ext.openssl.x509store.Name; -import org.jruby.ext.openssl.x509store.Store; -import org.jruby.ext.openssl.x509store.StoreContext; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.ext.openssl.x509store.X509Object; -import org.jruby.ext.openssl.x509store.X509Utils; -import org.jruby.javasupport.util.RuntimeHelpers; -import org.jruby.runtime.Arity; -import org.jruby.runtime.Block; -import org.jruby.runtime.BlockCallback; -import org.jruby.runtime.CallBlock; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class SSLContext extends RubyObject { - private static final long serialVersionUID = -6203496135962974777L; - - private final static String[] ctx_attrs = { - "cert", "key", "client_ca", "ca_file", "ca_path", - "timeout", "verify_mode", "verify_depth", - "verify_callback", "options", "cert_store", "extra_chain_cert", - "client_cert_cb", "tmp_dh_callback", "session_id_context"}; - - // Mapping table for OpenSSL's SSL_METHOD -> JSSE's SSLContext algorithm. - private final static Map SSL_VERSION_OSSL2JSSE; - // Mapping table for JSEE's enabled protocols for the algorithm. - private final static Map ENABLED_PROTOCOLS; - - static { - SSL_VERSION_OSSL2JSSE = new HashMap(); - ENABLED_PROTOCOLS = new HashMap(); - - SSL_VERSION_OSSL2JSSE.put("TLSv1", "TLSv1"); - SSL_VERSION_OSSL2JSSE.put("TLSv1_server", "TLSv1"); - SSL_VERSION_OSSL2JSSE.put("TLSv1_client", "TLSv1"); - ENABLED_PROTOCOLS.put("TLSv1", new String[] { "TLSv1" }); - - SSL_VERSION_OSSL2JSSE.put("SSLv2", "SSLv2"); - SSL_VERSION_OSSL2JSSE.put("SSLv2_server", "SSLv2"); - SSL_VERSION_OSSL2JSSE.put("SSLv2_client", "SSLv2"); - ENABLED_PROTOCOLS.put("SSLv2", new String[] { "SSLv2" }); - - SSL_VERSION_OSSL2JSSE.put("SSLv3", "SSLv3"); - SSL_VERSION_OSSL2JSSE.put("SSLv3_server", "SSLv3"); - SSL_VERSION_OSSL2JSSE.put("SSLv3_client", "SSLv3"); - ENABLED_PROTOCOLS.put("SSLv3", new String[] { "SSLv3" }); - - SSL_VERSION_OSSL2JSSE.put("SSLv23", "SSL"); - SSL_VERSION_OSSL2JSSE.put("SSLv23_server", "SSL"); - SSL_VERSION_OSSL2JSSE.put("SSLv23_client", "SSL"); - ENABLED_PROTOCOLS.put("SSL", new String[] { "SSLv2", "SSLv3", "TLSv1" }); - - // Followings(TLS, TLSv1.1) are JSSE only methods at present. Let's allow user to use it. - - SSL_VERSION_OSSL2JSSE.put("TLS", "TLS"); - ENABLED_PROTOCOLS.put("TLS", new String[] { "TLSv1", "TLSv1.1" }); - - SSL_VERSION_OSSL2JSSE.put("TLSv1.1", "TLSv1.1"); - ENABLED_PROTOCOLS.put("TLSv1.1", new String[] { "TLSv1.1" }); - } - - private static ObjectAllocator SSLCONTEXT_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new SSLContext(runtime, klass); - } - }; - - public static void createSSLContext(Ruby runtime, RubyModule mSSL) { - RubyClass cSSLContext = mSSL.defineClassUnder("SSLContext",runtime.getObject(),SSLCONTEXT_ALLOCATOR); - for(int i=0;i(); - for (X509Cert ele : convertToX509Certs(value)) { - internalCtx.extraChainCert.add(ele.getAuxCert()); - } - } - - value = getInstanceVariable("@key"); - PKey key = null; - if (value != null && !value.isNil()) { - Utils.checkKind(getRuntime(), value, "OpenSSL::PKey::PKey"); - key = (PKey) value; - } else { - key = getCallbackKey(); - } - value = getInstanceVariable("@cert"); - X509Cert cert = null; - if (value != null && !value.isNil()) { - Utils.checkKind(getRuntime(), value, "OpenSSL::X509::Certificate"); - cert = (X509Cert) value; - } else { - cert = getCallbackCert(); - } - if (key != null && cert != null) { - internalCtx.keyAlgorithm = key.getAlgorithm(); - internalCtx.privateKey = key.getPrivateKey(); - internalCtx.cert = cert.getAuxCert(); - } - - value = getInstanceVariable("@client_ca"); - if (value != null && !value.isNil()) { - if (value.respondsTo("each")) { - for (X509Cert ele : convertToX509Certs(value)) { - internalCtx.clientCa.add(ele.getAuxCert()); - } - } else { - Utils.checkKind(getRuntime(), value, "OpenSSL::X509::Certificate"); - internalCtx.clientCa.add(((X509Cert) value).getAuxCert()); - } - } - - String caFile = getCaFile(); - String caPath = getCaPath(); - if (caFile != null || caPath != null) { - try { - if (internalCtx.store.loadLocations(caFile, caPath) == 0) { - getRuntime().getWarnings().warn(ID.MISCELLANEOUS, "can't set verify locations"); - } - } catch (Exception e) { - throw newSSLError(getRuntime(), e.getMessage()); - } - } - - value = getInstanceVariable("@verify_mode"); - if (value != null && !value.isNil()) { - internalCtx.verifyMode = RubyNumeric.fix2int(value); - } else { - internalCtx.verifyMode = SSL.VERIFY_NONE; - } - value = getInstanceVariable("@verify_callback"); - if (value != null && !value.isNil()) { - internalCtx.store.setExtraData(1, value); - } else { - internalCtx.store.setExtraData(1, null); - } - - value = getInstanceVariable("@timeout"); - if (value != null && !value.isNil()) { - internalCtx.timeout = RubyNumeric.fix2int(value); - } - - value = getInstanceVariable("@verify_depth"); - if (value != null && !value.isNil()) { - internalCtx.store.setDepth(RubyNumeric.fix2int(value)); - } else { - internalCtx.store.setDepth(-1); - } - - /* TODO: should be implemented for SSLSession - val = ossl_sslctx_get_sess_id_ctx(self); - if (!NIL_P(val)){ - StringValue(val); - if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), - RSTRING_LEN(val))){ - ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); - } - } - - if (RTEST(rb_iv_get(self, "@session_get_cb"))) { - SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); - OSSL_Debug("SSL SESSION get callback added"); - } - if (RTEST(rb_iv_get(self, "@session_new_cb"))) { - SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); - OSSL_Debug("SSL SESSION new callback added"); - } - if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { - SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); - OSSL_Debug("SSL SESSION remove callback added"); - } - - val = rb_iv_get(self, "@servername_cb"); - if (!NIL_P(val)) { - SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); - OSSL_Debug("SSL TLSEXT servername callback added"); - } - */ - - try { - internalCtx.init(); - } catch(GeneralSecurityException gse) { - throw newSSLError(getRuntime(), gse.getMessage()); - } - return getRuntime().getTrue(); - } - - @JRubyMethod - public IRubyObject ciphers() { - List list = new ArrayList(); - Ruby rt = getRuntime(); - try { - String[] supported = getCipherSuites(createDummySSLEngine()); - List ciphs = CipherStrings.getMatchingCiphers(ciphers, supported); - for (CipherStrings.Def def : ciphs) { - RubyArray ele = getRuntime().newArray(4); - ele.set(0, rt.newString(def.name)); - ele.set(1, rt.newString(sslVersionString(def.algorithms))); - ele.set(2, rt.newFixnum(def.strength_bits)); - ele.set(3, rt.newFixnum(def.alg_bits)); - list.add(ele); - } - } catch (GeneralSecurityException gse) { - throw newSSLError(getRuntime(), gse.getMessage()); - } - return rt.newArray(list); - } - - @JRubyMethod(name = "ciphers=") - public IRubyObject set_ciphers(IRubyObject val) { - if (val.isNil()) { - ciphers = CipherStrings.SSL_DEFAULT_CIPHER_LIST; - } else if (val instanceof RubyArray) { - StringBuilder builder = new StringBuilder(); - String sep = ""; - for (IRubyObject obj : ((RubyArray) val).toJavaArray()) { - builder.append(sep).append(obj.toString()); - sep = ":"; - } - ciphers = builder.toString(); - } else { - ciphers = val.convertToString().toString(); - if (ciphers.equals("DEFAULT")) { - ciphers = CipherStrings.SSL_DEFAULT_CIPHER_LIST; - } - } - RubyArray ary = (RubyArray)ciphers(); - if (ary.size() == 0) { - throw newSSLError(getRuntime(), "no cipher match"); - } - return val; - } - - @JRubyMethod(name = "ssl_version=") - public IRubyObject set_ssl_version(IRubyObject val) { - String given; - - if (val instanceof RubyString) { - RubyString str = val.convertToString(); - given = str.toString(); - } else { - given = val.toString(); - } - String mapped = SSL_VERSION_OSSL2JSSE.get(given); - if (mapped == null) { - throw newSSLError(getRuntime(), String.format("unknown SSL method `%s'.", given)); - } - protocol = mapped; - protocolForServer = protocolForClient = true; - if (given.endsWith("_client")) { - protocolForServer = false; - } - if (given.endsWith("_server")) { - protocolForClient = false; - } - return val; - } - - boolean isProtocolForServer() { - return protocolForServer; - } - - boolean isProtocolForClient() { - return protocolForClient; - } - - int getLastVerifyResult() { - return verifyResult; - } - - void setLastVerifyResult(int verifyResult) { - this.verifyResult = verifyResult; - } - - SSLEngine createDummySSLEngine() throws GeneralSecurityException { - javax.net.ssl.SSLContext ctx = javax.net.ssl.SSLContext.getInstance(protocol); - ctx.init(null, null, null); - return ctx.createSSLEngine(); - } - - // should keep SSLContext as a member for introducin SSLSession. later... - SSLEngine createSSLEngine(String peerHost, int peerPort) throws NoSuchAlgorithmException, KeyManagementException { - SSLEngine engine = internalCtx.getSSLContext().createSSLEngine(peerHost, peerPort); - engine.setEnabledCipherSuites(getCipherSuites(engine)); - engine.setEnabledProtocols(getEnabledProtocols(engine)); - return engine; - } - - private String[] getCipherSuites(SSLEngine engine) { - List ciphs = CipherStrings.getMatchingCiphers(ciphers, engine.getSupportedCipherSuites()); - String[] result = new String[ciphs.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = ciphs.get(i).cipherSuite; - } - return result; - } - - private String[] getEnabledProtocols(SSLEngine engine) { - List candidates = new ArrayList(); - long options = getOptions(); - if (ENABLED_PROTOCOLS.get(protocol) != null) { - for (String enabled : ENABLED_PROTOCOLS.get(protocol)) { - if (((options & SSL.OP_NO_SSLv2) != 0) && enabled.equals("SSLv2")) { - continue; - } - if (((options & SSL.OP_NO_SSLv3) != 0) && enabled.equals("SSLv3")) { - continue; - } - if (((options & SSL.OP_NO_TLSv1) != 0) && enabled.equals("TLSv1")) { - continue; - } - for (String allowed : engine.getEnabledProtocols()) { - if (allowed.equals(enabled)) { - candidates.add(allowed); - } - } - } - } - return candidates.toArray(new String[candidates.size()]); - } - - private String sslVersionString(long bits) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - if ((bits & CipherStrings.SSL_SSLV3) != 0) { - if (!first) { - sb.append("/"); - } - first = false; - sb.append("TLSv1/SSLv3"); - } - if ((bits & CipherStrings.SSL_SSLV2) != 0) { - if (!first) { - sb.append("/"); - } - first = false; - sb.append("SSLv2"); - } - return sb.toString(); - } - - private PKey getCallbackKey() { - if (t_key != null) { - return t_key; - } - initFromCallback(); - return t_key; - } - - private X509Cert getCallbackCert() { - if (t_cert != null) { - return t_cert; - } - initFromCallback(); - return t_cert; - } - - private void initFromCallback() { - IRubyObject value = getInstanceVariable("@client_cert_cb"); - if (value != null && !value.isNil()) { - IRubyObject out = value.callMethod(getRuntime().getCurrentContext(), "call", this); - Utils.checkKind(getRuntime(), out, "Array"); - IRubyObject cert = (IRubyObject) ((RubyArray) out).getList().get(0); - IRubyObject key = (IRubyObject) ((RubyArray) out).getList().get(1); - Utils.checkKind(getRuntime(), cert, "OpenSSL::X509::Certificate"); - Utils.checkKind(getRuntime(), key, "OpenSSL::PKey::PKey"); - t_cert = (X509Cert) cert; - t_key = (PKey) key; - } - } - - private X509Store getCertStore() { - IRubyObject value = getInstanceVariable("@cert_store"); - if (value != null && !value.isNil() && (value instanceof X509Store)) { - Utils.checkKind(getRuntime(), value, "OpenSSL::X509::Store"); - return (X509Store) value; - } else { - return null; - } - } - - private String getCaFile() { - IRubyObject value = getInstanceVariable("@ca_file"); - if (value != null && !value.isNil()) { - return value.convertToString().toString(); - } else { - return null; - } - } - - private String getCaPath() { - IRubyObject value = getInstanceVariable("@ca_path"); - if (value != null && !value.isNil()) { - return value.convertToString().toString(); - } else { - return null; - } - } - - private long getOptions() { - IRubyObject value = getInstanceVariable("@options"); - if (value != null && !value.isNil()) { - return RubyNumeric.fix2long(value); - } else { - return 0; - } - } - - private X509Cert[] convertToX509Certs(IRubyObject value) { - final ArrayList result = new ArrayList(); - ThreadContext ctx = getRuntime().getCurrentContext(); - RubyClass klass = Utils.getClassFromPath(ctx.runtime, "OpenSSL::SSL::SSLContext"); - RuntimeHelpers.invoke(ctx, value, "each", CallBlock.newCallClosure(value, klass, Arity.NO_ARGUMENTS, new BlockCallback() { - - public IRubyObject call(ThreadContext context, IRubyObject[] args, Block block) { - Utils.checkKind(getRuntime(), args[0], "OpenSSL::X509::Certificate"); - result.add((X509Cert) args[0]); - return context.runtime.getNil(); - } - }, ctx)); - return result.toArray(new X509Cert[0]); - } - - /** - * c: SSL_CTX - */ - private class InternalContext { - - Store store = null; - int verifyMode = SSL.VERIFY_NONE; - X509AuxCertificate cert = null; - String keyAlgorithm = null; - PrivateKey privateKey = null; - List extraChainCert = null; - List clientCa = new ArrayList(); - int timeout = 0; - String protocol = null; - boolean protocolForServer = true; - boolean protocolForClient = true; - private javax.net.ssl.SSLContext sslCtx = null; - - void setLastVerifyResultInternal(int lastVerifyResult) { - setLastVerifyResult(lastVerifyResult); - } - - javax.net.ssl.SSLContext getSSLContext() { - return sslCtx; - } - - void init() throws GeneralSecurityException { - KM km = new KM(this); - TM tm = new TM(this); - sslCtx = javax.net.ssl.SSLContext.getInstance(protocol); - if (protocolForClient) { - sslCtx.getClientSessionContext().setSessionTimeout(timeout); - } - if (protocolForServer) { - sslCtx.getServerSessionContext().setSessionTimeout(timeout); - } - sslCtx.init(new javax.net.ssl.KeyManager[]{km}, new javax.net.ssl.TrustManager[]{tm}, null); - } - - // part of ssl_verify_cert_chain - StoreContext createStoreContext(String purpose) { - if (store == null) { - return null; - } - StoreContext ctx = new StoreContext(); - if (ctx.init(store, null, null) == 0) { - return null; - } - // for verify_cb - ctx.setExtraData(1, store.getExtraData(1)); - if (purpose != null) { - ctx.setDefault(purpose); - } - ctx.param.inherit(store.param); - return ctx; - } - } - - private static class KM extends javax.net.ssl.X509ExtendedKeyManager { - - private final InternalContext ctx; - - public KM(InternalContext ctx) { - super(); - this.ctx = ctx; - } - - @Override - public String chooseEngineClientAlias(String[] keyType, java.security.Principal[] issuers, javax.net.ssl.SSLEngine engine) { - if (ctx == null) { - return null; - } - if (ctx.privateKey == null) { - return null; - } - for (int i = 0; i < keyType.length; i++) { - if (keyType[i].equalsIgnoreCase(ctx.keyAlgorithm)) { - return keyType[i]; - } - } - return null; - } - - @Override - public String chooseEngineServerAlias(String keyType, java.security.Principal[] issuers, javax.net.ssl.SSLEngine engine) { - if (ctx == null || ctx.privateKey == null) { - return null; - } - if (keyType.equalsIgnoreCase(ctx.keyAlgorithm)) { - return keyType; - } - return null; - } - - public String chooseClientAlias(String[] keyType, java.security.Principal[] issuers, java.net.Socket socket) { - return null; - } - - public String chooseServerAlias(String keyType, java.security.Principal[] issuers, java.net.Socket socket) { - return null; - } - - // c: ssl3_output_cert_chain - public java.security.cert.X509Certificate[] getCertificateChain(String alias) { - if (ctx == null) { - return null; - } - ArrayList chain = new ArrayList(); - if (ctx.extraChainCert != null) { - chain.addAll(ctx.extraChainCert); - } else if (ctx.cert != null) { - StoreContext storeCtx = ctx.createStoreContext(null); - X509AuxCertificate x = ctx.cert; - while (true) { - chain.add(x); - if (x.getIssuerDN().equals(x.getSubjectDN())) { - break; - } - try { - Name xn = new Name(x.getIssuerX500Principal()); - X509Object[] s_obj = new X509Object[1]; - if (storeCtx.getBySubject(X509Utils.X509_LU_X509, xn, s_obj) <= 0) { - break; - } - x = ((Certificate) s_obj[0]).x509; - } catch (Exception e) { - break; - } - } - } - return chain.toArray(new java.security.cert.X509Certificate[0]); - } - - public String[] getClientAliases(String keyType, java.security.Principal[] issuers) { - return null; - } - - public java.security.PrivateKey getPrivateKey(String alias) { - if (ctx == null || ctx.privateKey == null) { - return null; - } - return ctx.privateKey; - } - - public String[] getServerAliases(String keyType, java.security.Principal[] issuers) { - return null; - } - } - - private static class TM implements javax.net.ssl.X509TrustManager { - - private InternalContext ctx; - - public TM(InternalContext ctx) { - super(); - this.ctx = ctx; - } - - public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - checkTrusted("ssl_client", chain); - } - - public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - checkTrusted("ssl_server", chain); - } - - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - if (ctx == null) { - return null; - } - ArrayList chain = new ArrayList(); - chain.addAll(ctx.clientCa); - return chain.toArray(new java.security.cert.X509Certificate[0]); - } - - // c: ssl_verify_cert_chain - private void checkTrusted(String purpose, X509Certificate[] chain) throws CertificateException { - if (ctx == null) { - throw new CertificateException("uninitialized trust manager"); - } - if (chain != null && chain.length > 0) { - if ((ctx.verifyMode & SSL.VERIFY_PEER) != 0) { - // verify_peer - StoreContext storeCtx = ctx.createStoreContext(purpose); - if (storeCtx == null) { - throw new CertificateException("couldn't initialize store"); - } - storeCtx.setCertificate(chain[0]); - storeCtx.setChain(chain); - verifyChain(storeCtx); - } - } else { - if ((ctx.verifyMode & SSL.VERIFY_FAIL_IF_NO_PEER_CERT) != 0) { - // fail if no peer cert - throw new CertificateException("no peer certificate"); - } - } - } - - private void verifyChain(StoreContext storeCtx) throws CertificateException { - try { - int ok = storeCtx.verifyCertificate(); - ctx.setLastVerifyResultInternal(storeCtx.error); - if (ok == 0) { - throw new CertificateException("certificate verify failed"); - } - } catch (Exception e) { - ctx.setLastVerifyResultInternal(storeCtx.error); - if (storeCtx.error == X509Utils.V_OK) { - ctx.setLastVerifyResultInternal(X509Utils.V_ERR_CERT_REJECTED); - } - throw new CertificateException("certificate verify failed", e); - } - } - } -}// SSLContext diff --git a/src/java/org/jruby/ext/openssl/SSLSocket.java b/src/java/org/jruby/ext/openssl/SSLSocket.java deleted file mode 100644 index 6cb5f02..0000000 --- a/src/java/org/jruby/ext/openssl/SSLSocket.java +++ /dev/null @@ -1,787 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.IOException; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.SocketChannel; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.util.Set; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; - -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyIO; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyObjectAdapter; -import org.jruby.RubyString; -import org.jruby.RubyThread; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.X509Utils; -import org.jruby.javasupport.JavaEmbedUtils; -import org.jruby.runtime.Arity; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class SSLSocket extends RubyObject { - private static final long serialVersionUID = -2276327900350542644L; - - private static ObjectAllocator SSLSOCKET_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new SSLSocket(runtime, klass); - } - }; - - private static RubyObjectAdapter api = JavaEmbedUtils.newObjectAdapter(); - - public static void createSSLSocket(Ruby runtime, RubyModule mSSL) { - RubyClass cSSLSocket = mSSL.defineClassUnder("SSLSocket",runtime.getObject(),SSLSOCKET_ALLOCATOR); - cSSLSocket.addReadWriteAttribute(runtime.getCurrentContext(), "io"); - cSSLSocket.addReadWriteAttribute(runtime.getCurrentContext(), "context"); - cSSLSocket.addReadWriteAttribute(runtime.getCurrentContext(), "sync_close"); - cSSLSocket.defineAlias("to_io","io"); - cSSLSocket.defineAnnotatedMethods(SSLSocket.class); - } - - public SSLSocket(Ruby runtime, RubyClass type) { - super(runtime,type); - verifyResult = X509Utils.V_OK; - } - - public static RaiseException newSSLError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::SSL::SSLError", message, false); - } - - private org.jruby.ext.openssl.SSLContext rubyCtx; - private SSLEngine engine; - private RubyIO io = null; - - private ByteBuffer peerAppData; - private ByteBuffer peerNetData; - private ByteBuffer netData; - private ByteBuffer dummy; - - private boolean initialHandshake = false; - - private SSLEngineResult.HandshakeStatus hsStatus; - private SSLEngineResult.Status status = null; - - int verifyResult; - - @JRubyMethod(name = "initialize", rest = true, frame = true) - public IRubyObject _initialize(IRubyObject[] args, Block unused) { - if (Arity.checkArgumentCount(getRuntime(), args, 1, 2) == 1) { - RubyClass sslContext = Utils.getClassFromPath(getRuntime(), "OpenSSL::SSL::SSLContext"); - rubyCtx = (org.jruby.ext.openssl.SSLContext) api.callMethod(sslContext, "new"); - } else { - rubyCtx = (org.jruby.ext.openssl.SSLContext) args[1]; - } - Utils.checkKind(getRuntime(), args[0], "IO"); - io = (RubyIO) args[0]; - api.callMethod(this, "io=", io); - // This is a bit of a hack: SSLSocket should share code with RubyBasicSocket, which always sets sync to true. - // Instead we set it here for now. - api.callMethod(io, "sync=", getRuntime().getTrue()); - api.callMethod(this, "context=", rubyCtx); - api.callMethod(this, "sync_close=", getRuntime().getFalse()); - rubyCtx.setup(); - return api.callSuper(this, args); - } - - private void ossl_ssl_setup() throws NoSuchAlgorithmException, KeyManagementException, IOException { - if(null == engine) { - Socket socket = getSocketChannel().socket(); - String peerHost = socket.getInetAddress().getHostName(); - int peerPort = socket.getPort(); - engine = rubyCtx.createSSLEngine(peerHost, peerPort); - SSLSession session = engine.getSession(); - peerNetData = ByteBuffer.allocate(session.getPacketBufferSize()); - peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize()); - netData = ByteBuffer.allocate(session.getPacketBufferSize()); - peerNetData.limit(0); - peerAppData.limit(0); - netData.limit(0); - dummy = ByteBuffer.allocate(0); - } - } - - @JRubyMethod - public IRubyObject connect(ThreadContext context) { - return connectCommon(context, true); - } - - @JRubyMethod - public IRubyObject connect_nonblock(ThreadContext context) { - return connectCommon(context, false); - } - - private IRubyObject connectCommon(ThreadContext context, boolean blocking) { - Ruby runtime = context.runtime; - if (!rubyCtx.isProtocolForClient()) { - throw newSSLError(runtime, "called a function you should not call"); - } - try { - if (!initialHandshake) { - ossl_ssl_setup(); - engine.setUseClientMode(true); - engine.beginHandshake(); - hsStatus = engine.getHandshakeStatus(); - initialHandshake = true; - } - doHandshake(blocking); - } catch(SSLHandshakeException e) { - // unlike server side, client should close outbound channel even if - // we have remaining data to be sent. - forceClose(); - Throwable v = e; - while(v.getCause() != null && (v instanceof SSLHandshakeException)) { - v = v.getCause(); - } - throw SSL.newSSLError(runtime, v); - } catch (NoSuchAlgorithmException ex) { - forceClose(); - throw SSL.newSSLError(runtime, ex); - } catch (KeyManagementException ex) { - forceClose(); - throw SSL.newSSLError(runtime, ex); - } catch (IOException ex) { - forceClose(); - throw SSL.newSSLError(runtime, ex); - } - return this; - } - - @JRubyMethod - public IRubyObject accept(ThreadContext context) { - return acceptCommon(context, true); - } - - @JRubyMethod - public IRubyObject accept_nonblock(ThreadContext context) { - return acceptCommon(context, false); - } - - public IRubyObject acceptCommon(ThreadContext context, boolean blocking) { - Ruby runtime = context.runtime; - if (!rubyCtx.isProtocolForServer()) { - throw newSSLError(runtime, "called a function you should not call"); - } - try { - int vfy = 0; - if (!initialHandshake) { - ossl_ssl_setup(); - engine.setUseClientMode(false); - if(!rubyCtx.isNil() && !rubyCtx.callMethod(context,"verify_mode").isNil()) { - vfy = RubyNumeric.fix2int(rubyCtx.callMethod(context,"verify_mode")); - if(vfy == 0) { //VERIFY_NONE - engine.setNeedClientAuth(false); - engine.setWantClientAuth(false); - } - if((vfy & 1) != 0) { //VERIFY_PEER - engine.setWantClientAuth(true); - } - if((vfy & 2) != 0) { //VERIFY_FAIL_IF_NO_PEER_CERT - engine.setNeedClientAuth(true); - } - } - engine.beginHandshake(); - hsStatus = engine.getHandshakeStatus(); - initialHandshake = true; - } - doHandshake(blocking); - } catch(SSLHandshakeException e) { - throw SSL.newSSLError(runtime, e); - } catch (NoSuchAlgorithmException ex) { - throw SSL.newSSLError(runtime, ex); - } catch (KeyManagementException ex) { - throw SSL.newSSLError(runtime, ex); - } catch (IOException ex) { - throw SSL.newSSLError(runtime, ex); - } - return this; - } - - @JRubyMethod - public IRubyObject verify_result() { - if (engine == null) { - getRuntime().getWarnings().warn("SSL session is not started yet."); - return getRuntime().getNil(); - } - return getRuntime().newFixnum(verifyResult); - } - - // This select impl is a copy of RubyThread.select, then blockingLock is - // removed. This impl just set - // SelectableChannel.configureBlocking(false) permanently instead of setting - // temporarily. SSLSocket requires wrapping IO to be selectable so it should - // be OK to set configureBlocking(false) permanently. - private boolean waitSelect(final int operations, final boolean blocking) throws IOException { - if (!(io.getChannel() instanceof SelectableChannel)) { - return true; - } - final Ruby runtime = getRuntime(); - RubyThread thread = runtime.getCurrentContext().getThread(); - - SelectableChannel selectable = (SelectableChannel)io.getChannel(); - selectable.configureBlocking(false); - final Selector selector = runtime.getSelectorPool().get(); - final SelectionKey key = selectable.register(selector, operations); - - try { - io.addBlockingThread(thread); - - final int[] result = new int[1]; - - thread.executeBlockingTask(new RubyThread.BlockingTask() { - public void run() throws InterruptedException { - try { - if (!blocking) { - result[0] = selector.selectNow(); - if (result[0] == 0) { - if ((operations & SelectionKey.OP_READ) != 0 && (operations & SelectionKey.OP_WRITE) != 0) { - if (key.isReadable()) { - writeWouldBlock(); - } else if (key.isWritable()) { - readWouldBlock(); - } else { //neither, pick one - readWouldBlock(); - } - } else if ((operations & SelectionKey.OP_READ) != 0) { - readWouldBlock(); - } else if ((operations & SelectionKey.OP_WRITE) != 0) { - writeWouldBlock(); - } - } - } else { - result[0] = selector.select(); - } - } catch (IOException ioe) { - throw runtime.newRuntimeError("Error with selector: " + ioe.getMessage()); - } - } - - public void wakeup() { - selector.wakeup(); - } - }); - - if (result[0] >= 1) { - Set keySet = selector.selectedKeys(); - - if (keySet.iterator().next() == key) { - return true; - } - } - - return false; - } catch (InterruptedException ie) { - return false; - } finally { - // Note: I don't like ignoring these exceptions, but it's - // unclear how likely they are to happen or what damage we - // might do by ignoring them. Note that the pieces are separate - // so that we can ensure one failing does not affect the others - // running. - - // clean up the key in the selector - try { - if (key != null) key.cancel(); - if (selector != null) selector.selectNow(); - } catch (Exception e) { - // ignore - } - - // shut down and null out the selector - try { - if (selector != null) { - runtime.getSelectorPool().put(selector); - } - } catch (Exception e) { - // ignore - } - - // remove this thread as a blocker against the given IO - io.removeBlockingThread(thread); - - // clear thread state from blocking call - thread.afterBlockingCall(); - } - } - - private void readWouldBlock() { - Ruby runtime = getRuntime(); - RaiseException eagain = newSSLError(runtime, "read would block"); - eagain.getException().extend(new IRubyObject[]{runtime.getIO().getConstant("WaitReadable")}); - throw eagain; - } - - private void writeWouldBlock() { - Ruby runtime = getRuntime(); - RaiseException eagain = newSSLError(runtime, "write would block"); - eagain.getException().extend(new IRubyObject[]{runtime.getIO().getConstant("WaitWritable")}); - throw eagain; - } - - private void doHandshake(boolean blocking) throws IOException { - while (true) { - SSLEngineResult res; - boolean ready = waitSelect(SelectionKey.OP_READ | SelectionKey.OP_WRITE, blocking); - - // if not blocking, raise EAGAIN - if (!blocking && !ready) { - Ruby runtime = getRuntime(); - - throw runtime.is1_9() ? - runtime.newErrnoEAGAINWritableError("Resource temporarily unavailable") : - runtime.newErrnoEAGAINError("Resource temporarily unavailable"); - } - - // otherwise, proceed as before - - switch (hsStatus) { - case FINISHED: - if (initialHandshake) { - finishInitialHandshake(); - } - return; - case NEED_TASK: - doTasks(); - break; - case NEED_UNWRAP: - if (readAndUnwrap(blocking) == -1 && hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { - throw new SSLHandshakeException("Socket closed"); - } - // during initialHandshake, calling readAndUnwrap that results UNDERFLOW - // does not mean writable. we explicitly wait for readable channel to avoid - // busy loop. - if (initialHandshake && status == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - waitSelect(SelectionKey.OP_READ, blocking); - } - break; - case NEED_WRAP: - if (netData.hasRemaining()) { - while (flushData()) { - } - } - netData.clear(); - res = engine.wrap(dummy, netData); - hsStatus = res.getHandshakeStatus(); - netData.flip(); - flushData(); - break; - case NOT_HANDSHAKING: - // Opposite side could close while unwrapping. Handle this as same as FINISHED - return; - default: - throw new IllegalStateException("Unknown handshaking status: " + hsStatus); - } - } - } - - private void doTasks() { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) { - task.run(); - } - hsStatus = engine.getHandshakeStatus(); - verifyResult = rubyCtx.getLastVerifyResult(); - } - - private boolean flushData() throws IOException { - try { - writeToChannel(netData); - } catch (IOException ioe) { - netData.position(netData.limit()); - throw ioe; - } - if (netData.hasRemaining()) { - return false; - } else { - return true; - } - } - - private int writeToChannel(ByteBuffer buffer) throws IOException { - int totalWritten = 0; - while (buffer.hasRemaining()) { - totalWritten += getSocketChannel().write(buffer); - } - return totalWritten; - } - - private void finishInitialHandshake() { - initialHandshake = false; - } - - public int write(ByteBuffer src) throws SSLException, IOException { - if(initialHandshake) { - throw new IOException("Writing not possible during handshake"); - } - if(netData.hasRemaining()) { - // TODO; remove - // This protect should be propagated from - // http://www.javadocexamples.com/java_source/ssl/SSLChannel.java.html - // to avoid IO selecting problem under MT. - // We have different model of selecting so it's safe to be removed I think. - throw new IOException("Another thread may be writing"); - } - netData.clear(); - SSLEngineResult res = engine.wrap(src, netData); - netData.flip(); - flushData(); - return res.bytesConsumed(); - } - - public int read(ByteBuffer dst, boolean blocking) throws IOException { - if(initialHandshake) { - return 0; - } - if (engine.isInboundDone()) { - return -1; - } - if (!peerAppData.hasRemaining()) { - int appBytesProduced = readAndUnwrap(blocking); - if (appBytesProduced == -1 || appBytesProduced == 0) { - return appBytesProduced; - } - } - int limit = Math.min(peerAppData.remaining(), dst.remaining()); - peerAppData.get(dst.array(), dst.arrayOffset(), limit); - dst.position(dst.arrayOffset() + limit); - return limit; - } - - private int readAndUnwrap(boolean blocking) throws IOException { - int bytesRead = getSocketChannel().read(peerNetData); - if (bytesRead == -1) { - if (!peerNetData.hasRemaining() || (status == SSLEngineResult.Status.BUFFER_UNDERFLOW)) { - closeInbound(); - return -1; - } - // inbound channel has been already closed but closeInbound() must - // be defered till the last engine.unwrap() call. - // peerNetData could not be empty. - } - peerAppData.clear(); - peerNetData.flip(); - SSLEngineResult res; - do { - res = engine.unwrap(peerNetData, peerAppData); - } while (res.getStatus() == SSLEngineResult.Status.OK && - res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP && - res.bytesProduced() == 0); - if(res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) { - finishInitialHandshake(); - } - if(peerAppData.position() == 0 && - res.getStatus() == SSLEngineResult.Status.OK && - peerNetData.hasRemaining()) { - res = engine.unwrap(peerNetData, peerAppData); - } - status = res.getStatus(); - hsStatus = res.getHandshakeStatus(); - if (bytesRead == -1 && !peerNetData.hasRemaining()) { - // now it's safe to call closeInbound(). - closeInbound(); - } - if(status == SSLEngineResult.Status.CLOSED) { - doShutdown(); - return -1; - } - peerNetData.compact(); - peerAppData.flip(); - if(!initialHandshake && (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK || - hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP || - hsStatus == SSLEngineResult.HandshakeStatus.FINISHED)) { - doHandshake(blocking); - } - return peerAppData.remaining(); - } - - private void closeInbound() { - try { - engine.closeInbound(); - } catch (SSLException ssle) { - // ignore any error on close. possibly an error like this; - // Inbound closed before receiving peer's close_notify: possible truncation attack? - } - } - - private void doShutdown() throws IOException { - if (engine.isOutboundDone()) { - return; - } - netData.clear(); - try { - engine.wrap(dummy, netData); - } catch(Exception e1) { - return; - } - netData.flip(); - flushData(); - } - - private IRubyObject do_sysread(ThreadContext context, IRubyObject[] args, boolean nonBlock) { - Ruby runtime = context.runtime; - int len = RubyNumeric.fix2int(args[0]); - RubyString str = null; - - if (args.length == 2 && !args[1].isNil()) { - str = args[1].convertToString(); - } else { - str = getRuntime().newString(""); - } - if(len == 0) { - str.clear(); - return str; - } - if (len < 0) { - throw runtime.newArgumentError("negative string size (or size too big)"); - } - - try { - // So we need to make sure to only block when there is no data left to process - if (engine == null || !(peerAppData.hasRemaining() || peerNetData.position() > 0)) { - waitSelect(SelectionKey.OP_READ, !nonBlock); - } - - ByteBuffer dst = ByteBuffer.allocate(len); - int rr = -1; - // ensure >0 bytes read; sysread is blocking read. - while (rr <= 0) { - if (engine == null) { - rr = getSocketChannel().read(dst); - } else { - rr = read(dst, !nonBlock); - } - if (rr == -1) { - throw getRuntime().newEOFError(); - } - } - byte[] bss = new byte[rr]; - dst.position(dst.position() - rr); - dst.get(bss); - str.setValue(new ByteList(bss)); - return str; - } catch (IOException ioe) { - throw getRuntime().newIOError(ioe.getMessage()); - } - } - - @JRubyMethod(rest = true, required = 1, optional = 1) - public IRubyObject sysread(ThreadContext context, IRubyObject[] args) { - return do_sysread(context, args, false); - } - - @JRubyMethod(rest = true, required = 1, optional = 1) - public IRubyObject sysread_nonblock(ThreadContext context, IRubyObject[] args) { - return do_sysread(context, args, true); - } - - private IRubyObject do_syswrite(ThreadContext context, IRubyObject arg, boolean nonBlock) { - Ruby runtime = context.runtime; - try { - checkClosed(); - - waitSelect(SelectionKey.OP_WRITE, !nonBlock); - - ByteList bls = arg.convertToString().getByteList(); - ByteBuffer b1 = ByteBuffer.wrap(bls.getUnsafeBytes(), bls.getBegin(), bls.getRealSize()); - int written; - if(engine == null) { - written = writeToChannel(b1); - } else { - written = write(b1); - } - ((RubyIO)api.callMethod(this,"io")).flush(); - - return getRuntime().newFixnum(written); - } catch (IOException ioe) { - throw runtime.newIOError(ioe.getMessage()); - } - } - - @JRubyMethod - public IRubyObject syswrite(ThreadContext context, IRubyObject arg) { - return do_syswrite(context, arg, false); - } - - @JRubyMethod - public IRubyObject syswrite_nonblock(ThreadContext context, IRubyObject arg) { - return do_syswrite(context, arg, true); - } - - private void checkClosed() { - if (!getSocketChannel().isOpen()) { - throw getRuntime().newIOError("closed stream"); - } - } - - // do shutdown even if we have remaining data to be sent. - // call this when you get an exception from client side. - private void forceClose() { - close(true); - } - - private void close(boolean force) { - if (engine == null) throw getRuntime().newEOFError(); - engine.closeOutbound(); - if (!force && netData.hasRemaining()) { - return; - } else { - try { - doShutdown(); - } catch (IOException ex) { - // ignore? - } - } - } - - @JRubyMethod - public IRubyObject sysclose() { - // no need to try shutdown when it's a server - close(rubyCtx.isProtocolForClient()); - ThreadContext tc = getRuntime().getCurrentContext(); - if(callMethod(tc,"sync_close").isTrue()) { - callMethod(tc,"io").callMethod(tc,"close"); - } - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject cert() { - if (engine == null) { - return getRuntime().getNil(); - } - try { - Certificate[] cert = engine.getSession().getLocalCertificates(); - if (cert != null && cert.length > 0) { - return X509Cert.wrap(getRuntime(), cert[0]); - } - } catch (CertificateEncodingException ex) { - throw X509Cert.newCertificateError(getRuntime(), ex); - } - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject peer_cert() { - if (engine == null) { - return getRuntime().getNil(); - } - try { - Certificate[] cert = engine.getSession().getPeerCertificates(); - if (cert.length > 0) { - return X509Cert.wrap(getRuntime(), cert[0]); - } - } catch (CertificateEncodingException ex) { - throw X509Cert.newCertificateError(getRuntime(), ex); - } catch (SSLPeerUnverifiedException ex) { - if (getRuntime().isVerbose()) { - getRuntime().getWarnings().warning(String.format("%s: %s", ex.getClass().getName(), ex.getMessage())); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject peer_cert_chain() { - if (engine == null) { - return getRuntime().getNil(); - } - try { - javax.security.cert.Certificate[] certs = engine.getSession().getPeerCertificateChain(); - RubyArray arr = getRuntime().newArray(certs.length); - for (int i = 0; i < certs.length; i++) { - arr.add(X509Cert.wrap(getRuntime(), certs[i])); - } - return arr; - } catch (javax.security.cert.CertificateEncodingException e) { - throw X509Cert.newCertificateError(getRuntime(), e); - } catch (SSLPeerUnverifiedException ex) { - if (getRuntime().isVerbose()) { - getRuntime().getWarnings().warning(String.format("%s: %s", ex.getClass().getName(), ex.getMessage())); - } - } - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject cipher() { - return getRuntime().newString(engine.getSession().getCipherSuite()); - } - - @JRubyMethod - public IRubyObject state() { - System.err.println("WARNING: unimplemented method called: SSLSocket#state"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject pending() { - System.err.println("WARNING: unimplemented method called: SSLSocket#pending"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject session_reused_p() { - throw new UnsupportedOperationException(); - } - - @JRubyMethod - public synchronized IRubyObject session_set(IRubyObject aSession) { - throw new UnsupportedOperationException(); - } - - private SocketChannel getSocketChannel() { - return (SocketChannel) io.getChannel(); - } -}// SSLSocket diff --git a/src/java/org/jruby/ext/openssl/SimpleSecretKey.java b/src/java/org/jruby/ext/openssl/SimpleSecretKey.java deleted file mode 100644 index 79ef9dd..0000000 --- a/src/java/org/jruby/ext/openssl/SimpleSecretKey.java +++ /dev/null @@ -1,53 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import javax.crypto.SecretKey; - -/** - * @author Ola Bini - */ -public class SimpleSecretKey implements SecretKey { - private static final long serialVersionUID = 1L; - - private final String algorithm; - private final byte[] value; - public SimpleSecretKey(String algorithm, byte[] value) { - this.algorithm = algorithm; - this.value = value; - } - public String getAlgorithm() { - return algorithm; - } - public byte[] getEncoded() { - return value; - } - public String getFormat() { - return "RAW"; - } -}// SimpleSecretKey diff --git a/src/java/org/jruby/ext/openssl/Utils.java b/src/java/org/jruby/ext/openssl/Utils.java deleted file mode 100644 index d05ece9..0000000 --- a/src/java/org/jruby/ext/openssl/Utils.java +++ /dev/null @@ -1,98 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class Utils { - private Utils() {} - public static String toHex(byte[] val) { - StringBuffer out = new StringBuffer(); - for(int i=0,j=val.length;i - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyModule; - -/** - * @author Ola Bini - */ -public class X509 { - public static void createX509(Ruby runtime, RubyModule ossl) { - RubyModule mX509 = ossl.defineModuleUnder("X509"); - - X509Name.createX509Name(runtime,mX509); - X509Cert.createX509Cert(runtime,mX509); - X509Extensions.createX509Ext(runtime,mX509); - X509CRL.createX509CRL(runtime,mX509); - X509Revoked.createX509Revoked(runtime,mX509); - X509Store.createX509Store(runtime,mX509); - Request.createRequest(runtime,mX509); - Attribute.createAttribute(runtime,mX509); - - mX509.setConstant("V_OK",runtime.newFixnum(0)); - mX509.setConstant("V_ERR_UNABLE_TO_GET_ISSUER_CERT",runtime.newFixnum(2)); - mX509.setConstant("V_ERR_UNABLE_TO_GET_CRL",runtime.newFixnum(3)); - mX509.setConstant("V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE",runtime.newFixnum(4)); - mX509.setConstant("V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE",runtime.newFixnum(5)); - mX509.setConstant("V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",runtime.newFixnum(6)); - mX509.setConstant("V_ERR_CERT_SIGNATURE_FAILURE",runtime.newFixnum(7)); - mX509.setConstant("V_ERR_CRL_SIGNATURE_FAILURE",runtime.newFixnum(8)); - mX509.setConstant("V_ERR_CERT_NOT_YET_VALID",runtime.newFixnum(9)); - mX509.setConstant("V_ERR_CERT_HAS_EXPIRED",runtime.newFixnum(10)); - mX509.setConstant("V_ERR_CRL_NOT_YET_VALID",runtime.newFixnum(11)); - mX509.setConstant("V_ERR_CRL_HAS_EXPIRED",runtime.newFixnum(12)); - mX509.setConstant("V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",runtime.newFixnum(13)); - mX509.setConstant("V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",runtime.newFixnum(14)); - mX509.setConstant("V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD",runtime.newFixnum(15)); - mX509.setConstant("V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD",runtime.newFixnum(16)); - mX509.setConstant("V_ERR_OUT_OF_MEM",runtime.newFixnum(17)); - mX509.setConstant("V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",runtime.newFixnum(18)); - mX509.setConstant("V_ERR_SELF_SIGNED_CERT_IN_CHAIN",runtime.newFixnum(19)); - mX509.setConstant("V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",runtime.newFixnum(20)); - mX509.setConstant("V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE",runtime.newFixnum(21)); - mX509.setConstant("V_ERR_CERT_CHAIN_TOO_LONG",runtime.newFixnum(22)); - mX509.setConstant("V_ERR_CERT_REVOKED",runtime.newFixnum(23)); - mX509.setConstant("V_ERR_INVALID_CA",runtime.newFixnum(24)); - mX509.setConstant("V_ERR_PATH_LENGTH_EXCEEDED",runtime.newFixnum(25)); - mX509.setConstant("V_ERR_INVALID_PURPOSE",runtime.newFixnum(26)); - mX509.setConstant("V_ERR_CERT_UNTRUSTED",runtime.newFixnum(27)); - mX509.setConstant("V_ERR_CERT_REJECTED",runtime.newFixnum(28)); - mX509.setConstant("V_ERR_SUBJECT_ISSUER_MISMATCH",runtime.newFixnum(29)); - mX509.setConstant("V_ERR_AKID_SKID_MISMATCH",runtime.newFixnum(30)); - mX509.setConstant("V_ERR_AKID_ISSUER_SERIAL_MISMATCH",runtime.newFixnum(31)); - mX509.setConstant("V_ERR_KEYUSAGE_NO_CERTSIGN",runtime.newFixnum(32)); - mX509.setConstant("V_ERR_APPLICATION_VERIFICATION",runtime.newFixnum(50)); - mX509.setConstant("V_FLAG_CRL_CHECK",runtime.newFixnum(4)); - mX509.setConstant("V_FLAG_CRL_CHECK_ALL",runtime.newFixnum(8)); - mX509.setConstant("PURPOSE_SSL_CLIENT",runtime.newFixnum(1)); - mX509.setConstant("PURPOSE_SSL_SERVER",runtime.newFixnum(2)); - mX509.setConstant("PURPOSE_NS_SSL_SERVER",runtime.newFixnum(3)); - mX509.setConstant("PURPOSE_SMIME_SIGN",runtime.newFixnum(4)); - mX509.setConstant("PURPOSE_SMIME_ENCRYPT",runtime.newFixnum(5)); - mX509.setConstant("PURPOSE_CRL_SIGN",runtime.newFixnum(6)); - mX509.setConstant("PURPOSE_ANY",runtime.newFixnum(7)); - mX509.setConstant("PURPOSE_OCSP_HELPER",runtime.newFixnum(8)); - mX509.setConstant("TRUST_COMPAT",runtime.newFixnum(1)); - mX509.setConstant("TRUST_SSL_CLIENT",runtime.newFixnum(2)); - mX509.setConstant("TRUST_SSL_SERVER",runtime.newFixnum(3)); - mX509.setConstant("TRUST_EMAIL",runtime.newFixnum(4)); - mX509.setConstant("TRUST_OBJECT_SIGN",runtime.newFixnum(5)); - mX509.setConstant("TRUST_OCSP_SIGN",runtime.newFixnum(6)); - mX509.setConstant("TRUST_OCSP_REQUEST",runtime.newFixnum(7)); - - // These should eventually point to correct things. - mX509.setConstant("DEFAULT_CERT_AREA", runtime.newString("/usr/lib/ssl")); - mX509.setConstant("DEFAULT_CERT_DIR", runtime.newString("/usr/lib/ssl/certs")); - mX509.setConstant("DEFAULT_CERT_FILE", runtime.newString("/usr/lib/ssl/cert.pem")); - mX509.setConstant("DEFAULT_CERT_DIR_ENV", runtime.newString("SSL_CERT_DIR")); - mX509.setConstant("DEFAULT_CERT_FILE_ENV", runtime.newString("SSL_CERT_FILE")); - mX509.setConstant("DEFAULT_PRIVATE_DIR", runtime.newString("/usr/lib/ssl/private")); - } -}// X509 diff --git a/src/java/org/jruby/ext/openssl/X509CRL.java b/src/java/org/jruby/ext/openssl/X509CRL.java deleted file mode 100644 index 7ecfba5..0000000 --- a/src/java/org/jruby/ext/openssl/X509CRL.java +++ /dev/null @@ -1,462 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.cert.CRLException; -import java.security.cert.CertificateFactory; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.RubyTime; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class X509CRL extends RubyObject { - private static final long serialVersionUID = -2463300006179688577L; - - private static ObjectAllocator X509CRL_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509CRL(runtime, klass); - } - }; - - public static void createX509CRL(Ruby runtime, RubyModule mX509) { - RubyClass cX509CRL = mX509.defineClassUnder("CRL",runtime.getObject(),X509CRL_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("CRLError",openSSLError,openSSLError.getAllocator()); - - cX509CRL.defineAnnotatedMethods(X509CRL.class); - } - - private IRubyObject version; - private IRubyObject issuer; - private IRubyObject last_update; - private IRubyObject next_update; - private IRubyObject revoked; - private List extensions; - - private IRubyObject sig_alg; - - private boolean changed = true; - - private org.bouncycastle.x509.X509V2CRLGenerator generator = new org.bouncycastle.x509.X509V2CRLGenerator(); - private java.security.cert.X509CRL crl; - - private DERObject crl_v; - - java.security.cert.X509CRL getCRL() { - return crl; - } - - public X509CRL(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - @JRubyMethod(name="initialize", rest=true, frame=true) - public IRubyObject _initialize(IRubyObject[] args, Block block) { - extensions = new ArrayList(); - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,0,1) == 0) { - version = getRuntime().getNil(); - issuer = getRuntime().getNil(); - last_update = getRuntime().getNil(); - next_update = getRuntime().getNil(); - revoked = getRuntime().newArray(); - return this; - } - - ByteArrayInputStream bis = new ByteArrayInputStream(args[0].convertToString().getBytes()); - try { - // SunJCE throws java.security.cert.CRLException: Invalid encoding of AuthorityKeyIdentifierExtension. - // FIXME: use BC for now. - CertificateFactory cf = OpenSSLReal.getX509CertificateFactoryBC(); - crl = (java.security.cert.X509CRL) cf.generateCRL(bis); - } catch (GeneralSecurityException gse) { - throw newX509CRLError(getRuntime(), gse.getMessage()); - } - - byte[] crl_bytes = OpenSSLImpl.readX509PEM(args[0]); - try { - crl_v = new ASN1InputStream(new ByteArrayInputStream(crl_bytes)).readObject(); - } catch (IOException ioe) { - throw newX509CRLError(getRuntime(), ioe.getMessage()); - } - - DEREncodable v0 = ((DERSequence)(((DERSequence)crl_v).getObjectAt(0))).getObjectAt(0); - if(v0 instanceof DERInteger) { - set_version(getRuntime().newFixnum(((DERInteger)v0).getValue().intValue())); - } else { - set_version(getRuntime().newFixnum(2)); - } - set_last_update(RubyTime.newTime(getRuntime(),crl.getThisUpdate().getTime())); - set_next_update(RubyTime.newTime(getRuntime(),crl.getNextUpdate().getTime())); - RubyString name = RubyString.newString(getRuntime(), crl.getIssuerX500Principal().getEncoded()); - set_issuer(Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Name", name)); - - revoked = getRuntime().newArray(); - - DERSequence seqa = (DERSequence)((DERSequence)crl_v).getObjectAt(0); - DERObject maybe_ext = (DERObject)seqa.getObjectAt(seqa.size()-1); - if(maybe_ext instanceof DERTaggedObject && ((DERTaggedObject)maybe_ext).getTagNo() == 0) { - DERSequence exts = (DERSequence)((DERTaggedObject)maybe_ext).getObject(); - for(int i=0;i0) { - sbe.append(IND8).append("CRL extensions\n"); - for(Iterator iter = extensions.iterator();iter.hasNext();) { - X509Extensions.Extension ext = (X509Extensions.Extension)iter.next(); - DERObjectIdentifier oiden = ext.getRealOid(); - sbe.append(IND12).append(ASN1.o2a(getRuntime(),oiden)).append(": "); - if(ext.getRealCritical()) { - sbe.append("critical"); - } - sbe.append("\n"); - sbe.append(IND16).append(ext.value()).append("\n"); - } - } - /* - 114 rev = X509_CRL_get_REVOKED(x); - 115 - 116 if(sk_X509_REVOKED_num(rev) > 0) - 117 BIO_printf(out, "Revoked Certificates:\n"); - 118 else BIO_printf(out, "No Revoked Certificates.\n"); - 119 - 120 for(i = 0; i < sk_X509_REVOKED_num(rev); i++) { - 121 r = sk_X509_REVOKED_value(rev, i); - 122 BIO_printf(out," Serial Number: "); - 123 i2a_ASN1_INTEGER(out,r->serialNumber); - 124 BIO_printf(out,"\n Revocation Date: "); - 125 ASN1_TIME_print(out,r->revocationDate); - 126 BIO_printf(out,"\n"); - 127 X509V3_extensions_print(out, "CRL entry extensions", - 128 r->extensions, 0, 8); - 129 } - 130 X509_signature_print(out, x->sig_alg, x->signature); - 131 - */ - return getRuntime().newString(sbe.toString()); - } - - @JRubyMethod - public IRubyObject version() { - return this.version; - } - - @JRubyMethod(name="version=") - public IRubyObject set_version(IRubyObject val) { - if(!val.equals(this.version)) { - changed = true; - } - this.version = val; - return val; - } - - @JRubyMethod - public IRubyObject signature_algorithm() { - return sig_alg; - } - - @JRubyMethod - public IRubyObject issuer() { - return this.issuer; - } - - @JRubyMethod(name="issuer=") - public IRubyObject set_issuer(IRubyObject val) { - if(!val.equals(this.issuer)) { - changed = true; - } - this.issuer = val; - generator.setIssuerDN(((X509Name)issuer).getRealName()); - return val; - } - - @JRubyMethod - public IRubyObject last_update() { - return this.last_update; - } - - @JRubyMethod(name="last_update=") - public IRubyObject set_last_update(IRubyObject val) { - changed = true; - last_update = val.callMethod(getRuntime().getCurrentContext(),"getutc"); - ((RubyTime)last_update).setMicroseconds(0); - generator.setThisUpdate(((RubyTime)last_update).getJavaDate()); - this.last_update = val; - return val; - } - - @JRubyMethod - public IRubyObject next_update() { - return this.next_update; - } - - @JRubyMethod(name="next_update=") - public IRubyObject set_next_update(IRubyObject val) { - changed = true; - next_update = val.callMethod(getRuntime().getCurrentContext(),"getutc"); - ((RubyTime)next_update).setMicroseconds(0); - generator.setNextUpdate(((RubyTime)next_update).getJavaDate()); - this.next_update = val; - return val; - } - - @JRubyMethod - public IRubyObject revoked() { - return this.revoked; - } - - @JRubyMethod(name="revoked=") - public IRubyObject set_revoked(IRubyObject val) { - changed = true; - this.revoked = val; - return val; - } - - @JRubyMethod - public IRubyObject add_revoked(IRubyObject val) { - changed = true; - this.revoked.callMethod(getRuntime().getCurrentContext(),"<<",val); - return val; - } - - @JRubyMethod - public IRubyObject extensions() { - return getRuntime().newArray(this.extensions); - } - - @SuppressWarnings("unchecked") - @JRubyMethod(name="extensions=") - public IRubyObject set_extensions(IRubyObject val) { - this.extensions = ((RubyArray)val).getList(); - return val; - } - - @JRubyMethod - public IRubyObject add_extension(IRubyObject val) { - this.extensions.add(val); - return val; - } - - @JRubyMethod - public IRubyObject sign(final IRubyObject key, IRubyObject digest) { - //System.err.println("WARNING: unimplemented method called: CRL#sign"); - // Have to obey some artificial constraints of the OpenSSL implementation. Stupid. - String keyAlg = ((PKey)key).getAlgorithm(); - String digAlg = ((Digest)digest).getShortAlgorithm(); - - if(("DSA".equalsIgnoreCase(keyAlg) && "MD5".equalsIgnoreCase(digAlg)) || - ("RSA".equalsIgnoreCase(keyAlg) && "DSS1".equals(((Digest)digest).name().toString())) || - ("DSA".equalsIgnoreCase(keyAlg) && "SHA1".equals(((Digest)digest).name().toString()))) { - throw newX509CRLError(getRuntime(), null); - } - - sig_alg = getRuntime().newString(digAlg); - generator.setSignatureAlgorithm(digAlg + "WITH" + keyAlg); - - for (IRubyObject obj : ((RubyArray)revoked).toJavaArray()) { - X509Revoked rev = (X509Revoked)obj; // TODO: can throw CCE - BigInteger serial = new BigInteger(rev.callMethod(getRuntime().getCurrentContext(),"serial").toString()); - IRubyObject t1 = rev.callMethod(getRuntime().getCurrentContext(),"time").callMethod(getRuntime().getCurrentContext(),"getutc"); - ((RubyTime)t1).setMicroseconds(0); - // Extensions ignored, for now - generator.addCRLEntry(serial,((RubyTime)t1).getJavaDate(),new org.bouncycastle.asn1.x509.X509Extensions(new Hashtable())); - } - - try { - for (Iterator iter = extensions.iterator(); iter.hasNext();) { - X509Extensions.Extension ag = (X509Extensions.Extension) iter.next(); - generator.addExtension(ag.getRealOid(), ag.getRealCritical(), ag.getRealValueBytes()); - } - } catch (IOException ioe) { - throw newX509CRLError(getRuntime(), ioe.getMessage()); - } - try { - // X509V2CRLGenerator(generator) depends BC. - OpenSSLReal.doWithBCProvider(new OpenSSLReal.Runnable() { - - public void run() throws GeneralSecurityException { - crl = generator.generate(((PKey) key).getPrivateKey(), "BC"); - } - }); - } catch (GeneralSecurityException gse) { - throw newX509CRLError(getRuntime(), gse.getMessage()); - } - - try { - crl_v = new ASN1InputStream(new ByteArrayInputStream(crl.getEncoded())).readObject(); - } catch (CRLException crle) { - throw newX509CRLError(getRuntime(), crle.getMessage()); - } catch (IOException ioe) { - throw newX509CRLError(getRuntime(), ioe.getMessage()); - } - DERSequence v1 = (DERSequence)(((DERSequence)crl_v).getObjectAt(0)); - ASN1EncodableVector build1 = new ASN1EncodableVector(); - int copyIndex = 0; - if(v1.getObjectAt(0) instanceof DERInteger) { - copyIndex++; - } - build1.add(new DERInteger(new java.math.BigInteger(version.toString()))); - while(copyIndex < v1.size()) { - build1.add(v1.getObjectAt(copyIndex++)); - } - ASN1EncodableVector build2 = new ASN1EncodableVector(); - build2.add(new DERSequence(build1)); - build2.add(((DERSequence)crl_v).getObjectAt(1)); - build2.add(((DERSequence)crl_v).getObjectAt(2)); - crl_v = new DERSequence(build2); - changed = false; - return this; - } - - @JRubyMethod - public IRubyObject verify(final IRubyObject key) { - if (changed) { - return getRuntime().getFalse(); - } - try { - crl.verify(((PKey) key).getPublicKey()); - return getRuntime().getTrue(); - } catch (Exception ignored) { - return getRuntime().getFalse(); - } - - } - - private static RaiseException newX509CRLError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::X509::CRLError", message); - } -}// X509CRL diff --git a/src/java/org/jruby/ext/openssl/X509Cert.java b/src/java/org/jruby/ext/openssl/X509Cert.java deleted file mode 100644 index 5a92b88..0000000 --- a/src/java/org/jruby/ext/openssl/X509Cert.java +++ /dev/null @@ -1,536 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.SignatureException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.x509.X509V3CertificateGenerator; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.RubyTime; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.ASN1Registry; -import org.jruby.ext.openssl.x509store.PEMInputOutput; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class X509Cert extends RubyObject { - private static final long serialVersionUID = 5626619026058595493L; - - private static ObjectAllocator X509CERT_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509Cert(runtime, klass); - } - }; - - public static void createX509Cert(Ruby runtime, RubyModule mX509) { - RubyClass cX509Cert = mX509.defineClassUnder("Certificate",runtime.getObject(),X509CERT_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("CertificateError",openSSLError,openSSLError.getAllocator()); - - cX509Cert.defineAnnotatedMethods(X509Cert.class); - } - - public X509Cert(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private IRubyObject serial; - private IRubyObject not_before; - private IRubyObject not_after; - private IRubyObject issuer; - private IRubyObject subject; - private IRubyObject public_key; - - private IRubyObject sig_alg; - private IRubyObject version; - - private List extensions; - - private boolean changed = true; - - private X509V3CertificateGenerator generator = new X509V3CertificateGenerator(); - private X509Certificate cert; - private String public_key_algorithm; - private byte[] public_key_encoded; - - X509AuxCertificate getAuxCert() { - if(null == cert) { - return null; - } - if(cert instanceof X509AuxCertificate) { - return (X509AuxCertificate)cert; - } - return new X509AuxCertificate(cert); - } - - public static IRubyObject wrap(Ruby runtime, Certificate c) throws CertificateEncodingException { - RubyClass cr = Utils.getClassFromPath(runtime, "OpenSSL::X509::Certificate"); - return cr.callMethod(runtime.getCurrentContext(), "new", RubyString.newString(runtime, c.getEncoded())); - } - - // this is the javax.security counterpart of the previous wrap method - public static IRubyObject wrap(Ruby runtime, javax.security.cert.Certificate c) throws javax.security.cert.CertificateEncodingException { - RubyClass cr = Utils.getClassFromPath(runtime, "OpenSSL::X509::Certificate"); - return cr.callMethod(runtime.getCurrentContext(), "new", RubyString.newString(runtime, c.getEncoded())); - } - - @JRubyMethod(name="initialize", optional = 1, frame=true) - public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block unusedBlock) { - Ruby runtime = context.runtime; - extensions = new ArrayList(); - if(args.length == 0) { - return this; - } - byte[] bytes = OpenSSLImpl.readX509PEM(args[0]); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - - CertificateFactory cf; - - RubyModule ossl = runtime.getModule("OpenSSL"); - RubyModule x509 = (RubyModule)ossl.getConstant("X509"); - IRubyObject x509Name = x509.getConstant("Name"); - - try { - cf = CertificateFactory.getInstance("X.509"); - cert = (X509Certificate)cf.generateCertificate(bis); - } catch (CertificateException ex) { - throw newCertificateError(runtime, ex); - } - if (cert == null) { - throw newCertificateError(runtime, (String) null); - } - - set_serial(RubyNumeric.str2inum(runtime,runtime.newString(cert.getSerialNumber().toString()),10)); - set_not_before(RubyTime.newTime(runtime,cert.getNotBefore().getTime())); - set_not_after(RubyTime.newTime(runtime,cert.getNotAfter().getTime())); - set_subject(x509Name.callMethod(context,"new",RubyString.newString(runtime, cert.getSubjectX500Principal().getEncoded()))); - set_issuer(x509Name.callMethod(context,"new",RubyString.newString(runtime, cert.getIssuerX500Principal().getEncoded()))); - - String algorithm = cert.getPublicKey().getAlgorithm(); - set_public_key(algorithm, cert.getPublicKey().getEncoded()); - - IRubyObject extFact = ((RubyClass)(x509.getConstant("ExtensionFactory"))).callMethod(context,"new"); - extFact.callMethod(context,"subject_certificate=",this); - - Set crit = cert.getCriticalExtensionOIDs(); - if (crit != null) { - for (Iterator iter = crit.iterator(); iter.hasNext();) { - String critOid = iter.next(); - byte[] value = cert.getExtensionValue(critOid); - IRubyObject rValue = ASN1.decode(ossl.getConstant("ASN1"), runtime.newString(new ByteList(value, false))).callMethod(context, "value"); - X509Extensions.Extension ext = (X509Extensions.Extension) x509.getConstant("Extension").callMethod(context, "new", - new IRubyObject[] { runtime.newString(critOid), rValue, runtime.getTrue() }); - add_extension(ext); - } - } - - Set ncrit = cert.getNonCriticalExtensionOIDs(); - if (ncrit != null) { - for (Iterator iter = ncrit.iterator(); iter.hasNext();) { - String ncritOid = iter.next(); - byte[] value = cert.getExtensionValue(ncritOid); - // TODO: wired. J9 returns null for an OID given in getNonCriticalExtensionOIDs() - if (value != null) { - IRubyObject rValue = ASN1.decode(ossl.getConstant("ASN1"), runtime.newString(new ByteList(value, false))).callMethod(context, "value"); - X509Extensions.Extension ext = (X509Extensions.Extension) x509.getConstant("Extension").callMethod(context, "new", - new IRubyObject[] { runtime.newString(ncritOid), rValue, runtime.getFalse() }); - add_extension(ext); - } - } - } - changed = false; - - return this; - } - - //Lazy method for public key instantiation - private void set_public_key(String algorithm, byte[] encoded) { - this.public_key_algorithm = algorithm; - this.public_key_encoded = encoded; - } - - public static RaiseException newCertificateError(Ruby runtime, Exception ex) { - return newCertificateError(runtime, ex.getMessage()); - } - - public static RaiseException newCertificateError(Ruby runtime, String message) { - throw Utils.newError(runtime, "OpenSSL::X509::CertificateError", message); - } - - @Override - @JRubyMethod - public IRubyObject initialize_copy(IRubyObject obj) { - if(this == obj) { - return this; - } - checkFrozen(); - return this; - } - - @JRubyMethod - public IRubyObject to_der() { - try { - return RubyString.newString(getRuntime(), cert.getEncoded()); - } catch (CertificateEncodingException ex) { - throw newCertificateError(getRuntime(), ex); - } - } - - @JRubyMethod(name={"to_pem","to_s"}) - public IRubyObject to_pem() { - try { - StringWriter w = new StringWriter(); - PEMInputOutput.writeX509Certificate(w, getAuxCert()); - w.close(); - return getRuntime().newString(w.toString()); - } catch (IOException ex) { - throw getRuntime().newIOErrorFromException(ex); - } - } - - @JRubyMethod - public IRubyObject to_text() { - return getRuntime().newString(getAuxCert().toString()); - } - - @Override - @JRubyMethod - public IRubyObject inspect() { - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject version() { - return version; - } - - @JRubyMethod(name="version=") - public IRubyObject set_version(IRubyObject arg) { - if(!arg.equals(this.version)) { - changed = true; - } - this.version = arg; - return arg; - } - - @JRubyMethod - public IRubyObject signature_algorithm() { - return sig_alg; - } - - @JRubyMethod - public IRubyObject serial() { - return serial; - } - - @JRubyMethod(name="serial=") - public IRubyObject set_serial(IRubyObject num) { - if(!num.equals(this.serial)) { - changed = true; - } - serial = num; - String s = serial.toString(); - - BigInteger bi; - if (s.equals("0")) { // MRI compatibility: allow 0 serial number - bi = BigInteger.ONE; - } else { - bi = new BigInteger(s); - } - generator.setSerialNumber(bi); - return num; - } - - @JRubyMethod - public IRubyObject subject() { - return subject; - } - - @JRubyMethod(name="subject=") - public IRubyObject set_subject(IRubyObject arg) { - if(!arg.equals(this.subject)) { - changed = true; - } - subject = arg; - generator.setSubjectDN(((X509Name)subject).getRealName()); - return arg; - } - - @JRubyMethod - public IRubyObject issuer() { - return issuer; - } - - @JRubyMethod(name="issuer=") - public IRubyObject set_issuer(IRubyObject arg) { - if(!arg.equals(this.issuer)) { - changed = true; - } - issuer = arg; - generator.setIssuerDN(((X509Name)issuer).getRealName()); - return arg; - } - - @JRubyMethod - public IRubyObject not_before() { - return not_before; - } - - @JRubyMethod(name="not_before=") - public IRubyObject set_not_before(IRubyObject arg) { - changed = true; - not_before = arg.callMethod(getRuntime().getCurrentContext(),"getutc"); - ((RubyTime)not_before).setMicroseconds(0); - generator.setNotBefore(((RubyTime)not_before).getJavaDate()); - return arg; - } - - @JRubyMethod - public IRubyObject not_after() { - return not_after; - } - - @JRubyMethod(name="not_after=") - public IRubyObject set_not_after(IRubyObject arg) { - changed = true; - not_after = arg.callMethod(getRuntime().getCurrentContext(),"getutc"); - ((RubyTime)not_after).setMicroseconds(0); - generator.setNotAfter(((RubyTime)not_after).getJavaDate()); - return arg; - } - - @JRubyMethod - public IRubyObject public_key() { - if (public_key == null) { - lazyInitializePublicKey(); - } - return public_key.callMethod(getRuntime().getCurrentContext(), "public_key"); - } - - @JRubyMethod(name="public_key=") - public IRubyObject set_public_key(IRubyObject arg) { - Utils.checkKind(getRuntime(), arg, "OpenSSL::PKey::PKey"); - if(!arg.equals(this.public_key)) { - changed = true; - } - public_key = arg; - generator.setPublicKey(((PKey)public_key).getPublicKey()); - return arg; - } - - private void lazyInitializePublicKey() { - if (public_key_encoded == null || public_key_algorithm == null) { - throw new IllegalStateException("lazy public key initialization failed"); - } - RubyModule ossl = getRuntime().getModule("OpenSSL"); - RubyModule pkey = (RubyModule) ossl.getConstant("PKey"); - ThreadContext tc = getRuntime().getCurrentContext(); - boolean backupChanged = changed; - if ("RSA".equalsIgnoreCase(public_key_algorithm)) { - set_public_key(pkey.getConstant("RSA").callMethod(tc, "new", RubyString.newString(getRuntime(), public_key_encoded))); - } else if ("DSA".equalsIgnoreCase(public_key_algorithm)) { - set_public_key(pkey.getConstant("DSA").callMethod(tc, "new", RubyString.newString(getRuntime(), public_key_encoded))); - } else { - throw newCertificateError(getRuntime(), "The algorithm " + public_key_algorithm + " is unsupported for public keys"); - } - changed = backupChanged; - } - - @JRubyMethod - public IRubyObject sign(ThreadContext context, final IRubyObject key, IRubyObject digest) { - Ruby runtime = context.runtime; - - // Have to obey some artificial constraints of the OpenSSL implementation. Stupid. - String keyAlg = ((PKey)key).getAlgorithm(); - String digAlg = ((Digest)digest).getShortAlgorithm(); - String digName = ((Digest)digest).name().toString(); - - if(("DSA".equalsIgnoreCase(keyAlg) && "MD5".equalsIgnoreCase(digAlg)) || - ("RSA".equalsIgnoreCase(keyAlg) && "DSS1".equals(digName))) { - throw newCertificateError(runtime, "signature_algorithm not supported"); - } - - for(Iterator iter = extensions.iterator();iter.hasNext();) { - X509Extensions.Extension ag = (X509Extensions.Extension)iter.next(); - try { - byte[] bytes = ag.getRealValueBytes(); - generator.addExtension(ag.getRealOid(),ag.getRealCritical(),bytes); - } catch (IOException ioe) { - throw runtime.newIOErrorFromException(ioe); - } - } - - generator.setSignatureAlgorithm(digAlg + "WITH" + keyAlg); - if (public_key == null) { - lazyInitializePublicKey(); - } - try { - // X509V3CertificateGenerator depends BC. - OpenSSLReal.doWithBCProvider(new OpenSSLReal.Runnable() { - - public void run() throws GeneralSecurityException { - cert = generator.generate(((PKey) key).getPrivateKey(), "BC"); - } - }); - } catch (GeneralSecurityException gse) { - throw newCertificateError(getRuntime(), gse.getMessage()); - } - if (cert == null) { - throw newCertificateError(runtime, (String) null); - } - String name = ASN1Registry.o2a(cert.getSigAlgOID()); - if (name == null) { - name = cert.getSigAlgOID(); - } - sig_alg = runtime.newString(name); - changed = false; - return this; - } - - @JRubyMethod - public IRubyObject verify(IRubyObject key) { - if(changed) { - return getRuntime().getFalse(); - } - try { - cert.verify(((PKey)key).getPublicKey()); - return getRuntime().getTrue(); - } catch (CertificateException ce) { - throw newCertificateError(getRuntime(), ce); - } catch (NoSuchAlgorithmException nsae) { - throw newCertificateError(getRuntime(), nsae); - } catch (NoSuchProviderException nspe) { - throw newCertificateError(getRuntime(), nspe); - } catch (SignatureException se) { - throw newCertificateError(getRuntime(), se); - } catch(InvalidKeyException e) { - return getRuntime().getFalse(); - } - } - - @JRubyMethod - public IRubyObject check_private_key(IRubyObject arg) { - PKey key = (PKey)arg; - PublicKey pkey = key.getPublicKey(); - PublicKey certPubKey = getAuxCert().getPublicKey(); - if (certPubKey.equals(pkey)) - return getRuntime().getTrue(); - return getRuntime().getFalse(); - } - - @JRubyMethod - public IRubyObject extensions() { - return getRuntime().newArray(extensions); - } - - @SuppressWarnings("unchecked") - @JRubyMethod(name="extensions=") - public IRubyObject set_extensions(IRubyObject arg) { - extensions = new ArrayList(((RubyArray)arg).getList()); - return arg; - } - - @JRubyMethod - public IRubyObject add_extension(IRubyObject arg) { - changed = true; - DERObjectIdentifier oid = ((X509Extensions.Extension)arg).getRealOid(); - if(oid.equals(new DERObjectIdentifier("2.5.29.17"))) { - boolean one = true; - for(Iterator iter = extensions.iterator();iter.hasNext();) { - X509Extensions.Extension ag = (X509Extensions.Extension)iter.next(); - if(ag.getRealOid().equals(new DERObjectIdentifier("2.5.29.17"))) { - ASN1EncodableVector v1 = new ASN1EncodableVector(); - - try { - GeneralName[] n1 = GeneralNames.getInstance(new ASN1InputStream(ag.getRealValueBytes()).readObject()).getNames(); - GeneralName[] n2 = GeneralNames.getInstance(new ASN1InputStream(((X509Extensions.Extension)arg).getRealValueBytes()).readObject()).getNames(); - - for(int i=0;i - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERString; -import org.bouncycastle.asn1.DERUnknownTag; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.impl.ASN1Registry; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.ThreadContext; -import org.jruby.runtime.builtin.IRubyObject; -import org.jruby.util.ByteList; - -/** - * @author Ola Bini - */ -public class X509Extensions { - public static void createX509Ext(Ruby runtime, RubyModule mX509) { - RubyClass cX509ExtFactory = mX509.defineClassUnder("ExtensionFactory",runtime.getObject(),ExtensionFactory.ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("ExtensionError",openSSLError,openSSLError.getAllocator()); - - cX509ExtFactory.attr_reader(runtime.getCurrentContext(), new IRubyObject[]{runtime.newString("issuer_certificate"),runtime.newString("subject_certificate"), - runtime.newString("subject_request"),runtime.newString("crl"), - runtime.newString("config")}); - - cX509ExtFactory.defineAnnotatedMethods(ExtensionFactory.class); - - RubyClass cX509Ext = mX509.defineClassUnder("Extension",runtime.getObject(),Extension.ALLOCATOR); - cX509Ext.defineAnnotatedMethods(Extension.class); - } - - public static class ExtensionFactory extends RubyObject { - private static final long serialVersionUID = 3180447029639456500L; - - public static ObjectAllocator ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new ExtensionFactory(runtime, klass); - } - }; - - public ExtensionFactory(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - @JRubyMethod(rest=true,frame=true) - public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { - org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,0,4); - if(args.length > 0 && !args[0].isNil()) { - set_issuer_cert(args[0]); - } - if(args.length > 1 && !args[1].isNil()) { - set_subject_cert(args[1]); - } - if(args.length > 2 && !args[2].isNil()) { - set_subject_req(args[2]); - } - if(args.length > 3 && !args[3].isNil()) { - set_crl(args[3]); - } - return this; - } - - @JRubyMethod(name="issuer_certificate=") - public IRubyObject set_issuer_cert(IRubyObject arg) { - setInstanceVariable("@issuer_certificate",arg); - return arg; - } - - @JRubyMethod(name="subject_certificate=") - public IRubyObject set_subject_cert(IRubyObject arg) { - setInstanceVariable("@subject_certificate",arg); - return arg; - } - - @JRubyMethod(name="subject_request=") - public IRubyObject set_subject_req(IRubyObject arg) { - setInstanceVariable("@subject_request",arg); - return arg; - } - - @JRubyMethod(name="crl=") - public IRubyObject set_crl(IRubyObject arg) { - setInstanceVariable("@crl",arg); - return arg; - } - - @JRubyMethod(name="config=") - public IRubyObject set_config(IRubyObject arg) { - setInstanceVariable("@config",arg); - return arg; - } - - private DERObjectIdentifier getObjectIdentifier(String nameOrOid) { - Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase()); - if(null != val1) { - return (DERObjectIdentifier)val1; - } - DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid); - return val2; - } - - private static boolean isHexDigit(char c) { - return ('0'<=c && c<='9') || ('A'<= c && c <= 'F') || ('a'<= c && c <= 'f'); - } - - private boolean isHexString(String str ){ - for(int i = 0; i< str.length(); i++) { - if (!isHexDigit(str.charAt(i))) return false; - } - return true; - } - - @JRubyMethod(rest=true) - public IRubyObject create_ext(IRubyObject[] args) { - IRubyObject critical = getRuntime().getFalse(); - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,2,3) == 3 && !args[2].isNil()) { - critical = args[2]; - } - String oid = args[0].toString(); - String valuex = args[1].toString(); - Object value = valuex; - - DERObjectIdentifier r_oid = null; - - try { - r_oid = getObjectIdentifier(oid); - } catch(IllegalArgumentException e) { - r_oid = null; - } - if (null == r_oid) { - throw newX509ExtError(getRuntime(), "unknown OID `" + oid + "'"); - } - - ThreadContext tc = getRuntime().getCurrentContext(); - Extension ext = (Extension) Utils.newRubyInstance(getRuntime(), "OpenSSL::X509::Extension"); - - if(valuex.startsWith("critical,")) { - critical = getRuntime().getTrue(); - valuex = valuex.substring(9).trim(); - } - - if(r_oid.equals(new DERObjectIdentifier("2.5.29.14"))) { //subjectKeyIdentifier - if("hash".equalsIgnoreCase(valuex)) { - IRubyObject pkey = getInstanceVariable("@subject_certificate").callMethod(tc,"public_key"); - IRubyObject val = null; - if(pkey instanceof PKeyRSA) { - val = pkey.callMethod(tc,"to_der"); - } else { - val = ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), pkey.callMethod(tc, "to_der")).callMethod(tc, "value") - .callMethod(tc, "[]", getRuntime().newFixnum(1)).callMethod(tc, "value"); - } - byte[] b = getSHA1Digest(getRuntime(), val.convertToString().getBytes()); - value = new String(ByteList.plain(new DEROctetString(b).getDEREncoded())); - } else if(valuex.length() == 20 || !isHexString(valuex)) { - value = new String(ByteList.plain(new DEROctetString(ByteList.plain(valuex)).getDEREncoded())); - } else { - StringBuffer nstr = new StringBuffer(); - for(int i = 0; i < valuex.length(); i+=2) { - if(i+1 >= valuex.length()) { - throw newX509ExtError(getRuntime(), oid + " = " + value + ": odd number of digits"); - } - - char c1 = valuex.charAt(i); - char c2 = valuex.charAt(i+1); - if(isHexDigit(c1) && isHexDigit(c2)) { - nstr.append(Character.toUpperCase(c1)).append(Character.toUpperCase(c2)); - } else { - throw newX509ExtError(getRuntime(), oid + " = " + value + ": illegal hex digit"); - } - while((i+2) < valuex.length() && valuex.charAt(i+2) == ':') { - i++; - } - } - String v = nstr.toString(); - byte[] arr = new byte[v.length()/2]; - for(int i=0;i 3 && spl[i].substring(0,3).equalsIgnoreCase("CA:")) { - asnv.add(new DERBoolean("TRUE".equalsIgnoreCase(spl[i].substring(3).trim()))); - } - } - for(int i=0;i 8 && spl[i].substring(0,8).equalsIgnoreCase("pathlen:")) { - asnv.add(new DERInteger(Integer.parseInt(spl[i].substring(8).trim()))); - } - } - value = new String(ByteList.plain(new DERSequence(asnv).getDEREncoded())); - } else if(r_oid.equals(new DERObjectIdentifier("2.5.29.15"))) { //keyUsage - byte[] inp = null; - try { - String[] exx = valuex.split(":"); - if(exx != null) { - inp = new byte[exx.length]; - for(int i=0;i-1; i--) { - if(inp[i] == 0) { - unused += 8; - } else { - byte a2 = inp[i]; - int x = 8; - while(a2 != 0) { - a2 <<= 1; - x--; - } - unused += x; - break; - } - } - - value = new String(ByteList.plain(new DERBitString(inp,unused).getDEREncoded())); - } else if(r_oid.equals(new DERObjectIdentifier("2.16.840.1.113730.1.1"))) { //nsCertType - byte v = 0; - if (valuex.length() < 3) { - byte[] inp = ByteList.plain(valuex); - v = inp[0]; - } else { - String[] spl = valuex.split(","); - for (int i = 0; i < spl.length; i++) { - spl[i] = spl[i].trim(); - } - for (int i = 0; i < spl.length; i++) { - if ("SSL Client".equals(spl[i]) || "client".equals(spl[i])) { - v |= (byte) 128; - } else if ("SSL Server".equals(spl[i]) || "server".equals(spl[i])) { - v |= (byte) 64; - } else if ("S/MIME".equals(spl[i]) || "email".equals(spl[i])) { - v |= (byte) 32; - } else if ("Object Signing".equals(spl[i]) || "objsign".equals(spl[i])) { - v |= (byte) 16; - } else if ("Unused".equals(spl[i]) || "reserved".equals(spl[i])) { - v |= (byte) 8; - } else if ("SSL CA".equals(spl[i]) || "sslCA".equals(spl[i])) { - v |= (byte) 4; - } else if ("S/MIME CA".equals(spl[i]) || "emailCA".equals(spl[i])) { - v |= (byte) 2; - } else if ("Object Signing CA".equals(spl[i]) || "objCA".equals(spl[i])) { - v |= (byte) 1; - } else { - throw newX509ExtError(getRuntime(), oid + " = " + valuex + ": unknown bit string argument"); - } - } - } - int unused = 0; - if (v == 0) { - unused += 8; - } else { - byte a2 = v; - int x = 8; - while (a2 != 0) { - a2 <<= 1; - x--; - } - unused += x; - } - value = new DERBitString(new byte[] { v }, unused); - } else if(r_oid.equals(new DERObjectIdentifier("2.5.29.17"))) { //subjectAltName - if(valuex.startsWith("DNS:")) { - value = new String(ByteList.plain(new GeneralNames(new GeneralName(GeneralName.dNSName,new DERIA5String(valuex.substring(4)))).getDEREncoded())); - } else if(valuex.startsWith("IP:")) { - String[] numbers = valuex.substring(3).split("\\."); - byte[] bs = new byte[4]; - bs[0] = (byte) (Integer.parseInt(numbers[0]) & 0xff); - bs[1] = (byte) (Integer.parseInt(numbers[1]) & 0xff); - bs[2] = (byte) (Integer.parseInt(numbers[2]) & 0xff); - bs[3] = (byte) (Integer.parseInt(numbers[3]) & 0xff); - value = new String(ByteList.plain(new GeneralNames(new GeneralName(GeneralName.iPAddress,new DEROctetString(bs))).getDEREncoded())); - } else if(valuex.startsWith("IP Address:")) { - String[] numbers = valuex.substring(11).split("\\."); - byte[] bs = new byte[4]; - bs[0] = (byte) (Integer.parseInt(numbers[0]) & 0xff); - bs[1] = (byte) (Integer.parseInt(numbers[1]) & 0xff); - bs[2] = (byte) (Integer.parseInt(numbers[2]) & 0xff); - bs[3] = (byte) (Integer.parseInt(numbers[3]) & 0xff); - value = new String(ByteList.plain(new GeneralNames(new GeneralName(GeneralName.iPAddress,new DEROctetString(bs))).getDEREncoded())); - } - } else if(r_oid.equals(new DERObjectIdentifier("2.5.29.37"))) { //extendedKeyUsage - String[] spl = valuex.split(", ?"); - ASN1EncodableVector vector = new ASN1EncodableVector(); - for(String name : spl) { - vector.add(ASN1Registry.sym2oid(name)); - } - value = new DERSequence(vector); - } else { - value = new DEROctetString(new DEROctetString(ByteList.plain(valuex)).getDEREncoded()); - } - - ext.setRealOid(r_oid); - ext.setRealValue(value); - ext.setRealCritical(critical.isTrue()); - - return ext; - } - } - - private static byte[] getSHA1Digest(Ruby runtime, byte[] bytes) { - try { - return MessageDigest.getInstance("SHA-1").digest(bytes); - } catch (GeneralSecurityException gse) { - throw newX509ExtError(runtime, gse.getMessage()); - } - } - - public static class Extension extends RubyObject { - private static final long serialVersionUID = -1160318458085651926L; - - public static ObjectAllocator ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new Extension(runtime, klass); - } - }; - - public Extension(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - private DERObjectIdentifier oid; - private Object value; - private boolean critical; - - void setRealOid(DERObjectIdentifier oid) { - this.oid = oid; - } - - void setRealValue(Object value) { - this.value = value; - } - - void setRealCritical(boolean critical) { - this.critical = critical; - } - - DERObjectIdentifier getRealOid() { - return oid; - } - - Object getRealValue() { - return value; - } - - byte[] getRealValueBytes() throws IOException { - if((value instanceof RubyString)) { - return ((RubyString) value).convertToString().getBytes(); - } else if(value instanceof String) { - return ByteList.plain((String) value); - } else if(value instanceof DEROctetString) { - return ((DEROctetString)value).getOctets(); - } else if(value instanceof DEREncodable) { - return ((ASN1Encodable)value).getEncoded(); - } else { - return ((ASN1.ASN1Data)value).toASN1().getDEREncoded(); - } - } - - boolean getRealCritical() { - return critical; - } - - DERObjectIdentifier getObjectIdentifier(String nameOrOid) { - Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase()); - if(null != val1) { - return (DERObjectIdentifier)val1; - } - DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid); - return val2; - } - - @JRubyMethod(name = "initialize", rest = true) - public IRubyObject _initialize(IRubyObject[] args) { - byte[] octets = null; - if (args.length == 1) { - try { - ASN1InputStream is = new ASN1InputStream(OpenSSLImpl.to_der_if_possible(args[0]).convertToString().getBytes()); - Object obj = is.readObject(); - ASN1Sequence seq = (ASN1Sequence) obj; - setRealOid((DERObjectIdentifier) (seq.getObjectAt(0))); - setRealCritical(((DERBoolean) (seq.getObjectAt(1))).isTrue()); - octets = ((DEROctetString) (seq.getObjectAt(2))).getOctets(); - } catch (IOException ioe) { - throw newX509ExtError(getRuntime(), ioe.getMessage()); - } - } else if (args.length > 1) { - setRealOid(getObjectIdentifier(args[0].toString())); - setRealValue(args[1]); - } - if (args.length > 2) { - setRealCritical(args[2].isTrue()); - } - if (args.length > 0 && octets != null) { - setRealValue(new String(ByteList.plain(octets))); - } - return this; - } - - @JRubyMethod(name="oid=") - public IRubyObject set_oid(IRubyObject arg) { - System.err.println("WARNING: calling ext#oid="); - return getRuntime().getNil(); - } - - @JRubyMethod(name="value=") - public IRubyObject set_value(IRubyObject arg) { - System.err.println("WARNING: calling ext#value="); - return getRuntime().getNil(); - } - - @JRubyMethod(name="critical=") - public IRubyObject set_critical(IRubyObject arg) { - System.err.println("WARNING: calling ext#critical="); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject oid() { - Object val = ASN1.getSymLookup(getRuntime()).get(oid); - if(null == val) { - val = oid.toString(); - } - return getRuntime().newString((String)(val)); - } - - @JRubyMethod - public IRubyObject value() { - Ruby runtime = getRuntime(); - try { - if (getRealOid().equals(new DERObjectIdentifier("2.5.29.19"))) { //basicConstraints - ASN1Sequence seq2 = (ASN1Sequence) (new ASN1InputStream(getRealValueBytes()).readObject()); - String c = ""; - String path = ""; - if (seq2.size() > 0) { - c = "CA:" + (((DERBoolean) (seq2.getObjectAt(0))).isTrue() ? "TRUE" : "FALSE"); - } - if (seq2.size() > 1) { - path = ", pathlen:" + seq2.getObjectAt(1).toString(); - } - return runtime.newString(c + path); - } else if (getRealOid().equals(new DERObjectIdentifier("2.5.29.15"))) { //keyUsage - byte[] bx = getRealValueBytes(); - byte[] bs = new byte[bx.length - 2]; - System.arraycopy(bx, 2, bs, 0, bs.length); - byte b1 = 0; - byte b2 = bs[0]; - if (bs.length > 1) { - b1 = bs[1]; - } - StringBuffer sbe = new StringBuffer(); - String sep = ""; - if ((b2 & (byte) 128) != 0) { - sbe.append(sep).append("Decipher Only"); - sep = ", "; - } - if ((b1 & (byte) 128) != 0) { - sbe.append(sep).append("Digital Signature"); - sep = ", "; - } - if ((b1 & (byte) 64) != 0) { - sbe.append(sep).append("Non Repudiation"); - sep = ", "; - } - if ((b1 & (byte) 32) != 0) { - sbe.append(sep).append("Key Encipherment"); - sep = ", "; - } - if ((b1 & (byte) 16) != 0) { - sbe.append(sep).append("Data Encipherment"); - sep = ", "; - } - if ((b1 & (byte) 8) != 0) { - sbe.append(sep).append("Key Agreement"); - sep = ", "; - } - if ((b1 & (byte) 4) != 0) { - sbe.append(sep).append("Key Cert Sign"); - sep = ", "; - } - if ((b1 & (byte) 2) != 0) { - sbe.append(sep).append("cRLSign"); - sep = ", "; - } - if ((b1 & (byte) 1) != 0) { - sbe.append(sep).append("Encipher Only"); - } - return runtime.newString(sbe.toString()); - } else if (getRealOid().equals(new DERObjectIdentifier("2.16.840.1.113730.1.1"))) { //nsCertType - byte[] bx = getRealValueBytes(); - byte b = bx[0]; - StringBuffer sbe = new StringBuffer(); - String sep = ""; - if ((b & (byte) 128) != 0) { - sbe.append(sep).append("SSL Client"); - sep = ", "; - } - if ((b & (byte) 64) != 0) { - sbe.append(sep).append("SSL Servern"); - sep = ", "; - } - if ((b & (byte) 32) != 0) { - sbe.append(sep).append("S/MIME"); - sep = ", "; - } - if ((b & (byte) 16) != 0) { - sbe.append(sep).append("Object Signing"); - sep = ", "; - } - if ((b & (byte) 8) != 0) { - sbe.append(sep).append("Unused"); - sep = ", "; - } - if ((b & (byte) 4) != 0) { - sbe.append(sep).append("SSL CA"); - sep = ", "; - } - if ((b & (byte) 2) != 0) { - sbe.append(sep).append("S/MIME CA"); - sep = ", "; - } - if ((b & (byte) 1) != 0) { - sbe.append(sep).append("Object Signing CA"); - } - return runtime.newString(sbe.toString()); - } else if (getRealOid().equals(new DERObjectIdentifier("2.5.29.14"))) { //subjectKeyIdentifier - byte[] b1 = getRealValueBytes(); - byte[] b2 = new byte[b1.length - 2]; - System.arraycopy(b1, 2, b2, 0, b2.length); - return runtime.newString(Utils.toHex(b2, ':')); - } else if (getRealOid().equals(new DERObjectIdentifier("2.5.29.35"))) { // authorityKeyIdentifier - DERSequence seq = (DERSequence) (new ASN1InputStream(getRealValueBytes()).readObject()); - StringBuffer out1 = new StringBuffer(); - if (seq.size() > 0) { - out1.append("keyid:"); - DERObject keyid = seq.getObjectAt(0).getDERObject(); - if (keyid instanceof DEROctetString) { - out1.append(Utils.toHex(((DEROctetString) keyid).getOctets(), ':')); - } else { - out1.append(Utils.toHex(keyid.getDEREncoded(), ':')); - } - } - return runtime.newString(out1.toString()); - } else if (getRealOid().equals(new DERObjectIdentifier("2.5.29.21"))) { // CRLReason - switch (RubyNumeric.fix2int(((IRubyObject) value).callMethod(runtime.getCurrentContext(), "value"))) { - case 0: - return runtime.newString("Unspecified"); - case 1: - return runtime.newString("Key Compromise"); - case 2: - return runtime.newString("CA Compromise"); - case 3: - return runtime.newString("Affiliation Changed"); - case 4: - return runtime.newString("Superseded"); - case 5: - return runtime.newString("Cessation Of Operation"); - case 6: - return runtime.newString("Certificate Hold"); - case 8: - return runtime.newString("Remove From CRL"); - case 9: - return runtime.newString("Privilege Withdrawn"); - default: - return runtime.newString("Unspecified"); - } - } else if (getRealOid().equals(new DERObjectIdentifier("2.5.29.17"))) { //subjectAltName - try { - DERObject seq = new ASN1InputStream(getRealValueBytes()).readObject(); - GeneralName[] n1 = null; - if (seq instanceof DERUnknownTag) { - n1 = new GeneralName[]{GeneralName.getInstance(seq)}; - } else if (seq instanceof org.bouncycastle.asn1.DERTaggedObject) { - n1 = new GeneralName[]{GeneralName.getInstance(seq)}; - } else { - n1 = GeneralNames.getInstance(seq).getNames(); - } - StringBuffer sbe = new StringBuffer(); - String sep = ""; - for (int i = 0; i < n1.length; i++) { - sbe.append(sep); - if (n1[i].getTagNo() == GeneralName.dNSName) { - sbe.append("DNS:"); - sbe.append(((DERString) n1[i].getName()).getString()); - } else if (n1[i].getTagNo() == GeneralName.iPAddress) { - sbe.append("IP Address:"); - byte[] bs = ((DEROctetString) n1[i].getName()).getOctets(); - String sep2 = ""; - for (int j = 0; j < bs.length; j++) { - sbe.append(sep2); - sbe.append(((int) bs[j]) & 0xff); - sep2 = "."; - } - } else { - sbe.append(n1[i].toString()); - } - sep = ", "; - } - return runtime.newString(sbe.toString()); - } catch (Exception e) { - return runtime.newString(getRealValue().toString()); - } - } else { - try { - return ASN1.decode(runtime.getClassFromPath("OpenSSL::ASN1"), RubyString.newString(runtime, getRealValueBytes())) - .callMethod(runtime.getCurrentContext(), "value").callMethod(runtime.getCurrentContext(), "to_s"); - } catch (Exception e) { - return runtime.newString(getRealValue().toString()); - } - } - } catch (IOException ioe) { - throw newX509ExtError(runtime, ioe.getMessage()); - } - } - - @JRubyMethod(name="critical?") - public IRubyObject critical_p() { - return critical ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @JRubyMethod - public IRubyObject to_der() { - ASN1EncodableVector all = new ASN1EncodableVector(); - try { - all.add(getRealOid()); - all.add(getRealCritical() ? DERBoolean.TRUE : DERBoolean.FALSE); - all.add(new DEROctetString(getRealValueBytes())); - return RubyString.newString(getRuntime(), new DERSequence(all).getDEREncoded()); - } catch (IOException ioe) { - throw newX509ExtError(getRuntime(), ioe.getMessage()); - } - } - } - - private static RaiseException newX509ExtError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::X509::ExtensionError", message); - } -}// X509Extensions diff --git a/src/java/org/jruby/ext/openssl/X509Name.java b/src/java/org/jruby/ext/openssl/X509Name.java deleted file mode 100644 index 058d845..0000000 --- a/src/java/org/jruby/ext/openssl/X509Name.java +++ /dev/null @@ -1,421 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Vector; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERString; -import org.bouncycastle.asn1.DERTags; -import org.bouncycastle.asn1.x509.X509DefaultEntryConverter; -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyFixnum; -import org.jruby.RubyHash; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyString; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.Name; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class X509Name extends RubyObject { - private static final long serialVersionUID = -226196051911335103L; - - private static ObjectAllocator X509NAME_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509Name(runtime, klass); - } - }; - - public static void createX509Name(Ruby runtime, RubyModule mX509) { - RubyClass cX509Name = mX509.defineClassUnder("Name",runtime.getObject(),X509NAME_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("NameError",openSSLError,openSSLError.getAllocator()); - - cX509Name.defineAnnotatedMethods(X509Name.class); - - cX509Name.setConstant("COMPAT",runtime.newFixnum(COMPAT)); - cX509Name.setConstant("RFC2253",runtime.newFixnum(RFC2253)); - cX509Name.setConstant("ONELINE",runtime.newFixnum(ONELINE)); - cX509Name.setConstant("MULTILINE",runtime.newFixnum(MULTILINE)); - - cX509Name.setConstant("DEFAULT_OBJECT_TYPE",runtime.newFixnum(DERTags.UTF8_STRING)); - - RubyHash hash = new RubyHash(runtime, runtime.newFixnum(DERTags.UTF8_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("C"),runtime.newFixnum(DERTags.PRINTABLE_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("countryName"),runtime.newFixnum(DERTags.PRINTABLE_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("serialNumber"),runtime.newFixnum(DERTags.PRINTABLE_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("dnQualifier"),runtime.newFixnum(DERTags.PRINTABLE_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("DC"),runtime.newFixnum(DERTags.IA5_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("domainComponent"),runtime.newFixnum(DERTags.IA5_STRING)); - hash.op_aset(runtime.getCurrentContext(), runtime.newString("emailAddress"),runtime.newFixnum(DERTags.IA5_STRING)); - cX509Name.setConstant("OBJECT_TYPE_TEMPLATE", hash); - } - - public static final int COMPAT = 0; - public static final int RFC2253 = 17892119; - public static final int ONELINE = 8520479; - public static final int MULTILINE = 44302342; - - public X509Name(Ruby runtime, RubyClass type) { - super(runtime,type); - oids = new ArrayList(); - values = new ArrayList(); - types = new ArrayList(); - } - - private List oids; - private List values; - private List types; - - void addEntry(Object oid, Object value, Object type) { - oids.add(oid); - values.add(value); - types.add(type); - } - - public static X509Name create(Ruby runtime, org.bouncycastle.asn1.x509.X509Name realName) { - X509Name name = new X509Name(runtime, Utils.getClassFromPath(runtime, "OpenSSL::X509::Name")); - name.fromASN1Sequence((ASN1Sequence)realName.getDERObject()); - return name; - } - - void fromASN1Sequence(ASN1Sequence seq) { - oids = new ArrayList(); - values = new ArrayList(); - types = new ArrayList(); - for (Enumeration enumRdn = seq.getObjects(); enumRdn.hasMoreElements();) { - ASN1Set rdn = (ASN1Set) enumRdn.nextElement(); - for (Enumeration enumTypeAndValue = rdn.getObjects(); enumTypeAndValue.hasMoreElements();) { - ASN1Sequence typeAndValue = (ASN1Sequence) enumTypeAndValue.nextElement(); - oids.add(typeAndValue.getObjectAt(0)); - if (typeAndValue.getObjectAt(1) instanceof DERString) { - values.add(((DERString) typeAndValue.getObjectAt(1)).getString()); - } else { - values.add(null); - } - types.add(getRuntime().newFixnum(ASN1.idForClass(typeAndValue.getObjectAt(1).getClass()))); - } - } - } - - @JRubyMethod(rest=true, frame=true) - public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,0,2) == 0) { - return this; - } - IRubyObject arg = args[0]; - IRubyObject template = getRuntime().getNil(); - if(args.length > 1) { - template = args[1]; - } - IRubyObject tmp = (arg instanceof RubyArray) ? arg : getRuntime().getNil(); - if(!tmp.isNil()) { - if(template.isNil()) { - template = getRuntime().getClassFromPath("OpenSSL::X509::Name").getConstant("OBJECT_TYPE_TEMPLATE"); - } - for (IRubyObject obj : ((RubyArray)tmp).toJavaArray()) { - RubyArray arr = (RubyArray) obj; - IRubyObject[] ele = arr.toJavaArray(); - IRubyObject[] entry = new IRubyObject[3]; - if (ele.length > 1) { - entry[0] = ele[0]; - entry[1] = ele[1]; - } - if (ele.length > 2) { - entry[2] = ele[2]; - } - if (entry[2] == null || entry[2].isNil()) { - entry[2] = template.callMethod(getRuntime().getCurrentContext(),"[]",entry[0]); - } - if (entry[2] == null || entry[2].isNil()) { - entry[2] = getRuntime().getClassFromPath("OpenSSL::X509::Name").getConstant("DEFAULT_OBJECT_TYPE"); - } - add_entry(entry); - } - } else { - try { - fromASN1Sequence((ASN1Sequence)new ASN1InputStream(OpenSSLImpl.to_der_if_possible(arg).convertToString().getBytes()).readObject()); - } catch(Exception e) { - System.err.println("exception in init for X509Name: " + e); - } - } - return this; - } - - /* - private void printASN(org.bouncycastle.asn1.DERObject obj) { - printASN(obj,0); - } - private void printASN(org.bouncycastle.asn1.DERObject obj, int indent) { - if(obj instanceof org.bouncycastle.asn1.ASN1Sequence) { - for(int i=0;i 2 && !args[2].isNil()) { - type = args[2]; - } - DERObjectIdentifier oid_v; - try { - oid_v = getObjectIdentifier(oid); - } catch (IllegalArgumentException e) { - throw newX509NameError(getRuntime(), "invalid field name: " + e.getMessage()); - } - if (null == oid_v) { - throw newX509NameError(getRuntime(), null); - } - oids.add(oid_v); - values.add(value); - types.add(type); - return this; - } - - @JRubyMethod(name="to_s", rest=true) - public IRubyObject _to_s(IRubyObject[] args) { - /* -Should follow parameters like this: -if 0 (COMPAT): -irb(main):025:0> x.to_s(OpenSSL::X509::Name::COMPAT) -=> "CN=ola.bini, O=sweden/streetAddress=sweden, O=sweden/2.5.4.43343=sweden" -irb(main):026:0> x.to_s(OpenSSL::X509::Name::ONELINE) -=> "CN = ola.bini, O = sweden, streetAddress = sweden, O = sweden, 2.5.4.43343 = sweden" -irb(main):027:0> x.to_s(OpenSSL::X509::Name::MULTILINE) -=> "commonName = ola.bini\norganizationName = sweden\nstreetAddress = sweden\norganizationName = sweden\n2.5.4.43343 = sweden" -irb(main):028:0> x.to_s(OpenSSL::X509::Name::RFC2253) -=> "2.5.4.43343=#0C0673776564656E,O=sweden,streetAddress=sweden,O=sweden,CN=ola.bini" -else -=> /CN=ola.bini/O=sweden/streetAddress=sweden/O=sweden/2.5.4.43343=sweden - - */ - - int flag = -1; - if(args.length > 0 && !args[0].isNil()) { - flag = RubyNumeric.fix2int(args[0]); - } - - StringBuffer sb = new StringBuffer(); - Map lookup = ASN1.getSymLookup(getRuntime()); - Iterator oiter = null; - Iterator viter = null; - if(flag == RFC2253) { - List ao = new ArrayList(oids); - List av = new ArrayList(values); - java.util.Collections.reverse(ao); - java.util.Collections.reverse(av); - oiter = ao.iterator(); - viter = av.iterator(); - } else { - oiter = oids.iterator(); - viter = values.iterator(); - } - - String sep = ""; - for(;oiter.hasNext();) { - DERObjectIdentifier oid = (DERObjectIdentifier)oiter.next(); - String val = (String)viter.next(); - String outOid = lookup.get(oid); - if(null == outOid) { - outOid = oid.toString(); - } - if(flag == RFC2253) { - sb.append(sep).append(outOid).append("=").append(val); - sep = ","; - } else { - sb.append("/").append(outOid).append("=").append(val); - } - } - return getRuntime().newString(sb.toString()); - } - - @Override - @JRubyMethod - public RubyArray to_a() { - List entries = new ArrayList(); - Map lookup = ASN1.getSymLookup(getRuntime()); - Iterator oiter = oids.iterator(); - Iterator viter = values.iterator(); - Iterator titer = types.iterator(); - for(;oiter.hasNext();) { - DERObjectIdentifier oid = (DERObjectIdentifier)oiter.next(); - String val = (String)viter.next(); - String outOid = lookup.get(oid); - if(null == outOid) { - outOid = "UNDEF"; - } - IRubyObject type = (IRubyObject)titer.next(); - entries.add(getRuntime().newArrayNoCopy(new IRubyObject[]{getRuntime().newString(outOid),getRuntime().newString(val),type})); - } - return getRuntime().newArray(entries); - } - - @JRubyMethod(name={"cmp","<=>"}) - public IRubyObject cmp(IRubyObject other) { - if(eql_p(other).isTrue()) { - return RubyFixnum.zero(getRuntime()); - } - // TODO: huh? - return RubyFixnum.one(getRuntime()); - } - - org.bouncycastle.asn1.x509.X509Name getRealName() { - return new org.bouncycastle.asn1.x509.X509Name(new Vector(oids),new Vector(values)); - } - - @Override - @JRubyMethod(name="eql?") - public IRubyObject eql_p(IRubyObject other) { - if(!(other instanceof X509Name)) { - return getRuntime().getFalse(); - } - X509Name o = (X509Name)other; - org.bouncycastle.asn1.x509.X509Name nm = new org.bouncycastle.asn1.x509.X509Name(new Vector(oids),new Vector(values)); - org.bouncycastle.asn1.x509.X509Name o_nm = new org.bouncycastle.asn1.x509.X509Name(new Vector(o.oids),new Vector(o.values)); - return nm.equals(o_nm) ? getRuntime().getTrue() : getRuntime().getFalse(); - } - - @Override - @JRubyMethod - public RubyFixnum hash() { - Name name = new Name(new org.bouncycastle.asn1.x509.X509Name(new Vector(oids),new Vector(values))); - return getRuntime().newFixnum(name.hash()); - } - - @JRubyMethod - public IRubyObject to_der() { - DERSequence seq = null; - if(oids.size()>0) { - ASN1EncodableVector vec = new ASN1EncodableVector(); - ASN1EncodableVector sVec = new ASN1EncodableVector(); - DERObjectIdentifier lstOid = null; - for (int i = 0; i != oids.size(); i++) { - ASN1EncodableVector v = new ASN1EncodableVector(); - DERObjectIdentifier oid = (DERObjectIdentifier)oids.get(i); - v.add(oid); - String str = (String)values.get(i); - v.add(convert(oid,str,RubyNumeric.fix2int(((RubyFixnum)types.get(i))))); - if (lstOid == null) { - sVec.add(new DERSequence(v)); - } else { - vec.add(new DERSet(sVec)); - sVec = new ASN1EncodableVector(); - sVec.add(new DERSequence(v)); - } - lstOid = oid; - } - vec.add(new DERSet(sVec)); - seq = new DERSequence(vec); - } else { - seq = new DERSequence(); - } - - return RubyString.newString(getRuntime(), seq.getDEREncoded()); - } - - private DERObject convert(DERObjectIdentifier oid, String value, int type) { - try { - Class clzz = ASN1.classForId(type); - if (clzz != null) { - java.lang.reflect.Constructor ctor = clzz.getConstructor(new Class[]{String.class}); - if (null != ctor) { - return (DERObject) ctor.newInstance(new Object[]{value}); - } - } - return new X509DefaultEntryConverter().getConvertedValue(oid, value); - } catch (Exception e) { - throw newX509NameError(getRuntime(), e.getMessage()); - } - } - - private static RaiseException newX509NameError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::X509::NameError", message); - } -}// X509Name diff --git a/src/java/org/jruby/ext/openssl/X509Revoked.java b/src/java/org/jruby/ext/openssl/X509Revoked.java deleted file mode 100644 index eb44222..0000000 --- a/src/java/org/jruby/ext/openssl/X509Revoked.java +++ /dev/null @@ -1,113 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyObject; -import org.jruby.anno.JRubyMethod; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class X509Revoked extends RubyObject { - private static final long serialVersionUID = 1L; - - private static ObjectAllocator X509REVOKED_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509Revoked(runtime, klass); - } - }; - - public static void createX509Revoked(Ruby runtime, RubyModule mX509) { - RubyClass cX509Rev = mX509.defineClassUnder("Revoked",runtime.getObject(),X509REVOKED_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("RevokedError",openSSLError,openSSLError.getAllocator()); - - cX509Rev.defineAnnotatedMethods(X509Revoked.class); - } - - private IRubyObject serial; - private IRubyObject extensions; - private IRubyObject time; - - public X509Revoked(Ruby runtime, RubyClass type) { - super(runtime,type); - } - - @JRubyMethod(name="initialize",rest=true,frame=true) - public IRubyObject _initialize(IRubyObject[] args, Block unusedBlock) { - serial = getRuntime().getNil(); - time = getRuntime().getNil(); - extensions = getRuntime().newArray(); - return this; - } - - @JRubyMethod - public IRubyObject serial() { - return this.serial; - } - - @JRubyMethod(name="serial=") - public IRubyObject set_serial(IRubyObject val) { - this.serial = val; - return val; - } - - @JRubyMethod - public IRubyObject time() { - return this.time; - } - - @JRubyMethod(name="time=") - public IRubyObject set_time(IRubyObject val) { - this.time = val; - return val; - } - - @JRubyMethod - public IRubyObject extensions() { - return this.extensions; - } - - @JRubyMethod(name="extensions=") - public IRubyObject set_extensions(IRubyObject val) { - this.extensions = val; - return val; - } - - @JRubyMethod - public IRubyObject add_extension(IRubyObject val) { - this.extensions.callMethod(getRuntime().getCurrentContext(),"<<",val); - return val; - } -}// X509Revoked diff --git a/src/java/org/jruby/ext/openssl/X509Store.java b/src/java/org/jruby/ext/openssl/X509Store.java deleted file mode 100644 index cee58cc..0000000 --- a/src/java/org/jruby/ext/openssl/X509Store.java +++ /dev/null @@ -1,240 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import org.jruby.Ruby; -import org.jruby.RubyBoolean; -import org.jruby.RubyClass; -import org.jruby.RubyFixnum; -import org.jruby.RubyHash; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.ext.openssl.x509store.Store; -import org.jruby.ext.openssl.x509store.StoreContext; -import org.jruby.ext.openssl.x509store.X509Utils; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class X509Store extends RubyObject { - private static final long serialVersionUID = 7987156710610206194L; - - private static ObjectAllocator X509STORE_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509Store(runtime, klass); - } - }; - - public static void createX509Store(Ruby runtime, RubyModule mX509) { - RubyClass cX509Store = mX509.defineClassUnder("Store",runtime.getObject(),X509STORE_ALLOCATOR); - RubyClass openSSLError = runtime.getModule("OpenSSL").getClass("OpenSSLError"); - mX509.defineClassUnder("StoreError",openSSLError,openSSLError.getAllocator()); - cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "verify_callback"); - cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "error"); - cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "error_string"); - cX509Store.addReadWriteAttribute(runtime.getCurrentContext(), "chain"); - cX509Store.defineAnnotatedMethods(X509Store.class); - - X509StoreCtx.createX509StoreCtx(runtime, mX509); - } - - private RubyClass cStoreError; - private RubyClass cStoreContext; - - public X509Store(Ruby runtime, RubyClass type) { - super(runtime,type); - store = new Store(); - cStoreError = Utils.getClassFromPath(runtime, "OpenSSL::X509::StoreError"); - cStoreContext = Utils.getClassFromPath(runtime, "OpenSSL::X509::StoreContext"); - } - - private Store store; - - Store getStore() { - return store; - } - - private void raise(String msg) { - throw new RaiseException(getRuntime(),cStoreError, msg, true); - } - - @JRubyMethod(name="initialize", rest=true, frame=true) - public IRubyObject _initialize(IRubyObject[] args, Block block) { - store.setVerifyCallbackFunction(ossl_verify_cb); - this.set_verify_callback(getRuntime().getNil()); - this.setInstanceVariable("@flags",RubyFixnum.zero(getRuntime())); - this.setInstanceVariable("@purpose",RubyFixnum.zero(getRuntime())); - this.setInstanceVariable("@trust",RubyFixnum.zero(getRuntime())); - - this.setInstanceVariable("@error",getRuntime().getNil()); - this.setInstanceVariable("@error_string",getRuntime().getNil()); - this.setInstanceVariable("@chain",getRuntime().getNil()); - this.setInstanceVariable("@time",getRuntime().getNil()); - return this; - } - - @JRubyMethod(name="verify_callback=") - public IRubyObject set_verify_callback(IRubyObject cb) { - store.setExtraData(1, cb); - this.setInstanceVariable("@verify_callback", cb); - return cb; - } - - @JRubyMethod(name="flags=") - public IRubyObject set_flags(IRubyObject arg) { - store.setFlags(RubyNumeric.fix2long(arg)); - return arg; - } - - @JRubyMethod(name="purpose=") - public IRubyObject set_purpose(IRubyObject arg) { - store.setPurpose(RubyNumeric.fix2int(arg)); - return arg; - } - - @JRubyMethod(name="trust=") - public IRubyObject set_trust(IRubyObject arg) { - store.setTrust(RubyNumeric.fix2int(arg)); - return arg; - } - - @JRubyMethod(name="time=") - public IRubyObject set_time(IRubyObject arg) { - setInstanceVariable("@time",arg); - return arg; - } - - @JRubyMethod - public IRubyObject add_path(IRubyObject arg) { - getRuntime().getWarnings().warn("unimplemented method called: Store#add_path"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject add_file(IRubyObject arg) { - String file = arg.toString(); - try { - store.loadLocations(file, null); - } catch (Exception e) { - raise("loading file failed: " + e.getMessage()); - } - return this; - } - - @JRubyMethod - public IRubyObject set_default_paths() { - try { - store.setDefaultPaths(); - } - catch(Exception e) { - raise("setting default path failed: " + e.getMessage()); - } - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject add_cert(IRubyObject _cert) { - X509AuxCertificate cert = (_cert instanceof X509Cert) ? ((X509Cert)_cert).getAuxCert() : (X509AuxCertificate)null; - if(store.addCertificate(cert) != 1) { - raise(null); - } - return this; - } - - @JRubyMethod - public IRubyObject add_crl(IRubyObject arg) { - java.security.cert.X509CRL crl = (arg instanceof X509CRL) ? ((X509CRL)arg).getCRL() : null; - if(store.addCRL(crl) != 1) { - raise(null); - } - return this; - } - - @JRubyMethod(rest=true, frame=true) - public IRubyObject verify(IRubyObject[] args, Block block) { - IRubyObject cert, chain; - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,1,2) == 2) { - chain = args[1]; - } else { - chain = getRuntime().getNil(); - } - cert = args[0]; - IRubyObject proc, result; - X509StoreCtx ctx = (X509StoreCtx)cStoreContext.callMethod(getRuntime().getCurrentContext(),"new",new IRubyObject[]{this,cert,chain}); - if (block.isGiven()) { - proc = getRuntime().newProc(Block.Type.PROC, block); - } else { - proc = getInstanceVariable("@verify_callback"); - } - ctx.setInstanceVariable("@verify_callback",proc); - result = ctx.callMethod(getRuntime().getCurrentContext(),"verify"); - this.setInstanceVariable("@error",ctx.error()); - this.setInstanceVariable("@error_string",ctx.error_string()); - this.setInstanceVariable("@chain",ctx.chain()); - return result; - } - - public final static Store.VerifyCallbackFunction ossl_verify_cb = new Store.VerifyCallbackFunction() { - - public int call(Object a1, Object a2) throws Exception { - StoreContext ctx = (StoreContext) a2; - int ok = ((Integer) a1).intValue(); - IRubyObject proc = (IRubyObject) ctx.getExtraData(1); - if (null == proc) { - proc = (IRubyObject) ctx.ctx.getExtraData(0); - } - if (null == proc) { - return ok; - } - if (!proc.isNil()) { - Ruby rt = proc.getRuntime(); - RubyClass cStoreContext = Utils.getClassFromPath(rt, "OpenSSL::X509::StoreContext"); - X509StoreCtx rctx = new X509StoreCtx(rt, cStoreContext, ctx); - RubyBoolean rok = rt.newBoolean(ok != 0); - IRubyObject ret = proc.callMethod(rt.getCurrentContext(), "call", new IRubyObject[]{rok, rctx}); - if (ret.isTrue()) { - ctx.setError(X509Utils.V_OK); - ok = 1; - } else { - if (ctx.getError() == X509Utils.V_OK) { - ctx.setError(X509Utils.V_ERR_CERT_REJECTED); - } - ok = 0; - } - } - return ok; - } - }; -}// X509Store diff --git a/src/java/org/jruby/ext/openssl/X509StoreCtx.java b/src/java/org/jruby/ext/openssl/X509StoreCtx.java deleted file mode 100644 index e84e786..0000000 --- a/src/java/org/jruby/ext/openssl/X509StoreCtx.java +++ /dev/null @@ -1,228 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006, 2007 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl; - -import java.security.cert.CertificateEncodingException; -import java.util.ArrayList; -import java.util.List; - -import org.jruby.Ruby; -import org.jruby.RubyArray; -import org.jruby.RubyClass; -import org.jruby.RubyModule; -import org.jruby.RubyNumeric; -import org.jruby.RubyObject; -import org.jruby.RubyObjectAdapter; -import org.jruby.RubyString; -import org.jruby.RubyTime; -import org.jruby.anno.JRubyMethod; -import org.jruby.exceptions.RaiseException; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.ext.openssl.x509store.Store; -import org.jruby.ext.openssl.x509store.StoreContext; -import org.jruby.javasupport.JavaEmbedUtils; -import org.jruby.runtime.Block; -import org.jruby.runtime.ObjectAllocator; -import org.jruby.runtime.builtin.IRubyObject; - -/** - * @author Ola Bini - */ -public class X509StoreCtx extends RubyObject { - private static final long serialVersionUID = 2029690161026120504L; - - private static ObjectAllocator X509STORECTX_ALLOCATOR = new ObjectAllocator() { - public IRubyObject allocate(Ruby runtime, RubyClass klass) { - return new X509StoreCtx(runtime, klass); - } - }; - - private static RubyObjectAdapter api = JavaEmbedUtils.newObjectAdapter(); - - public static void createX509StoreCtx(Ruby runtime, RubyModule mX509) { - RubyClass cX509StoreContext = mX509.defineClassUnder("StoreContext",runtime.getObject(),X509STORECTX_ALLOCATOR); - cX509StoreContext.defineAnnotatedMethods(X509StoreCtx.class); - } - - private StoreContext ctx; - private RubyClass cX509Cert; - - public X509StoreCtx(Ruby runtime, RubyClass type) { - super(runtime, type); - ctx = new StoreContext(); - cX509Cert = Utils.getClassFromPath(runtime, "OpenSSL::X509::Certificate"); - } - - // constructor for creating callback parameter object of verify_cb - X509StoreCtx(Ruby runtime, RubyClass type, StoreContext ctx) { - super(runtime, type); - this.ctx = ctx; - cX509Cert = Utils.getClassFromPath(runtime, "OpenSSL::X509::Certificate"); - } - - @JRubyMethod(name="initialize", rest=true, frame=true) - public IRubyObject _initialize(IRubyObject[] args, Block block) { - IRubyObject store; - IRubyObject cert = getRuntime().getNil(); - IRubyObject chain = getRuntime().getNil(); - Store x509st; - X509AuxCertificate x509 = null; - List x509s = new ArrayList(); - - if(org.jruby.runtime.Arity.checkArgumentCount(getRuntime(),args,1,3) > 1) { - cert = args[1]; - } - if(args.length > 2) { - chain = args[2]; - } - store = args[0]; - x509st = ((X509Store)store).getStore(); - if(!cert.isNil()) { - x509 = ((X509Cert)cert).getAuxCert(); - } - if(!chain.isNil()) { - x509s = new ArrayList(); - for (IRubyObject obj : ((RubyArray)chain).toJavaArray()) { - x509s.add(((X509Cert)obj).getAuxCert()); - } - } - if(ctx.init(x509st,x509,x509s) != 1) { - throw newStoreError(getRuntime(), null); - } - IRubyObject t = api.getInstanceVariable(store,"@time"); - if(!t.isNil()) { - set_time(t); - } - api.setInstanceVariable(this, "@verify_callback", api.getInstanceVariable(store, "@verify_callback")); - api.setInstanceVariable(this, "@cert", cert); - return this; - } - - @JRubyMethod - public IRubyObject verify() { - ctx.setExtraData(1, getInstanceVariable("@verify_callback")); - try { - int result = ctx.verifyCertificate(); - return result != 0 ? getRuntime().getTrue() : getRuntime().getFalse(); - } catch (Exception e) { - // TODO: define suitable exception for jopenssl and catch it. - throw newStoreError(getRuntime(), e.getMessage()); - } - } - - @JRubyMethod - public IRubyObject chain() { - List chain = ctx.getChain(); - if (chain == null) { - return getRuntime().getNil(); - } - List ary = new ArrayList(); - try { - for (X509AuxCertificate x509 : chain) { - ary.add(cX509Cert.callMethod(getRuntime().getCurrentContext(), "new", RubyString.newString(getRuntime(), x509.getEncoded()))); - } - } catch (CertificateEncodingException cee) { - throw newStoreError(getRuntime(), cee.getMessage()); - } - return getRuntime().newArray(ary); - } - - @JRubyMethod - public IRubyObject error() { - return getRuntime().newFixnum(ctx.getError()); - } - - @JRubyMethod(name="error=") - public IRubyObject set_error(IRubyObject arg) { - ctx.setError(RubyNumeric.fix2int(arg)); - return arg; - } - - @JRubyMethod - public IRubyObject error_string() { - int err = ctx.getError(); - return getRuntime().newString(org.jruby.ext.openssl.x509store.X509Utils.verifyCertificateErrorString(err)); - } - - @JRubyMethod - public IRubyObject error_depth() { - System.err.println("WARNING: unimplemented method called: StoreContext#error_depth"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject current_cert() { - Ruby rt = getRuntime(); - X509AuxCertificate x509 = ctx.getCurrentCertificate(); - try { - return cX509Cert.callMethod(rt.getCurrentContext(), "new", RubyString.newString(rt, x509.getEncoded())); - } catch (CertificateEncodingException cee) { - throw newStoreError(getRuntime(), cee.getMessage()); - } - } - - @JRubyMethod - public IRubyObject current_crl() { - System.err.println("WARNING: unimplemented method called: StoreContext#current_crl"); - return getRuntime().getNil(); - } - - @JRubyMethod - public IRubyObject cleanup() { - System.err.println("WARNING: unimplemented method called: StoreContext#cleanup"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="flags=") - public IRubyObject set_flags(IRubyObject arg) { - System.err.println("WARNING: unimplemented method called: StoreContext#set_flags"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="purpose=") - public IRubyObject set_purpose(IRubyObject arg) { - System.err.println("WARNING: unimplemented method called: StoreContext#set_purpose"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="trust=") - public IRubyObject set_trust(IRubyObject arg) { - System.err.println("WARNING: unimplemented method called: StoreContext#set_trust"); - return getRuntime().getNil(); - } - - @JRubyMethod(name="time=") - public IRubyObject set_time(IRubyObject arg) { - ctx.setTime(0,((RubyTime)arg).getJavaDate()); - return arg; - } - - private static RaiseException newStoreError(Ruby runtime, String message) { - return Utils.newError(runtime, "OpenSSL::X509::StoreError", message); - } -}// X509StoreCtx diff --git a/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java b/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java deleted file mode 100644 index 95e4485..0000000 --- a/src/java/org/jruby/ext/openssl/impl/ASN1Registry.java +++ /dev/null @@ -1,5152 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.util.HashMap; -import java.util.Map; -import org.bouncycastle.asn1.DERObjectIdentifier; - -/** - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class ASN1Registry { - @SuppressWarnings("unchecked") - private static Map SYM_TO_OID = new HashMap(org.bouncycastle.asn1.x509.X509Name.DefaultLookUp); - @SuppressWarnings("unchecked") - private static Map OID_TO_SYM = new HashMap(org.bouncycastle.asn1.x509.X509Name.DefaultSymbols); - private static Map OID_TO_NID = new HashMap(); - private static Map NID_TO_OID = new HashMap(); - private static Map NID_TO_SN = new HashMap(); - private static Map NID_TO_LN = new HashMap(); - - public static Integer obj2nid(String oid) { - return obj2nid(new DERObjectIdentifier(oid)); - } - - public static String ln2oid(String ln) { - return SYM_TO_OID.get(ln.toLowerCase()).getId(); - } - - public static Integer obj2nid(DERObjectIdentifier oid) { - return OID_TO_NID.get(oid); - } - - public static String o2a(String oid) { - return o2a(new DERObjectIdentifier(oid)); - } - - public static String o2a(DERObjectIdentifier obj) { - Integer nid = obj2nid(obj); - String one = NID_TO_LN.get(nid); - if(one == null) { - one = NID_TO_SN.get(nid); - } - return one; - } - - public static DERObjectIdentifier sym2oid(String name) { - return SYM_TO_OID.get(name.toLowerCase()); - } - - public static int sym2nid(String name) { - return OID_TO_NID.get(SYM_TO_OID.get(name.toLowerCase())); - } - - public static String nid2ln(int nid) { - return nid2ln(Integer.valueOf(nid)); - } - - public static DERObjectIdentifier nid2obj(int nid) { - return NID_TO_OID.get(nid); - } - - public static String nid2ln(Integer nid) { - return NID_TO_LN.get(nid); - } - - static void addObject(int nid, String sn, String ln, String oid) { - if(null != oid && oid.length() > 2 && (null != sn || null != ln)) { - DERObjectIdentifier ident = new DERObjectIdentifier(oid); - if(sn != null) { - SYM_TO_OID.put(sn.toLowerCase(),ident); - } - if(ln != null) { - SYM_TO_OID.put(ln.toLowerCase(),ident); - } - OID_TO_SYM.put(ident,sn == null ? ln : sn); - OID_TO_NID.put(ident,nid); - NID_TO_OID.put(nid,ident); - NID_TO_SN.put(nid,sn); - NID_TO_LN.put(nid,ln); - } - } - - - public final static int NID_id_pkix = 127; - public final static String SN_id_pkix = "PKIX"; - public final static String OBJ_id_pkix = "1.3.6.1.5.5.7"; - - public final static int NID_id_ad = 176; - public final static String SN_id_ad = "id-ad"; - public final static String OBJ_id_ad = OBJ_id_pkix + ".48"; - - public final static int NID_ad_OCSP = 178; - public final static String SN_ad_OCSP = "OCSP"; - public final static String LN_ad_OCSP = "OCSP"; - public final static String OBJ_ad_OCSP = OBJ_id_ad + ".1"; - - public final static String OBJ_id_pkix_OCSP = OBJ_ad_OCSP; - - public final static int NID_iso = 181; - public final static String SN_iso = "ISO"; - public final static String LN_iso = "iso"; - public final static String OBJ_iso = "1"; - - public final static int NID_org = 379; - public final static String SN_org = "ORG"; - public final static String LN_org = "org"; - public final static String OBJ_org = OBJ_iso + ".3"; - - public final static int NID_dod = 380; - public final static String SN_dod = "DOD"; - public final static String LN_dod = "dod"; - public final static String OBJ_dod = OBJ_org + ".6"; - - public final static int NID_iana = 381; - public final static String SN_iana = "IANA"; - public final static String LN_iana = "iana"; - public final static String OBJ_iana = OBJ_dod + ".1"; - - public final static String OBJ_internet = OBJ_iana; - - public final static String OBJ_csor = "2.16.840.1.101.3"; - - public final static int NID_member_body = 182; - public final static String SN_member_body = "member-body"; - public final static String LN_member_body = "ISO Member Body"; - public final static String OBJ_member_body = OBJ_iso + ".2"; - - public final static int NID_ISO_US = 183; - public final static String SN_ISO_US = "ISO-US"; - public final static String LN_ISO_US = "ISO US Member Body"; - public final static String OBJ_ISO_US = OBJ_member_body + ".840"; - - public final static int NID_rsadsi = 1; - public final static String SN_rsadsi = "rsadsi"; - public final static String LN_rsadsi = "RSA Data Security, Inc."; - public final static String OBJ_rsadsi = OBJ_ISO_US + ".113549"; - - public final static int NID_pkcs = 2; - public final static String SN_pkcs = "pkcs"; - public final static String LN_pkcs = "RSA Data Security, Inc. PKCS"; - public final static String OBJ_pkcs = OBJ_rsadsi + ".1"; - - public final static String OBJ_pkcs12 = OBJ_pkcs + ".12"; - - public final static int NID_X9_57 = 184; - public final static String SN_X9_57 = "X9-57"; - public final static String LN_X9_57 = "X9.57"; - public final static String OBJ_X9_57 = OBJ_ISO_US + ".10040"; - - public final static int NID_ansi_X9_62 = 405; - public final static String SN_ansi_X9_62 = "ansi-X9-62"; - public final static String LN_ansi_X9_62 = "ANSI X9.62"; - public final static String OBJ_ansi_X9_62 = OBJ_ISO_US + ".10045"; - - public final static String OBJ_holdInstruction = OBJ_X9_57 + ".2"; - - public final static String OBJ_X9_62_id_fieldType = OBJ_ansi_X9_62 + ".1"; - - public final static String OBJ_X9_62_ellipticCurve = OBJ_ansi_X9_62 + ".3"; - - public final static String OBJ_X9_62_id_publicKeyType = OBJ_ansi_X9_62 + ".2"; - - public final static String OBJ_X9_62_id_ecSigType = OBJ_ansi_X9_62 + ".4"; - - public final static String OBJ_X9_62_primeCurve = OBJ_X9_62_ellipticCurve + ".1"; - - public final static String OBJ_X9_62_c_TwoCurve = OBJ_X9_62_ellipticCurve + ".0"; - - public final static String OBJ_nistAlgorithms = OBJ_csor + ".4"; - - public final static int NID_joint_iso_itu_t = 646; - public final static String SN_joint_iso_itu_t = "JOINT-ISO-ITU-T"; - public final static String LN_joint_iso_itu_t = "joint-iso-itu-t"; - public final static String OBJ_joint_iso_itu_t = "2"; - - public final static int NID_international_organizations = 647; - public final static String SN_international_organizations = "international-organizations"; - public final static String LN_international_organizations = "International Organizations"; - public final static String OBJ_international_organizations = OBJ_joint_iso_itu_t + ".23"; - - public final static int NID_wap = 678; - public final static String SN_wap = "wap"; - public final static String OBJ_wap = OBJ_international_organizations + ".43"; - - public final static int NID_wap_wsg = 679; - public final static String SN_wap_wsg = "wap-wsg"; - public final static String OBJ_wap_wsg = OBJ_wap + ".13"; - - public final static String OBJ_wap_wsg_idm_ecid = OBJ_wap_wsg + ".4"; - - public final static String OBJ_nist_hashalgs = OBJ_nistAlgorithms + ".2"; - - public final static String OBJ_pkcs12_Version1 = OBJ_pkcs12 + ".10"; - - public final static int NID_pkcs9 = 47; - public final static String SN_pkcs9 = "pkcs9"; - public final static String OBJ_pkcs9 = OBJ_pkcs + ".9"; - - public final static String OBJ_certTypes = OBJ_pkcs9 + ".22"; - - public final static String OBJ_crlTypes = OBJ_pkcs9 + ".23"; - - public final static int NID_identified_organization = 676; - public final static String SN_identified_organization = "identified-organization"; - public final static String OBJ_identified_organization = OBJ_iso + ".3"; - - public final static int NID_certicom_arc = 677; - public final static String SN_certicom_arc = "certicom-arc"; - public final static String OBJ_certicom_arc = OBJ_identified_organization + ".132"; - - public final static String OBJ_secg_ellipticCurve = OBJ_certicom_arc + ".0"; - - public final static String OBJ_aes = OBJ_nistAlgorithms + ".1"; - - public final static String OBJ_pkcs12_BagIds = OBJ_pkcs12_Version1 + ".1"; - - public final static String OBJ_dsa_with_sha2 = OBJ_nistAlgorithms + ".3"; - - public final static int NID_undef = 0; - public final static String SN_undef = "UNDEF"; - public final static String LN_undef = "undefined"; - public final static String OBJ_undef = "0"; - - public final static int NID_md2 = 3; - public final static String SN_md2 = "MD2"; - public final static String LN_md2 = "md2"; - public final static String OBJ_md2 = OBJ_rsadsi + ".2.2"; - - public final static int NID_md5 = 4; - public final static String SN_md5 = "MD5"; - public final static String LN_md5 = "md5"; - public final static String OBJ_md5 = OBJ_rsadsi + ".2.5"; - - public final static int NID_rc4 = 5; - public final static String SN_rc4 = "RC4"; - public final static String LN_rc4 = "rc4"; - public final static String OBJ_rc4 = OBJ_rsadsi + ".3.4"; - - public final static int NID_pkcs1 = 186; - public final static String SN_pkcs1 = "pkcs1"; - public final static String OBJ_pkcs1 = OBJ_pkcs + ".1"; - - public final static int NID_rsaEncryption = 6; - public final static String LN_rsaEncryption = "rsaEncryption"; - public final static String OBJ_rsaEncryption = OBJ_pkcs1 + ".1"; - - public final static int NID_md2WithRSAEncryption = 7; - public final static String SN_md2WithRSAEncryption = "RSA-MD2"; - public final static String LN_md2WithRSAEncryption = "md2WithRSAEncryption"; - public final static String OBJ_md2WithRSAEncryption = OBJ_pkcs1 + ".2"; - - public final static int NID_md5WithRSAEncryption = 8; - public final static String SN_md5WithRSAEncryption = "RSA-MD5"; - public final static String LN_md5WithRSAEncryption = "md5WithRSAEncryption"; - public final static String OBJ_md5WithRSAEncryption = OBJ_pkcs1 + ".4"; - - public final static int NID_pkcs5 = 187; - public final static String SN_pkcs5 = "pkcs5"; - public final static String OBJ_pkcs5 = OBJ_pkcs + ".5"; - - public final static int NID_pbeWithMD2AndDES_CBC = 9; - public final static String SN_pbeWithMD2AndDES_CBC = "PBE-MD2-DES"; - public final static String LN_pbeWithMD2AndDES_CBC = "pbeWithMD2AndDES-CBC"; - public final static String OBJ_pbeWithMD2AndDES_CBC = OBJ_pkcs5 + ".1"; - - public final static int NID_pbeWithMD5AndDES_CBC = 10; - public final static String SN_pbeWithMD5AndDES_CBC = "PBE-MD5-DES"; - public final static String LN_pbeWithMD5AndDES_CBC = "pbeWithMD5AndDES-CBC"; - public final static String OBJ_pbeWithMD5AndDES_CBC = OBJ_pkcs5 + ".3"; - - public final static int NID_X500 = 11; - public final static String SN_X500 = "X500"; - public final static String LN_X500 = "directory services (X.500)"; - public final static String OBJ_X500 = "2.5"; - - public final static int NID_X509 = 12; - public final static String SN_X509 = "X509"; - public final static String OBJ_X509 = OBJ_X500 + ".4"; - - public final static int NID_commonName = 13; - public final static String SN_commonName = "CN"; - public final static String LN_commonName = "commonName"; - public final static String OBJ_commonName = OBJ_X509 + ".3"; - - public final static int NID_countryName = 14; - public final static String SN_countryName = "C"; - public final static String LN_countryName = "countryName"; - public final static String OBJ_countryName = OBJ_X509 + ".6"; - - public final static int NID_localityName = 15; - public final static String SN_localityName = "L"; - public final static String LN_localityName = "localityName"; - public final static String OBJ_localityName = OBJ_X509 + ".7"; - - public final static int NID_stateOrProvinceName = 16; - public final static String SN_stateOrProvinceName = "ST"; - public final static String LN_stateOrProvinceName = "stateOrProvinceName"; - public final static String OBJ_stateOrProvinceName = OBJ_X509 + ".8"; - - public final static int NID_organizationName = 17; - public final static String SN_organizationName = "O"; - public final static String LN_organizationName = "organizationName"; - public final static String OBJ_organizationName = OBJ_X509 + ".10"; - - public final static int NID_organizationalUnitName = 18; - public final static String SN_organizationalUnitName = "OU"; - public final static String LN_organizationalUnitName = "organizationalUnitName"; - public final static String OBJ_organizationalUnitName = OBJ_X509 + ".11"; - - public final static int NID_X500algorithms = 378; - public final static String SN_X500algorithms = "X500algorithms"; - public final static String LN_X500algorithms = "directory services - algorithms"; - public final static String OBJ_X500algorithms = OBJ_X500 + ".8"; - - public final static int NID_rsa = 19; - public final static String SN_rsa = "RSA"; - public final static String LN_rsa = "rsa"; - public final static String OBJ_rsa = OBJ_X500algorithms + ".1.1"; - - public final static int NID_pkcs7 = 20; - public final static String SN_pkcs7 = "pkcs7"; - public final static String OBJ_pkcs7 = OBJ_pkcs + ".7"; - - public final static int NID_pkcs7_data = 21; - public final static String LN_pkcs7_data = "pkcs7-data"; - public final static String OBJ_pkcs7_data = OBJ_pkcs7 + ".1"; - - public final static int NID_pkcs7_signed = 22; - public final static String LN_pkcs7_signed = "pkcs7-signedData"; - public final static String OBJ_pkcs7_signed = OBJ_pkcs7 + ".2"; - - public final static int NID_pkcs7_enveloped = 23; - public final static String LN_pkcs7_enveloped = "pkcs7-envelopedData"; - public final static String OBJ_pkcs7_enveloped = OBJ_pkcs7 + ".3"; - - public final static int NID_pkcs7_signedAndEnveloped = 24; - public final static String LN_pkcs7_signedAndEnveloped = "pkcs7-signedAndEnvelopedData"; - public final static String OBJ_pkcs7_signedAndEnveloped = OBJ_pkcs7 + ".4"; - - public final static int NID_pkcs7_digest = 25; - public final static String LN_pkcs7_digest = "pkcs7-digestData"; - public final static String OBJ_pkcs7_digest = OBJ_pkcs7 + ".5"; - - public final static int NID_pkcs7_encrypted = 26; - public final static String LN_pkcs7_encrypted = "pkcs7-encryptedData"; - public final static String OBJ_pkcs7_encrypted = OBJ_pkcs7 + ".6"; - - public final static int NID_pkcs3 = 27; - public final static String SN_pkcs3 = "pkcs3"; - public final static String OBJ_pkcs3 = OBJ_pkcs + ".3"; - - public final static int NID_dhKeyAgreement = 28; - public final static String LN_dhKeyAgreement = "dhKeyAgreement"; - public final static String OBJ_dhKeyAgreement = OBJ_pkcs3 + ".1"; - - public final static int NID_algorithm = 376; - public final static String SN_algorithm = "algorithm"; - public final static String LN_algorithm = "algorithm"; - public final static String OBJ_algorithm = "1.3.14.3.2"; - - public final static int NID_des_ecb = 29; - public final static String SN_des_ecb = "DES-ECB"; - public final static String LN_des_ecb = "des-ecb"; - public final static String OBJ_des_ecb = OBJ_algorithm + ".6"; - - public final static int NID_des_cfb64 = 30; - public final static String SN_des_cfb64 = "DES-CFB"; - public final static String LN_des_cfb64 = "des-cfb"; - public final static String OBJ_des_cfb64 = OBJ_algorithm + ".9"; - - public final static int NID_des_cbc = 31; - public final static String SN_des_cbc = "DES-CBC"; - public final static String LN_des_cbc = "des-cbc"; - public final static String OBJ_des_cbc = OBJ_algorithm + ".7"; - - public final static int NID_des_ede_ecb = 32; - public final static String SN_des_ede_ecb = "DES-EDE"; - public final static String LN_des_ede_ecb = "des-ede"; - public final static String OBJ_des_ede_ecb = OBJ_algorithm + ".17"; - - public final static int NID_des_ede3_ecb = 33; - public final static String SN_des_ede3_ecb = "DES-EDE3"; - public final static String LN_des_ede3_ecb = "des-ede3"; - - public final static int NID_idea_cbc = 34; - public final static String SN_idea_cbc = "IDEA-CBC"; - public final static String LN_idea_cbc = "idea-cbc"; - public final static String OBJ_idea_cbc = "1.3.6.1.4.1.188.7.1.1.2"; - - public final static int NID_idea_cfb64 = 35; - public final static String SN_idea_cfb64 = "IDEA-CFB"; - public final static String LN_idea_cfb64 = "idea-cfb"; - - public final static int NID_idea_ecb = 36; - public final static String SN_idea_ecb = "IDEA-ECB"; - public final static String LN_idea_ecb = "idea-ecb"; - - public final static int NID_rc2_cbc = 37; - public final static String SN_rc2_cbc = "RC2-CBC"; - public final static String LN_rc2_cbc = "rc2-cbc"; - public final static String OBJ_rc2_cbc = OBJ_rsadsi + ".3.2"; - - public final static int NID_rc2_ecb = 38; - public final static String SN_rc2_ecb = "RC2-ECB"; - public final static String LN_rc2_ecb = "rc2-ecb"; - - public final static int NID_rc2_cfb64 = 39; - public final static String SN_rc2_cfb64 = "RC2-CFB"; - public final static String LN_rc2_cfb64 = "rc2-cfb"; - - public final static int NID_rc2_ofb64 = 40; - public final static String SN_rc2_ofb64 = "RC2-OFB"; - public final static String LN_rc2_ofb64 = "rc2-ofb"; - - public final static int NID_sha = 41; - public final static String SN_sha = "SHA"; - public final static String LN_sha = "sha"; - public final static String OBJ_sha = OBJ_algorithm + ".18"; - - public final static int NID_shaWithRSAEncryption = 42; - public final static String SN_shaWithRSAEncryption = "RSA-SHA"; - public final static String LN_shaWithRSAEncryption = "shaWithRSAEncryption"; - public final static String OBJ_shaWithRSAEncryption = OBJ_algorithm + ".15"; - - public final static int NID_des_ede_cbc = 43; - public final static String SN_des_ede_cbc = "DES-EDE-CBC"; - public final static String LN_des_ede_cbc = "des-ede-cbc"; - - public final static int NID_des_ede3_cbc = 44; - public final static String SN_des_ede3_cbc = "DES-EDE3-CBC"; - public final static String LN_des_ede3_cbc = "des-ede3-cbc"; - public final static String OBJ_des_ede3_cbc = OBJ_rsadsi + ".3.7"; - - public final static int NID_des_ofb64 = 45; - public final static String SN_des_ofb64 = "DES-OFB"; - public final static String LN_des_ofb64 = "des-ofb"; - public final static String OBJ_des_ofb64 = OBJ_algorithm + ".8"; - - public final static int NID_idea_ofb64 = 46; - public final static String SN_idea_ofb64 = "IDEA-OFB"; - public final static String LN_idea_ofb64 = "idea-ofb"; - - public final static int NID_pkcs9_emailAddress = 48; - public final static String LN_pkcs9_emailAddress = "emailAddress"; - public final static String OBJ_pkcs9_emailAddress = OBJ_pkcs9 + ".1"; - - public final static int NID_pkcs9_unstructuredName = 49; - public final static String LN_pkcs9_unstructuredName = "unstructuredName"; - public final static String OBJ_pkcs9_unstructuredName = OBJ_pkcs9 + ".2"; - - public final static int NID_pkcs9_contentType = 50; - public final static String LN_pkcs9_contentType = "contentType"; - public final static String OBJ_pkcs9_contentType = OBJ_pkcs9 + ".3"; - - public final static int NID_pkcs9_messageDigest = 51; - public final static String LN_pkcs9_messageDigest = "messageDigest"; - public final static String OBJ_pkcs9_messageDigest = OBJ_pkcs9 + ".4"; - - public final static int NID_pkcs9_signingTime = 52; - public final static String LN_pkcs9_signingTime = "signingTime"; - public final static String OBJ_pkcs9_signingTime = OBJ_pkcs9 + ".5"; - - public final static int NID_pkcs9_countersignature = 53; - public final static String LN_pkcs9_countersignature = "countersignature"; - public final static String OBJ_pkcs9_countersignature = OBJ_pkcs9 + ".6"; - - public final static int NID_pkcs9_challengePassword = 54; - public final static String LN_pkcs9_challengePassword = "challengePassword"; - public final static String OBJ_pkcs9_challengePassword = OBJ_pkcs9 + ".7"; - - public final static int NID_pkcs9_unstructuredAddress = 55; - public final static String LN_pkcs9_unstructuredAddress = "unstructuredAddress"; - public final static String OBJ_pkcs9_unstructuredAddress = OBJ_pkcs9 + ".8"; - - public final static int NID_pkcs9_extCertAttributes = 56; - public final static String LN_pkcs9_extCertAttributes = "extendedCertificateAttributes"; - public final static String OBJ_pkcs9_extCertAttributes = OBJ_pkcs9 + ".9"; - - public final static int NID_netscape = 57; - public final static String SN_netscape = "Netscape"; - public final static String LN_netscape = "Netscape Communications Corp."; - public final static String OBJ_netscape = "2.16.840.1.113730"; - - public final static int NID_netscape_cert_extension = 58; - public final static String SN_netscape_cert_extension = "nsCertExt"; - public final static String LN_netscape_cert_extension = "Netscape Certificate Extension"; - public final static String OBJ_netscape_cert_extension = OBJ_netscape + ".1"; - - public final static int NID_netscape_data_type = 59; - public final static String SN_netscape_data_type = "nsDataType"; - public final static String LN_netscape_data_type = "Netscape Data Type"; - public final static String OBJ_netscape_data_type = OBJ_netscape + ".2"; - - public final static int NID_des_ede_cfb64 = 60; - public final static String SN_des_ede_cfb64 = "DES-EDE-CFB"; - public final static String LN_des_ede_cfb64 = "des-ede-cfb"; - - public final static int NID_des_ede3_cfb64 = 61; - public final static String SN_des_ede3_cfb64 = "DES-EDE3-CFB"; - public final static String LN_des_ede3_cfb64 = "des-ede3-cfb"; - - public final static int NID_des_ede_ofb64 = 62; - public final static String SN_des_ede_ofb64 = "DES-EDE-OFB"; - public final static String LN_des_ede_ofb64 = "des-ede-ofb"; - - public final static int NID_des_ede3_ofb64 = 63; - public final static String SN_des_ede3_ofb64 = "DES-EDE3-OFB"; - public final static String LN_des_ede3_ofb64 = "des-ede3-ofb"; - - public final static int NID_sha1 = 64; - public final static String SN_sha1 = "SHA1"; - public final static String LN_sha1 = "sha1"; - public final static String OBJ_sha1 = OBJ_algorithm + ".26"; - - public final static int NID_sha1WithRSAEncryption = 65; - public final static String SN_sha1WithRSAEncryption = "RSA-SHA1"; - public final static String LN_sha1WithRSAEncryption = "sha1WithRSAEncryption"; - public final static String OBJ_sha1WithRSAEncryption = OBJ_pkcs1 + ".5"; - - public final static int NID_dsaWithSHA = 66; - public final static String SN_dsaWithSHA = "DSA-SHA"; - public final static String LN_dsaWithSHA = "dsaWithSHA"; - public final static String OBJ_dsaWithSHA = OBJ_algorithm + ".13"; - - public final static int NID_dsa_2 = 67; - public final static String SN_dsa_2 = "DSA-old"; - public final static String LN_dsa_2 = "dsaEncryption-old"; - public final static String OBJ_dsa_2 = OBJ_algorithm + ".12"; - - public final static int NID_pbeWithSHA1AndRC2_CBC = 68; - public final static String SN_pbeWithSHA1AndRC2_CBC = "PBE-SHA1-RC2-64"; - public final static String LN_pbeWithSHA1AndRC2_CBC = "pbeWithSHA1AndRC2-CBC"; - public final static String OBJ_pbeWithSHA1AndRC2_CBC = OBJ_pkcs5 + ".11"; - - public final static int NID_id_pbkdf2 = 69; - public final static String LN_id_pbkdf2 = "PBKDF2"; - public final static String OBJ_id_pbkdf2 = OBJ_pkcs5 + ".12"; - - public final static int NID_dsaWithSHA1_2 = 70; - public final static String SN_dsaWithSHA1_2 = "DSA-SHA1-old"; - public final static String LN_dsaWithSHA1_2 = "dsaWithSHA1-old"; - public final static String OBJ_dsaWithSHA1_2 = OBJ_algorithm + ".27"; - - public final static int NID_netscape_cert_type = 71; - public final static String SN_netscape_cert_type = "nsCertType"; - public final static String LN_netscape_cert_type = "Netscape Cert Type"; - public final static String OBJ_netscape_cert_type = OBJ_netscape_cert_extension + ".1"; - - public final static int NID_netscape_base_url = 72; - public final static String SN_netscape_base_url = "nsBaseUrl"; - public final static String LN_netscape_base_url = "Netscape Base Url"; - public final static String OBJ_netscape_base_url = OBJ_netscape_cert_extension + ".2"; - - public final static int NID_netscape_revocation_url = 73; - public final static String SN_netscape_revocation_url = "nsRevocationUrl"; - public final static String LN_netscape_revocation_url = "Netscape Revocation Url"; - public final static String OBJ_netscape_revocation_url = OBJ_netscape_cert_extension + ".3"; - - public final static int NID_netscape_ca_revocation_url = 74; - public final static String SN_netscape_ca_revocation_url = "nsCaRevocationUrl"; - public final static String LN_netscape_ca_revocation_url = "Netscape CA Revocation Url"; - public final static String OBJ_netscape_ca_revocation_url = OBJ_netscape_cert_extension + ".4"; - - public final static int NID_netscape_renewal_url = 75; - public final static String SN_netscape_renewal_url = "nsRenewalUrl"; - public final static String LN_netscape_renewal_url = "Netscape Renewal Url"; - public final static String OBJ_netscape_renewal_url = OBJ_netscape_cert_extension + ".7"; - - public final static int NID_netscape_ca_policy_url = 76; - public final static String SN_netscape_ca_policy_url = "nsCaPolicyUrl"; - public final static String LN_netscape_ca_policy_url = "Netscape CA Policy Url"; - public final static String OBJ_netscape_ca_policy_url = OBJ_netscape_cert_extension + ".8"; - - public final static int NID_netscape_ssl_server_name = 77; - public final static String SN_netscape_ssl_server_name = "nsSslServerName"; - public final static String LN_netscape_ssl_server_name = "Netscape SSL Server Name"; - public final static String OBJ_netscape_ssl_server_name = OBJ_netscape_cert_extension + ".12"; - - public final static int NID_netscape_comment = 78; - public final static String SN_netscape_comment = "nsComment"; - public final static String LN_netscape_comment = "Netscape Comment"; - public final static String OBJ_netscape_comment = OBJ_netscape_cert_extension + ".13"; - - public final static int NID_netscape_cert_sequence = 79; - public final static String SN_netscape_cert_sequence = "nsCertSequence"; - public final static String LN_netscape_cert_sequence = "Netscape Certificate Sequence"; - public final static String OBJ_netscape_cert_sequence = OBJ_netscape_data_type + ".5"; - - public final static int NID_desx_cbc = 80; - public final static String SN_desx_cbc = "DESX-CBC"; - public final static String LN_desx_cbc = "desx-cbc"; - - public final static int NID_id_ce = 81; - public final static String SN_id_ce = "id-ce"; - public final static String OBJ_id_ce = OBJ_X500 + ".29"; - - public final static int NID_subject_key_identifier = 82; - public final static String SN_subject_key_identifier = "subjectKeyIdentifier"; - public final static String LN_subject_key_identifier = "X509v3 Subject Key Identifier"; - public final static String OBJ_subject_key_identifier = OBJ_id_ce + ".14"; - - public final static int NID_key_usage = 83; - public final static String SN_key_usage = "keyUsage"; - public final static String LN_key_usage = "X509v3 Key Usage"; - public final static String OBJ_key_usage = OBJ_id_ce + ".15"; - - public final static int NID_private_key_usage_period = 84; - public final static String SN_private_key_usage_period = "privateKeyUsagePeriod"; - public final static String LN_private_key_usage_period = "X509v3 Private Key Usage Period"; - public final static String OBJ_private_key_usage_period = OBJ_id_ce + ".16"; - - public final static int NID_subject_alt_name = 85; - public final static String SN_subject_alt_name = "subjectAltName"; - public final static String LN_subject_alt_name = "X509v3 Subject Alternative Name"; - public final static String OBJ_subject_alt_name = OBJ_id_ce + ".17"; - - public final static int NID_issuer_alt_name = 86; - public final static String SN_issuer_alt_name = "issuerAltName"; - public final static String LN_issuer_alt_name = "X509v3 Issuer Alternative Name"; - public final static String OBJ_issuer_alt_name = OBJ_id_ce + ".18"; - - public final static int NID_basic_constraints = 87; - public final static String SN_basic_constraints = "basicConstraints"; - public final static String LN_basic_constraints = "X509v3 Basic Constraints"; - public final static String OBJ_basic_constraints = OBJ_id_ce + ".19"; - - public final static int NID_crl_number = 88; - public final static String SN_crl_number = "crlNumber"; - public final static String LN_crl_number = "X509v3 CRL Number"; - public final static String OBJ_crl_number = OBJ_id_ce + ".20"; - - public final static int NID_certificate_policies = 89; - public final static String SN_certificate_policies = "certificatePolicies"; - public final static String LN_certificate_policies = "X509v3 Certificate Policies"; - public final static String OBJ_certificate_policies = OBJ_id_ce + ".32"; - - public final static int NID_authority_key_identifier = 90; - public final static String SN_authority_key_identifier = "authorityKeyIdentifier"; - public final static String LN_authority_key_identifier = "X509v3 Authority Key Identifier"; - public final static String OBJ_authority_key_identifier = OBJ_id_ce + ".35"; - - public final static int NID_bf_cbc = 91; - public final static String SN_bf_cbc = "BF-CBC"; - public final static String LN_bf_cbc = "bf-cbc"; - public final static String OBJ_bf_cbc = "1.3.6.1.4.1.3029.1.2"; - - public final static int NID_bf_ecb = 92; - public final static String SN_bf_ecb = "BF-ECB"; - public final static String LN_bf_ecb = "bf-ecb"; - - public final static int NID_bf_cfb64 = 93; - public final static String SN_bf_cfb64 = "BF-CFB"; - public final static String LN_bf_cfb64 = "bf-cfb"; - - public final static int NID_bf_ofb64 = 94; - public final static String SN_bf_ofb64 = "BF-OFB"; - public final static String LN_bf_ofb64 = "bf-ofb"; - - public final static int NID_mdc2 = 95; - public final static String SN_mdc2 = "MDC2"; - public final static String LN_mdc2 = "mdc2"; - public final static String OBJ_mdc2 = OBJ_X500algorithms + ".3.101"; - - public final static int NID_mdc2WithRSA = 96; - public final static String SN_mdc2WithRSA = "RSA-MDC2"; - public final static String LN_mdc2WithRSA = "mdc2WithRSA"; - public final static String OBJ_mdc2WithRSA = OBJ_X500algorithms + ".3.100"; - - public final static int NID_rc4_40 = 97; - public final static String SN_rc4_40 = "RC4-40"; - public final static String LN_rc4_40 = "rc4-40"; - - public final static int NID_rc2_40_cbc = 98; - public final static String SN_rc2_40_cbc = "RC2-40-CBC"; - public final static String LN_rc2_40_cbc = "rc2-40-cbc"; - public final static String OBJ_rc2_40_cbc = OBJ_rsadsi + ".3.2"; - - public final static int NID_givenName = 99; - public final static String SN_givenName = "GN"; - public final static String LN_givenName = "givenName"; - public final static String OBJ_givenName = OBJ_X509 + ".42"; - - public final static int NID_surname = 100; - public final static String SN_surname = "SN"; - public final static String LN_surname = "surname"; - public final static String OBJ_surname = OBJ_X509 + ".4"; - - public final static int NID_initials = 101; - public final static String LN_initials = "initials"; - public final static String OBJ_initials = OBJ_X509 + ".43"; - - public final static int NID_crl_distribution_points = 103; - public final static String SN_crl_distribution_points = "crlDistributionPoints"; - public final static String LN_crl_distribution_points = "X509v3 CRL Distribution Points"; - public final static String OBJ_crl_distribution_points = OBJ_id_ce + ".31"; - - public final static int NID_md5WithRSA = 104; - public final static String SN_md5WithRSA = "RSA-NP-MD5"; - public final static String LN_md5WithRSA = "md5WithRSA"; - public final static String OBJ_md5WithRSA = OBJ_algorithm + ".3"; - - public final static int NID_serialNumber = 105; - public final static String LN_serialNumber = "serialNumber"; - public final static String OBJ_serialNumber = OBJ_X509 + ".5"; - - public final static int NID_title = 106; - public final static String LN_title = "title"; - public final static String OBJ_title = OBJ_X509 + ".12"; - - public final static int NID_description = 107; - public final static String LN_description = "description"; - public final static String OBJ_description = OBJ_X509 + ".13"; - - public final static int NID_cast5_cbc = 108; - public final static String SN_cast5_cbc = "CAST5-CBC"; - public final static String LN_cast5_cbc = "cast5-cbc"; - public final static String OBJ_cast5_cbc = OBJ_ISO_US + ".113533.7.66.10"; - - public final static int NID_cast5_ecb = 109; - public final static String SN_cast5_ecb = "CAST5-ECB"; - public final static String LN_cast5_ecb = "cast5-ecb"; - - public final static int NID_cast5_cfb64 = 110; - public final static String SN_cast5_cfb64 = "CAST5-CFB"; - public final static String LN_cast5_cfb64 = "cast5-cfb"; - - public final static int NID_cast5_ofb64 = 111; - public final static String SN_cast5_ofb64 = "CAST5-OFB"; - public final static String LN_cast5_ofb64 = "cast5-ofb"; - - public final static int NID_pbeWithMD5AndCast5_CBC = 112; - public final static String LN_pbeWithMD5AndCast5_CBC = "pbeWithMD5AndCast5CBC"; - public final static String OBJ_pbeWithMD5AndCast5_CBC = OBJ_ISO_US + ".113533.7.66.12"; - - public final static int NID_X9cm = 185; - public final static String SN_X9cm = "X9cm"; - public final static String LN_X9cm = "X9.57 CM ?"; - public final static String OBJ_X9cm = OBJ_X9_57 + ".4"; - - public final static int NID_dsaWithSHA1 = 113; - public final static String SN_dsaWithSHA1 = "DSA-SHA1"; - public final static String LN_dsaWithSHA1 = "dsaWithSHA1"; - public final static String OBJ_dsaWithSHA1 = OBJ_X9cm + ".3"; - - public final static int NID_md5_sha1 = 114; - public final static String SN_md5_sha1 = "MD5-SHA1"; - public final static String LN_md5_sha1 = "md5-sha1"; - - public final static int NID_sha1WithRSA = 115; - public final static String SN_sha1WithRSA = "RSA-SHA1-2"; - public final static String LN_sha1WithRSA = "sha1WithRSA"; - public final static String OBJ_sha1WithRSA = OBJ_algorithm + ".29"; - - public final static int NID_dsa = 116; - public final static String SN_dsa = "DSA"; - public final static String LN_dsa = "dsaEncryption"; - public final static String OBJ_dsa = OBJ_X9cm + ".1"; - - public final static int NID_ripemd160 = 117; - public final static String SN_ripemd160 = "RIPEMD160"; - public final static String LN_ripemd160 = "ripemd160"; - public final static String OBJ_ripemd160 = "1.3.36.3.2.1"; - - public final static int NID_ripemd160WithRSA = 119; - public final static String SN_ripemd160WithRSA = "RSA-RIPEMD160"; - public final static String LN_ripemd160WithRSA = "ripemd160WithRSA"; - public final static String OBJ_ripemd160WithRSA = "1.3.36.3.3.1.2"; - - public final static int NID_rc5_cbc = 120; - public final static String SN_rc5_cbc = "RC5-CBC"; - public final static String LN_rc5_cbc = "rc5-cbc"; - public final static String OBJ_rc5_cbc = OBJ_rsadsi + ".3.8"; - - public final static int NID_rc5_ecb = 121; - public final static String SN_rc5_ecb = "RC5-ECB"; - public final static String LN_rc5_ecb = "rc5-ecb"; - - public final static int NID_rc5_cfb64 = 122; - public final static String SN_rc5_cfb64 = "RC5-CFB"; - public final static String LN_rc5_cfb64 = "rc5-cfb"; - - public final static int NID_rc5_ofb64 = 123; - public final static String SN_rc5_ofb64 = "RC5-OFB"; - public final static String LN_rc5_ofb64 = "rc5-ofb"; - - public final static int NID_rle_compression = 124; - public final static String SN_rle_compression = "RLE"; - public final static String LN_rle_compression = "run length compression"; - public final static String OBJ_rle_compression = "1.1.1.1.666.1"; - - public final static int NID_zlib_compression = 125; - public final static String SN_zlib_compression = "ZLIB"; - public final static String LN_zlib_compression = "zlib compression"; - public final static String OBJ_zlib_compression = "1.1.1.1.666.2"; - - public final static int NID_ext_key_usage = 126; - public final static String SN_ext_key_usage = "extendedKeyUsage"; - public final static String LN_ext_key_usage = "X509v3 Extended Key Usage"; - public final static String OBJ_ext_key_usage = OBJ_id_ce + ".37"; - - public final static int NID_id_kp = 128; - public final static String SN_id_kp = "id-kp"; - public final static String OBJ_id_kp = OBJ_id_pkix + ".3"; - - public final static int NID_server_auth = 129; - public final static String SN_server_auth = "serverAuth"; - public final static String LN_server_auth = "TLS Web Server Authentication"; - public final static String OBJ_server_auth = OBJ_id_kp + ".1"; - - public final static int NID_client_auth = 130; - public final static String SN_client_auth = "clientAuth"; - public final static String LN_client_auth = "TLS Web Client Authentication"; - public final static String OBJ_client_auth = OBJ_id_kp + ".2"; - - public final static int NID_code_sign = 131; - public final static String SN_code_sign = "codeSigning"; - public final static String LN_code_sign = "Code Signing"; - public final static String OBJ_code_sign = OBJ_id_kp + ".3"; - - public final static int NID_email_protect = 132; - public final static String SN_email_protect = "emailProtection"; - public final static String LN_email_protect = "E-mail Protection"; - public final static String OBJ_email_protect = OBJ_id_kp + ".4"; - - public final static int NID_time_stamp = 133; - public final static String SN_time_stamp = "timeStamping"; - public final static String LN_time_stamp = "Time Stamping"; - public final static String OBJ_time_stamp = OBJ_id_kp + ".8"; - - public final static int NID_ms_code_ind = 134; - public final static String SN_ms_code_ind = "msCodeInd"; - public final static String LN_ms_code_ind = "Microsoft Individual Code Signing"; - public final static String OBJ_ms_code_ind = "1.3.6.1.4.1.311.2.1.21"; - - public final static int NID_ms_code_com = 135; - public final static String SN_ms_code_com = "msCodeCom"; - public final static String LN_ms_code_com = "Microsoft Commercial Code Signing"; - public final static String OBJ_ms_code_com = "1.3.6.1.4.1.311.2.1.22"; - - public final static int NID_ms_ctl_sign = 136; - public final static String SN_ms_ctl_sign = "msCTLSign"; - public final static String LN_ms_ctl_sign = "Microsoft Trust List Signing"; - public final static String OBJ_ms_ctl_sign = "1.3.6.1.4.1.311.10.3.1"; - - public final static int NID_ms_sgc = 137; - public final static String SN_ms_sgc = "msSGC"; - public final static String LN_ms_sgc = "Microsoft Server Gated Crypto"; - public final static String OBJ_ms_sgc = "1.3.6.1.4.1.311.10.3.3"; - - public final static int NID_ms_efs = 138; - public final static String SN_ms_efs = "msEFS"; - public final static String LN_ms_efs = "Microsoft Encrypted File System"; - public final static String OBJ_ms_efs = "1.3.6.1.4.1.311.10.3.4"; - - public final static int NID_ns_sgc = 139; - public final static String SN_ns_sgc = "nsSGC"; - public final static String LN_ns_sgc = "Netscape Server Gated Crypto"; - public final static String OBJ_ns_sgc = OBJ_netscape + ".4.1"; - - public final static int NID_delta_crl = 140; - public final static String SN_delta_crl = "deltaCRL"; - public final static String LN_delta_crl = "X509v3 Delta CRL Indicator"; - public final static String OBJ_delta_crl = OBJ_id_ce + ".27"; - - public final static int NID_crl_reason = 141; - public final static String SN_crl_reason = "CRLReason"; - public final static String LN_crl_reason = "X509v3 CRL Reason Code"; - public final static String OBJ_crl_reason = OBJ_id_ce + ".21"; - - public final static int NID_invalidity_date = 142; - public final static String SN_invalidity_date = "invalidityDate"; - public final static String LN_invalidity_date = "Invalidity Date"; - public final static String OBJ_invalidity_date = OBJ_id_ce + ".24"; - - public final static int NID_sxnet = 143; - public final static String SN_sxnet = "SXNetID"; - public final static String LN_sxnet = "Strong Extranet ID"; - public final static String OBJ_sxnet = "1.3.101.1.4.1"; - - public final static String OBJ_pkcs12_pbeids = OBJ_pkcs12 + ".1"; - - public final static int NID_pbe_WithSHA1And128BitRC4 = 144; - public final static String SN_pbe_WithSHA1And128BitRC4 = "PBE-SHA1-RC4-128"; - public final static String LN_pbe_WithSHA1And128BitRC4 = "pbeWithSHA1And128BitRC4"; - public final static String OBJ_pbe_WithSHA1And128BitRC4 = OBJ_pkcs12_pbeids + ".1"; - - public final static int NID_pbe_WithSHA1And40BitRC4 = 145; - public final static String SN_pbe_WithSHA1And40BitRC4 = "PBE-SHA1-RC4-40"; - public final static String LN_pbe_WithSHA1And40BitRC4 = "pbeWithSHA1And40BitRC4"; - public final static String OBJ_pbe_WithSHA1And40BitRC4 = OBJ_pkcs12_pbeids + ".2"; - - public final static int NID_pbe_WithSHA1And3_Key_TripleDES_CBC = 146; - public final static String SN_pbe_WithSHA1And3_Key_TripleDES_CBC = "PBE-SHA1-3DES"; - public final static String LN_pbe_WithSHA1And3_Key_TripleDES_CBC = "pbeWithSHA1And3-KeyTripleDES-CBC"; - public final static String OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC = OBJ_pkcs12_pbeids + ".3"; - - public final static int NID_pbe_WithSHA1And2_Key_TripleDES_CBC = 147; - public final static String SN_pbe_WithSHA1And2_Key_TripleDES_CBC = "PBE-SHA1-2DES"; - public final static String LN_pbe_WithSHA1And2_Key_TripleDES_CBC = "pbeWithSHA1And2-KeyTripleDES-CBC"; - public final static String OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC = OBJ_pkcs12_pbeids + ".4"; - - public final static int NID_pbe_WithSHA1And128BitRC2_CBC = 148; - public final static String SN_pbe_WithSHA1And128BitRC2_CBC = "PBE-SHA1-RC2-128"; - public final static String LN_pbe_WithSHA1And128BitRC2_CBC = "pbeWithSHA1And128BitRC2-CBC"; - public final static String OBJ_pbe_WithSHA1And128BitRC2_CBC = OBJ_pkcs12_pbeids + ".5"; - - public final static int NID_pbe_WithSHA1And40BitRC2_CBC = 149; - public final static String SN_pbe_WithSHA1And40BitRC2_CBC = "PBE-SHA1-RC2-40"; - public final static String LN_pbe_WithSHA1And40BitRC2_CBC = "pbeWithSHA1And40BitRC2-CBC"; - public final static String OBJ_pbe_WithSHA1And40BitRC2_CBC = OBJ_pkcs12_pbeids + ".6"; - - public final static int NID_keyBag = 150; - public final static String LN_keyBag = "keyBag"; - public final static String OBJ_keyBag = OBJ_pkcs12_BagIds + ".1"; - - public final static int NID_pkcs8ShroudedKeyBag = 151; - public final static String LN_pkcs8ShroudedKeyBag = "pkcs8ShroudedKeyBag"; - public final static String OBJ_pkcs8ShroudedKeyBag = OBJ_pkcs12_BagIds + ".2"; - - public final static int NID_certBag = 152; - public final static String LN_certBag = "certBag"; - public final static String OBJ_certBag = OBJ_pkcs12_BagIds + ".3"; - - public final static int NID_crlBag = 153; - public final static String LN_crlBag = "crlBag"; - public final static String OBJ_crlBag = OBJ_pkcs12_BagIds + ".4"; - - public final static int NID_secretBag = 154; - public final static String LN_secretBag = "secretBag"; - public final static String OBJ_secretBag = OBJ_pkcs12_BagIds + ".5"; - - public final static int NID_safeContentsBag = 155; - public final static String LN_safeContentsBag = "safeContentsBag"; - public final static String OBJ_safeContentsBag = OBJ_pkcs12_BagIds + ".6"; - - public final static int NID_friendlyName = 156; - public final static String LN_friendlyName = "friendlyName"; - public final static String OBJ_friendlyName = OBJ_pkcs9 + ".20"; - - public final static int NID_localKeyID = 157; - public final static String LN_localKeyID = "localKeyID"; - public final static String OBJ_localKeyID = OBJ_pkcs9 + ".21"; - - public final static int NID_x509Certificate = 158; - public final static String LN_x509Certificate = "x509Certificate"; - public final static String OBJ_x509Certificate = OBJ_certTypes + ".1"; - - public final static int NID_sdsiCertificate = 159; - public final static String LN_sdsiCertificate = "sdsiCertificate"; - public final static String OBJ_sdsiCertificate = OBJ_certTypes + ".2"; - - public final static int NID_x509Crl = 160; - public final static String LN_x509Crl = "x509Crl"; - public final static String OBJ_x509Crl = OBJ_crlTypes + ".1"; - - public final static int NID_pbes2 = 161; - public final static String LN_pbes2 = "PBES2"; - public final static String OBJ_pbes2 = OBJ_pkcs5 + ".13"; - - public final static int NID_pbmac1 = 162; - public final static String LN_pbmac1 = "PBMAC1"; - public final static String OBJ_pbmac1 = OBJ_pkcs5 + ".14"; - - public final static int NID_hmacWithSHA1 = 163; - public final static String LN_hmacWithSHA1 = "hmacWithSHA1"; - public final static String OBJ_hmacWithSHA1 = OBJ_rsadsi + ".2.7"; - - public final static int NID_id_qt = 259; - public final static String SN_id_qt = "id-qt"; - public final static String OBJ_id_qt = OBJ_id_pkix + ".2"; - - public final static int NID_id_qt_cps = 164; - public final static String SN_id_qt_cps = "id-qt-cps"; - public final static String LN_id_qt_cps = "Policy Qualifier CPS"; - public final static String OBJ_id_qt_cps = OBJ_id_qt + ".1"; - - public final static int NID_id_qt_unotice = 165; - public final static String SN_id_qt_unotice = "id-qt-unotice"; - public final static String LN_id_qt_unotice = "Policy Qualifier User Notice"; - public final static String OBJ_id_qt_unotice = OBJ_id_qt + ".2"; - - public final static int NID_rc2_64_cbc = 166; - public final static String SN_rc2_64_cbc = "RC2-64-CBC"; - public final static String LN_rc2_64_cbc = "rc2-64-cbc"; - - public final static int NID_SMIMECapabilities = 167; - public final static String SN_SMIMECapabilities = "SMIME-CAPS"; - public final static String LN_SMIMECapabilities = "S/MIME Capabilities"; - public final static String OBJ_SMIMECapabilities = OBJ_pkcs9 + ".15"; - - public final static int NID_pbeWithMD2AndRC2_CBC = 168; - public final static String SN_pbeWithMD2AndRC2_CBC = "PBE-MD2-RC2-64"; - public final static String LN_pbeWithMD2AndRC2_CBC = "pbeWithMD2AndRC2-CBC"; - public final static String OBJ_pbeWithMD2AndRC2_CBC = OBJ_pkcs5 + ".4"; - - public final static int NID_pbeWithMD5AndRC2_CBC = 169; - public final static String SN_pbeWithMD5AndRC2_CBC = "PBE-MD5-RC2-64"; - public final static String LN_pbeWithMD5AndRC2_CBC = "pbeWithMD5AndRC2-CBC"; - public final static String OBJ_pbeWithMD5AndRC2_CBC = OBJ_pkcs5 + ".6"; - - public final static int NID_pbeWithSHA1AndDES_CBC = 170; - public final static String SN_pbeWithSHA1AndDES_CBC = "PBE-SHA1-DES"; - public final static String LN_pbeWithSHA1AndDES_CBC = "pbeWithSHA1AndDES-CBC"; - public final static String OBJ_pbeWithSHA1AndDES_CBC = OBJ_pkcs5 + ".10"; - - public final static int NID_ms_ext_req = 171; - public final static String SN_ms_ext_req = "msExtReq"; - public final static String LN_ms_ext_req = "Microsoft Extension Request"; - public final static String OBJ_ms_ext_req = "1.3.6.1.4.1.311.2.1.14"; - - public final static int NID_ext_req = 172; - public final static String SN_ext_req = "extReq"; - public final static String LN_ext_req = "Extension Request"; - public final static String OBJ_ext_req = OBJ_pkcs9 + ".14"; - - public final static int NID_name = 173; - public final static String SN_name = "name"; - public final static String LN_name = "name"; - public final static String OBJ_name = OBJ_X509 + ".41"; - - public final static int NID_dnQualifier = 174; - public final static String SN_dnQualifier = "dnQualifier"; - public final static String LN_dnQualifier = "dnQualifier"; - public final static String OBJ_dnQualifier = OBJ_X509 + ".46"; - - public final static int NID_id_pe = 175; - public final static String SN_id_pe = "id-pe"; - public final static String OBJ_id_pe = OBJ_id_pkix + ".1"; - - public final static int NID_info_access = 177; - public final static String SN_info_access = "authorityInfoAccess"; - public final static String LN_info_access = "Authority Information Access"; - public final static String OBJ_info_access = OBJ_id_pe + ".1"; - - public final static int NID_ad_ca_issuers = 179; - public final static String SN_ad_ca_issuers = "caIssuers"; - public final static String LN_ad_ca_issuers = "CA Issuers"; - public final static String OBJ_ad_ca_issuers = OBJ_id_ad + ".2"; - - public final static int NID_OCSP_sign = 180; - public final static String SN_OCSP_sign = "OCSPSigning"; - public final static String LN_OCSP_sign = "OCSP Signing"; - public final static String OBJ_OCSP_sign = OBJ_id_kp + ".9"; - - public final static int NID_SMIME = 188; - public final static String SN_SMIME = "SMIME"; - public final static String LN_SMIME = "S/MIME"; - public final static String OBJ_SMIME = OBJ_pkcs9 + ".16"; - - public final static int NID_id_smime_mod = 189; - public final static String SN_id_smime_mod = "id-smime-mod"; - public final static String OBJ_id_smime_mod = OBJ_SMIME + ".0"; - - public final static int NID_id_smime_ct = 190; - public final static String SN_id_smime_ct = "id-smime-ct"; - public final static String OBJ_id_smime_ct = OBJ_SMIME + ".1"; - - public final static int NID_id_smime_aa = 191; - public final static String SN_id_smime_aa = "id-smime-aa"; - public final static String OBJ_id_smime_aa = OBJ_SMIME + ".2"; - - public final static int NID_id_smime_alg = 192; - public final static String SN_id_smime_alg = "id-smime-alg"; - public final static String OBJ_id_smime_alg = OBJ_SMIME + ".3"; - - public final static int NID_id_smime_cd = 193; - public final static String SN_id_smime_cd = "id-smime-cd"; - public final static String OBJ_id_smime_cd = OBJ_SMIME + ".4"; - - public final static int NID_id_smime_spq = 194; - public final static String SN_id_smime_spq = "id-smime-spq"; - public final static String OBJ_id_smime_spq = OBJ_SMIME + ".5"; - - public final static int NID_id_smime_cti = 195; - public final static String SN_id_smime_cti = "id-smime-cti"; - public final static String OBJ_id_smime_cti = OBJ_SMIME + ".6"; - - public final static int NID_id_smime_mod_cms = 196; - public final static String SN_id_smime_mod_cms = "id-smime-mod-cms"; - public final static String OBJ_id_smime_mod_cms = OBJ_id_smime_mod + ".1"; - - public final static int NID_id_smime_mod_ess = 197; - public final static String SN_id_smime_mod_ess = "id-smime-mod-ess"; - public final static String OBJ_id_smime_mod_ess = OBJ_id_smime_mod + ".2"; - - public final static int NID_id_smime_mod_oid = 198; - public final static String SN_id_smime_mod_oid = "id-smime-mod-oid"; - public final static String OBJ_id_smime_mod_oid = OBJ_id_smime_mod + ".3"; - - public final static int NID_id_smime_mod_msg_v3 = 199; - public final static String SN_id_smime_mod_msg_v3 = "id-smime-mod-msg-v3"; - public final static String OBJ_id_smime_mod_msg_v3 = OBJ_id_smime_mod + ".4"; - - public final static int NID_id_smime_mod_ets_eSignature_88 = 200; - public final static String SN_id_smime_mod_ets_eSignature_88 = "id-smime-mod-ets-eSignature-88"; - public final static String OBJ_id_smime_mod_ets_eSignature_88 = OBJ_id_smime_mod + ".5"; - - public final static int NID_id_smime_mod_ets_eSignature_97 = 201; - public final static String SN_id_smime_mod_ets_eSignature_97 = "id-smime-mod-ets-eSignature-97"; - public final static String OBJ_id_smime_mod_ets_eSignature_97 = OBJ_id_smime_mod + ".6"; - - public final static int NID_id_smime_mod_ets_eSigPolicy_88 = 202; - public final static String SN_id_smime_mod_ets_eSigPolicy_88 = "id-smime-mod-ets-eSigPolicy-88"; - public final static String OBJ_id_smime_mod_ets_eSigPolicy_88 = OBJ_id_smime_mod + ".7"; - - public final static int NID_id_smime_mod_ets_eSigPolicy_97 = 203; - public final static String SN_id_smime_mod_ets_eSigPolicy_97 = "id-smime-mod-ets-eSigPolicy-97"; - public final static String OBJ_id_smime_mod_ets_eSigPolicy_97 = OBJ_id_smime_mod + ".8"; - - public final static int NID_id_smime_ct_receipt = 204; - public final static String SN_id_smime_ct_receipt = "id-smime-ct-receipt"; - public final static String OBJ_id_smime_ct_receipt = OBJ_id_smime_ct + ".1"; - - public final static int NID_id_smime_ct_authData = 205; - public final static String SN_id_smime_ct_authData = "id-smime-ct-authData"; - public final static String OBJ_id_smime_ct_authData = OBJ_id_smime_ct + ".2"; - - public final static int NID_id_smime_ct_publishCert = 206; - public final static String SN_id_smime_ct_publishCert = "id-smime-ct-publishCert"; - public final static String OBJ_id_smime_ct_publishCert = OBJ_id_smime_ct + ".3"; - - public final static int NID_id_smime_ct_TSTInfo = 207; - public final static String SN_id_smime_ct_TSTInfo = "id-smime-ct-TSTInfo"; - public final static String OBJ_id_smime_ct_TSTInfo = OBJ_id_smime_ct + ".4"; - - public final static int NID_id_smime_ct_TDTInfo = 208; - public final static String SN_id_smime_ct_TDTInfo = "id-smime-ct-TDTInfo"; - public final static String OBJ_id_smime_ct_TDTInfo = OBJ_id_smime_ct + ".5"; - - public final static int NID_id_smime_ct_contentInfo = 209; - public final static String SN_id_smime_ct_contentInfo = "id-smime-ct-contentInfo"; - public final static String OBJ_id_smime_ct_contentInfo = OBJ_id_smime_ct + ".6"; - - public final static int NID_id_smime_ct_DVCSRequestData = 210; - public final static String SN_id_smime_ct_DVCSRequestData = "id-smime-ct-DVCSRequestData"; - public final static String OBJ_id_smime_ct_DVCSRequestData = OBJ_id_smime_ct + ".7"; - - public final static int NID_id_smime_ct_DVCSResponseData = 211; - public final static String SN_id_smime_ct_DVCSResponseData = "id-smime-ct-DVCSResponseData"; - public final static String OBJ_id_smime_ct_DVCSResponseData = OBJ_id_smime_ct + ".8"; - - public final static int NID_id_smime_aa_receiptRequest = 212; - public final static String SN_id_smime_aa_receiptRequest = "id-smime-aa-receiptRequest"; - public final static String OBJ_id_smime_aa_receiptRequest = OBJ_id_smime_aa + ".1"; - - public final static int NID_id_smime_aa_securityLabel = 213; - public final static String SN_id_smime_aa_securityLabel = "id-smime-aa-securityLabel"; - public final static String OBJ_id_smime_aa_securityLabel = OBJ_id_smime_aa + ".2"; - - public final static int NID_id_smime_aa_mlExpandHistory = 214; - public final static String SN_id_smime_aa_mlExpandHistory = "id-smime-aa-mlExpandHistory"; - public final static String OBJ_id_smime_aa_mlExpandHistory = OBJ_id_smime_aa + ".3"; - - public final static int NID_id_smime_aa_contentHint = 215; - public final static String SN_id_smime_aa_contentHint = "id-smime-aa-contentHint"; - public final static String OBJ_id_smime_aa_contentHint = OBJ_id_smime_aa + ".4"; - - public final static int NID_id_smime_aa_msgSigDigest = 216; - public final static String SN_id_smime_aa_msgSigDigest = "id-smime-aa-msgSigDigest"; - public final static String OBJ_id_smime_aa_msgSigDigest = OBJ_id_smime_aa + ".5"; - - public final static int NID_id_smime_aa_encapContentType = 217; - public final static String SN_id_smime_aa_encapContentType = "id-smime-aa-encapContentType"; - public final static String OBJ_id_smime_aa_encapContentType = OBJ_id_smime_aa + ".6"; - - public final static int NID_id_smime_aa_contentIdentifier = 218; - public final static String SN_id_smime_aa_contentIdentifier = "id-smime-aa-contentIdentifier"; - public final static String OBJ_id_smime_aa_contentIdentifier = OBJ_id_smime_aa + ".7"; - - public final static int NID_id_smime_aa_macValue = 219; - public final static String SN_id_smime_aa_macValue = "id-smime-aa-macValue"; - public final static String OBJ_id_smime_aa_macValue = OBJ_id_smime_aa + ".8"; - - public final static int NID_id_smime_aa_equivalentLabels = 220; - public final static String SN_id_smime_aa_equivalentLabels = "id-smime-aa-equivalentLabels"; - public final static String OBJ_id_smime_aa_equivalentLabels = OBJ_id_smime_aa + ".9"; - - public final static int NID_id_smime_aa_contentReference = 221; - public final static String SN_id_smime_aa_contentReference = "id-smime-aa-contentReference"; - public final static String OBJ_id_smime_aa_contentReference = OBJ_id_smime_aa + ".10"; - - public final static int NID_id_smime_aa_encrypKeyPref = 222; - public final static String SN_id_smime_aa_encrypKeyPref = "id-smime-aa-encrypKeyPref"; - public final static String OBJ_id_smime_aa_encrypKeyPref = OBJ_id_smime_aa + ".11"; - - public final static int NID_id_smime_aa_signingCertificate = 223; - public final static String SN_id_smime_aa_signingCertificate = "id-smime-aa-signingCertificate"; - public final static String OBJ_id_smime_aa_signingCertificate = OBJ_id_smime_aa + ".12"; - - public final static int NID_id_smime_aa_smimeEncryptCerts = 224; - public final static String SN_id_smime_aa_smimeEncryptCerts = "id-smime-aa-smimeEncryptCerts"; - public final static String OBJ_id_smime_aa_smimeEncryptCerts = OBJ_id_smime_aa + ".13"; - - public final static int NID_id_smime_aa_timeStampToken = 225; - public final static String SN_id_smime_aa_timeStampToken = "id-smime-aa-timeStampToken"; - public final static String OBJ_id_smime_aa_timeStampToken = OBJ_id_smime_aa + ".14"; - - public final static int NID_id_smime_aa_ets_sigPolicyId = 226; - public final static String SN_id_smime_aa_ets_sigPolicyId = "id-smime-aa-ets-sigPolicyId"; - public final static String OBJ_id_smime_aa_ets_sigPolicyId = OBJ_id_smime_aa + ".15"; - - public final static int NID_id_smime_aa_ets_commitmentType = 227; - public final static String SN_id_smime_aa_ets_commitmentType = "id-smime-aa-ets-commitmentType"; - public final static String OBJ_id_smime_aa_ets_commitmentType = OBJ_id_smime_aa + ".16"; - - public final static int NID_id_smime_aa_ets_signerLocation = 228; - public final static String SN_id_smime_aa_ets_signerLocation = "id-smime-aa-ets-signerLocation"; - public final static String OBJ_id_smime_aa_ets_signerLocation = OBJ_id_smime_aa + ".17"; - - public final static int NID_id_smime_aa_ets_signerAttr = 229; - public final static String SN_id_smime_aa_ets_signerAttr = "id-smime-aa-ets-signerAttr"; - public final static String OBJ_id_smime_aa_ets_signerAttr = OBJ_id_smime_aa + ".18"; - - public final static int NID_id_smime_aa_ets_otherSigCert = 230; - public final static String SN_id_smime_aa_ets_otherSigCert = "id-smime-aa-ets-otherSigCert"; - public final static String OBJ_id_smime_aa_ets_otherSigCert = OBJ_id_smime_aa + ".19"; - - public final static int NID_id_smime_aa_ets_contentTimestamp = 231; - public final static String SN_id_smime_aa_ets_contentTimestamp = "id-smime-aa-ets-contentTimestamp"; - public final static String OBJ_id_smime_aa_ets_contentTimestamp = OBJ_id_smime_aa + ".20"; - - public final static int NID_id_smime_aa_ets_CertificateRefs = 232; - public final static String SN_id_smime_aa_ets_CertificateRefs = "id-smime-aa-ets-CertificateRefs"; - public final static String OBJ_id_smime_aa_ets_CertificateRefs = OBJ_id_smime_aa + ".21"; - - public final static int NID_id_smime_aa_ets_RevocationRefs = 233; - public final static String SN_id_smime_aa_ets_RevocationRefs = "id-smime-aa-ets-RevocationRefs"; - public final static String OBJ_id_smime_aa_ets_RevocationRefs = OBJ_id_smime_aa + ".22"; - - public final static int NID_id_smime_aa_ets_certValues = 234; - public final static String SN_id_smime_aa_ets_certValues = "id-smime-aa-ets-certValues"; - public final static String OBJ_id_smime_aa_ets_certValues = OBJ_id_smime_aa + ".23"; - - public final static int NID_id_smime_aa_ets_revocationValues = 235; - public final static String SN_id_smime_aa_ets_revocationValues = "id-smime-aa-ets-revocationValues"; - public final static String OBJ_id_smime_aa_ets_revocationValues = OBJ_id_smime_aa + ".24"; - - public final static int NID_id_smime_aa_ets_escTimeStamp = 236; - public final static String SN_id_smime_aa_ets_escTimeStamp = "id-smime-aa-ets-escTimeStamp"; - public final static String OBJ_id_smime_aa_ets_escTimeStamp = OBJ_id_smime_aa + ".25"; - - public final static int NID_id_smime_aa_ets_certCRLTimestamp = 237; - public final static String SN_id_smime_aa_ets_certCRLTimestamp = "id-smime-aa-ets-certCRLTimestamp"; - public final static String OBJ_id_smime_aa_ets_certCRLTimestamp = OBJ_id_smime_aa + ".26"; - - public final static int NID_id_smime_aa_ets_archiveTimeStamp = 238; - public final static String SN_id_smime_aa_ets_archiveTimeStamp = "id-smime-aa-ets-archiveTimeStamp"; - public final static String OBJ_id_smime_aa_ets_archiveTimeStamp = OBJ_id_smime_aa + ".27"; - - public final static int NID_id_smime_aa_signatureType = 239; - public final static String SN_id_smime_aa_signatureType = "id-smime-aa-signatureType"; - public final static String OBJ_id_smime_aa_signatureType = OBJ_id_smime_aa + ".28"; - - public final static int NID_id_smime_aa_dvcs_dvc = 240; - public final static String SN_id_smime_aa_dvcs_dvc = "id-smime-aa-dvcs-dvc"; - public final static String OBJ_id_smime_aa_dvcs_dvc = OBJ_id_smime_aa + ".29"; - - public final static int NID_id_smime_alg_ESDHwith3DES = 241; - public final static String SN_id_smime_alg_ESDHwith3DES = "id-smime-alg-ESDHwith3DES"; - public final static String OBJ_id_smime_alg_ESDHwith3DES = OBJ_id_smime_alg + ".1"; - - public final static int NID_id_smime_alg_ESDHwithRC2 = 242; - public final static String SN_id_smime_alg_ESDHwithRC2 = "id-smime-alg-ESDHwithRC2"; - public final static String OBJ_id_smime_alg_ESDHwithRC2 = OBJ_id_smime_alg + ".2"; - - public final static int NID_id_smime_alg_3DESwrap = 243; - public final static String SN_id_smime_alg_3DESwrap = "id-smime-alg-3DESwrap"; - public final static String OBJ_id_smime_alg_3DESwrap = OBJ_id_smime_alg + ".3"; - - public final static int NID_id_smime_alg_RC2wrap = 244; - public final static String SN_id_smime_alg_RC2wrap = "id-smime-alg-RC2wrap"; - public final static String OBJ_id_smime_alg_RC2wrap = OBJ_id_smime_alg + ".4"; - - public final static int NID_id_smime_alg_ESDH = 245; - public final static String SN_id_smime_alg_ESDH = "id-smime-alg-ESDH"; - public final static String OBJ_id_smime_alg_ESDH = OBJ_id_smime_alg + ".5"; - - public final static int NID_id_smime_alg_CMS3DESwrap = 246; - public final static String SN_id_smime_alg_CMS3DESwrap = "id-smime-alg-CMS3DESwrap"; - public final static String OBJ_id_smime_alg_CMS3DESwrap = OBJ_id_smime_alg + ".6"; - - public final static int NID_id_smime_alg_CMSRC2wrap = 247; - public final static String SN_id_smime_alg_CMSRC2wrap = "id-smime-alg-CMSRC2wrap"; - public final static String OBJ_id_smime_alg_CMSRC2wrap = OBJ_id_smime_alg + ".7"; - - public final static int NID_id_smime_cd_ldap = 248; - public final static String SN_id_smime_cd_ldap = "id-smime-cd-ldap"; - public final static String OBJ_id_smime_cd_ldap = OBJ_id_smime_cd + ".1"; - - public final static int NID_id_smime_spq_ets_sqt_uri = 249; - public final static String SN_id_smime_spq_ets_sqt_uri = "id-smime-spq-ets-sqt-uri"; - public final static String OBJ_id_smime_spq_ets_sqt_uri = OBJ_id_smime_spq + ".1"; - - public final static int NID_id_smime_spq_ets_sqt_unotice = 250; - public final static String SN_id_smime_spq_ets_sqt_unotice = "id-smime-spq-ets-sqt-unotice"; - public final static String OBJ_id_smime_spq_ets_sqt_unotice = OBJ_id_smime_spq + ".2"; - - public final static int NID_id_smime_cti_ets_proofOfOrigin = 251; - public final static String SN_id_smime_cti_ets_proofOfOrigin = "id-smime-cti-ets-proofOfOrigin"; - public final static String OBJ_id_smime_cti_ets_proofOfOrigin = OBJ_id_smime_cti + ".1"; - - public final static int NID_id_smime_cti_ets_proofOfReceipt = 252; - public final static String SN_id_smime_cti_ets_proofOfReceipt = "id-smime-cti-ets-proofOfReceipt"; - public final static String OBJ_id_smime_cti_ets_proofOfReceipt = OBJ_id_smime_cti + ".2"; - - public final static int NID_id_smime_cti_ets_proofOfDelivery = 253; - public final static String SN_id_smime_cti_ets_proofOfDelivery = "id-smime-cti-ets-proofOfDelivery"; - public final static String OBJ_id_smime_cti_ets_proofOfDelivery = OBJ_id_smime_cti + ".3"; - - public final static int NID_id_smime_cti_ets_proofOfSender = 254; - public final static String SN_id_smime_cti_ets_proofOfSender = "id-smime-cti-ets-proofOfSender"; - public final static String OBJ_id_smime_cti_ets_proofOfSender = OBJ_id_smime_cti + ".4"; - - public final static int NID_id_smime_cti_ets_proofOfApproval = 255; - public final static String SN_id_smime_cti_ets_proofOfApproval = "id-smime-cti-ets-proofOfApproval"; - public final static String OBJ_id_smime_cti_ets_proofOfApproval = OBJ_id_smime_cti + ".5"; - - public final static int NID_id_smime_cti_ets_proofOfCreation = 256; - public final static String SN_id_smime_cti_ets_proofOfCreation = "id-smime-cti-ets-proofOfCreation"; - public final static String OBJ_id_smime_cti_ets_proofOfCreation = OBJ_id_smime_cti + ".6"; - - public final static int NID_md4 = 257; - public final static String SN_md4 = "MD4"; - public final static String LN_md4 = "md4"; - public final static String OBJ_md4 = OBJ_rsadsi + ".2.4"; - - public final static int NID_id_pkix_mod = 258; - public final static String SN_id_pkix_mod = "id-pkix-mod"; - public final static String OBJ_id_pkix_mod = OBJ_id_pkix + ".0"; - - public final static int NID_id_it = 260; - public final static String SN_id_it = "id-it"; - public final static String OBJ_id_it = OBJ_id_pkix + ".4"; - - public final static int NID_id_pkip = 261; - public final static String SN_id_pkip = "id-pkip"; - public final static String OBJ_id_pkip = OBJ_id_pkix + ".5"; - - public final static int NID_id_alg = 262; - public final static String SN_id_alg = "id-alg"; - public final static String OBJ_id_alg = OBJ_id_pkix + ".6"; - - public final static int NID_id_cmc = 263; - public final static String SN_id_cmc = "id-cmc"; - public final static String OBJ_id_cmc = OBJ_id_pkix + ".7"; - - public final static int NID_id_on = 264; - public final static String SN_id_on = "id-on"; - public final static String OBJ_id_on = OBJ_id_pkix + ".8"; - - public final static int NID_id_pda = 265; - public final static String SN_id_pda = "id-pda"; - public final static String OBJ_id_pda = OBJ_id_pkix + ".9"; - - public final static int NID_id_aca = 266; - public final static String SN_id_aca = "id-aca"; - public final static String OBJ_id_aca = OBJ_id_pkix + ".10"; - - public final static int NID_id_qcs = 267; - public final static String SN_id_qcs = "id-qcs"; - public final static String OBJ_id_qcs = OBJ_id_pkix + ".11"; - - public final static int NID_id_cct = 268; - public final static String SN_id_cct = "id-cct"; - public final static String OBJ_id_cct = OBJ_id_pkix + ".12"; - - public final static int NID_id_pkix1_explicit_88 = 269; - public final static String SN_id_pkix1_explicit_88 = "id-pkix1-explicit-88"; - public final static String OBJ_id_pkix1_explicit_88 = OBJ_id_pkix_mod + ".1"; - - public final static int NID_id_pkix1_implicit_88 = 270; - public final static String SN_id_pkix1_implicit_88 = "id-pkix1-implicit-88"; - public final static String OBJ_id_pkix1_implicit_88 = OBJ_id_pkix_mod + ".2"; - - public final static int NID_id_pkix1_explicit_93 = 271; - public final static String SN_id_pkix1_explicit_93 = "id-pkix1-explicit-93"; - public final static String OBJ_id_pkix1_explicit_93 = OBJ_id_pkix_mod + ".3"; - - public final static int NID_id_pkix1_implicit_93 = 272; - public final static String SN_id_pkix1_implicit_93 = "id-pkix1-implicit-93"; - public final static String OBJ_id_pkix1_implicit_93 = OBJ_id_pkix_mod + ".4"; - - public final static int NID_id_mod_crmf = 273; - public final static String SN_id_mod_crmf = "id-mod-crmf"; - public final static String OBJ_id_mod_crmf = OBJ_id_pkix_mod + ".5"; - - public final static int NID_id_mod_cmc = 274; - public final static String SN_id_mod_cmc = "id-mod-cmc"; - public final static String OBJ_id_mod_cmc = OBJ_id_pkix_mod + ".6"; - - public final static int NID_id_mod_kea_profile_88 = 275; - public final static String SN_id_mod_kea_profile_88 = "id-mod-kea-profile-88"; - public final static String OBJ_id_mod_kea_profile_88 = OBJ_id_pkix_mod + ".7"; - - public final static int NID_id_mod_kea_profile_93 = 276; - public final static String SN_id_mod_kea_profile_93 = "id-mod-kea-profile-93"; - public final static String OBJ_id_mod_kea_profile_93 = OBJ_id_pkix_mod + ".8"; - - public final static int NID_id_mod_cmp = 277; - public final static String SN_id_mod_cmp = "id-mod-cmp"; - public final static String OBJ_id_mod_cmp = OBJ_id_pkix_mod + ".9"; - - public final static int NID_id_mod_qualified_cert_88 = 278; - public final static String SN_id_mod_qualified_cert_88 = "id-mod-qualified-cert-88"; - public final static String OBJ_id_mod_qualified_cert_88 = OBJ_id_pkix_mod + ".10"; - - public final static int NID_id_mod_qualified_cert_93 = 279; - public final static String SN_id_mod_qualified_cert_93 = "id-mod-qualified-cert-93"; - public final static String OBJ_id_mod_qualified_cert_93 = OBJ_id_pkix_mod + ".11"; - - public final static int NID_id_mod_attribute_cert = 280; - public final static String SN_id_mod_attribute_cert = "id-mod-attribute-cert"; - public final static String OBJ_id_mod_attribute_cert = OBJ_id_pkix_mod + ".12"; - - public final static int NID_id_mod_timestamp_protocol = 281; - public final static String SN_id_mod_timestamp_protocol = "id-mod-timestamp-protocol"; - public final static String OBJ_id_mod_timestamp_protocol = OBJ_id_pkix_mod + ".13"; - - public final static int NID_id_mod_ocsp = 282; - public final static String SN_id_mod_ocsp = "id-mod-ocsp"; - public final static String OBJ_id_mod_ocsp = OBJ_id_pkix_mod + ".14"; - - public final static int NID_id_mod_dvcs = 283; - public final static String SN_id_mod_dvcs = "id-mod-dvcs"; - public final static String OBJ_id_mod_dvcs = OBJ_id_pkix_mod + ".15"; - - public final static int NID_id_mod_cmp2000 = 284; - public final static String SN_id_mod_cmp2000 = "id-mod-cmp2000"; - public final static String OBJ_id_mod_cmp2000 = OBJ_id_pkix_mod + ".16"; - - public final static int NID_biometricInfo = 285; - public final static String SN_biometricInfo = "biometricInfo"; - public final static String LN_biometricInfo = "Biometric Info"; - public final static String OBJ_biometricInfo = OBJ_id_pe + ".2"; - - public final static int NID_qcStatements = 286; - public final static String SN_qcStatements = "qcStatements"; - public final static String OBJ_qcStatements = OBJ_id_pe + ".3"; - - public final static int NID_ac_auditEntity = 287; - public final static String SN_ac_auditEntity = "ac-auditEntity"; - public final static String OBJ_ac_auditEntity = OBJ_id_pe + ".4"; - - public final static int NID_ac_targeting = 288; - public final static String SN_ac_targeting = "ac-targeting"; - public final static String OBJ_ac_targeting = OBJ_id_pe + ".5"; - - public final static int NID_aaControls = 289; - public final static String SN_aaControls = "aaControls"; - public final static String OBJ_aaControls = OBJ_id_pe + ".6"; - - public final static int NID_sbgp_ipAddrBlock = 290; - public final static String SN_sbgp_ipAddrBlock = "sbgp-ipAddrBlock"; - public final static String OBJ_sbgp_ipAddrBlock = OBJ_id_pe + ".7"; - - public final static int NID_sbgp_autonomousSysNum = 291; - public final static String SN_sbgp_autonomousSysNum = "sbgp-autonomousSysNum"; - public final static String OBJ_sbgp_autonomousSysNum = OBJ_id_pe + ".8"; - - public final static int NID_sbgp_routerIdentifier = 292; - public final static String SN_sbgp_routerIdentifier = "sbgp-routerIdentifier"; - public final static String OBJ_sbgp_routerIdentifier = OBJ_id_pe + ".9"; - - public final static int NID_textNotice = 293; - public final static String SN_textNotice = "textNotice"; - public final static String OBJ_textNotice = OBJ_id_qt + ".3"; - - public final static int NID_ipsecEndSystem = 294; - public final static String SN_ipsecEndSystem = "ipsecEndSystem"; - public final static String LN_ipsecEndSystem = "IPSec End System"; - public final static String OBJ_ipsecEndSystem = OBJ_id_kp + ".5"; - - public final static int NID_ipsecTunnel = 295; - public final static String SN_ipsecTunnel = "ipsecTunnel"; - public final static String LN_ipsecTunnel = "IPSec Tunnel"; - public final static String OBJ_ipsecTunnel = OBJ_id_kp + ".6"; - - public final static int NID_ipsecUser = 296; - public final static String SN_ipsecUser = "ipsecUser"; - public final static String LN_ipsecUser = "IPSec User"; - public final static String OBJ_ipsecUser = OBJ_id_kp + ".7"; - - public final static int NID_dvcs = 297; - public final static String SN_dvcs = "DVCS"; - public final static String LN_dvcs = "dvcs"; - public final static String OBJ_dvcs = OBJ_id_kp + ".10"; - - public final static int NID_id_it_caProtEncCert = 298; - public final static String SN_id_it_caProtEncCert = "id-it-caProtEncCert"; - public final static String OBJ_id_it_caProtEncCert = OBJ_id_it + ".1"; - - public final static int NID_id_it_signKeyPairTypes = 299; - public final static String SN_id_it_signKeyPairTypes = "id-it-signKeyPairTypes"; - public final static String OBJ_id_it_signKeyPairTypes = OBJ_id_it + ".2"; - - public final static int NID_id_it_encKeyPairTypes = 300; - public final static String SN_id_it_encKeyPairTypes = "id-it-encKeyPairTypes"; - public final static String OBJ_id_it_encKeyPairTypes = OBJ_id_it + ".3"; - - public final static int NID_id_it_preferredSymmAlg = 301; - public final static String SN_id_it_preferredSymmAlg = "id-it-preferredSymmAlg"; - public final static String OBJ_id_it_preferredSymmAlg = OBJ_id_it + ".4"; - - public final static int NID_id_it_caKeyUpdateInfo = 302; - public final static String SN_id_it_caKeyUpdateInfo = "id-it-caKeyUpdateInfo"; - public final static String OBJ_id_it_caKeyUpdateInfo = OBJ_id_it + ".5"; - - public final static int NID_id_it_currentCRL = 303; - public final static String SN_id_it_currentCRL = "id-it-currentCRL"; - public final static String OBJ_id_it_currentCRL = OBJ_id_it + ".6"; - - public final static int NID_id_it_unsupportedOIDs = 304; - public final static String SN_id_it_unsupportedOIDs = "id-it-unsupportedOIDs"; - public final static String OBJ_id_it_unsupportedOIDs = OBJ_id_it + ".7"; - - public final static int NID_id_it_subscriptionRequest = 305; - public final static String SN_id_it_subscriptionRequest = "id-it-subscriptionRequest"; - public final static String OBJ_id_it_subscriptionRequest = OBJ_id_it + ".8"; - - public final static int NID_id_it_subscriptionResponse = 306; - public final static String SN_id_it_subscriptionResponse = "id-it-subscriptionResponse"; - public final static String OBJ_id_it_subscriptionResponse = OBJ_id_it + ".9"; - - public final static int NID_id_it_keyPairParamReq = 307; - public final static String SN_id_it_keyPairParamReq = "id-it-keyPairParamReq"; - public final static String OBJ_id_it_keyPairParamReq = OBJ_id_it + ".10"; - - public final static int NID_id_it_keyPairParamRep = 308; - public final static String SN_id_it_keyPairParamRep = "id-it-keyPairParamRep"; - public final static String OBJ_id_it_keyPairParamRep = OBJ_id_it + ".11"; - - public final static int NID_id_it_revPassphrase = 309; - public final static String SN_id_it_revPassphrase = "id-it-revPassphrase"; - public final static String OBJ_id_it_revPassphrase = OBJ_id_it + ".12"; - - public final static int NID_id_it_implicitConfirm = 310; - public final static String SN_id_it_implicitConfirm = "id-it-implicitConfirm"; - public final static String OBJ_id_it_implicitConfirm = OBJ_id_it + ".13"; - - public final static int NID_id_it_confirmWaitTime = 311; - public final static String SN_id_it_confirmWaitTime = "id-it-confirmWaitTime"; - public final static String OBJ_id_it_confirmWaitTime = OBJ_id_it + ".14"; - - public final static int NID_id_it_origPKIMessage = 312; - public final static String SN_id_it_origPKIMessage = "id-it-origPKIMessage"; - public final static String OBJ_id_it_origPKIMessage = OBJ_id_it + ".15"; - - public final static int NID_id_regCtrl = 313; - public final static String SN_id_regCtrl = "id-regCtrl"; - public final static String OBJ_id_regCtrl = OBJ_id_pkip + ".1"; - - public final static int NID_id_regInfo = 314; - public final static String SN_id_regInfo = "id-regInfo"; - public final static String OBJ_id_regInfo = OBJ_id_pkip + ".2"; - - public final static int NID_id_regCtrl_regToken = 315; - public final static String SN_id_regCtrl_regToken = "id-regCtrl-regToken"; - public final static String OBJ_id_regCtrl_regToken = OBJ_id_regCtrl + ".1"; - - public final static int NID_id_regCtrl_authenticator = 316; - public final static String SN_id_regCtrl_authenticator = "id-regCtrl-authenticator"; - public final static String OBJ_id_regCtrl_authenticator = OBJ_id_regCtrl + ".2"; - - public final static int NID_id_regCtrl_pkiPublicationInfo = 317; - public final static String SN_id_regCtrl_pkiPublicationInfo = "id-regCtrl-pkiPublicationInfo"; - public final static String OBJ_id_regCtrl_pkiPublicationInfo = OBJ_id_regCtrl + ".3"; - - public final static int NID_id_regCtrl_pkiArchiveOptions = 318; - public final static String SN_id_regCtrl_pkiArchiveOptions = "id-regCtrl-pkiArchiveOptions"; - public final static String OBJ_id_regCtrl_pkiArchiveOptions = OBJ_id_regCtrl + ".4"; - - public final static int NID_id_regCtrl_oldCertID = 319; - public final static String SN_id_regCtrl_oldCertID = "id-regCtrl-oldCertID"; - public final static String OBJ_id_regCtrl_oldCertID = OBJ_id_regCtrl + ".5"; - - public final static int NID_id_regCtrl_protocolEncrKey = 320; - public final static String SN_id_regCtrl_protocolEncrKey = "id-regCtrl-protocolEncrKey"; - public final static String OBJ_id_regCtrl_protocolEncrKey = OBJ_id_regCtrl + ".6"; - - public final static int NID_id_regInfo_utf8Pairs = 321; - public final static String SN_id_regInfo_utf8Pairs = "id-regInfo-utf8Pairs"; - public final static String OBJ_id_regInfo_utf8Pairs = OBJ_id_regInfo + ".1"; - - public final static int NID_id_regInfo_certReq = 322; - public final static String SN_id_regInfo_certReq = "id-regInfo-certReq"; - public final static String OBJ_id_regInfo_certReq = OBJ_id_regInfo + ".2"; - - public final static int NID_id_alg_des40 = 323; - public final static String SN_id_alg_des40 = "id-alg-des40"; - public final static String OBJ_id_alg_des40 = OBJ_id_alg + ".1"; - - public final static int NID_id_alg_noSignature = 324; - public final static String SN_id_alg_noSignature = "id-alg-noSignature"; - public final static String OBJ_id_alg_noSignature = OBJ_id_alg + ".2"; - - public final static int NID_id_alg_dh_sig_hmac_sha1 = 325; - public final static String SN_id_alg_dh_sig_hmac_sha1 = "id-alg-dh-sig-hmac-sha1"; - public final static String OBJ_id_alg_dh_sig_hmac_sha1 = OBJ_id_alg + ".3"; - - public final static int NID_id_alg_dh_pop = 326; - public final static String SN_id_alg_dh_pop = "id-alg-dh-pop"; - public final static String OBJ_id_alg_dh_pop = OBJ_id_alg + ".4"; - - public final static int NID_id_cmc_statusInfo = 327; - public final static String SN_id_cmc_statusInfo = "id-cmc-statusInfo"; - public final static String OBJ_id_cmc_statusInfo = OBJ_id_cmc + ".1"; - - public final static int NID_id_cmc_identification = 328; - public final static String SN_id_cmc_identification = "id-cmc-identification"; - public final static String OBJ_id_cmc_identification = OBJ_id_cmc + ".2"; - - public final static int NID_id_cmc_identityProof = 329; - public final static String SN_id_cmc_identityProof = "id-cmc-identityProof"; - public final static String OBJ_id_cmc_identityProof = OBJ_id_cmc + ".3"; - - public final static int NID_id_cmc_dataReturn = 330; - public final static String SN_id_cmc_dataReturn = "id-cmc-dataReturn"; - public final static String OBJ_id_cmc_dataReturn = OBJ_id_cmc + ".4"; - - public final static int NID_id_cmc_transactionId = 331; - public final static String SN_id_cmc_transactionId = "id-cmc-transactionId"; - public final static String OBJ_id_cmc_transactionId = OBJ_id_cmc + ".5"; - - public final static int NID_id_cmc_senderNonce = 332; - public final static String SN_id_cmc_senderNonce = "id-cmc-senderNonce"; - public final static String OBJ_id_cmc_senderNonce = OBJ_id_cmc + ".6"; - - public final static int NID_id_cmc_recipientNonce = 333; - public final static String SN_id_cmc_recipientNonce = "id-cmc-recipientNonce"; - public final static String OBJ_id_cmc_recipientNonce = OBJ_id_cmc + ".7"; - - public final static int NID_id_cmc_addExtensions = 334; - public final static String SN_id_cmc_addExtensions = "id-cmc-addExtensions"; - public final static String OBJ_id_cmc_addExtensions = OBJ_id_cmc + ".8"; - - public final static int NID_id_cmc_encryptedPOP = 335; - public final static String SN_id_cmc_encryptedPOP = "id-cmc-encryptedPOP"; - public final static String OBJ_id_cmc_encryptedPOP = OBJ_id_cmc + ".9"; - - public final static int NID_id_cmc_decryptedPOP = 336; - public final static String SN_id_cmc_decryptedPOP = "id-cmc-decryptedPOP"; - public final static String OBJ_id_cmc_decryptedPOP = OBJ_id_cmc + ".10"; - - public final static int NID_id_cmc_lraPOPWitness = 337; - public final static String SN_id_cmc_lraPOPWitness = "id-cmc-lraPOPWitness"; - public final static String OBJ_id_cmc_lraPOPWitness = OBJ_id_cmc + ".11"; - - public final static int NID_id_cmc_getCert = 338; - public final static String SN_id_cmc_getCert = "id-cmc-getCert"; - public final static String OBJ_id_cmc_getCert = OBJ_id_cmc + ".15"; - - public final static int NID_id_cmc_getCRL = 339; - public final static String SN_id_cmc_getCRL = "id-cmc-getCRL"; - public final static String OBJ_id_cmc_getCRL = OBJ_id_cmc + ".16"; - - public final static int NID_id_cmc_revokeRequest = 340; - public final static String SN_id_cmc_revokeRequest = "id-cmc-revokeRequest"; - public final static String OBJ_id_cmc_revokeRequest = OBJ_id_cmc + ".17"; - - public final static int NID_id_cmc_regInfo = 341; - public final static String SN_id_cmc_regInfo = "id-cmc-regInfo"; - public final static String OBJ_id_cmc_regInfo = OBJ_id_cmc + ".18"; - - public final static int NID_id_cmc_responseInfo = 342; - public final static String SN_id_cmc_responseInfo = "id-cmc-responseInfo"; - public final static String OBJ_id_cmc_responseInfo = OBJ_id_cmc + ".19"; - - public final static int NID_id_cmc_queryPending = 343; - public final static String SN_id_cmc_queryPending = "id-cmc-queryPending"; - public final static String OBJ_id_cmc_queryPending = OBJ_id_cmc + ".21"; - - public final static int NID_id_cmc_popLinkRandom = 344; - public final static String SN_id_cmc_popLinkRandom = "id-cmc-popLinkRandom"; - public final static String OBJ_id_cmc_popLinkRandom = OBJ_id_cmc + ".22"; - - public final static int NID_id_cmc_popLinkWitness = 345; - public final static String SN_id_cmc_popLinkWitness = "id-cmc-popLinkWitness"; - public final static String OBJ_id_cmc_popLinkWitness = OBJ_id_cmc + ".23"; - - public final static int NID_id_cmc_confirmCertAcceptance = 346; - public final static String SN_id_cmc_confirmCertAcceptance = "id-cmc-confirmCertAcceptance"; - public final static String OBJ_id_cmc_confirmCertAcceptance = OBJ_id_cmc + ".24"; - - public final static int NID_id_on_personalData = 347; - public final static String SN_id_on_personalData = "id-on-personalData"; - public final static String OBJ_id_on_personalData = OBJ_id_on + ".1"; - - public final static int NID_id_pda_dateOfBirth = 348; - public final static String SN_id_pda_dateOfBirth = "id-pda-dateOfBirth"; - public final static String OBJ_id_pda_dateOfBirth = OBJ_id_pda + ".1"; - - public final static int NID_id_pda_placeOfBirth = 349; - public final static String SN_id_pda_placeOfBirth = "id-pda-placeOfBirth"; - public final static String OBJ_id_pda_placeOfBirth = OBJ_id_pda + ".2"; - - public final static int NID_id_pda_gender = 351; - public final static String SN_id_pda_gender = "id-pda-gender"; - public final static String OBJ_id_pda_gender = OBJ_id_pda + ".3"; - - public final static int NID_id_pda_countryOfCitizenship = 352; - public final static String SN_id_pda_countryOfCitizenship = "id-pda-countryOfCitizenship"; - public final static String OBJ_id_pda_countryOfCitizenship = OBJ_id_pda + ".4"; - - public final static int NID_id_pda_countryOfResidence = 353; - public final static String SN_id_pda_countryOfResidence = "id-pda-countryOfResidence"; - public final static String OBJ_id_pda_countryOfResidence = OBJ_id_pda + ".5"; - - public final static int NID_id_aca_authenticationInfo = 354; - public final static String SN_id_aca_authenticationInfo = "id-aca-authenticationInfo"; - public final static String OBJ_id_aca_authenticationInfo = OBJ_id_aca + ".1"; - - public final static int NID_id_aca_accessIdentity = 355; - public final static String SN_id_aca_accessIdentity = "id-aca-accessIdentity"; - public final static String OBJ_id_aca_accessIdentity = OBJ_id_aca + ".2"; - - public final static int NID_id_aca_chargingIdentity = 356; - public final static String SN_id_aca_chargingIdentity = "id-aca-chargingIdentity"; - public final static String OBJ_id_aca_chargingIdentity = OBJ_id_aca + ".3"; - - public final static int NID_id_aca_group = 357; - public final static String SN_id_aca_group = "id-aca-group"; - public final static String OBJ_id_aca_group = OBJ_id_aca + ".4"; - - public final static int NID_id_aca_role = 358; - public final static String SN_id_aca_role = "id-aca-role"; - public final static String OBJ_id_aca_role = OBJ_id_aca + ".5"; - - public final static int NID_id_qcs_pkixQCSyntax_v1 = 359; - public final static String SN_id_qcs_pkixQCSyntax_v1 = "id-qcs-pkixQCSyntax-v1"; - public final static String OBJ_id_qcs_pkixQCSyntax_v1 = OBJ_id_qcs + ".1"; - - public final static int NID_id_cct_crs = 360; - public final static String SN_id_cct_crs = "id-cct-crs"; - public final static String OBJ_id_cct_crs = OBJ_id_cct + ".1"; - - public final static int NID_id_cct_PKIData = 361; - public final static String SN_id_cct_PKIData = "id-cct-PKIData"; - public final static String OBJ_id_cct_PKIData = OBJ_id_cct + ".2"; - - public final static int NID_id_cct_PKIResponse = 362; - public final static String SN_id_cct_PKIResponse = "id-cct-PKIResponse"; - public final static String OBJ_id_cct_PKIResponse = OBJ_id_cct + ".3"; - - public final static int NID_ad_timeStamping = 363; - public final static String SN_ad_timeStamping = "ad_timestamping"; - public final static String LN_ad_timeStamping = "AD Time Stamping"; - public final static String OBJ_ad_timeStamping = OBJ_id_ad + ".3"; - - public final static int NID_ad_dvcs = 364; - public final static String SN_ad_dvcs = "AD_DVCS"; - public final static String LN_ad_dvcs = "ad dvcs"; - public final static String OBJ_ad_dvcs = OBJ_id_ad + ".4"; - - public final static int NID_id_pkix_OCSP_basic = 365; - public final static String SN_id_pkix_OCSP_basic = "basicOCSPResponse"; - public final static String LN_id_pkix_OCSP_basic = "Basic OCSP Response"; - public final static String OBJ_id_pkix_OCSP_basic = OBJ_id_pkix_OCSP + ".1"; - - public final static int NID_id_pkix_OCSP_Nonce = 366; - public final static String SN_id_pkix_OCSP_Nonce = "Nonce"; - public final static String LN_id_pkix_OCSP_Nonce = "OCSP Nonce"; - public final static String OBJ_id_pkix_OCSP_Nonce = OBJ_id_pkix_OCSP + ".2"; - - public final static int NID_id_pkix_OCSP_CrlID = 367; - public final static String SN_id_pkix_OCSP_CrlID = "CrlID"; - public final static String LN_id_pkix_OCSP_CrlID = "OCSP CRL ID"; - public final static String OBJ_id_pkix_OCSP_CrlID = OBJ_id_pkix_OCSP + ".3"; - - public final static int NID_id_pkix_OCSP_acceptableResponses = 368; - public final static String SN_id_pkix_OCSP_acceptableResponses = "acceptableResponses"; - public final static String LN_id_pkix_OCSP_acceptableResponses = "Acceptable OCSP Responses"; - public final static String OBJ_id_pkix_OCSP_acceptableResponses = OBJ_id_pkix_OCSP + ".4"; - - public final static int NID_id_pkix_OCSP_noCheck = 369; - public final static String SN_id_pkix_OCSP_noCheck = "noCheck"; - public final static String LN_id_pkix_OCSP_noCheck = "OCSP No Check"; - public final static String OBJ_id_pkix_OCSP_noCheck = OBJ_id_pkix_OCSP + ".5"; - - public final static int NID_id_pkix_OCSP_archiveCutoff = 370; - public final static String SN_id_pkix_OCSP_archiveCutoff = "archiveCutoff"; - public final static String LN_id_pkix_OCSP_archiveCutoff = "OCSP Archive Cutoff"; - public final static String OBJ_id_pkix_OCSP_archiveCutoff = OBJ_id_pkix_OCSP + ".6"; - - public final static int NID_id_pkix_OCSP_serviceLocator = 371; - public final static String SN_id_pkix_OCSP_serviceLocator = "serviceLocator"; - public final static String LN_id_pkix_OCSP_serviceLocator = "OCSP Service Locator"; - public final static String OBJ_id_pkix_OCSP_serviceLocator = OBJ_id_pkix_OCSP + ".7"; - - public final static int NID_id_pkix_OCSP_extendedStatus = 372; - public final static String SN_id_pkix_OCSP_extendedStatus = "extendedStatus"; - public final static String LN_id_pkix_OCSP_extendedStatus = "Extended OCSP Status"; - public final static String OBJ_id_pkix_OCSP_extendedStatus = OBJ_id_pkix_OCSP + ".8"; - - public final static int NID_id_pkix_OCSP_valid = 373; - public final static String SN_id_pkix_OCSP_valid = "valid"; - public final static String OBJ_id_pkix_OCSP_valid = OBJ_id_pkix_OCSP + ".9"; - - public final static int NID_id_pkix_OCSP_path = 374; - public final static String SN_id_pkix_OCSP_path = "path"; - public final static String OBJ_id_pkix_OCSP_path = OBJ_id_pkix_OCSP + ".10"; - - public final static int NID_id_pkix_OCSP_trustRoot = 375; - public final static String SN_id_pkix_OCSP_trustRoot = "trustRoot"; - public final static String LN_id_pkix_OCSP_trustRoot = "Trust Root"; - public final static String OBJ_id_pkix_OCSP_trustRoot = OBJ_id_pkix_OCSP + ".11"; - - public final static int NID_rsaSignature = 377; - public final static String SN_rsaSignature = "rsaSignature"; - public final static String OBJ_rsaSignature = OBJ_algorithm + ".11"; - - public final static int NID_Directory = 382; - public final static String SN_Directory = "directory"; - public final static String LN_Directory = "Directory"; - public final static String OBJ_Directory = OBJ_internet + ".1"; - - public final static int NID_Management = 383; - public final static String SN_Management = "mgmt"; - public final static String LN_Management = "Management"; - public final static String OBJ_Management = OBJ_internet + ".2"; - - public final static int NID_Experimental = 384; - public final static String SN_Experimental = "experimental"; - public final static String LN_Experimental = "Experimental"; - public final static String OBJ_Experimental = OBJ_internet + ".3"; - - public final static int NID_Private = 385; - public final static String SN_Private = "private"; - public final static String LN_Private = "Private"; - public final static String OBJ_Private = OBJ_internet + ".4"; - - public final static int NID_Security = 386; - public final static String SN_Security = "security"; - public final static String LN_Security = "Security"; - public final static String OBJ_Security = OBJ_internet + ".5"; - - public final static int NID_SNMPv2 = 387; - public final static String SN_SNMPv2 = "snmpv2"; - public final static String LN_SNMPv2 = "SNMPv2"; - public final static String OBJ_SNMPv2 = OBJ_internet + ".6"; - - public final static int NID_Mail = 388; - public final static String LN_Mail = "Mail"; - public final static String OBJ_Mail = OBJ_internet + ".7"; - - public final static int NID_Enterprises = 389; - public final static String SN_Enterprises = "enterprises"; - public final static String LN_Enterprises = "Enterprises"; - public final static String OBJ_Enterprises = OBJ_Private + ".1"; - - public final static int NID_dcObject = 390; - public final static String SN_dcObject = "dcobject"; - public final static String LN_dcObject = "dcObject"; - public final static String OBJ_dcObject = OBJ_Enterprises + ".1466.344"; - - public final static int NID_itu_t = 645; - public final static String SN_itu_t = "ITU-T"; - public final static String LN_itu_t = "itu-t"; - public final static String OBJ_itu_t = "0"; - - public final static int NID_data = 434; - public final static String SN_data = "data"; - public final static String OBJ_data = OBJ_itu_t + ".9"; - - public final static int NID_pss = 435; - public final static String SN_pss = "pss"; - public final static String OBJ_pss = OBJ_data + ".2342"; - - public final static int NID_ucl = 436; - public final static String SN_ucl = "ucl"; - public final static String OBJ_ucl = OBJ_pss + ".19200300"; - - public final static int NID_pilot = 437; - public final static String SN_pilot = "pilot"; - public final static String OBJ_pilot = OBJ_ucl + ".100"; - - public final static int NID_pilotAttributeType = 438; - public final static String LN_pilotAttributeType = "pilotAttributeType"; - public final static String OBJ_pilotAttributeType = OBJ_pilot + ".1"; - - public final static int NID_domainComponent = 391; - public final static String SN_domainComponent = "DC"; - public final static String LN_domainComponent = "domainComponent"; - public final static String OBJ_domainComponent = OBJ_pilotAttributeType + ".25"; - - public final static int NID_pilotObjectClass = 440; - public final static String LN_pilotObjectClass = "pilotObjectClass"; - public final static String OBJ_pilotObjectClass = OBJ_pilot + ".4"; - - public final static int NID_Domain = 392; - public final static String SN_Domain = "domain"; - public final static String LN_Domain = "Domain"; - public final static String OBJ_Domain = OBJ_pilotObjectClass + ".13"; - - public final static int NID_joint_iso_ccitt = 393; - public final static String OBJ_joint_iso_ccitt = "OBJ_joint_iso_itu_t"; - - public final static int NID_selected_attribute_types = 394; - public final static String SN_selected_attribute_types = "selected-attribute-types"; - public final static String LN_selected_attribute_types = "Selected Attribute Types"; - public final static String OBJ_selected_attribute_types = OBJ_joint_iso_itu_t + ".5.1.5"; - - public final static int NID_clearance = 395; - public final static String SN_clearance = "clearance"; - public final static String OBJ_clearance = OBJ_selected_attribute_types + ".55"; - - public final static int NID_md4WithRSAEncryption = 396; - public final static String SN_md4WithRSAEncryption = "RSA-MD4"; - public final static String LN_md4WithRSAEncryption = "md4WithRSAEncryption"; - public final static String OBJ_md4WithRSAEncryption = OBJ_pkcs1 + ".3"; - - public final static int NID_ac_proxying = 397; - public final static String SN_ac_proxying = "ac-proxying"; - public final static String OBJ_ac_proxying = OBJ_id_pe + ".10"; - - public final static int NID_sinfo_access = 398; - public final static String SN_sinfo_access = "subjectInfoAccess"; - public final static String LN_sinfo_access = "Subject Information Access"; - public final static String OBJ_sinfo_access = OBJ_id_pe + ".11"; - - public final static int NID_id_aca_encAttrs = 399; - public final static String SN_id_aca_encAttrs = "id-aca-encAttrs"; - public final static String OBJ_id_aca_encAttrs = OBJ_id_aca + ".6"; - - public final static int NID_role = 400; - public final static String SN_role = "role"; - public final static String LN_role = "role"; - public final static String OBJ_role = OBJ_X509 + ".72"; - - public final static int NID_policy_constraints = 401; - public final static String SN_policy_constraints = "policyConstraints"; - public final static String LN_policy_constraints = "X509v3 Policy Constraints"; - public final static String OBJ_policy_constraints = OBJ_id_ce + ".36"; - - public final static int NID_target_information = 402; - public final static String SN_target_information = "targetInformation"; - public final static String LN_target_information = "X509v3 AC Targeting"; - public final static String OBJ_target_information = OBJ_id_ce + ".55"; - - public final static int NID_no_rev_avail = 403; - public final static String SN_no_rev_avail = "noRevAvail"; - public final static String LN_no_rev_avail = "X509v3 No Revocation Available"; - public final static String OBJ_no_rev_avail = OBJ_id_ce + ".56"; - - public final static int NID_ccitt = 404; - public final static String OBJ_ccitt = "OBJ_itu_t"; - - public final static int NID_X9_62_prime_field = 406; - public final static String SN_X9_62_prime_field = "prime-field"; - public final static String OBJ_X9_62_prime_field = OBJ_X9_62_id_fieldType + ".1"; - - public final static int NID_X9_62_characteristic_two_field = 407; - public final static String SN_X9_62_characteristic_two_field = "characteristic-two-field"; - public final static String OBJ_X9_62_characteristic_two_field = OBJ_X9_62_id_fieldType + ".2"; - - public final static int NID_X9_62_id_ecPublicKey = 408; - public final static String SN_X9_62_id_ecPublicKey = "id-ecPublicKey"; - public final static String OBJ_X9_62_id_ecPublicKey = OBJ_X9_62_id_publicKeyType + ".1"; - - public final static int NID_X9_62_prime192v1 = 409; - public final static String SN_X9_62_prime192v1 = "prime192v1"; - public final static String OBJ_X9_62_prime192v1 = OBJ_X9_62_primeCurve + ".1"; - - public final static int NID_X9_62_prime192v2 = 410; - public final static String SN_X9_62_prime192v2 = "prime192v2"; - public final static String OBJ_X9_62_prime192v2 = OBJ_X9_62_primeCurve + ".2"; - - public final static int NID_X9_62_prime192v3 = 411; - public final static String SN_X9_62_prime192v3 = "prime192v3"; - public final static String OBJ_X9_62_prime192v3 = OBJ_X9_62_primeCurve + ".3"; - - public final static int NID_X9_62_prime239v1 = 412; - public final static String SN_X9_62_prime239v1 = "prime239v1"; - public final static String OBJ_X9_62_prime239v1 = OBJ_X9_62_primeCurve + ".4"; - - public final static int NID_X9_62_prime239v2 = 413; - public final static String SN_X9_62_prime239v2 = "prime239v2"; - public final static String OBJ_X9_62_prime239v2 = OBJ_X9_62_primeCurve + ".5"; - - public final static int NID_X9_62_prime239v3 = 414; - public final static String SN_X9_62_prime239v3 = "prime239v3"; - public final static String OBJ_X9_62_prime239v3 = OBJ_X9_62_primeCurve + ".6"; - - public final static int NID_X9_62_prime256v1 = 415; - public final static String SN_X9_62_prime256v1 = "prime256v1"; - public final static String OBJ_X9_62_prime256v1 = OBJ_X9_62_primeCurve + ".7"; - - public final static int NID_ecdsa_with_SHA1 = 416; - public final static String SN_ecdsa_with_SHA1 = "ecdsa-with-SHA1"; - public final static String OBJ_ecdsa_with_SHA1 = OBJ_X9_62_id_ecSigType + ".1"; - - public final static int NID_ms_csp_name = 417; - public final static String SN_ms_csp_name = "CSPName"; - public final static String LN_ms_csp_name = "Microsoft CSP Name"; - public final static String OBJ_ms_csp_name = "1.3.6.1.4.1.311.17.1"; - - public final static int NID_aes_128_ecb = 418; - public final static String SN_aes_128_ecb = "AES-128-ECB"; - public final static String LN_aes_128_ecb = "aes-128-ecb"; - public final static String OBJ_aes_128_ecb = OBJ_aes + ".1"; - - public final static int NID_aes_128_cbc = 419; - public final static String SN_aes_128_cbc = "AES-128-CBC"; - public final static String LN_aes_128_cbc = "aes-128-cbc"; - public final static String OBJ_aes_128_cbc = OBJ_aes + ".2"; - - public final static int NID_aes_128_ofb128 = 420; - public final static String SN_aes_128_ofb128 = "AES-128-OFB"; - public final static String LN_aes_128_ofb128 = "aes-128-ofb"; - public final static String OBJ_aes_128_ofb128 = OBJ_aes + ".3"; - - public final static int NID_aes_128_cfb128 = 421; - public final static String SN_aes_128_cfb128 = "AES-128-CFB"; - public final static String LN_aes_128_cfb128 = "aes-128-cfb"; - public final static String OBJ_aes_128_cfb128 = OBJ_aes + ".4"; - - public final static int NID_aes_192_ecb = 422; - public final static String SN_aes_192_ecb = "AES-192-ECB"; - public final static String LN_aes_192_ecb = "aes-192-ecb"; - public final static String OBJ_aes_192_ecb = OBJ_aes + ".21"; - - public final static int NID_aes_192_cbc = 423; - public final static String SN_aes_192_cbc = "AES-192-CBC"; - public final static String LN_aes_192_cbc = "aes-192-cbc"; - public final static String OBJ_aes_192_cbc = OBJ_aes + ".22"; - - public final static int NID_aes_192_ofb128 = 424; - public final static String SN_aes_192_ofb128 = "AES-192-OFB"; - public final static String LN_aes_192_ofb128 = "aes-192-ofb"; - public final static String OBJ_aes_192_ofb128 = OBJ_aes + ".23"; - - public final static int NID_aes_192_cfb128 = 425; - public final static String SN_aes_192_cfb128 = "AES-192-CFB"; - public final static String LN_aes_192_cfb128 = "aes-192-cfb"; - public final static String OBJ_aes_192_cfb128 = OBJ_aes + ".24"; - - public final static int NID_aes_256_ecb = 426; - public final static String SN_aes_256_ecb = "AES-256-ECB"; - public final static String LN_aes_256_ecb = "aes-256-ecb"; - public final static String OBJ_aes_256_ecb = OBJ_aes + ".41"; - - public final static int NID_aes_256_cbc = 427; - public final static String SN_aes_256_cbc = "AES-256-CBC"; - public final static String LN_aes_256_cbc = "aes-256-cbc"; - public final static String OBJ_aes_256_cbc = OBJ_aes + ".42"; - - public final static int NID_aes_256_ofb128 = 428; - public final static String SN_aes_256_ofb128 = "AES-256-OFB"; - public final static String LN_aes_256_ofb128 = "aes-256-ofb"; - public final static String OBJ_aes_256_ofb128 = OBJ_aes + ".43"; - - public final static int NID_aes_256_cfb128 = 429; - public final static String SN_aes_256_cfb128 = "AES-256-CFB"; - public final static String LN_aes_256_cfb128 = "aes-256-cfb"; - public final static String OBJ_aes_256_cfb128 = OBJ_aes + ".44"; - - public final static int NID_hold_instruction_code = 430; - public final static String SN_hold_instruction_code = "holdInstructionCode"; - public final static String LN_hold_instruction_code = "Hold Instruction Code"; - public final static String OBJ_hold_instruction_code = OBJ_id_ce + ".23"; - - public final static int NID_hold_instruction_none = 431; - public final static String SN_hold_instruction_none = "holdInstructionNone"; - public final static String LN_hold_instruction_none = "Hold Instruction None"; - public final static String OBJ_hold_instruction_none = OBJ_holdInstruction + ".1"; - - public final static int NID_hold_instruction_call_issuer = 432; - public final static String SN_hold_instruction_call_issuer = "holdInstructionCallIssuer"; - public final static String LN_hold_instruction_call_issuer = "Hold Instruction Call Issuer"; - public final static String OBJ_hold_instruction_call_issuer = OBJ_holdInstruction + ".2"; - - public final static int NID_hold_instruction_reject = 433; - public final static String SN_hold_instruction_reject = "holdInstructionReject"; - public final static String LN_hold_instruction_reject = "Hold Instruction Reject"; - public final static String OBJ_hold_instruction_reject = OBJ_holdInstruction + ".3"; - - public final static int NID_pilotAttributeSyntax = 439; - public final static String LN_pilotAttributeSyntax = "pilotAttributeSyntax"; - public final static String OBJ_pilotAttributeSyntax = OBJ_pilot + ".3"; - - public final static int NID_pilotGroups = 441; - public final static String LN_pilotGroups = "pilotGroups"; - public final static String OBJ_pilotGroups = OBJ_pilot + ".10"; - - public final static int NID_iA5StringSyntax = 442; - public final static String LN_iA5StringSyntax = "iA5StringSyntax"; - public final static String OBJ_iA5StringSyntax = OBJ_pilotAttributeSyntax + ".4"; - - public final static int NID_caseIgnoreIA5StringSyntax = 443; - public final static String LN_caseIgnoreIA5StringSyntax = "caseIgnoreIA5StringSyntax"; - public final static String OBJ_caseIgnoreIA5StringSyntax = OBJ_pilotAttributeSyntax + ".5"; - - public final static int NID_pilotObject = 444; - public final static String LN_pilotObject = "pilotObject"; - public final static String OBJ_pilotObject = OBJ_pilotObjectClass + ".3"; - - public final static int NID_pilotPerson = 445; - public final static String LN_pilotPerson = "pilotPerson"; - public final static String OBJ_pilotPerson = OBJ_pilotObjectClass + ".4"; - - public final static int NID_account = 446; - public final static String SN_account = "account"; - public final static String OBJ_account = OBJ_pilotObjectClass + ".5"; - - public final static int NID_document = 447; - public final static String SN_document = "document"; - public final static String OBJ_document = OBJ_pilotObjectClass + ".6"; - - public final static int NID_room = 448; - public final static String SN_room = "room"; - public final static String OBJ_room = OBJ_pilotObjectClass + ".7"; - - public final static int NID_documentSeries = 449; - public final static String LN_documentSeries = "documentSeries"; - public final static String OBJ_documentSeries = OBJ_pilotObjectClass + ".9"; - - public final static int NID_rFC822localPart = 450; - public final static String LN_rFC822localPart = "rFC822localPart"; - public final static String OBJ_rFC822localPart = OBJ_pilotObjectClass + ".14"; - - public final static int NID_dNSDomain = 451; - public final static String LN_dNSDomain = "dNSDomain"; - public final static String OBJ_dNSDomain = OBJ_pilotObjectClass + ".15"; - - public final static int NID_domainRelatedObject = 452; - public final static String LN_domainRelatedObject = "domainRelatedObject"; - public final static String OBJ_domainRelatedObject = OBJ_pilotObjectClass + ".17"; - - public final static int NID_friendlyCountry = 453; - public final static String LN_friendlyCountry = "friendlyCountry"; - public final static String OBJ_friendlyCountry = OBJ_pilotObjectClass + ".18"; - - public final static int NID_simpleSecurityObject = 454; - public final static String LN_simpleSecurityObject = "simpleSecurityObject"; - public final static String OBJ_simpleSecurityObject = OBJ_pilotObjectClass + ".19"; - - public final static int NID_pilotOrganization = 455; - public final static String LN_pilotOrganization = "pilotOrganization"; - public final static String OBJ_pilotOrganization = OBJ_pilotObjectClass + ".20"; - - public final static int NID_pilotDSA = 456; - public final static String LN_pilotDSA = "pilotDSA"; - public final static String OBJ_pilotDSA = OBJ_pilotObjectClass + ".21"; - - public final static int NID_qualityLabelledData = 457; - public final static String LN_qualityLabelledData = "qualityLabelledData"; - public final static String OBJ_qualityLabelledData = OBJ_pilotObjectClass + ".22"; - - public final static int NID_userId = 458; - public final static String SN_userId = "UID"; - public final static String LN_userId = "userId"; - public final static String OBJ_userId = OBJ_pilotAttributeType + ".1"; - - public final static int NID_textEncodedORAddress = 459; - public final static String LN_textEncodedORAddress = "textEncodedORAddress"; - public final static String OBJ_textEncodedORAddress = OBJ_pilotAttributeType + ".2"; - - public final static int NID_rfc822Mailbox = 460; - public final static String SN_rfc822Mailbox = "mail"; - public final static String LN_rfc822Mailbox = "rfc822Mailbox"; - public final static String OBJ_rfc822Mailbox = OBJ_pilotAttributeType + ".3"; - - public final static int NID_info = 461; - public final static String SN_info = "info"; - public final static String OBJ_info = OBJ_pilotAttributeType + ".4"; - - public final static int NID_favouriteDrink = 462; - public final static String LN_favouriteDrink = "favouriteDrink"; - public final static String OBJ_favouriteDrink = OBJ_pilotAttributeType + ".5"; - - public final static int NID_roomNumber = 463; - public final static String LN_roomNumber = "roomNumber"; - public final static String OBJ_roomNumber = OBJ_pilotAttributeType + ".6"; - - public final static int NID_photo = 464; - public final static String SN_photo = "photo"; - public final static String OBJ_photo = OBJ_pilotAttributeType + ".7"; - - public final static int NID_userClass = 465; - public final static String LN_userClass = "userClass"; - public final static String OBJ_userClass = OBJ_pilotAttributeType + ".8"; - - public final static int NID_host = 466; - public final static String SN_host = "host"; - public final static String OBJ_host = OBJ_pilotAttributeType + ".9"; - - public final static int NID_manager = 467; - public final static String SN_manager = "manager"; - public final static String OBJ_manager = OBJ_pilotAttributeType + ".10"; - - public final static int NID_documentIdentifier = 468; - public final static String LN_documentIdentifier = "documentIdentifier"; - public final static String OBJ_documentIdentifier = OBJ_pilotAttributeType + ".11"; - - public final static int NID_documentTitle = 469; - public final static String LN_documentTitle = "documentTitle"; - public final static String OBJ_documentTitle = OBJ_pilotAttributeType + ".12"; - - public final static int NID_documentVersion = 470; - public final static String LN_documentVersion = "documentVersion"; - public final static String OBJ_documentVersion = OBJ_pilotAttributeType + ".13"; - - public final static int NID_documentAuthor = 471; - public final static String LN_documentAuthor = "documentAuthor"; - public final static String OBJ_documentAuthor = OBJ_pilotAttributeType + ".14"; - - public final static int NID_documentLocation = 472; - public final static String LN_documentLocation = "documentLocation"; - public final static String OBJ_documentLocation = OBJ_pilotAttributeType + ".15"; - - public final static int NID_homeTelephoneNumber = 473; - public final static String LN_homeTelephoneNumber = "homeTelephoneNumber"; - public final static String OBJ_homeTelephoneNumber = OBJ_pilotAttributeType + ".20"; - - public final static int NID_secretary = 474; - public final static String SN_secretary = "secretary"; - public final static String OBJ_secretary = OBJ_pilotAttributeType + ".21"; - - public final static int NID_otherMailbox = 475; - public final static String LN_otherMailbox = "otherMailbox"; - public final static String OBJ_otherMailbox = OBJ_pilotAttributeType + ".22"; - - public final static int NID_lastModifiedTime = 476; - public final static String LN_lastModifiedTime = "lastModifiedTime"; - public final static String OBJ_lastModifiedTime = OBJ_pilotAttributeType + ".23"; - - public final static int NID_lastModifiedBy = 477; - public final static String LN_lastModifiedBy = "lastModifiedBy"; - public final static String OBJ_lastModifiedBy = OBJ_pilotAttributeType + ".24"; - - public final static int NID_aRecord = 478; - public final static String LN_aRecord = "aRecord"; - public final static String OBJ_aRecord = OBJ_pilotAttributeType + ".26"; - - public final static int NID_pilotAttributeType27 = 479; - public final static String LN_pilotAttributeType27 = "pilotAttributeType27"; - public final static String OBJ_pilotAttributeType27 = OBJ_pilotAttributeType + ".27"; - - public final static int NID_mXRecord = 480; - public final static String LN_mXRecord = "mXRecord"; - public final static String OBJ_mXRecord = OBJ_pilotAttributeType + ".28"; - - public final static int NID_nSRecord = 481; - public final static String LN_nSRecord = "nSRecord"; - public final static String OBJ_nSRecord = OBJ_pilotAttributeType + ".29"; - - public final static int NID_sOARecord = 482; - public final static String LN_sOARecord = "sOARecord"; - public final static String OBJ_sOARecord = OBJ_pilotAttributeType + ".30"; - - public final static int NID_cNAMERecord = 483; - public final static String LN_cNAMERecord = "cNAMERecord"; - public final static String OBJ_cNAMERecord = OBJ_pilotAttributeType + ".31"; - - public final static int NID_associatedDomain = 484; - public final static String LN_associatedDomain = "associatedDomain"; - public final static String OBJ_associatedDomain = OBJ_pilotAttributeType + ".37"; - - public final static int NID_associatedName = 485; - public final static String LN_associatedName = "associatedName"; - public final static String OBJ_associatedName = OBJ_pilotAttributeType + ".38"; - - public final static int NID_homePostalAddress = 486; - public final static String LN_homePostalAddress = "homePostalAddress"; - public final static String OBJ_homePostalAddress = OBJ_pilotAttributeType + ".39"; - - public final static int NID_personalTitle = 487; - public final static String LN_personalTitle = "personalTitle"; - public final static String OBJ_personalTitle = OBJ_pilotAttributeType + ".40"; - - public final static int NID_mobileTelephoneNumber = 488; - public final static String LN_mobileTelephoneNumber = "mobileTelephoneNumber"; - public final static String OBJ_mobileTelephoneNumber = OBJ_pilotAttributeType + ".41"; - - public final static int NID_pagerTelephoneNumber = 489; - public final static String LN_pagerTelephoneNumber = "pagerTelephoneNumber"; - public final static String OBJ_pagerTelephoneNumber = OBJ_pilotAttributeType + ".42"; - - public final static int NID_friendlyCountryName = 490; - public final static String LN_friendlyCountryName = "friendlyCountryName"; - public final static String OBJ_friendlyCountryName = OBJ_pilotAttributeType + ".43"; - - public final static int NID_organizationalStatus = 491; - public final static String LN_organizationalStatus = "organizationalStatus"; - public final static String OBJ_organizationalStatus = OBJ_pilotAttributeType + ".45"; - - public final static int NID_janetMailbox = 492; - public final static String LN_janetMailbox = "janetMailbox"; - public final static String OBJ_janetMailbox = OBJ_pilotAttributeType + ".46"; - - public final static int NID_mailPreferenceOption = 493; - public final static String LN_mailPreferenceOption = "mailPreferenceOption"; - public final static String OBJ_mailPreferenceOption = OBJ_pilotAttributeType + ".47"; - - public final static int NID_buildingName = 494; - public final static String LN_buildingName = "buildingName"; - public final static String OBJ_buildingName = OBJ_pilotAttributeType + ".48"; - - public final static int NID_dSAQuality = 495; - public final static String LN_dSAQuality = "dSAQuality"; - public final static String OBJ_dSAQuality = OBJ_pilotAttributeType + ".49"; - - public final static int NID_singleLevelQuality = 496; - public final static String LN_singleLevelQuality = "singleLevelQuality"; - public final static String OBJ_singleLevelQuality = OBJ_pilotAttributeType + ".50"; - - public final static int NID_subtreeMinimumQuality = 497; - public final static String LN_subtreeMinimumQuality = "subtreeMinimumQuality"; - public final static String OBJ_subtreeMinimumQuality = OBJ_pilotAttributeType + ".51"; - - public final static int NID_subtreeMaximumQuality = 498; - public final static String LN_subtreeMaximumQuality = "subtreeMaximumQuality"; - public final static String OBJ_subtreeMaximumQuality = OBJ_pilotAttributeType + ".52"; - - public final static int NID_personalSignature = 499; - public final static String LN_personalSignature = "personalSignature"; - public final static String OBJ_personalSignature = OBJ_pilotAttributeType + ".53"; - - public final static int NID_dITRedirect = 500; - public final static String LN_dITRedirect = "dITRedirect"; - public final static String OBJ_dITRedirect = OBJ_pilotAttributeType + ".54"; - - public final static int NID_audio = 501; - public final static String SN_audio = "audio"; - public final static String OBJ_audio = OBJ_pilotAttributeType + ".55"; - - public final static int NID_documentPublisher = 502; - public final static String LN_documentPublisher = "documentPublisher"; - public final static String OBJ_documentPublisher = OBJ_pilotAttributeType + ".56"; - - public final static int NID_x500UniqueIdentifier = 503; - public final static String LN_x500UniqueIdentifier = "x500UniqueIdentifier"; - public final static String OBJ_x500UniqueIdentifier = OBJ_X509 + ".45"; - - public final static int NID_mime_mhs = 504; - public final static String SN_mime_mhs = "mime-mhs"; - public final static String LN_mime_mhs = "MIME MHS"; - public final static String OBJ_mime_mhs = OBJ_Mail + ".1"; - - public final static int NID_mime_mhs_headings = 505; - public final static String SN_mime_mhs_headings = "mime-mhs-headings"; - public final static String LN_mime_mhs_headings = "mime-mhs-headings"; - public final static String OBJ_mime_mhs_headings = OBJ_mime_mhs + ".1"; - - public final static int NID_mime_mhs_bodies = 506; - public final static String SN_mime_mhs_bodies = "mime-mhs-bodies"; - public final static String LN_mime_mhs_bodies = "mime-mhs-bodies"; - public final static String OBJ_mime_mhs_bodies = OBJ_mime_mhs + ".2"; - - public final static int NID_id_hex_partial_message = 507; - public final static String SN_id_hex_partial_message = "id-hex-partial-message"; - public final static String LN_id_hex_partial_message = "id-hex-partial-message"; - public final static String OBJ_id_hex_partial_message = OBJ_mime_mhs_headings + ".1"; - - public final static int NID_id_hex_multipart_message = 508; - public final static String SN_id_hex_multipart_message = "id-hex-multipart-message"; - public final static String LN_id_hex_multipart_message = "id-hex-multipart-message"; - public final static String OBJ_id_hex_multipart_message = OBJ_mime_mhs_headings + ".2"; - - public final static int NID_generationQualifier = 509; - public final static String LN_generationQualifier = "generationQualifier"; - public final static String OBJ_generationQualifier = OBJ_X509 + ".44"; - - public final static int NID_pseudonym = 510; - public final static String LN_pseudonym = "pseudonym"; - public final static String OBJ_pseudonym = OBJ_X509 + ".65"; - - public final static int NID_id_set = 512; - public final static String SN_id_set = "id-set"; - public final static String LN_id_set = "Secure Electronic Transactions"; - public final static String OBJ_id_set = OBJ_international_organizations + ".42"; - - public final static int NID_set_ctype = 513; - public final static String SN_set_ctype = "set-ctype"; - public final static String LN_set_ctype = "content types"; - public final static String OBJ_set_ctype = OBJ_id_set + ".0"; - - public final static int NID_set_msgExt = 514; - public final static String SN_set_msgExt = "set-msgExt"; - public final static String LN_set_msgExt = "message extensions"; - public final static String OBJ_set_msgExt = OBJ_id_set + ".1"; - - public final static int NID_set_attr = 515; - public final static String SN_set_attr = "set-attr"; - public final static String OBJ_set_attr = OBJ_id_set + ".3"; - - public final static int NID_set_policy = 516; - public final static String SN_set_policy = "set-policy"; - public final static String OBJ_set_policy = OBJ_id_set + ".5"; - - public final static int NID_set_certExt = 517; - public final static String SN_set_certExt = "set-certExt"; - public final static String LN_set_certExt = "certificate extensions"; - public final static String OBJ_set_certExt = OBJ_id_set + ".7"; - - public final static int NID_set_brand = 518; - public final static String SN_set_brand = "set-brand"; - public final static String OBJ_set_brand = OBJ_id_set + ".8"; - - public final static int NID_setct_PANData = 519; - public final static String SN_setct_PANData = "setct-PANData"; - public final static String OBJ_setct_PANData = OBJ_set_ctype + ".0"; - - public final static int NID_setct_PANToken = 520; - public final static String SN_setct_PANToken = "setct-PANToken"; - public final static String OBJ_setct_PANToken = OBJ_set_ctype + ".1"; - - public final static int NID_setct_PANOnly = 521; - public final static String SN_setct_PANOnly = "setct-PANOnly"; - public final static String OBJ_setct_PANOnly = OBJ_set_ctype + ".2"; - - public final static int NID_setct_OIData = 522; - public final static String SN_setct_OIData = "setct-OIData"; - public final static String OBJ_setct_OIData = OBJ_set_ctype + ".3"; - - public final static int NID_setct_PI = 523; - public final static String SN_setct_PI = "setct-PI"; - public final static String OBJ_setct_PI = OBJ_set_ctype + ".4"; - - public final static int NID_setct_PIData = 524; - public final static String SN_setct_PIData = "setct-PIData"; - public final static String OBJ_setct_PIData = OBJ_set_ctype + ".5"; - - public final static int NID_setct_PIDataUnsigned = 525; - public final static String SN_setct_PIDataUnsigned = "setct-PIDataUnsigned"; - public final static String OBJ_setct_PIDataUnsigned = OBJ_set_ctype + ".6"; - - public final static int NID_setct_HODInput = 526; - public final static String SN_setct_HODInput = "setct-HODInput"; - public final static String OBJ_setct_HODInput = OBJ_set_ctype + ".7"; - - public final static int NID_setct_AuthResBaggage = 527; - public final static String SN_setct_AuthResBaggage = "setct-AuthResBaggage"; - public final static String OBJ_setct_AuthResBaggage = OBJ_set_ctype + ".8"; - - public final static int NID_setct_AuthRevReqBaggage = 528; - public final static String SN_setct_AuthRevReqBaggage = "setct-AuthRevReqBaggage"; - public final static String OBJ_setct_AuthRevReqBaggage = OBJ_set_ctype + ".9"; - - public final static int NID_setct_AuthRevResBaggage = 529; - public final static String SN_setct_AuthRevResBaggage = "setct-AuthRevResBaggage"; - public final static String OBJ_setct_AuthRevResBaggage = OBJ_set_ctype + ".10"; - - public final static int NID_setct_CapTokenSeq = 530; - public final static String SN_setct_CapTokenSeq = "setct-CapTokenSeq"; - public final static String OBJ_setct_CapTokenSeq = OBJ_set_ctype + ".11"; - - public final static int NID_setct_PInitResData = 531; - public final static String SN_setct_PInitResData = "setct-PInitResData"; - public final static String OBJ_setct_PInitResData = OBJ_set_ctype + ".12"; - - public final static int NID_setct_PI_TBS = 532; - public final static String SN_setct_PI_TBS = "setct-PI-TBS"; - public final static String OBJ_setct_PI_TBS = OBJ_set_ctype + ".13"; - - public final static int NID_setct_PResData = 533; - public final static String SN_setct_PResData = "setct-PResData"; - public final static String OBJ_setct_PResData = OBJ_set_ctype + ".14"; - - public final static int NID_setct_AuthReqTBS = 534; - public final static String SN_setct_AuthReqTBS = "setct-AuthReqTBS"; - public final static String OBJ_setct_AuthReqTBS = OBJ_set_ctype + ".16"; - - public final static int NID_setct_AuthResTBS = 535; - public final static String SN_setct_AuthResTBS = "setct-AuthResTBS"; - public final static String OBJ_setct_AuthResTBS = OBJ_set_ctype + ".17"; - - public final static int NID_setct_AuthResTBSX = 536; - public final static String SN_setct_AuthResTBSX = "setct-AuthResTBSX"; - public final static String OBJ_setct_AuthResTBSX = OBJ_set_ctype + ".18"; - - public final static int NID_setct_AuthTokenTBS = 537; - public final static String SN_setct_AuthTokenTBS = "setct-AuthTokenTBS"; - public final static String OBJ_setct_AuthTokenTBS = OBJ_set_ctype + ".19"; - - public final static int NID_setct_CapTokenData = 538; - public final static String SN_setct_CapTokenData = "setct-CapTokenData"; - public final static String OBJ_setct_CapTokenData = OBJ_set_ctype + ".20"; - - public final static int NID_setct_CapTokenTBS = 539; - public final static String SN_setct_CapTokenTBS = "setct-CapTokenTBS"; - public final static String OBJ_setct_CapTokenTBS = OBJ_set_ctype + ".21"; - - public final static int NID_setct_AcqCardCodeMsg = 540; - public final static String SN_setct_AcqCardCodeMsg = "setct-AcqCardCodeMsg"; - public final static String OBJ_setct_AcqCardCodeMsg = OBJ_set_ctype + ".22"; - - public final static int NID_setct_AuthRevReqTBS = 541; - public final static String SN_setct_AuthRevReqTBS = "setct-AuthRevReqTBS"; - public final static String OBJ_setct_AuthRevReqTBS = OBJ_set_ctype + ".23"; - - public final static int NID_setct_AuthRevResData = 542; - public final static String SN_setct_AuthRevResData = "setct-AuthRevResData"; - public final static String OBJ_setct_AuthRevResData = OBJ_set_ctype + ".24"; - - public final static int NID_setct_AuthRevResTBS = 543; - public final static String SN_setct_AuthRevResTBS = "setct-AuthRevResTBS"; - public final static String OBJ_setct_AuthRevResTBS = OBJ_set_ctype + ".25"; - - public final static int NID_setct_CapReqTBS = 544; - public final static String SN_setct_CapReqTBS = "setct-CapReqTBS"; - public final static String OBJ_setct_CapReqTBS = OBJ_set_ctype + ".26"; - - public final static int NID_setct_CapReqTBSX = 545; - public final static String SN_setct_CapReqTBSX = "setct-CapReqTBSX"; - public final static String OBJ_setct_CapReqTBSX = OBJ_set_ctype + ".27"; - - public final static int NID_setct_CapResData = 546; - public final static String SN_setct_CapResData = "setct-CapResData"; - public final static String OBJ_setct_CapResData = OBJ_set_ctype + ".28"; - - public final static int NID_setct_CapRevReqTBS = 547; - public final static String SN_setct_CapRevReqTBS = "setct-CapRevReqTBS"; - public final static String OBJ_setct_CapRevReqTBS = OBJ_set_ctype + ".29"; - - public final static int NID_setct_CapRevReqTBSX = 548; - public final static String SN_setct_CapRevReqTBSX = "setct-CapRevReqTBSX"; - public final static String OBJ_setct_CapRevReqTBSX = OBJ_set_ctype + ".30"; - - public final static int NID_setct_CapRevResData = 549; - public final static String SN_setct_CapRevResData = "setct-CapRevResData"; - public final static String OBJ_setct_CapRevResData = OBJ_set_ctype + ".31"; - - public final static int NID_setct_CredReqTBS = 550; - public final static String SN_setct_CredReqTBS = "setct-CredReqTBS"; - public final static String OBJ_setct_CredReqTBS = OBJ_set_ctype + ".32"; - - public final static int NID_setct_CredReqTBSX = 551; - public final static String SN_setct_CredReqTBSX = "setct-CredReqTBSX"; - public final static String OBJ_setct_CredReqTBSX = OBJ_set_ctype + ".33"; - - public final static int NID_setct_CredResData = 552; - public final static String SN_setct_CredResData = "setct-CredResData"; - public final static String OBJ_setct_CredResData = OBJ_set_ctype + ".34"; - - public final static int NID_setct_CredRevReqTBS = 553; - public final static String SN_setct_CredRevReqTBS = "setct-CredRevReqTBS"; - public final static String OBJ_setct_CredRevReqTBS = OBJ_set_ctype + ".35"; - - public final static int NID_setct_CredRevReqTBSX = 554; - public final static String SN_setct_CredRevReqTBSX = "setct-CredRevReqTBSX"; - public final static String OBJ_setct_CredRevReqTBSX = OBJ_set_ctype + ".36"; - - public final static int NID_setct_CredRevResData = 555; - public final static String SN_setct_CredRevResData = "setct-CredRevResData"; - public final static String OBJ_setct_CredRevResData = OBJ_set_ctype + ".37"; - - public final static int NID_setct_PCertReqData = 556; - public final static String SN_setct_PCertReqData = "setct-PCertReqData"; - public final static String OBJ_setct_PCertReqData = OBJ_set_ctype + ".38"; - - public final static int NID_setct_PCertResTBS = 557; - public final static String SN_setct_PCertResTBS = "setct-PCertResTBS"; - public final static String OBJ_setct_PCertResTBS = OBJ_set_ctype + ".39"; - - public final static int NID_setct_BatchAdminReqData = 558; - public final static String SN_setct_BatchAdminReqData = "setct-BatchAdminReqData"; - public final static String OBJ_setct_BatchAdminReqData = OBJ_set_ctype + ".40"; - - public final static int NID_setct_BatchAdminResData = 559; - public final static String SN_setct_BatchAdminResData = "setct-BatchAdminResData"; - public final static String OBJ_setct_BatchAdminResData = OBJ_set_ctype + ".41"; - - public final static int NID_setct_CardCInitResTBS = 560; - public final static String SN_setct_CardCInitResTBS = "setct-CardCInitResTBS"; - public final static String OBJ_setct_CardCInitResTBS = OBJ_set_ctype + ".42"; - - public final static int NID_setct_MeAqCInitResTBS = 561; - public final static String SN_setct_MeAqCInitResTBS = "setct-MeAqCInitResTBS"; - public final static String OBJ_setct_MeAqCInitResTBS = OBJ_set_ctype + ".43"; - - public final static int NID_setct_RegFormResTBS = 562; - public final static String SN_setct_RegFormResTBS = "setct-RegFormResTBS"; - public final static String OBJ_setct_RegFormResTBS = OBJ_set_ctype + ".44"; - - public final static int NID_setct_CertReqData = 563; - public final static String SN_setct_CertReqData = "setct-CertReqData"; - public final static String OBJ_setct_CertReqData = OBJ_set_ctype + ".45"; - - public final static int NID_setct_CertReqTBS = 564; - public final static String SN_setct_CertReqTBS = "setct-CertReqTBS"; - public final static String OBJ_setct_CertReqTBS = OBJ_set_ctype + ".46"; - - public final static int NID_setct_CertResData = 565; - public final static String SN_setct_CertResData = "setct-CertResData"; - public final static String OBJ_setct_CertResData = OBJ_set_ctype + ".47"; - - public final static int NID_setct_CertInqReqTBS = 566; - public final static String SN_setct_CertInqReqTBS = "setct-CertInqReqTBS"; - public final static String OBJ_setct_CertInqReqTBS = OBJ_set_ctype + ".48"; - - public final static int NID_setct_ErrorTBS = 567; - public final static String SN_setct_ErrorTBS = "setct-ErrorTBS"; - public final static String OBJ_setct_ErrorTBS = OBJ_set_ctype + ".49"; - - public final static int NID_setct_PIDualSignedTBE = 568; - public final static String SN_setct_PIDualSignedTBE = "setct-PIDualSignedTBE"; - public final static String OBJ_setct_PIDualSignedTBE = OBJ_set_ctype + ".50"; - - public final static int NID_setct_PIUnsignedTBE = 569; - public final static String SN_setct_PIUnsignedTBE = "setct-PIUnsignedTBE"; - public final static String OBJ_setct_PIUnsignedTBE = OBJ_set_ctype + ".51"; - - public final static int NID_setct_AuthReqTBE = 570; - public final static String SN_setct_AuthReqTBE = "setct-AuthReqTBE"; - public final static String OBJ_setct_AuthReqTBE = OBJ_set_ctype + ".52"; - - public final static int NID_setct_AuthResTBE = 571; - public final static String SN_setct_AuthResTBE = "setct-AuthResTBE"; - public final static String OBJ_setct_AuthResTBE = OBJ_set_ctype + ".53"; - - public final static int NID_setct_AuthResTBEX = 572; - public final static String SN_setct_AuthResTBEX = "setct-AuthResTBEX"; - public final static String OBJ_setct_AuthResTBEX = OBJ_set_ctype + ".54"; - - public final static int NID_setct_AuthTokenTBE = 573; - public final static String SN_setct_AuthTokenTBE = "setct-AuthTokenTBE"; - public final static String OBJ_setct_AuthTokenTBE = OBJ_set_ctype + ".55"; - - public final static int NID_setct_CapTokenTBE = 574; - public final static String SN_setct_CapTokenTBE = "setct-CapTokenTBE"; - public final static String OBJ_setct_CapTokenTBE = OBJ_set_ctype + ".56"; - - public final static int NID_setct_CapTokenTBEX = 575; - public final static String SN_setct_CapTokenTBEX = "setct-CapTokenTBEX"; - public final static String OBJ_setct_CapTokenTBEX = OBJ_set_ctype + ".57"; - - public final static int NID_setct_AcqCardCodeMsgTBE = 576; - public final static String SN_setct_AcqCardCodeMsgTBE = "setct-AcqCardCodeMsgTBE"; - public final static String OBJ_setct_AcqCardCodeMsgTBE = OBJ_set_ctype + ".58"; - - public final static int NID_setct_AuthRevReqTBE = 577; - public final static String SN_setct_AuthRevReqTBE = "setct-AuthRevReqTBE"; - public final static String OBJ_setct_AuthRevReqTBE = OBJ_set_ctype + ".59"; - - public final static int NID_setct_AuthRevResTBE = 578; - public final static String SN_setct_AuthRevResTBE = "setct-AuthRevResTBE"; - public final static String OBJ_setct_AuthRevResTBE = OBJ_set_ctype + ".60"; - - public final static int NID_setct_AuthRevResTBEB = 579; - public final static String SN_setct_AuthRevResTBEB = "setct-AuthRevResTBEB"; - public final static String OBJ_setct_AuthRevResTBEB = OBJ_set_ctype + ".61"; - - public final static int NID_setct_CapReqTBE = 580; - public final static String SN_setct_CapReqTBE = "setct-CapReqTBE"; - public final static String OBJ_setct_CapReqTBE = OBJ_set_ctype + ".62"; - - public final static int NID_setct_CapReqTBEX = 581; - public final static String SN_setct_CapReqTBEX = "setct-CapReqTBEX"; - public final static String OBJ_setct_CapReqTBEX = OBJ_set_ctype + ".63"; - - public final static int NID_setct_CapResTBE = 582; - public final static String SN_setct_CapResTBE = "setct-CapResTBE"; - public final static String OBJ_setct_CapResTBE = OBJ_set_ctype + ".64"; - - public final static int NID_setct_CapRevReqTBE = 583; - public final static String SN_setct_CapRevReqTBE = "setct-CapRevReqTBE"; - public final static String OBJ_setct_CapRevReqTBE = OBJ_set_ctype + ".65"; - - public final static int NID_setct_CapRevReqTBEX = 584; - public final static String SN_setct_CapRevReqTBEX = "setct-CapRevReqTBEX"; - public final static String OBJ_setct_CapRevReqTBEX = OBJ_set_ctype + ".66"; - - public final static int NID_setct_CapRevResTBE = 585; - public final static String SN_setct_CapRevResTBE = "setct-CapRevResTBE"; - public final static String OBJ_setct_CapRevResTBE = OBJ_set_ctype + ".67"; - - public final static int NID_setct_CredReqTBE = 586; - public final static String SN_setct_CredReqTBE = "setct-CredReqTBE"; - public final static String OBJ_setct_CredReqTBE = OBJ_set_ctype + ".68"; - - public final static int NID_setct_CredReqTBEX = 587; - public final static String SN_setct_CredReqTBEX = "setct-CredReqTBEX"; - public final static String OBJ_setct_CredReqTBEX = OBJ_set_ctype + ".69"; - - public final static int NID_setct_CredResTBE = 588; - public final static String SN_setct_CredResTBE = "setct-CredResTBE"; - public final static String OBJ_setct_CredResTBE = OBJ_set_ctype + ".70"; - - public final static int NID_setct_CredRevReqTBE = 589; - public final static String SN_setct_CredRevReqTBE = "setct-CredRevReqTBE"; - public final static String OBJ_setct_CredRevReqTBE = OBJ_set_ctype + ".71"; - - public final static int NID_setct_CredRevReqTBEX = 590; - public final static String SN_setct_CredRevReqTBEX = "setct-CredRevReqTBEX"; - public final static String OBJ_setct_CredRevReqTBEX = OBJ_set_ctype + ".72"; - - public final static int NID_setct_CredRevResTBE = 591; - public final static String SN_setct_CredRevResTBE = "setct-CredRevResTBE"; - public final static String OBJ_setct_CredRevResTBE = OBJ_set_ctype + ".73"; - - public final static int NID_setct_BatchAdminReqTBE = 592; - public final static String SN_setct_BatchAdminReqTBE = "setct-BatchAdminReqTBE"; - public final static String OBJ_setct_BatchAdminReqTBE = OBJ_set_ctype + ".74"; - - public final static int NID_setct_BatchAdminResTBE = 593; - public final static String SN_setct_BatchAdminResTBE = "setct-BatchAdminResTBE"; - public final static String OBJ_setct_BatchAdminResTBE = OBJ_set_ctype + ".75"; - - public final static int NID_setct_RegFormReqTBE = 594; - public final static String SN_setct_RegFormReqTBE = "setct-RegFormReqTBE"; - public final static String OBJ_setct_RegFormReqTBE = OBJ_set_ctype + ".76"; - - public final static int NID_setct_CertReqTBE = 595; - public final static String SN_setct_CertReqTBE = "setct-CertReqTBE"; - public final static String OBJ_setct_CertReqTBE = OBJ_set_ctype + ".77"; - - public final static int NID_setct_CertReqTBEX = 596; - public final static String SN_setct_CertReqTBEX = "setct-CertReqTBEX"; - public final static String OBJ_setct_CertReqTBEX = OBJ_set_ctype + ".78"; - - public final static int NID_setct_CertResTBE = 597; - public final static String SN_setct_CertResTBE = "setct-CertResTBE"; - public final static String OBJ_setct_CertResTBE = OBJ_set_ctype + ".79"; - - public final static int NID_setct_CRLNotificationTBS = 598; - public final static String SN_setct_CRLNotificationTBS = "setct-CRLNotificationTBS"; - public final static String OBJ_setct_CRLNotificationTBS = OBJ_set_ctype + ".80"; - - public final static int NID_setct_CRLNotificationResTBS = 599; - public final static String SN_setct_CRLNotificationResTBS = "setct-CRLNotificationResTBS"; - public final static String OBJ_setct_CRLNotificationResTBS = OBJ_set_ctype + ".81"; - - public final static int NID_setct_BCIDistributionTBS = 600; - public final static String SN_setct_BCIDistributionTBS = "setct-BCIDistributionTBS"; - public final static String OBJ_setct_BCIDistributionTBS = OBJ_set_ctype + ".82"; - - public final static int NID_setext_genCrypt = 601; - public final static String SN_setext_genCrypt = "setext-genCrypt"; - public final static String LN_setext_genCrypt = "generic cryptogram"; - public final static String OBJ_setext_genCrypt = OBJ_set_msgExt + ".1"; - - public final static int NID_setext_miAuth = 602; - public final static String SN_setext_miAuth = "setext-miAuth"; - public final static String LN_setext_miAuth = "merchant initiated auth"; - public final static String OBJ_setext_miAuth = OBJ_set_msgExt + ".3"; - - public final static int NID_setext_pinSecure = 603; - public final static String SN_setext_pinSecure = "setext-pinSecure"; - public final static String OBJ_setext_pinSecure = OBJ_set_msgExt + ".4"; - - public final static int NID_setext_pinAny = 604; - public final static String SN_setext_pinAny = "setext-pinAny"; - public final static String OBJ_setext_pinAny = OBJ_set_msgExt + ".5"; - - public final static int NID_setext_track2 = 605; - public final static String SN_setext_track2 = "setext-track2"; - public final static String OBJ_setext_track2 = OBJ_set_msgExt + ".7"; - - public final static int NID_setext_cv = 606; - public final static String SN_setext_cv = "setext-cv"; - public final static String LN_setext_cv = "additional verification"; - public final static String OBJ_setext_cv = OBJ_set_msgExt + ".8"; - - public final static int NID_set_policy_root = 607; - public final static String SN_set_policy_root = "set-policy-root"; - public final static String OBJ_set_policy_root = OBJ_set_policy + ".0"; - - public final static int NID_setCext_hashedRoot = 608; - public final static String SN_setCext_hashedRoot = "setCext-hashedRoot"; - public final static String OBJ_setCext_hashedRoot = OBJ_set_certExt + ".0"; - - public final static int NID_setCext_certType = 609; - public final static String SN_setCext_certType = "setCext-certType"; - public final static String OBJ_setCext_certType = OBJ_set_certExt + ".1"; - - public final static int NID_setCext_merchData = 610; - public final static String SN_setCext_merchData = "setCext-merchData"; - public final static String OBJ_setCext_merchData = OBJ_set_certExt + ".2"; - - public final static int NID_setCext_cCertRequired = 611; - public final static String SN_setCext_cCertRequired = "setCext-cCertRequired"; - public final static String OBJ_setCext_cCertRequired = OBJ_set_certExt + ".3"; - - public final static int NID_setCext_tunneling = 612; - public final static String SN_setCext_tunneling = "setCext-tunneling"; - public final static String OBJ_setCext_tunneling = OBJ_set_certExt + ".4"; - - public final static int NID_setCext_setExt = 613; - public final static String SN_setCext_setExt = "setCext-setExt"; - public final static String OBJ_setCext_setExt = OBJ_set_certExt + ".5"; - - public final static int NID_setCext_setQualf = 614; - public final static String SN_setCext_setQualf = "setCext-setQualf"; - public final static String OBJ_setCext_setQualf = OBJ_set_certExt + ".6"; - - public final static int NID_setCext_PGWYcapabilities = 615; - public final static String SN_setCext_PGWYcapabilities = "setCext-PGWYcapabilities"; - public final static String OBJ_setCext_PGWYcapabilities = OBJ_set_certExt + ".7"; - - public final static int NID_setCext_TokenIdentifier = 616; - public final static String SN_setCext_TokenIdentifier = "setCext-TokenIdentifier"; - public final static String OBJ_setCext_TokenIdentifier = OBJ_set_certExt + ".8"; - - public final static int NID_setCext_Track2Data = 617; - public final static String SN_setCext_Track2Data = "setCext-Track2Data"; - public final static String OBJ_setCext_Track2Data = OBJ_set_certExt + ".9"; - - public final static int NID_setCext_TokenType = 618; - public final static String SN_setCext_TokenType = "setCext-TokenType"; - public final static String OBJ_setCext_TokenType = OBJ_set_certExt + ".10"; - - public final static int NID_setCext_IssuerCapabilities = 619; - public final static String SN_setCext_IssuerCapabilities = "setCext-IssuerCapabilities"; - public final static String OBJ_setCext_IssuerCapabilities = OBJ_set_certExt + ".11"; - - public final static int NID_setAttr_Cert = 620; - public final static String SN_setAttr_Cert = "setAttr-Cert"; - public final static String OBJ_setAttr_Cert = OBJ_set_attr + ".0"; - - public final static int NID_setAttr_PGWYcap = 621; - public final static String SN_setAttr_PGWYcap = "setAttr-PGWYcap"; - public final static String LN_setAttr_PGWYcap = "payment gateway capabilities"; - public final static String OBJ_setAttr_PGWYcap = OBJ_set_attr + ".1"; - - public final static int NID_setAttr_TokenType = 622; - public final static String SN_setAttr_TokenType = "setAttr-TokenType"; - public final static String OBJ_setAttr_TokenType = OBJ_set_attr + ".2"; - - public final static int NID_setAttr_IssCap = 623; - public final static String SN_setAttr_IssCap = "setAttr-IssCap"; - public final static String LN_setAttr_IssCap = "issuer capabilities"; - public final static String OBJ_setAttr_IssCap = OBJ_set_attr + ".3"; - - public final static int NID_set_rootKeyThumb = 624; - public final static String SN_set_rootKeyThumb = "set-rootKeyThumb"; - public final static String OBJ_set_rootKeyThumb = OBJ_setAttr_Cert + ".0"; - - public final static int NID_set_addPolicy = 625; - public final static String SN_set_addPolicy = "set-addPolicy"; - public final static String OBJ_set_addPolicy = OBJ_setAttr_Cert + ".1"; - - public final static int NID_setAttr_Token_EMV = 626; - public final static String SN_setAttr_Token_EMV = "setAttr-Token-EMV"; - public final static String OBJ_setAttr_Token_EMV = OBJ_setAttr_TokenType + ".1"; - - public final static int NID_setAttr_Token_B0Prime = 627; - public final static String SN_setAttr_Token_B0Prime = "setAttr-Token-B0Prime"; - public final static String OBJ_setAttr_Token_B0Prime = OBJ_setAttr_TokenType + ".2"; - - public final static int NID_setAttr_IssCap_CVM = 628; - public final static String SN_setAttr_IssCap_CVM = "setAttr-IssCap-CVM"; - public final static String OBJ_setAttr_IssCap_CVM = OBJ_setAttr_IssCap + ".3"; - - public final static int NID_setAttr_IssCap_T2 = 629; - public final static String SN_setAttr_IssCap_T2 = "setAttr-IssCap-T2"; - public final static String OBJ_setAttr_IssCap_T2 = OBJ_setAttr_IssCap + ".4"; - - public final static int NID_setAttr_IssCap_Sig = 630; - public final static String SN_setAttr_IssCap_Sig = "setAttr-IssCap-Sig"; - public final static String OBJ_setAttr_IssCap_Sig = OBJ_setAttr_IssCap + ".5"; - - public final static int NID_setAttr_GenCryptgrm = 631; - public final static String SN_setAttr_GenCryptgrm = "setAttr-GenCryptgrm"; - public final static String LN_setAttr_GenCryptgrm = "generate cryptogram"; - public final static String OBJ_setAttr_GenCryptgrm = OBJ_setAttr_IssCap_CVM + ".1"; - - public final static int NID_setAttr_T2Enc = 632; - public final static String SN_setAttr_T2Enc = "setAttr-T2Enc"; - public final static String LN_setAttr_T2Enc = "encrypted track 2"; - public final static String OBJ_setAttr_T2Enc = OBJ_setAttr_IssCap_T2 + ".1"; - - public final static int NID_setAttr_T2cleartxt = 633; - public final static String SN_setAttr_T2cleartxt = "setAttr-T2cleartxt"; - public final static String LN_setAttr_T2cleartxt = "cleartext track 2"; - public final static String OBJ_setAttr_T2cleartxt = OBJ_setAttr_IssCap_T2 + ".2"; - - public final static int NID_setAttr_TokICCsig = 634; - public final static String SN_setAttr_TokICCsig = "setAttr-TokICCsig"; - public final static String LN_setAttr_TokICCsig = "ICC or token signature"; - public final static String OBJ_setAttr_TokICCsig = OBJ_setAttr_IssCap_Sig + ".1"; - - public final static int NID_setAttr_SecDevSig = 635; - public final static String SN_setAttr_SecDevSig = "setAttr-SecDevSig"; - public final static String LN_setAttr_SecDevSig = "secure device signature"; - public final static String OBJ_setAttr_SecDevSig = OBJ_setAttr_IssCap_Sig + ".2"; - - public final static int NID_set_brand_IATA_ATA = 636; - public final static String SN_set_brand_IATA_ATA = "set-brand-IATA-ATA"; - public final static String OBJ_set_brand_IATA_ATA = OBJ_set_brand + ".1"; - - public final static int NID_set_brand_Diners = 637; - public final static String SN_set_brand_Diners = "set-brand-Diners"; - public final static String OBJ_set_brand_Diners = OBJ_set_brand + ".30"; - - public final static int NID_set_brand_AmericanExpress = 638; - public final static String SN_set_brand_AmericanExpress = "set-brand-AmericanExpress"; - public final static String OBJ_set_brand_AmericanExpress = OBJ_set_brand + ".34"; - - public final static int NID_set_brand_JCB = 639; - public final static String SN_set_brand_JCB = "set-brand-JCB"; - public final static String OBJ_set_brand_JCB = OBJ_set_brand + ".35"; - - public final static int NID_set_brand_Visa = 640; - public final static String SN_set_brand_Visa = "set-brand-Visa"; - public final static String OBJ_set_brand_Visa = OBJ_set_brand + ".4"; - - public final static int NID_set_brand_MasterCard = 641; - public final static String SN_set_brand_MasterCard = "set-brand-MasterCard"; - public final static String OBJ_set_brand_MasterCard = OBJ_set_brand + ".5"; - - public final static int NID_set_brand_Novus = 642; - public final static String SN_set_brand_Novus = "set-brand-Novus"; - public final static String OBJ_set_brand_Novus = OBJ_set_brand + ".6011"; - - public final static int NID_des_cdmf = 643; - public final static String SN_des_cdmf = "DES-CDMF"; - public final static String LN_des_cdmf = "des-cdmf"; - public final static String OBJ_des_cdmf = OBJ_rsadsi + ".3.10"; - - public final static int NID_rsaOAEPEncryptionSET = 644; - public final static String SN_rsaOAEPEncryptionSET = "rsaOAEPEncryptionSET"; - public final static String OBJ_rsaOAEPEncryptionSET = OBJ_rsadsi + ".1.1.6"; - - public final static int NID_ms_smartcard_login = 648; - public final static String SN_ms_smartcard_login = "msSmartcardLogin"; - public final static String LN_ms_smartcard_login = "Microsoft Smartcardlogin"; - public final static String OBJ_ms_smartcard_login = "1.3.6.1.4.1.311.20.2.2"; - - public final static int NID_ms_upn = 649; - public final static String SN_ms_upn = "msUPN"; - public final static String LN_ms_upn = "Microsoft Universal Principal Name"; - public final static String OBJ_ms_upn = "1.3.6.1.4.1.311.20.2.3"; - - public final static int NID_aes_128_cfb1 = 650; - public final static String SN_aes_128_cfb1 = "AES-128-CFB1"; - public final static String LN_aes_128_cfb1 = "aes-128-cfb1"; - - public final static int NID_aes_192_cfb1 = 651; - public final static String SN_aes_192_cfb1 = "AES-192-CFB1"; - public final static String LN_aes_192_cfb1 = "aes-192-cfb1"; - - public final static int NID_aes_256_cfb1 = 652; - public final static String SN_aes_256_cfb1 = "AES-256-CFB1"; - public final static String LN_aes_256_cfb1 = "aes-256-cfb1"; - - public final static int NID_aes_128_cfb8 = 653; - public final static String SN_aes_128_cfb8 = "AES-128-CFB8"; - public final static String LN_aes_128_cfb8 = "aes-128-cfb8"; - - public final static int NID_aes_192_cfb8 = 654; - public final static String SN_aes_192_cfb8 = "AES-192-CFB8"; - public final static String LN_aes_192_cfb8 = "aes-192-cfb8"; - - public final static int NID_aes_256_cfb8 = 655; - public final static String SN_aes_256_cfb8 = "AES-256-CFB8"; - public final static String LN_aes_256_cfb8 = "aes-256-cfb8"; - - public final static int NID_des_cfb1 = 656; - public final static String SN_des_cfb1 = "DES-CFB1"; - public final static String LN_des_cfb1 = "des-cfb1"; - - public final static int NID_des_cfb8 = 657; - public final static String SN_des_cfb8 = "DES-CFB8"; - public final static String LN_des_cfb8 = "des-cfb8"; - - public final static int NID_des_ede3_cfb1 = 658; - public final static String SN_des_ede3_cfb1 = "DES-EDE3-CFB1"; - public final static String LN_des_ede3_cfb1 = "des-ede3-cfb1"; - - public final static int NID_des_ede3_cfb8 = 659; - public final static String SN_des_ede3_cfb8 = "DES-EDE3-CFB8"; - public final static String LN_des_ede3_cfb8 = "des-ede3-cfb8"; - - public final static int NID_streetAddress = 660; - public final static String LN_streetAddress = "streetAddress"; - public final static String OBJ_streetAddress = OBJ_X509 + ".9"; - - public final static int NID_postalCode = 661; - public final static String LN_postalCode = "postalCode"; - public final static String OBJ_postalCode = OBJ_X509 + ".17"; - - public final static int NID_id_ppl = 662; - public final static String SN_id_ppl = "id-ppl"; - public final static String OBJ_id_ppl = OBJ_id_pkix + ".21"; - - public final static int NID_proxyCertInfo = 663; - public final static String SN_proxyCertInfo = "proxyCertInfo"; - public final static String LN_proxyCertInfo = "Proxy Certificate Information"; - public final static String OBJ_proxyCertInfo = OBJ_id_pe + ".14"; - - public final static int NID_id_ppl_anyLanguage = 664; - public final static String SN_id_ppl_anyLanguage = "id-ppl-anyLanguage"; - public final static String LN_id_ppl_anyLanguage = "Any language"; - public final static String OBJ_id_ppl_anyLanguage = OBJ_id_ppl + ".0"; - - public final static int NID_id_ppl_inheritAll = 665; - public final static String SN_id_ppl_inheritAll = "id-ppl-inheritAll"; - public final static String LN_id_ppl_inheritAll = "Inherit all"; - public final static String OBJ_id_ppl_inheritAll = OBJ_id_ppl + ".1"; - - public final static int NID_name_constraints = 666; - public final static String SN_name_constraints = "nameConstraints"; - public final static String LN_name_constraints = "X509v3 Name Constraints"; - public final static String OBJ_name_constraints = OBJ_id_ce + ".30"; - - public final static int NID_Independent = 667; - public final static String SN_Independent = "id-ppl-independent"; - public final static String LN_Independent = "Independent"; - public final static String OBJ_Independent = OBJ_id_ppl + ".2"; - - public final static int NID_sha256WithRSAEncryption = 668; - public final static String SN_sha256WithRSAEncryption = "RSA-SHA256"; - public final static String LN_sha256WithRSAEncryption = "sha256WithRSAEncryption"; - public final static String OBJ_sha256WithRSAEncryption = OBJ_pkcs1 + ".11"; - - public final static int NID_sha384WithRSAEncryption = 669; - public final static String SN_sha384WithRSAEncryption = "RSA-SHA384"; - public final static String LN_sha384WithRSAEncryption = "sha384WithRSAEncryption"; - public final static String OBJ_sha384WithRSAEncryption = OBJ_pkcs1 + ".12"; - - public final static int NID_sha512WithRSAEncryption = 670; - public final static String SN_sha512WithRSAEncryption = "RSA-SHA512"; - public final static String LN_sha512WithRSAEncryption = "sha512WithRSAEncryption"; - public final static String OBJ_sha512WithRSAEncryption = OBJ_pkcs1 + ".13"; - - public final static int NID_sha224WithRSAEncryption = 671; - public final static String SN_sha224WithRSAEncryption = "RSA-SHA224"; - public final static String LN_sha224WithRSAEncryption = "sha224WithRSAEncryption"; - public final static String OBJ_sha224WithRSAEncryption = OBJ_pkcs1 + ".14"; - - public final static int NID_sha256 = 672; - public final static String SN_sha256 = "SHA256"; - public final static String LN_sha256 = "sha256"; - public final static String OBJ_sha256 = OBJ_nist_hashalgs + ".1"; - - public final static int NID_sha384 = 673; - public final static String SN_sha384 = "SHA384"; - public final static String LN_sha384 = "sha384"; - public final static String OBJ_sha384 = OBJ_nist_hashalgs + ".2"; - - public final static int NID_sha512 = 674; - public final static String SN_sha512 = "SHA512"; - public final static String LN_sha512 = "sha512"; - public final static String OBJ_sha512 = OBJ_nist_hashalgs + ".3"; - - public final static int NID_sha224 = 675; - public final static String SN_sha224 = "SHA224"; - public final static String LN_sha224 = "sha224"; - public final static String OBJ_sha224 = OBJ_nist_hashalgs + ".4"; - - public final static int NID_dsa_with_SHA224 = 802; - public final static String SN_dsa_with_SHA224 = "dsa_with_SHA224"; - public final static String OBJ_dsa_with_SHA224 = OBJ_dsa_with_sha2 + ".1"; - - public final static String SN_dsa_with_SHA256 = "dsa_with_SHA256"; - public final static int NID_dsa_with_SHA256 = 803; - public final static String OBJ_dsa_with_SHA256 = OBJ_dsa_with_sha2 + ".2"; - - public final static int NID_X9_62_id_characteristic_two_basis = 680; - public final static String SN_X9_62_id_characteristic_two_basis = "id-characteristic-two-basis"; - public final static String OBJ_X9_62_id_characteristic_two_basis = OBJ_X9_62_characteristic_two_field + ".3"; - - public final static int NID_X9_62_onBasis = 681; - public final static String SN_X9_62_onBasis = "onBasis"; - public final static String OBJ_X9_62_onBasis = OBJ_X9_62_id_characteristic_two_basis + ".1"; - - public final static int NID_X9_62_tpBasis = 682; - public final static String SN_X9_62_tpBasis = "tpBasis"; - public final static String OBJ_X9_62_tpBasis = OBJ_X9_62_id_characteristic_two_basis + ".2"; - - public final static int NID_X9_62_ppBasis = 683; - public final static String SN_X9_62_ppBasis = "ppBasis"; - public final static String OBJ_X9_62_ppBasis = OBJ_X9_62_id_characteristic_two_basis + ".3"; - - public final static int NID_X9_62_c2pnb163v1 = 684; - public final static String SN_X9_62_c2pnb163v1 = "c2pnb163v1"; - public final static String OBJ_X9_62_c2pnb163v1 = OBJ_X9_62_c_TwoCurve + ".1"; - - public final static int NID_X9_62_c2pnb163v2 = 685; - public final static String SN_X9_62_c2pnb163v2 = "c2pnb163v2"; - public final static String OBJ_X9_62_c2pnb163v2 = OBJ_X9_62_c_TwoCurve + ".2"; - - public final static int NID_X9_62_c2pnb163v3 = 686; - public final static String SN_X9_62_c2pnb163v3 = "c2pnb163v3"; - public final static String OBJ_X9_62_c2pnb163v3 = OBJ_X9_62_c_TwoCurve + ".3"; - - public final static int NID_X9_62_c2pnb176v1 = 687; - public final static String SN_X9_62_c2pnb176v1 = "c2pnb176v1"; - public final static String OBJ_X9_62_c2pnb176v1 = OBJ_X9_62_c_TwoCurve + ".4"; - - public final static int NID_X9_62_c2tnb191v1 = 688; - public final static String SN_X9_62_c2tnb191v1 = "c2tnb191v1"; - public final static String OBJ_X9_62_c2tnb191v1 = OBJ_X9_62_c_TwoCurve + ".5"; - - public final static int NID_X9_62_c2tnb191v2 = 689; - public final static String SN_X9_62_c2tnb191v2 = "c2tnb191v2"; - public final static String OBJ_X9_62_c2tnb191v2 = OBJ_X9_62_c_TwoCurve + ".6"; - - public final static int NID_X9_62_c2tnb191v3 = 690; - public final static String SN_X9_62_c2tnb191v3 = "c2tnb191v3"; - public final static String OBJ_X9_62_c2tnb191v3 = OBJ_X9_62_c_TwoCurve + ".7"; - - public final static int NID_X9_62_c2onb191v4 = 691; - public final static String SN_X9_62_c2onb191v4 = "c2onb191v4"; - public final static String OBJ_X9_62_c2onb191v4 = OBJ_X9_62_c_TwoCurve + ".8"; - - public final static int NID_X9_62_c2onb191v5 = 692; - public final static String SN_X9_62_c2onb191v5 = "c2onb191v5"; - public final static String OBJ_X9_62_c2onb191v5 = OBJ_X9_62_c_TwoCurve + ".9"; - - public final static int NID_X9_62_c2pnb208w1 = 693; - public final static String SN_X9_62_c2pnb208w1 = "c2pnb208w1"; - public final static String OBJ_X9_62_c2pnb208w1 = OBJ_X9_62_c_TwoCurve + ".10"; - - public final static int NID_X9_62_c2tnb239v1 = 694; - public final static String SN_X9_62_c2tnb239v1 = "c2tnb239v1"; - public final static String OBJ_X9_62_c2tnb239v1 = OBJ_X9_62_c_TwoCurve + ".11"; - - public final static int NID_X9_62_c2tnb239v2 = 695; - public final static String SN_X9_62_c2tnb239v2 = "c2tnb239v2"; - public final static String OBJ_X9_62_c2tnb239v2 = OBJ_X9_62_c_TwoCurve + ".12"; - - public final static int NID_X9_62_c2tnb239v3 = 696; - public final static String SN_X9_62_c2tnb239v3 = "c2tnb239v3"; - public final static String OBJ_X9_62_c2tnb239v3 = OBJ_X9_62_c_TwoCurve + ".13"; - - public final static int NID_X9_62_c2onb239v4 = 697; - public final static String SN_X9_62_c2onb239v4 = "c2onb239v4"; - public final static String OBJ_X9_62_c2onb239v4 = OBJ_X9_62_c_TwoCurve + ".14"; - - public final static int NID_X9_62_c2onb239v5 = 698; - public final static String SN_X9_62_c2onb239v5 = "c2onb239v5"; - public final static String OBJ_X9_62_c2onb239v5 = OBJ_X9_62_c_TwoCurve + ".15"; - - public final static int NID_X9_62_c2pnb272w1 = 699; - public final static String SN_X9_62_c2pnb272w1 = "c2pnb272w1"; - public final static String OBJ_X9_62_c2pnb272w1 = OBJ_X9_62_c_TwoCurve + ".16"; - - public final static int NID_X9_62_c2pnb304w1 = 700; - public final static String SN_X9_62_c2pnb304w1 = "c2pnb304w1"; - public final static String OBJ_X9_62_c2pnb304w1 = OBJ_X9_62_c_TwoCurve + ".17"; - - public final static int NID_X9_62_c2tnb359v1 = 701; - public final static String SN_X9_62_c2tnb359v1 = "c2tnb359v1"; - public final static String OBJ_X9_62_c2tnb359v1 = OBJ_X9_62_c_TwoCurve + ".18"; - - public final static int NID_X9_62_c2pnb368w1 = 702; - public final static String SN_X9_62_c2pnb368w1 = "c2pnb368w1"; - public final static String OBJ_X9_62_c2pnb368w1 = OBJ_X9_62_c_TwoCurve + ".19"; - - public final static int NID_X9_62_c2tnb431r1 = 703; - public final static String SN_X9_62_c2tnb431r1 = "c2tnb431r1"; - public final static String OBJ_X9_62_c2tnb431r1 = OBJ_X9_62_c_TwoCurve + ".20"; - - public final static int NID_secp112r1 = 704; - public final static String SN_secp112r1 = "secp112r1"; - public final static String OBJ_secp112r1 = OBJ_secg_ellipticCurve + ".6"; - - public final static int NID_secp112r2 = 705; - public final static String SN_secp112r2 = "secp112r2"; - public final static String OBJ_secp112r2 = OBJ_secg_ellipticCurve + ".7"; - - public final static int NID_secp128r1 = 706; - public final static String SN_secp128r1 = "secp128r1"; - public final static String OBJ_secp128r1 = OBJ_secg_ellipticCurve + ".28"; - - public final static int NID_secp128r2 = 707; - public final static String SN_secp128r2 = "secp128r2"; - public final static String OBJ_secp128r2 = OBJ_secg_ellipticCurve + ".29"; - - public final static int NID_secp160k1 = 708; - public final static String SN_secp160k1 = "secp160k1"; - public final static String OBJ_secp160k1 = OBJ_secg_ellipticCurve + ".9"; - - public final static int NID_secp160r1 = 709; - public final static String SN_secp160r1 = "secp160r1"; - public final static String OBJ_secp160r1 = OBJ_secg_ellipticCurve + ".8"; - - public final static int NID_secp160r2 = 710; - public final static String SN_secp160r2 = "secp160r2"; - public final static String OBJ_secp160r2 = OBJ_secg_ellipticCurve + ".30"; - - public final static int NID_secp192k1 = 711; - public final static String SN_secp192k1 = "secp192k1"; - public final static String OBJ_secp192k1 = OBJ_secg_ellipticCurve + ".31"; - - public final static int NID_secp224k1 = 712; - public final static String SN_secp224k1 = "secp224k1"; - public final static String OBJ_secp224k1 = OBJ_secg_ellipticCurve + ".32"; - - public final static int NID_secp224r1 = 713; - public final static String SN_secp224r1 = "secp224r1"; - public final static String OBJ_secp224r1 = OBJ_secg_ellipticCurve + ".33"; - - public final static int NID_secp256k1 = 714; - public final static String SN_secp256k1 = "secp256k1"; - public final static String OBJ_secp256k1 = OBJ_secg_ellipticCurve + ".10"; - - public final static int NID_secp384r1 = 715; - public final static String SN_secp384r1 = "secp384r1"; - public final static String OBJ_secp384r1 = OBJ_secg_ellipticCurve + ".34"; - - public final static int NID_secp521r1 = 716; - public final static String SN_secp521r1 = "secp521r1"; - public final static String OBJ_secp521r1 = OBJ_secg_ellipticCurve + ".35"; - - public final static int NID_sect113r1 = 717; - public final static String SN_sect113r1 = "sect113r1"; - public final static String OBJ_sect113r1 = OBJ_secg_ellipticCurve + ".4"; - - public final static int NID_sect113r2 = 718; - public final static String SN_sect113r2 = "sect113r2"; - public final static String OBJ_sect113r2 = OBJ_secg_ellipticCurve + ".5"; - - public final static int NID_sect131r1 = 719; - public final static String SN_sect131r1 = "sect131r1"; - public final static String OBJ_sect131r1 = OBJ_secg_ellipticCurve + ".22"; - - public final static int NID_sect131r2 = 720; - public final static String SN_sect131r2 = "sect131r2"; - public final static String OBJ_sect131r2 = OBJ_secg_ellipticCurve + ".23"; - - public final static int NID_sect163k1 = 721; - public final static String SN_sect163k1 = "sect163k1"; - public final static String OBJ_sect163k1 = OBJ_secg_ellipticCurve + ".1"; - - public final static int NID_sect163r1 = 722; - public final static String SN_sect163r1 = "sect163r1"; - public final static String OBJ_sect163r1 = OBJ_secg_ellipticCurve + ".2"; - - public final static int NID_sect163r2 = 723; - public final static String SN_sect163r2 = "sect163r2"; - public final static String OBJ_sect163r2 = OBJ_secg_ellipticCurve + ".15"; - - public final static int NID_sect193r1 = 724; - public final static String SN_sect193r1 = "sect193r1"; - public final static String OBJ_sect193r1 = OBJ_secg_ellipticCurve + ".24"; - - public final static int NID_sect193r2 = 725; - public final static String SN_sect193r2 = "sect193r2"; - public final static String OBJ_sect193r2 = OBJ_secg_ellipticCurve + ".25"; - - public final static int NID_sect233k1 = 726; - public final static String SN_sect233k1 = "sect233k1"; - public final static String OBJ_sect233k1 = OBJ_secg_ellipticCurve + ".26"; - - public final static int NID_sect233r1 = 727; - public final static String SN_sect233r1 = "sect233r1"; - public final static String OBJ_sect233r1 = OBJ_secg_ellipticCurve + ".27"; - - public final static int NID_sect239k1 = 728; - public final static String SN_sect239k1 = "sect239k1"; - public final static String OBJ_sect239k1 = OBJ_secg_ellipticCurve + ".3"; - - public final static int NID_sect283k1 = 729; - public final static String SN_sect283k1 = "sect283k1"; - public final static String OBJ_sect283k1 = OBJ_secg_ellipticCurve + ".16"; - - public final static int NID_sect283r1 = 730; - public final static String SN_sect283r1 = "sect283r1"; - public final static String OBJ_sect283r1 = OBJ_secg_ellipticCurve + ".17"; - - public final static int NID_sect409k1 = 731; - public final static String SN_sect409k1 = "sect409k1"; - public final static String OBJ_sect409k1 = OBJ_secg_ellipticCurve + ".36"; - - public final static int NID_sect409r1 = 732; - public final static String SN_sect409r1 = "sect409r1"; - public final static String OBJ_sect409r1 = OBJ_secg_ellipticCurve + ".37"; - - public final static int NID_sect571k1 = 733; - public final static String SN_sect571k1 = "sect571k1"; - public final static String OBJ_sect571k1 = OBJ_secg_ellipticCurve + ".38"; - - public final static int NID_sect571r1 = 734; - public final static String SN_sect571r1 = "sect571r1"; - public final static String OBJ_sect571r1 = OBJ_secg_ellipticCurve + ".39"; - - public final static int NID_wap_wsg_idm_ecid_wtls1 = 735; - public final static String SN_wap_wsg_idm_ecid_wtls1 = "wap-wsg-idm-ecid-wtls1"; - public final static String OBJ_wap_wsg_idm_ecid_wtls1 = OBJ_wap_wsg_idm_ecid + ".1"; - - public final static int NID_wap_wsg_idm_ecid_wtls3 = 736; - public final static String SN_wap_wsg_idm_ecid_wtls3 = "wap-wsg-idm-ecid-wtls3"; - public final static String OBJ_wap_wsg_idm_ecid_wtls3 = OBJ_wap_wsg_idm_ecid + ".3"; - - public final static int NID_wap_wsg_idm_ecid_wtls4 = 737; - public final static String SN_wap_wsg_idm_ecid_wtls4 = "wap-wsg-idm-ecid-wtls4"; - public final static String OBJ_wap_wsg_idm_ecid_wtls4 = OBJ_wap_wsg_idm_ecid + ".4"; - - public final static int NID_wap_wsg_idm_ecid_wtls5 = 738; - public final static String SN_wap_wsg_idm_ecid_wtls5 = "wap-wsg-idm-ecid-wtls5"; - public final static String OBJ_wap_wsg_idm_ecid_wtls5 = OBJ_wap_wsg_idm_ecid + ".5"; - - public final static int NID_wap_wsg_idm_ecid_wtls6 = 739; - public final static String SN_wap_wsg_idm_ecid_wtls6 = "wap-wsg-idm-ecid-wtls6"; - public final static String OBJ_wap_wsg_idm_ecid_wtls6 = OBJ_wap_wsg_idm_ecid + ".6"; - - public final static int NID_wap_wsg_idm_ecid_wtls7 = 740; - public final static String SN_wap_wsg_idm_ecid_wtls7 = "wap-wsg-idm-ecid-wtls7"; - public final static String OBJ_wap_wsg_idm_ecid_wtls7 = OBJ_wap_wsg_idm_ecid + ".7"; - - public final static int NID_wap_wsg_idm_ecid_wtls8 = 741; - public final static String SN_wap_wsg_idm_ecid_wtls8 = "wap-wsg-idm-ecid-wtls8"; - public final static String OBJ_wap_wsg_idm_ecid_wtls8 = OBJ_wap_wsg_idm_ecid + ".8"; - - public final static int NID_wap_wsg_idm_ecid_wtls9 = 742; - public final static String SN_wap_wsg_idm_ecid_wtls9 = "wap-wsg-idm-ecid-wtls9"; - public final static String OBJ_wap_wsg_idm_ecid_wtls9 = OBJ_wap_wsg_idm_ecid + ".9"; - - public final static int NID_wap_wsg_idm_ecid_wtls10 = 743; - public final static String SN_wap_wsg_idm_ecid_wtls10 = "wap-wsg-idm-ecid-wtls10"; - public final static String OBJ_wap_wsg_idm_ecid_wtls10 = OBJ_wap_wsg_idm_ecid + ".10"; - - public final static int NID_wap_wsg_idm_ecid_wtls11 = 744; - public final static String SN_wap_wsg_idm_ecid_wtls11 = "wap-wsg-idm-ecid-wtls11"; - public final static String OBJ_wap_wsg_idm_ecid_wtls11 = OBJ_wap_wsg_idm_ecid + ".11"; - - public final static int NID_wap_wsg_idm_ecid_wtls12 = 745; - public final static String SN_wap_wsg_idm_ecid_wtls12 = "wap-wsg-idm-ecid-wtls12"; - public final static String OBJ_wap_wsg_idm_ecid_wtls12 = OBJ_wap_wsg_idm_ecid + ".12"; - - public final static int NID_any_policy = 746; - public final static String SN_any_policy = "anyPolicy"; - public final static String LN_any_policy = "X509v3 Any Policy"; - public final static String OBJ_any_policy = OBJ_certificate_policies + ".0"; - - public final static int NID_policy_mappings = 747; - public final static String SN_policy_mappings = "policyMappings"; - public final static String LN_policy_mappings = "X509v3 Policy Mappings"; - public final static String OBJ_policy_mappings = OBJ_id_ce + ".33"; - - public final static int NID_inhibit_any_policy = 748; - public final static String SN_inhibit_any_policy = "inhibitAnyPolicy"; - public final static String LN_inhibit_any_policy = "X509v3 Inhibit Any Policy"; - public final static String OBJ_inhibit_any_policy = OBJ_id_ce + ".54"; - - public final static int NID_ipsec3 = 749; - public final static String SN_ipsec3 = "Oakley-EC2N-3"; - public final static String LN_ipsec3 = "ipsec3"; - - public final static int NID_ipsec4 = 750; - public final static String SN_ipsec4 = "Oakley-EC2N-4"; - public final static String LN_ipsec4 = "ipsec4"; - - static { - addObject(NID_undef, SN_undef, LN_undef, OBJ_undef); // NID: 0 - addObject(NID_rsadsi, SN_rsadsi, LN_rsadsi, OBJ_rsadsi); // NID: 1 - addObject(NID_pkcs, SN_pkcs, LN_pkcs, OBJ_pkcs); // NID: 2 - addObject(NID_md2, SN_md2, LN_md2, OBJ_md2); // NID: 3 - addObject(NID_md5, SN_md5, LN_md5, OBJ_md5); // NID: 4 - addObject(NID_rc4, SN_rc4, LN_rc4, OBJ_rc4); // NID: 5 - addObject(NID_rsaEncryption, null, LN_rsaEncryption, OBJ_rsaEncryption); // NID: 6 - addObject(NID_md2WithRSAEncryption, SN_md2WithRSAEncryption, LN_md2WithRSAEncryption, OBJ_md2WithRSAEncryption); // NID: 7 - addObject(NID_md5WithRSAEncryption, SN_md5WithRSAEncryption, LN_md5WithRSAEncryption, OBJ_md5WithRSAEncryption); // NID: 8 - addObject(NID_pbeWithMD2AndDES_CBC, SN_pbeWithMD2AndDES_CBC, LN_pbeWithMD2AndDES_CBC, OBJ_pbeWithMD2AndDES_CBC); // NID: 9 - addObject(NID_pbeWithMD5AndDES_CBC, SN_pbeWithMD5AndDES_CBC, LN_pbeWithMD5AndDES_CBC, OBJ_pbeWithMD5AndDES_CBC); // NID: 10 - addObject(NID_X500, SN_X500, LN_X500, OBJ_X500); // NID: 11 - addObject(NID_X509, SN_X509, null, OBJ_X509); // NID: 12 - addObject(NID_commonName, SN_commonName, LN_commonName, OBJ_commonName); // NID: 13 - addObject(NID_countryName, SN_countryName, LN_countryName, OBJ_countryName); // NID: 14 - addObject(NID_localityName, SN_localityName, LN_localityName, OBJ_localityName); // NID: 15 - addObject(NID_stateOrProvinceName, SN_stateOrProvinceName, LN_stateOrProvinceName, OBJ_stateOrProvinceName); // NID: 16 - addObject(NID_organizationName, SN_organizationName, LN_organizationName, OBJ_organizationName); // NID: 17 - addObject(NID_organizationalUnitName, SN_organizationalUnitName, LN_organizationalUnitName, OBJ_organizationalUnitName); // NID: 18 - addObject(NID_rsa, SN_rsa, LN_rsa, OBJ_rsa); // NID: 19 - addObject(NID_pkcs7, SN_pkcs7, null, OBJ_pkcs7); // NID: 20 - addObject(NID_pkcs7_data, null, LN_pkcs7_data, OBJ_pkcs7_data); // NID: 21 - addObject(NID_pkcs7_signed, null, LN_pkcs7_signed, OBJ_pkcs7_signed); // NID: 22 - addObject(NID_pkcs7_enveloped, null, LN_pkcs7_enveloped, OBJ_pkcs7_enveloped); // NID: 23 - addObject(NID_pkcs7_signedAndEnveloped, null, LN_pkcs7_signedAndEnveloped, OBJ_pkcs7_signedAndEnveloped); // NID: 24 - addObject(NID_pkcs7_digest, null, LN_pkcs7_digest, OBJ_pkcs7_digest); // NID: 25 - addObject(NID_pkcs7_encrypted, null, LN_pkcs7_encrypted, OBJ_pkcs7_encrypted); // NID: 26 - addObject(NID_pkcs3, SN_pkcs3, null, OBJ_pkcs3); // NID: 27 - addObject(NID_dhKeyAgreement, null, LN_dhKeyAgreement, OBJ_dhKeyAgreement); // NID: 28 - addObject(NID_des_ecb, SN_des_ecb, LN_des_ecb, OBJ_des_ecb); // NID: 29 - addObject(NID_des_cfb64, SN_des_cfb64, LN_des_cfb64, OBJ_des_cfb64); // NID: 30 - addObject(NID_des_cbc, SN_des_cbc, LN_des_cbc, OBJ_des_cbc); // NID: 31 - addObject(NID_des_ede_ecb, SN_des_ede_ecb, LN_des_ede_ecb, OBJ_des_ede_ecb); // NID: 32 - addObject(NID_des_ede3_ecb, SN_des_ede3_ecb, LN_des_ede3_ecb, null); // NID: 33 - addObject(NID_idea_cbc, SN_idea_cbc, LN_idea_cbc, OBJ_idea_cbc); // NID: 34 - addObject(NID_idea_cfb64, SN_idea_cfb64, LN_idea_cfb64, null); // NID: 35 - addObject(NID_idea_ecb, SN_idea_ecb, LN_idea_ecb, null); // NID: 36 - addObject(NID_rc2_cbc, SN_rc2_cbc, LN_rc2_cbc, OBJ_rc2_cbc); // NID: 37 - addObject(NID_rc2_ecb, SN_rc2_ecb, LN_rc2_ecb, null); // NID: 38 - addObject(NID_rc2_cfb64, SN_rc2_cfb64, LN_rc2_cfb64, null); // NID: 39 - addObject(NID_rc2_ofb64, SN_rc2_ofb64, LN_rc2_ofb64, null); // NID: 40 - addObject(NID_sha, SN_sha, LN_sha, OBJ_sha); // NID: 41 - addObject(NID_shaWithRSAEncryption, SN_shaWithRSAEncryption, LN_shaWithRSAEncryption, OBJ_shaWithRSAEncryption); // NID: 42 - addObject(NID_des_ede_cbc, SN_des_ede_cbc, LN_des_ede_cbc, null); // NID: 43 - addObject(NID_des_ede3_cbc, SN_des_ede3_cbc, LN_des_ede3_cbc, OBJ_des_ede3_cbc); // NID: 44 - addObject(NID_des_ofb64, SN_des_ofb64, LN_des_ofb64, OBJ_des_ofb64); // NID: 45 - addObject(NID_idea_ofb64, SN_idea_ofb64, LN_idea_ofb64, null); // NID: 46 - addObject(NID_pkcs9, SN_pkcs9, null, OBJ_pkcs9); // NID: 47 - addObject(NID_pkcs9_emailAddress, null, LN_pkcs9_emailAddress, OBJ_pkcs9_emailAddress); // NID: 48 - addObject(NID_pkcs9_unstructuredName, null, LN_pkcs9_unstructuredName, OBJ_pkcs9_unstructuredName); // NID: 49 - addObject(NID_pkcs9_contentType, null, LN_pkcs9_contentType, OBJ_pkcs9_contentType); // NID: 50 - addObject(NID_pkcs9_messageDigest, null, LN_pkcs9_messageDigest, OBJ_pkcs9_messageDigest); // NID: 51 - addObject(NID_pkcs9_signingTime, null, LN_pkcs9_signingTime, OBJ_pkcs9_signingTime); // NID: 52 - addObject(NID_pkcs9_countersignature, null, LN_pkcs9_countersignature, OBJ_pkcs9_countersignature); // NID: 53 - addObject(NID_pkcs9_challengePassword, null, LN_pkcs9_challengePassword, OBJ_pkcs9_challengePassword); // NID: 54 - addObject(NID_pkcs9_unstructuredAddress, null, LN_pkcs9_unstructuredAddress, OBJ_pkcs9_unstructuredAddress); // NID: 55 - addObject(NID_pkcs9_extCertAttributes, null, LN_pkcs9_extCertAttributes, OBJ_pkcs9_extCertAttributes); // NID: 56 - addObject(NID_netscape, SN_netscape, LN_netscape, OBJ_netscape); // NID: 57 - addObject(NID_netscape_cert_extension, SN_netscape_cert_extension, LN_netscape_cert_extension, OBJ_netscape_cert_extension); // NID: 58 - addObject(NID_netscape_data_type, SN_netscape_data_type, LN_netscape_data_type, OBJ_netscape_data_type); // NID: 59 - addObject(NID_des_ede_cfb64, SN_des_ede_cfb64, LN_des_ede_cfb64, null); // NID: 60 - addObject(NID_des_ede3_cfb64, SN_des_ede3_cfb64, LN_des_ede3_cfb64, null); // NID: 61 - addObject(NID_des_ede_ofb64, SN_des_ede_ofb64, LN_des_ede_ofb64, null); // NID: 62 - addObject(NID_des_ede3_ofb64, SN_des_ede3_ofb64, LN_des_ede3_ofb64, null); // NID: 63 - addObject(NID_sha1, SN_sha1, LN_sha1, OBJ_sha1); // NID: 64 - addObject(NID_sha1WithRSAEncryption, SN_sha1WithRSAEncryption, LN_sha1WithRSAEncryption, OBJ_sha1WithRSAEncryption); // NID: 65 - addObject(NID_dsaWithSHA, SN_dsaWithSHA, LN_dsaWithSHA, OBJ_dsaWithSHA); // NID: 66 - addObject(NID_dsa_2, SN_dsa_2, LN_dsa_2, OBJ_dsa_2); // NID: 67 - addObject(NID_pbeWithSHA1AndRC2_CBC, SN_pbeWithSHA1AndRC2_CBC, LN_pbeWithSHA1AndRC2_CBC, OBJ_pbeWithSHA1AndRC2_CBC); // NID: 68 - addObject(NID_id_pbkdf2, null, LN_id_pbkdf2, OBJ_id_pbkdf2); // NID: 69 - addObject(NID_dsaWithSHA1_2, SN_dsaWithSHA1_2, LN_dsaWithSHA1_2, OBJ_dsaWithSHA1_2); // NID: 70 - addObject(NID_netscape_cert_type, SN_netscape_cert_type, LN_netscape_cert_type, OBJ_netscape_cert_type); // NID: 71 - addObject(NID_netscape_base_url, SN_netscape_base_url, LN_netscape_base_url, OBJ_netscape_base_url); // NID: 72 - addObject(NID_netscape_revocation_url, SN_netscape_revocation_url, LN_netscape_revocation_url, OBJ_netscape_revocation_url); // NID: 73 - addObject(NID_netscape_ca_revocation_url, SN_netscape_ca_revocation_url, LN_netscape_ca_revocation_url, OBJ_netscape_ca_revocation_url); // NID: 74 - addObject(NID_netscape_renewal_url, SN_netscape_renewal_url, LN_netscape_renewal_url, OBJ_netscape_renewal_url); // NID: 75 - addObject(NID_netscape_ca_policy_url, SN_netscape_ca_policy_url, LN_netscape_ca_policy_url, OBJ_netscape_ca_policy_url); // NID: 76 - addObject(NID_netscape_ssl_server_name, SN_netscape_ssl_server_name, LN_netscape_ssl_server_name, OBJ_netscape_ssl_server_name); // NID: 77 - addObject(NID_netscape_comment, SN_netscape_comment, LN_netscape_comment, OBJ_netscape_comment); // NID: 78 - addObject(NID_netscape_cert_sequence, SN_netscape_cert_sequence, LN_netscape_cert_sequence, OBJ_netscape_cert_sequence); // NID: 79 - addObject(NID_desx_cbc, SN_desx_cbc, LN_desx_cbc, null); // NID: 80 - addObject(NID_id_ce, SN_id_ce, null, OBJ_id_ce); // NID: 81 - addObject(NID_subject_key_identifier, SN_subject_key_identifier, LN_subject_key_identifier, OBJ_subject_key_identifier); // NID: 82 - addObject(NID_key_usage, SN_key_usage, LN_key_usage, OBJ_key_usage); // NID: 83 - addObject(NID_private_key_usage_period, SN_private_key_usage_period, LN_private_key_usage_period, OBJ_private_key_usage_period); // NID: 84 - addObject(NID_subject_alt_name, SN_subject_alt_name, LN_subject_alt_name, OBJ_subject_alt_name); // NID: 85 - addObject(NID_issuer_alt_name, SN_issuer_alt_name, LN_issuer_alt_name, OBJ_issuer_alt_name); // NID: 86 - addObject(NID_basic_constraints, SN_basic_constraints, LN_basic_constraints, OBJ_basic_constraints); // NID: 87 - addObject(NID_crl_number, SN_crl_number, LN_crl_number, OBJ_crl_number); // NID: 88 - addObject(NID_certificate_policies, SN_certificate_policies, LN_certificate_policies, OBJ_certificate_policies); // NID: 89 - addObject(NID_authority_key_identifier, SN_authority_key_identifier, LN_authority_key_identifier, OBJ_authority_key_identifier); // NID: 90 - addObject(NID_bf_cbc, SN_bf_cbc, LN_bf_cbc, OBJ_bf_cbc); // NID: 91 - addObject(NID_bf_ecb, SN_bf_ecb, LN_bf_ecb, null); // NID: 92 - addObject(NID_bf_cfb64, SN_bf_cfb64, LN_bf_cfb64, null); // NID: 93 - addObject(NID_bf_ofb64, SN_bf_ofb64, LN_bf_ofb64, null); // NID: 94 - addObject(NID_mdc2, SN_mdc2, LN_mdc2, OBJ_mdc2); // NID: 95 - addObject(NID_mdc2WithRSA, SN_mdc2WithRSA, LN_mdc2WithRSA, OBJ_mdc2WithRSA); // NID: 96 - addObject(NID_rc4_40, SN_rc4_40, LN_rc4_40, null); // NID: 97 - addObject(NID_rc2_40_cbc, SN_rc2_40_cbc, LN_rc2_40_cbc, OBJ_rc2_40_cbc); // NID: 98 - addObject(NID_givenName, SN_givenName, LN_givenName, OBJ_givenName); // NID: 99 - addObject(NID_surname, SN_surname, LN_surname, OBJ_surname); // NID: 100 - addObject(NID_initials, null, LN_initials, OBJ_initials); // NID: 101 - addObject(NID_crl_distribution_points, SN_crl_distribution_points, LN_crl_distribution_points, OBJ_crl_distribution_points); // NID: 103 - addObject(NID_md5WithRSA, SN_md5WithRSA, LN_md5WithRSA, OBJ_md5WithRSA); // NID: 104 - addObject(NID_serialNumber, null, LN_serialNumber, OBJ_serialNumber); // NID: 105 - addObject(NID_title, null, LN_title, OBJ_title); // NID: 106 - addObject(NID_description, null, LN_description, OBJ_description); // NID: 107 - addObject(NID_cast5_cbc, SN_cast5_cbc, LN_cast5_cbc, OBJ_cast5_cbc); // NID: 108 - addObject(NID_cast5_ecb, SN_cast5_ecb, LN_cast5_ecb, null); // NID: 109 - addObject(NID_cast5_cfb64, SN_cast5_cfb64, LN_cast5_cfb64, null); // NID: 110 - addObject(NID_cast5_ofb64, SN_cast5_ofb64, LN_cast5_ofb64, null); // NID: 111 - addObject(NID_pbeWithMD5AndCast5_CBC, null, LN_pbeWithMD5AndCast5_CBC, OBJ_pbeWithMD5AndCast5_CBC); // NID: 112 - addObject(NID_dsaWithSHA1, SN_dsaWithSHA1, LN_dsaWithSHA1, OBJ_dsaWithSHA1); // NID: 113 - addObject(NID_md5_sha1, SN_md5_sha1, LN_md5_sha1, null); // NID: 114 - addObject(NID_sha1WithRSA, SN_sha1WithRSA, LN_sha1WithRSA, OBJ_sha1WithRSA); // NID: 115 - addObject(NID_dsa, SN_dsa, LN_dsa, OBJ_dsa); // NID: 116 - addObject(NID_ripemd160, SN_ripemd160, LN_ripemd160, OBJ_ripemd160); // NID: 117 - addObject(NID_ripemd160WithRSA, SN_ripemd160WithRSA, LN_ripemd160WithRSA, OBJ_ripemd160WithRSA); // NID: 119 - addObject(NID_rc5_cbc, SN_rc5_cbc, LN_rc5_cbc, OBJ_rc5_cbc); // NID: 120 - addObject(NID_rc5_ecb, SN_rc5_ecb, LN_rc5_ecb, null); // NID: 121 - addObject(NID_rc5_cfb64, SN_rc5_cfb64, LN_rc5_cfb64, null); // NID: 122 - addObject(NID_rc5_ofb64, SN_rc5_ofb64, LN_rc5_ofb64, null); // NID: 123 - addObject(NID_rle_compression, SN_rle_compression, LN_rle_compression, OBJ_rle_compression); // NID: 124 - addObject(NID_zlib_compression, SN_zlib_compression, LN_zlib_compression, OBJ_zlib_compression); // NID: 125 - addObject(NID_ext_key_usage, SN_ext_key_usage, LN_ext_key_usage, OBJ_ext_key_usage); // NID: 126 - addObject(NID_id_pkix, SN_id_pkix, null, OBJ_id_pkix); // NID: 127 - addObject(NID_id_kp, SN_id_kp, null, OBJ_id_kp); // NID: 128 - addObject(NID_server_auth, SN_server_auth, LN_server_auth, OBJ_server_auth); // NID: 129 - addObject(NID_client_auth, SN_client_auth, LN_client_auth, OBJ_client_auth); // NID: 130 - addObject(NID_code_sign, SN_code_sign, LN_code_sign, OBJ_code_sign); // NID: 131 - addObject(NID_email_protect, SN_email_protect, LN_email_protect, OBJ_email_protect); // NID: 132 - addObject(NID_time_stamp, SN_time_stamp, LN_time_stamp, OBJ_time_stamp); // NID: 133 - addObject(NID_ms_code_ind, SN_ms_code_ind, LN_ms_code_ind, OBJ_ms_code_ind); // NID: 134 - addObject(NID_ms_code_com, SN_ms_code_com, LN_ms_code_com, OBJ_ms_code_com); // NID: 135 - addObject(NID_ms_ctl_sign, SN_ms_ctl_sign, LN_ms_ctl_sign, OBJ_ms_ctl_sign); // NID: 136 - addObject(NID_ms_sgc, SN_ms_sgc, LN_ms_sgc, OBJ_ms_sgc); // NID: 137 - addObject(NID_ms_efs, SN_ms_efs, LN_ms_efs, OBJ_ms_efs); // NID: 138 - addObject(NID_ns_sgc, SN_ns_sgc, LN_ns_sgc, OBJ_ns_sgc); // NID: 139 - addObject(NID_delta_crl, SN_delta_crl, LN_delta_crl, OBJ_delta_crl); // NID: 140 - addObject(NID_crl_reason, SN_crl_reason, LN_crl_reason, OBJ_crl_reason); // NID: 141 - addObject(NID_invalidity_date, SN_invalidity_date, LN_invalidity_date, OBJ_invalidity_date); // NID: 142 - addObject(NID_sxnet, SN_sxnet, LN_sxnet, OBJ_sxnet); // NID: 143 - addObject(NID_pbe_WithSHA1And128BitRC4, SN_pbe_WithSHA1And128BitRC4, LN_pbe_WithSHA1And128BitRC4, OBJ_pbe_WithSHA1And128BitRC4); // NID: 144 - addObject(NID_pbe_WithSHA1And40BitRC4, SN_pbe_WithSHA1And40BitRC4, LN_pbe_WithSHA1And40BitRC4, OBJ_pbe_WithSHA1And40BitRC4); // NID: 145 - addObject(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, SN_pbe_WithSHA1And3_Key_TripleDES_CBC, LN_pbe_WithSHA1And3_Key_TripleDES_CBC, OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC); // NID: 146 - addObject(NID_pbe_WithSHA1And2_Key_TripleDES_CBC, SN_pbe_WithSHA1And2_Key_TripleDES_CBC, LN_pbe_WithSHA1And2_Key_TripleDES_CBC, OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC); // NID: 147 - addObject(NID_pbe_WithSHA1And128BitRC2_CBC, SN_pbe_WithSHA1And128BitRC2_CBC, LN_pbe_WithSHA1And128BitRC2_CBC, OBJ_pbe_WithSHA1And128BitRC2_CBC); // NID: 148 - addObject(NID_pbe_WithSHA1And40BitRC2_CBC, SN_pbe_WithSHA1And40BitRC2_CBC, LN_pbe_WithSHA1And40BitRC2_CBC, OBJ_pbe_WithSHA1And40BitRC2_CBC); // NID: 149 - addObject(NID_keyBag, null, LN_keyBag, OBJ_keyBag); // NID: 150 - addObject(NID_pkcs8ShroudedKeyBag, null, LN_pkcs8ShroudedKeyBag, OBJ_pkcs8ShroudedKeyBag); // NID: 151 - addObject(NID_certBag, null, LN_certBag, OBJ_certBag); // NID: 152 - addObject(NID_crlBag, null, LN_crlBag, OBJ_crlBag); // NID: 153 - addObject(NID_secretBag, null, LN_secretBag, OBJ_secretBag); // NID: 154 - addObject(NID_safeContentsBag, null, LN_safeContentsBag, OBJ_safeContentsBag); // NID: 155 - addObject(NID_friendlyName, null, LN_friendlyName, OBJ_friendlyName); // NID: 156 - addObject(NID_localKeyID, null, LN_localKeyID, OBJ_localKeyID); // NID: 157 - addObject(NID_x509Certificate, null, LN_x509Certificate, OBJ_x509Certificate); // NID: 158 - addObject(NID_sdsiCertificate, null, LN_sdsiCertificate, OBJ_sdsiCertificate); // NID: 159 - addObject(NID_x509Crl, null, LN_x509Crl, OBJ_x509Crl); // NID: 160 - addObject(NID_pbes2, null, LN_pbes2, OBJ_pbes2); // NID: 161 - addObject(NID_pbmac1, null, LN_pbmac1, OBJ_pbmac1); // NID: 162 - addObject(NID_hmacWithSHA1, null, LN_hmacWithSHA1, OBJ_hmacWithSHA1); // NID: 163 - addObject(NID_id_qt_cps, SN_id_qt_cps, LN_id_qt_cps, OBJ_id_qt_cps); // NID: 164 - addObject(NID_id_qt_unotice, SN_id_qt_unotice, LN_id_qt_unotice, OBJ_id_qt_unotice); // NID: 165 - addObject(NID_rc2_64_cbc, SN_rc2_64_cbc, LN_rc2_64_cbc, null); // NID: 166 - addObject(NID_SMIMECapabilities, SN_SMIMECapabilities, LN_SMIMECapabilities, OBJ_SMIMECapabilities); // NID: 167 - addObject(NID_pbeWithMD2AndRC2_CBC, SN_pbeWithMD2AndRC2_CBC, LN_pbeWithMD2AndRC2_CBC, OBJ_pbeWithMD2AndRC2_CBC); // NID: 168 - addObject(NID_pbeWithMD5AndRC2_CBC, SN_pbeWithMD5AndRC2_CBC, LN_pbeWithMD5AndRC2_CBC, OBJ_pbeWithMD5AndRC2_CBC); // NID: 169 - addObject(NID_pbeWithSHA1AndDES_CBC, SN_pbeWithSHA1AndDES_CBC, LN_pbeWithSHA1AndDES_CBC, OBJ_pbeWithSHA1AndDES_CBC); // NID: 170 - addObject(NID_ms_ext_req, SN_ms_ext_req, LN_ms_ext_req, OBJ_ms_ext_req); // NID: 171 - addObject(NID_ext_req, SN_ext_req, LN_ext_req, OBJ_ext_req); // NID: 172 - addObject(NID_name, SN_name, LN_name, OBJ_name); // NID: 173 - addObject(NID_dnQualifier, SN_dnQualifier, LN_dnQualifier, OBJ_dnQualifier); // NID: 174 - addObject(NID_id_pe, SN_id_pe, null, OBJ_id_pe); // NID: 175 - addObject(NID_id_ad, SN_id_ad, null, OBJ_id_ad); // NID: 176 - addObject(NID_info_access, SN_info_access, LN_info_access, OBJ_info_access); // NID: 177 - addObject(NID_ad_OCSP, SN_ad_OCSP, LN_ad_OCSP, OBJ_ad_OCSP); // NID: 178 - addObject(NID_ad_ca_issuers, SN_ad_ca_issuers, LN_ad_ca_issuers, OBJ_ad_ca_issuers); // NID: 179 - addObject(NID_OCSP_sign, SN_OCSP_sign, LN_OCSP_sign, OBJ_OCSP_sign); // NID: 180 - addObject(NID_iso, SN_iso, LN_iso, OBJ_iso); // NID: 181 - addObject(NID_member_body, SN_member_body, LN_member_body, OBJ_member_body); // NID: 182 - addObject(NID_ISO_US, SN_ISO_US, LN_ISO_US, OBJ_ISO_US); // NID: 183 - addObject(NID_X9_57, SN_X9_57, LN_X9_57, OBJ_X9_57); // NID: 184 - addObject(NID_X9cm, SN_X9cm, LN_X9cm, OBJ_X9cm); // NID: 185 - addObject(NID_pkcs1, SN_pkcs1, null, OBJ_pkcs1); // NID: 186 - addObject(NID_pkcs5, SN_pkcs5, null, OBJ_pkcs5); // NID: 187 - addObject(NID_SMIME, SN_SMIME, LN_SMIME, OBJ_SMIME); // NID: 188 - addObject(NID_id_smime_mod, SN_id_smime_mod, null, OBJ_id_smime_mod); // NID: 189 - addObject(NID_id_smime_ct, SN_id_smime_ct, null, OBJ_id_smime_ct); // NID: 190 - addObject(NID_id_smime_aa, SN_id_smime_aa, null, OBJ_id_smime_aa); // NID: 191 - addObject(NID_id_smime_alg, SN_id_smime_alg, null, OBJ_id_smime_alg); // NID: 192 - addObject(NID_id_smime_cd, SN_id_smime_cd, null, OBJ_id_smime_cd); // NID: 193 - addObject(NID_id_smime_spq, SN_id_smime_spq, null, OBJ_id_smime_spq); // NID: 194 - addObject(NID_id_smime_cti, SN_id_smime_cti, null, OBJ_id_smime_cti); // NID: 195 - addObject(NID_id_smime_mod_cms, SN_id_smime_mod_cms, null, OBJ_id_smime_mod_cms); // NID: 196 - addObject(NID_id_smime_mod_ess, SN_id_smime_mod_ess, null, OBJ_id_smime_mod_ess); // NID: 197 - addObject(NID_id_smime_mod_oid, SN_id_smime_mod_oid, null, OBJ_id_smime_mod_oid); // NID: 198 - addObject(NID_id_smime_mod_msg_v3, SN_id_smime_mod_msg_v3, null, OBJ_id_smime_mod_msg_v3); // NID: 199 - addObject(NID_id_smime_mod_ets_eSignature_88, SN_id_smime_mod_ets_eSignature_88, null, OBJ_id_smime_mod_ets_eSignature_88); // NID: 200 - addObject(NID_id_smime_mod_ets_eSignature_97, SN_id_smime_mod_ets_eSignature_97, null, OBJ_id_smime_mod_ets_eSignature_97); // NID: 201 - addObject(NID_id_smime_mod_ets_eSigPolicy_88, SN_id_smime_mod_ets_eSigPolicy_88, null, OBJ_id_smime_mod_ets_eSigPolicy_88); // NID: 202 - addObject(NID_id_smime_mod_ets_eSigPolicy_97, SN_id_smime_mod_ets_eSigPolicy_97, null, OBJ_id_smime_mod_ets_eSigPolicy_97); // NID: 203 - addObject(NID_id_smime_ct_receipt, SN_id_smime_ct_receipt, null, OBJ_id_smime_ct_receipt); // NID: 204 - addObject(NID_id_smime_ct_authData, SN_id_smime_ct_authData, null, OBJ_id_smime_ct_authData); // NID: 205 - addObject(NID_id_smime_ct_publishCert, SN_id_smime_ct_publishCert, null, OBJ_id_smime_ct_publishCert); // NID: 206 - addObject(NID_id_smime_ct_TSTInfo, SN_id_smime_ct_TSTInfo, null, OBJ_id_smime_ct_TSTInfo); // NID: 207 - addObject(NID_id_smime_ct_TDTInfo, SN_id_smime_ct_TDTInfo, null, OBJ_id_smime_ct_TDTInfo); // NID: 208 - addObject(NID_id_smime_ct_contentInfo, SN_id_smime_ct_contentInfo, null, OBJ_id_smime_ct_contentInfo); // NID: 209 - addObject(NID_id_smime_ct_DVCSRequestData, SN_id_smime_ct_DVCSRequestData, null, OBJ_id_smime_ct_DVCSRequestData); // NID: 210 - addObject(NID_id_smime_ct_DVCSResponseData, SN_id_smime_ct_DVCSResponseData, null, OBJ_id_smime_ct_DVCSResponseData); // NID: 211 - addObject(NID_id_smime_aa_receiptRequest, SN_id_smime_aa_receiptRequest, null, OBJ_id_smime_aa_receiptRequest); // NID: 212 - addObject(NID_id_smime_aa_securityLabel, SN_id_smime_aa_securityLabel, null, OBJ_id_smime_aa_securityLabel); // NID: 213 - addObject(NID_id_smime_aa_mlExpandHistory, SN_id_smime_aa_mlExpandHistory, null, OBJ_id_smime_aa_mlExpandHistory); // NID: 214 - addObject(NID_id_smime_aa_contentHint, SN_id_smime_aa_contentHint, null, OBJ_id_smime_aa_contentHint); // NID: 215 - addObject(NID_id_smime_aa_msgSigDigest, SN_id_smime_aa_msgSigDigest, null, OBJ_id_smime_aa_msgSigDigest); // NID: 216 - addObject(NID_id_smime_aa_encapContentType, SN_id_smime_aa_encapContentType, null, OBJ_id_smime_aa_encapContentType); // NID: 217 - addObject(NID_id_smime_aa_contentIdentifier, SN_id_smime_aa_contentIdentifier, null, OBJ_id_smime_aa_contentIdentifier); // NID: 218 - addObject(NID_id_smime_aa_macValue, SN_id_smime_aa_macValue, null, OBJ_id_smime_aa_macValue); // NID: 219 - addObject(NID_id_smime_aa_equivalentLabels, SN_id_smime_aa_equivalentLabels, null, OBJ_id_smime_aa_equivalentLabels); // NID: 220 - addObject(NID_id_smime_aa_contentReference, SN_id_smime_aa_contentReference, null, OBJ_id_smime_aa_contentReference); // NID: 221 - addObject(NID_id_smime_aa_encrypKeyPref, SN_id_smime_aa_encrypKeyPref, null, OBJ_id_smime_aa_encrypKeyPref); // NID: 222 - addObject(NID_id_smime_aa_signingCertificate, SN_id_smime_aa_signingCertificate, null, OBJ_id_smime_aa_signingCertificate); // NID: 223 - addObject(NID_id_smime_aa_smimeEncryptCerts, SN_id_smime_aa_smimeEncryptCerts, null, OBJ_id_smime_aa_smimeEncryptCerts); // NID: 224 - addObject(NID_id_smime_aa_timeStampToken, SN_id_smime_aa_timeStampToken, null, OBJ_id_smime_aa_timeStampToken); // NID: 225 - addObject(NID_id_smime_aa_ets_sigPolicyId, SN_id_smime_aa_ets_sigPolicyId, null, OBJ_id_smime_aa_ets_sigPolicyId); // NID: 226 - addObject(NID_id_smime_aa_ets_commitmentType, SN_id_smime_aa_ets_commitmentType, null, OBJ_id_smime_aa_ets_commitmentType); // NID: 227 - addObject(NID_id_smime_aa_ets_signerLocation, SN_id_smime_aa_ets_signerLocation, null, OBJ_id_smime_aa_ets_signerLocation); // NID: 228 - addObject(NID_id_smime_aa_ets_signerAttr, SN_id_smime_aa_ets_signerAttr, null, OBJ_id_smime_aa_ets_signerAttr); // NID: 229 - addObject(NID_id_smime_aa_ets_otherSigCert, SN_id_smime_aa_ets_otherSigCert, null, OBJ_id_smime_aa_ets_otherSigCert); // NID: 230 - addObject(NID_id_smime_aa_ets_contentTimestamp, SN_id_smime_aa_ets_contentTimestamp, null, OBJ_id_smime_aa_ets_contentTimestamp); // NID: 231 - addObject(NID_id_smime_aa_ets_CertificateRefs, SN_id_smime_aa_ets_CertificateRefs, null, OBJ_id_smime_aa_ets_CertificateRefs); // NID: 232 - addObject(NID_id_smime_aa_ets_RevocationRefs, SN_id_smime_aa_ets_RevocationRefs, null, OBJ_id_smime_aa_ets_RevocationRefs); // NID: 233 - addObject(NID_id_smime_aa_ets_certValues, SN_id_smime_aa_ets_certValues, null, OBJ_id_smime_aa_ets_certValues); // NID: 234 - addObject(NID_id_smime_aa_ets_revocationValues, SN_id_smime_aa_ets_revocationValues, null, OBJ_id_smime_aa_ets_revocationValues); // NID: 235 - addObject(NID_id_smime_aa_ets_escTimeStamp, SN_id_smime_aa_ets_escTimeStamp, null, OBJ_id_smime_aa_ets_escTimeStamp); // NID: 236 - addObject(NID_id_smime_aa_ets_certCRLTimestamp, SN_id_smime_aa_ets_certCRLTimestamp, null, OBJ_id_smime_aa_ets_certCRLTimestamp); // NID: 237 - addObject(NID_id_smime_aa_ets_archiveTimeStamp, SN_id_smime_aa_ets_archiveTimeStamp, null, OBJ_id_smime_aa_ets_archiveTimeStamp); // NID: 238 - addObject(NID_id_smime_aa_signatureType, SN_id_smime_aa_signatureType, null, OBJ_id_smime_aa_signatureType); // NID: 239 - addObject(NID_id_smime_aa_dvcs_dvc, SN_id_smime_aa_dvcs_dvc, null, OBJ_id_smime_aa_dvcs_dvc); // NID: 240 - addObject(NID_id_smime_alg_ESDHwith3DES, SN_id_smime_alg_ESDHwith3DES, null, OBJ_id_smime_alg_ESDHwith3DES); // NID: 241 - addObject(NID_id_smime_alg_ESDHwithRC2, SN_id_smime_alg_ESDHwithRC2, null, OBJ_id_smime_alg_ESDHwithRC2); // NID: 242 - addObject(NID_id_smime_alg_3DESwrap, SN_id_smime_alg_3DESwrap, null, OBJ_id_smime_alg_3DESwrap); // NID: 243 - addObject(NID_id_smime_alg_RC2wrap, SN_id_smime_alg_RC2wrap, null, OBJ_id_smime_alg_RC2wrap); // NID: 244 - addObject(NID_id_smime_alg_ESDH, SN_id_smime_alg_ESDH, null, OBJ_id_smime_alg_ESDH); // NID: 245 - addObject(NID_id_smime_alg_CMS3DESwrap, SN_id_smime_alg_CMS3DESwrap, null, OBJ_id_smime_alg_CMS3DESwrap); // NID: 246 - addObject(NID_id_smime_alg_CMSRC2wrap, SN_id_smime_alg_CMSRC2wrap, null, OBJ_id_smime_alg_CMSRC2wrap); // NID: 247 - addObject(NID_id_smime_cd_ldap, SN_id_smime_cd_ldap, null, OBJ_id_smime_cd_ldap); // NID: 248 - addObject(NID_id_smime_spq_ets_sqt_uri, SN_id_smime_spq_ets_sqt_uri, null, OBJ_id_smime_spq_ets_sqt_uri); // NID: 249 - addObject(NID_id_smime_spq_ets_sqt_unotice, SN_id_smime_spq_ets_sqt_unotice, null, OBJ_id_smime_spq_ets_sqt_unotice); // NID: 250 - addObject(NID_id_smime_cti_ets_proofOfOrigin, SN_id_smime_cti_ets_proofOfOrigin, null, OBJ_id_smime_cti_ets_proofOfOrigin); // NID: 251 - addObject(NID_id_smime_cti_ets_proofOfReceipt, SN_id_smime_cti_ets_proofOfReceipt, null, OBJ_id_smime_cti_ets_proofOfReceipt); // NID: 252 - addObject(NID_id_smime_cti_ets_proofOfDelivery, SN_id_smime_cti_ets_proofOfDelivery, null, OBJ_id_smime_cti_ets_proofOfDelivery); // NID: 253 - addObject(NID_id_smime_cti_ets_proofOfSender, SN_id_smime_cti_ets_proofOfSender, null, OBJ_id_smime_cti_ets_proofOfSender); // NID: 254 - addObject(NID_id_smime_cti_ets_proofOfApproval, SN_id_smime_cti_ets_proofOfApproval, null, OBJ_id_smime_cti_ets_proofOfApproval); // NID: 255 - addObject(NID_id_smime_cti_ets_proofOfCreation, SN_id_smime_cti_ets_proofOfCreation, null, OBJ_id_smime_cti_ets_proofOfCreation); // NID: 256 - addObject(NID_md4, SN_md4, LN_md4, OBJ_md4); // NID: 257 - addObject(NID_id_pkix_mod, SN_id_pkix_mod, null, OBJ_id_pkix_mod); // NID: 258 - addObject(NID_id_qt, SN_id_qt, null, OBJ_id_qt); // NID: 259 - addObject(NID_id_it, SN_id_it, null, OBJ_id_it); // NID: 260 - addObject(NID_id_pkip, SN_id_pkip, null, OBJ_id_pkip); // NID: 261 - addObject(NID_id_alg, SN_id_alg, null, OBJ_id_alg); // NID: 262 - addObject(NID_id_cmc, SN_id_cmc, null, OBJ_id_cmc); // NID: 263 - addObject(NID_id_on, SN_id_on, null, OBJ_id_on); // NID: 264 - addObject(NID_id_pda, SN_id_pda, null, OBJ_id_pda); // NID: 265 - addObject(NID_id_aca, SN_id_aca, null, OBJ_id_aca); // NID: 266 - addObject(NID_id_qcs, SN_id_qcs, null, OBJ_id_qcs); // NID: 267 - addObject(NID_id_cct, SN_id_cct, null, OBJ_id_cct); // NID: 268 - addObject(NID_id_pkix1_explicit_88, SN_id_pkix1_explicit_88, null, OBJ_id_pkix1_explicit_88); // NID: 269 - addObject(NID_id_pkix1_implicit_88, SN_id_pkix1_implicit_88, null, OBJ_id_pkix1_implicit_88); // NID: 270 - addObject(NID_id_pkix1_explicit_93, SN_id_pkix1_explicit_93, null, OBJ_id_pkix1_explicit_93); // NID: 271 - addObject(NID_id_pkix1_implicit_93, SN_id_pkix1_implicit_93, null, OBJ_id_pkix1_implicit_93); // NID: 272 - addObject(NID_id_mod_crmf, SN_id_mod_crmf, null, OBJ_id_mod_crmf); // NID: 273 - addObject(NID_id_mod_cmc, SN_id_mod_cmc, null, OBJ_id_mod_cmc); // NID: 274 - addObject(NID_id_mod_kea_profile_88, SN_id_mod_kea_profile_88, null, OBJ_id_mod_kea_profile_88); // NID: 275 - addObject(NID_id_mod_kea_profile_93, SN_id_mod_kea_profile_93, null, OBJ_id_mod_kea_profile_93); // NID: 276 - addObject(NID_id_mod_cmp, SN_id_mod_cmp, null, OBJ_id_mod_cmp); // NID: 277 - addObject(NID_id_mod_qualified_cert_88, SN_id_mod_qualified_cert_88, null, OBJ_id_mod_qualified_cert_88); // NID: 278 - addObject(NID_id_mod_qualified_cert_93, SN_id_mod_qualified_cert_93, null, OBJ_id_mod_qualified_cert_93); // NID: 279 - addObject(NID_id_mod_attribute_cert, SN_id_mod_attribute_cert, null, OBJ_id_mod_attribute_cert); // NID: 280 - addObject(NID_id_mod_timestamp_protocol, SN_id_mod_timestamp_protocol, null, OBJ_id_mod_timestamp_protocol); // NID: 281 - addObject(NID_id_mod_ocsp, SN_id_mod_ocsp, null, OBJ_id_mod_ocsp); // NID: 282 - addObject(NID_id_mod_dvcs, SN_id_mod_dvcs, null, OBJ_id_mod_dvcs); // NID: 283 - addObject(NID_id_mod_cmp2000, SN_id_mod_cmp2000, null, OBJ_id_mod_cmp2000); // NID: 284 - addObject(NID_biometricInfo, SN_biometricInfo, LN_biometricInfo, OBJ_biometricInfo); // NID: 285 - addObject(NID_qcStatements, SN_qcStatements, null, OBJ_qcStatements); // NID: 286 - addObject(NID_ac_auditEntity, SN_ac_auditEntity, null, OBJ_ac_auditEntity); // NID: 287 - addObject(NID_ac_targeting, SN_ac_targeting, null, OBJ_ac_targeting); // NID: 288 - addObject(NID_aaControls, SN_aaControls, null, OBJ_aaControls); // NID: 289 - addObject(NID_sbgp_ipAddrBlock, SN_sbgp_ipAddrBlock, null, OBJ_sbgp_ipAddrBlock); // NID: 290 - addObject(NID_sbgp_autonomousSysNum, SN_sbgp_autonomousSysNum, null, OBJ_sbgp_autonomousSysNum); // NID: 291 - addObject(NID_sbgp_routerIdentifier, SN_sbgp_routerIdentifier, null, OBJ_sbgp_routerIdentifier); // NID: 292 - addObject(NID_textNotice, SN_textNotice, null, OBJ_textNotice); // NID: 293 - addObject(NID_ipsecEndSystem, SN_ipsecEndSystem, LN_ipsecEndSystem, OBJ_ipsecEndSystem); // NID: 294 - addObject(NID_ipsecTunnel, SN_ipsecTunnel, LN_ipsecTunnel, OBJ_ipsecTunnel); // NID: 295 - addObject(NID_ipsecUser, SN_ipsecUser, LN_ipsecUser, OBJ_ipsecUser); // NID: 296 - addObject(NID_dvcs, SN_dvcs, LN_dvcs, OBJ_dvcs); // NID: 297 - addObject(NID_id_it_caProtEncCert, SN_id_it_caProtEncCert, null, OBJ_id_it_caProtEncCert); // NID: 298 - addObject(NID_id_it_signKeyPairTypes, SN_id_it_signKeyPairTypes, null, OBJ_id_it_signKeyPairTypes); // NID: 299 - addObject(NID_id_it_encKeyPairTypes, SN_id_it_encKeyPairTypes, null, OBJ_id_it_encKeyPairTypes); // NID: 300 - addObject(NID_id_it_preferredSymmAlg, SN_id_it_preferredSymmAlg, null, OBJ_id_it_preferredSymmAlg); // NID: 301 - addObject(NID_id_it_caKeyUpdateInfo, SN_id_it_caKeyUpdateInfo, null, OBJ_id_it_caKeyUpdateInfo); // NID: 302 - addObject(NID_id_it_currentCRL, SN_id_it_currentCRL, null, OBJ_id_it_currentCRL); // NID: 303 - addObject(NID_id_it_unsupportedOIDs, SN_id_it_unsupportedOIDs, null, OBJ_id_it_unsupportedOIDs); // NID: 304 - addObject(NID_id_it_subscriptionRequest, SN_id_it_subscriptionRequest, null, OBJ_id_it_subscriptionRequest); // NID: 305 - addObject(NID_id_it_subscriptionResponse, SN_id_it_subscriptionResponse, null, OBJ_id_it_subscriptionResponse); // NID: 306 - addObject(NID_id_it_keyPairParamReq, SN_id_it_keyPairParamReq, null, OBJ_id_it_keyPairParamReq); // NID: 307 - addObject(NID_id_it_keyPairParamRep, SN_id_it_keyPairParamRep, null, OBJ_id_it_keyPairParamRep); // NID: 308 - addObject(NID_id_it_revPassphrase, SN_id_it_revPassphrase, null, OBJ_id_it_revPassphrase); // NID: 309 - addObject(NID_id_it_implicitConfirm, SN_id_it_implicitConfirm, null, OBJ_id_it_implicitConfirm); // NID: 310 - addObject(NID_id_it_confirmWaitTime, SN_id_it_confirmWaitTime, null, OBJ_id_it_confirmWaitTime); // NID: 311 - addObject(NID_id_it_origPKIMessage, SN_id_it_origPKIMessage, null, OBJ_id_it_origPKIMessage); // NID: 312 - addObject(NID_id_regCtrl, SN_id_regCtrl, null, OBJ_id_regCtrl); // NID: 313 - addObject(NID_id_regInfo, SN_id_regInfo, null, OBJ_id_regInfo); // NID: 314 - addObject(NID_id_regCtrl_regToken, SN_id_regCtrl_regToken, null, OBJ_id_regCtrl_regToken); // NID: 315 - addObject(NID_id_regCtrl_authenticator, SN_id_regCtrl_authenticator, null, OBJ_id_regCtrl_authenticator); // NID: 316 - addObject(NID_id_regCtrl_pkiPublicationInfo, SN_id_regCtrl_pkiPublicationInfo, null, OBJ_id_regCtrl_pkiPublicationInfo); // NID: 317 - addObject(NID_id_regCtrl_pkiArchiveOptions, SN_id_regCtrl_pkiArchiveOptions, null, OBJ_id_regCtrl_pkiArchiveOptions); // NID: 318 - addObject(NID_id_regCtrl_oldCertID, SN_id_regCtrl_oldCertID, null, OBJ_id_regCtrl_oldCertID); // NID: 319 - addObject(NID_id_regCtrl_protocolEncrKey, SN_id_regCtrl_protocolEncrKey, null, OBJ_id_regCtrl_protocolEncrKey); // NID: 320 - addObject(NID_id_regInfo_utf8Pairs, SN_id_regInfo_utf8Pairs, null, OBJ_id_regInfo_utf8Pairs); // NID: 321 - addObject(NID_id_regInfo_certReq, SN_id_regInfo_certReq, null, OBJ_id_regInfo_certReq); // NID: 322 - addObject(NID_id_alg_des40, SN_id_alg_des40, null, OBJ_id_alg_des40); // NID: 323 - addObject(NID_id_alg_noSignature, SN_id_alg_noSignature, null, OBJ_id_alg_noSignature); // NID: 324 - addObject(NID_id_alg_dh_sig_hmac_sha1, SN_id_alg_dh_sig_hmac_sha1, null, OBJ_id_alg_dh_sig_hmac_sha1); // NID: 325 - addObject(NID_id_alg_dh_pop, SN_id_alg_dh_pop, null, OBJ_id_alg_dh_pop); // NID: 326 - addObject(NID_id_cmc_statusInfo, SN_id_cmc_statusInfo, null, OBJ_id_cmc_statusInfo); // NID: 327 - addObject(NID_id_cmc_identification, SN_id_cmc_identification, null, OBJ_id_cmc_identification); // NID: 328 - addObject(NID_id_cmc_identityProof, SN_id_cmc_identityProof, null, OBJ_id_cmc_identityProof); // NID: 329 - addObject(NID_id_cmc_dataReturn, SN_id_cmc_dataReturn, null, OBJ_id_cmc_dataReturn); // NID: 330 - addObject(NID_id_cmc_transactionId, SN_id_cmc_transactionId, null, OBJ_id_cmc_transactionId); // NID: 331 - addObject(NID_id_cmc_senderNonce, SN_id_cmc_senderNonce, null, OBJ_id_cmc_senderNonce); // NID: 332 - addObject(NID_id_cmc_recipientNonce, SN_id_cmc_recipientNonce, null, OBJ_id_cmc_recipientNonce); // NID: 333 - addObject(NID_id_cmc_addExtensions, SN_id_cmc_addExtensions, null, OBJ_id_cmc_addExtensions); // NID: 334 - addObject(NID_id_cmc_encryptedPOP, SN_id_cmc_encryptedPOP, null, OBJ_id_cmc_encryptedPOP); // NID: 335 - addObject(NID_id_cmc_decryptedPOP, SN_id_cmc_decryptedPOP, null, OBJ_id_cmc_decryptedPOP); // NID: 336 - addObject(NID_id_cmc_lraPOPWitness, SN_id_cmc_lraPOPWitness, null, OBJ_id_cmc_lraPOPWitness); // NID: 337 - addObject(NID_id_cmc_getCert, SN_id_cmc_getCert, null, OBJ_id_cmc_getCert); // NID: 338 - addObject(NID_id_cmc_getCRL, SN_id_cmc_getCRL, null, OBJ_id_cmc_getCRL); // NID: 339 - addObject(NID_id_cmc_revokeRequest, SN_id_cmc_revokeRequest, null, OBJ_id_cmc_revokeRequest); // NID: 340 - addObject(NID_id_cmc_regInfo, SN_id_cmc_regInfo, null, OBJ_id_cmc_regInfo); // NID: 341 - addObject(NID_id_cmc_responseInfo, SN_id_cmc_responseInfo, null, OBJ_id_cmc_responseInfo); // NID: 342 - addObject(NID_id_cmc_queryPending, SN_id_cmc_queryPending, null, OBJ_id_cmc_queryPending); // NID: 343 - addObject(NID_id_cmc_popLinkRandom, SN_id_cmc_popLinkRandom, null, OBJ_id_cmc_popLinkRandom); // NID: 344 - addObject(NID_id_cmc_popLinkWitness, SN_id_cmc_popLinkWitness, null, OBJ_id_cmc_popLinkWitness); // NID: 345 - addObject(NID_id_cmc_confirmCertAcceptance, SN_id_cmc_confirmCertAcceptance, null, OBJ_id_cmc_confirmCertAcceptance); // NID: 346 - addObject(NID_id_on_personalData, SN_id_on_personalData, null, OBJ_id_on_personalData); // NID: 347 - addObject(NID_id_pda_dateOfBirth, SN_id_pda_dateOfBirth, null, OBJ_id_pda_dateOfBirth); // NID: 348 - addObject(NID_id_pda_placeOfBirth, SN_id_pda_placeOfBirth, null, OBJ_id_pda_placeOfBirth); // NID: 349 - addObject(NID_id_pda_gender, SN_id_pda_gender, null, OBJ_id_pda_gender); // NID: 351 - addObject(NID_id_pda_countryOfCitizenship, SN_id_pda_countryOfCitizenship, null, OBJ_id_pda_countryOfCitizenship); // NID: 352 - addObject(NID_id_pda_countryOfResidence, SN_id_pda_countryOfResidence, null, OBJ_id_pda_countryOfResidence); // NID: 353 - addObject(NID_id_aca_authenticationInfo, SN_id_aca_authenticationInfo, null, OBJ_id_aca_authenticationInfo); // NID: 354 - addObject(NID_id_aca_accessIdentity, SN_id_aca_accessIdentity, null, OBJ_id_aca_accessIdentity); // NID: 355 - addObject(NID_id_aca_chargingIdentity, SN_id_aca_chargingIdentity, null, OBJ_id_aca_chargingIdentity); // NID: 356 - addObject(NID_id_aca_group, SN_id_aca_group, null, OBJ_id_aca_group); // NID: 357 - addObject(NID_id_aca_role, SN_id_aca_role, null, OBJ_id_aca_role); // NID: 358 - addObject(NID_id_qcs_pkixQCSyntax_v1, SN_id_qcs_pkixQCSyntax_v1, null, OBJ_id_qcs_pkixQCSyntax_v1); // NID: 359 - addObject(NID_id_cct_crs, SN_id_cct_crs, null, OBJ_id_cct_crs); // NID: 360 - addObject(NID_id_cct_PKIData, SN_id_cct_PKIData, null, OBJ_id_cct_PKIData); // NID: 361 - addObject(NID_id_cct_PKIResponse, SN_id_cct_PKIResponse, null, OBJ_id_cct_PKIResponse); // NID: 362 - addObject(NID_ad_timeStamping, SN_ad_timeStamping, LN_ad_timeStamping, OBJ_ad_timeStamping); // NID: 363 - addObject(NID_ad_dvcs, SN_ad_dvcs, LN_ad_dvcs, OBJ_ad_dvcs); // NID: 364 - addObject(NID_id_pkix_OCSP_basic, SN_id_pkix_OCSP_basic, LN_id_pkix_OCSP_basic, OBJ_id_pkix_OCSP_basic); // NID: 365 - addObject(NID_id_pkix_OCSP_Nonce, SN_id_pkix_OCSP_Nonce, LN_id_pkix_OCSP_Nonce, OBJ_id_pkix_OCSP_Nonce); // NID: 366 - addObject(NID_id_pkix_OCSP_CrlID, SN_id_pkix_OCSP_CrlID, LN_id_pkix_OCSP_CrlID, OBJ_id_pkix_OCSP_CrlID); // NID: 367 - addObject(NID_id_pkix_OCSP_acceptableResponses, SN_id_pkix_OCSP_acceptableResponses, LN_id_pkix_OCSP_acceptableResponses, OBJ_id_pkix_OCSP_acceptableResponses); // NID: 368 - addObject(NID_id_pkix_OCSP_noCheck, SN_id_pkix_OCSP_noCheck, LN_id_pkix_OCSP_noCheck, OBJ_id_pkix_OCSP_noCheck); // NID: 369 - addObject(NID_id_pkix_OCSP_archiveCutoff, SN_id_pkix_OCSP_archiveCutoff, LN_id_pkix_OCSP_archiveCutoff, OBJ_id_pkix_OCSP_archiveCutoff); // NID: 370 - addObject(NID_id_pkix_OCSP_serviceLocator, SN_id_pkix_OCSP_serviceLocator, LN_id_pkix_OCSP_serviceLocator, OBJ_id_pkix_OCSP_serviceLocator); // NID: 371 - addObject(NID_id_pkix_OCSP_extendedStatus, SN_id_pkix_OCSP_extendedStatus, LN_id_pkix_OCSP_extendedStatus, OBJ_id_pkix_OCSP_extendedStatus); // NID: 372 - addObject(NID_id_pkix_OCSP_valid, SN_id_pkix_OCSP_valid, null, OBJ_id_pkix_OCSP_valid); // NID: 373 - addObject(NID_id_pkix_OCSP_path, SN_id_pkix_OCSP_path, null, OBJ_id_pkix_OCSP_path); // NID: 374 - addObject(NID_id_pkix_OCSP_trustRoot, SN_id_pkix_OCSP_trustRoot, LN_id_pkix_OCSP_trustRoot, OBJ_id_pkix_OCSP_trustRoot); // NID: 375 - addObject(NID_algorithm, SN_algorithm, LN_algorithm, OBJ_algorithm); // NID: 376 - addObject(NID_rsaSignature, SN_rsaSignature, null, OBJ_rsaSignature); // NID: 377 - addObject(NID_X500algorithms, SN_X500algorithms, LN_X500algorithms, OBJ_X500algorithms); // NID: 378 - addObject(NID_org, SN_org, LN_org, OBJ_org); // NID: 379 - addObject(NID_dod, SN_dod, LN_dod, OBJ_dod); // NID: 380 - addObject(NID_iana, SN_iana, LN_iana, OBJ_iana); // NID: 381 - addObject(NID_Directory, SN_Directory, LN_Directory, OBJ_Directory); // NID: 382 - addObject(NID_Management, SN_Management, LN_Management, OBJ_Management); // NID: 383 - addObject(NID_Experimental, SN_Experimental, LN_Experimental, OBJ_Experimental); // NID: 384 - addObject(NID_Private, SN_Private, LN_Private, OBJ_Private); // NID: 385 - addObject(NID_Security, SN_Security, LN_Security, OBJ_Security); // NID: 386 - addObject(NID_SNMPv2, SN_SNMPv2, LN_SNMPv2, OBJ_SNMPv2); // NID: 387 - addObject(NID_Mail, null, LN_Mail, OBJ_Mail); // NID: 388 - addObject(NID_Enterprises, SN_Enterprises, LN_Enterprises, OBJ_Enterprises); // NID: 389 - addObject(NID_dcObject, SN_dcObject, LN_dcObject, OBJ_dcObject); // NID: 390 - addObject(NID_domainComponent, SN_domainComponent, LN_domainComponent, OBJ_domainComponent); // NID: 391 - addObject(NID_Domain, SN_Domain, LN_Domain, OBJ_Domain); // NID: 392 - addObject(NID_joint_iso_ccitt, null, null, OBJ_joint_iso_ccitt); // NID: 393 - addObject(NID_selected_attribute_types, SN_selected_attribute_types, LN_selected_attribute_types, OBJ_selected_attribute_types); // NID: 394 - addObject(NID_clearance, SN_clearance, null, OBJ_clearance); // NID: 395 - addObject(NID_md4WithRSAEncryption, SN_md4WithRSAEncryption, LN_md4WithRSAEncryption, OBJ_md4WithRSAEncryption); // NID: 396 - addObject(NID_ac_proxying, SN_ac_proxying, null, OBJ_ac_proxying); // NID: 397 - addObject(NID_sinfo_access, SN_sinfo_access, LN_sinfo_access, OBJ_sinfo_access); // NID: 398 - addObject(NID_id_aca_encAttrs, SN_id_aca_encAttrs, null, OBJ_id_aca_encAttrs); // NID: 399 - addObject(NID_role, SN_role, LN_role, OBJ_role); // NID: 400 - addObject(NID_policy_constraints, SN_policy_constraints, LN_policy_constraints, OBJ_policy_constraints); // NID: 401 - addObject(NID_target_information, SN_target_information, LN_target_information, OBJ_target_information); // NID: 402 - addObject(NID_no_rev_avail, SN_no_rev_avail, LN_no_rev_avail, OBJ_no_rev_avail); // NID: 403 - addObject(NID_ccitt, null, null, OBJ_ccitt); // NID: 404 - addObject(NID_ansi_X9_62, SN_ansi_X9_62, LN_ansi_X9_62, OBJ_ansi_X9_62); // NID: 405 - addObject(NID_X9_62_prime_field, SN_X9_62_prime_field, null, OBJ_X9_62_prime_field); // NID: 406 - addObject(NID_X9_62_characteristic_two_field, SN_X9_62_characteristic_two_field, null, OBJ_X9_62_characteristic_two_field); // NID: 407 - addObject(NID_X9_62_id_ecPublicKey, SN_X9_62_id_ecPublicKey, null, OBJ_X9_62_id_ecPublicKey); // NID: 408 - addObject(NID_X9_62_prime192v1, SN_X9_62_prime192v1, null, OBJ_X9_62_prime192v1); // NID: 409 - addObject(NID_X9_62_prime192v2, SN_X9_62_prime192v2, null, OBJ_X9_62_prime192v2); // NID: 410 - addObject(NID_X9_62_prime192v3, SN_X9_62_prime192v3, null, OBJ_X9_62_prime192v3); // NID: 411 - addObject(NID_X9_62_prime239v1, SN_X9_62_prime239v1, null, OBJ_X9_62_prime239v1); // NID: 412 - addObject(NID_X9_62_prime239v2, SN_X9_62_prime239v2, null, OBJ_X9_62_prime239v2); // NID: 413 - addObject(NID_X9_62_prime239v3, SN_X9_62_prime239v3, null, OBJ_X9_62_prime239v3); // NID: 414 - addObject(NID_X9_62_prime256v1, SN_X9_62_prime256v1, null, OBJ_X9_62_prime256v1); // NID: 415 - addObject(NID_ecdsa_with_SHA1, SN_ecdsa_with_SHA1, null, OBJ_ecdsa_with_SHA1); // NID: 416 - addObject(NID_ms_csp_name, SN_ms_csp_name, LN_ms_csp_name, OBJ_ms_csp_name); // NID: 417 - addObject(NID_aes_128_ecb, SN_aes_128_ecb, LN_aes_128_ecb, OBJ_aes_128_ecb); // NID: 418 - addObject(NID_aes_128_cbc, SN_aes_128_cbc, LN_aes_128_cbc, OBJ_aes_128_cbc); // NID: 419 - addObject(NID_aes_128_ofb128, SN_aes_128_ofb128, LN_aes_128_ofb128, OBJ_aes_128_ofb128); // NID: 420 - addObject(NID_aes_128_cfb128, SN_aes_128_cfb128, LN_aes_128_cfb128, OBJ_aes_128_cfb128); // NID: 421 - addObject(NID_aes_192_ecb, SN_aes_192_ecb, LN_aes_192_ecb, OBJ_aes_192_ecb); // NID: 422 - addObject(NID_aes_192_cbc, SN_aes_192_cbc, LN_aes_192_cbc, OBJ_aes_192_cbc); // NID: 423 - addObject(NID_aes_192_ofb128, SN_aes_192_ofb128, LN_aes_192_ofb128, OBJ_aes_192_ofb128); // NID: 424 - addObject(NID_aes_192_cfb128, SN_aes_192_cfb128, LN_aes_192_cfb128, OBJ_aes_192_cfb128); // NID: 425 - addObject(NID_aes_256_ecb, SN_aes_256_ecb, LN_aes_256_ecb, OBJ_aes_256_ecb); // NID: 426 - addObject(NID_aes_256_cbc, SN_aes_256_cbc, LN_aes_256_cbc, OBJ_aes_256_cbc); // NID: 427 - addObject(NID_aes_256_ofb128, SN_aes_256_ofb128, LN_aes_256_ofb128, OBJ_aes_256_ofb128); // NID: 428 - addObject(NID_aes_256_cfb128, SN_aes_256_cfb128, LN_aes_256_cfb128, OBJ_aes_256_cfb128); // NID: 429 - addObject(NID_hold_instruction_code, SN_hold_instruction_code, LN_hold_instruction_code, OBJ_hold_instruction_code); // NID: 430 - addObject(NID_hold_instruction_none, SN_hold_instruction_none, LN_hold_instruction_none, OBJ_hold_instruction_none); // NID: 431 - addObject(NID_hold_instruction_call_issuer, SN_hold_instruction_call_issuer, LN_hold_instruction_call_issuer, OBJ_hold_instruction_call_issuer); // NID: 432 - addObject(NID_hold_instruction_reject, SN_hold_instruction_reject, LN_hold_instruction_reject, OBJ_hold_instruction_reject); // NID: 433 - addObject(NID_data, SN_data, null, OBJ_data); // NID: 434 - addObject(NID_pss, SN_pss, null, OBJ_pss); // NID: 435 - addObject(NID_ucl, SN_ucl, null, OBJ_ucl); // NID: 436 - addObject(NID_pilot, SN_pilot, null, OBJ_pilot); // NID: 437 - addObject(NID_pilotAttributeType, null, LN_pilotAttributeType, OBJ_pilotAttributeType); // NID: 438 - addObject(NID_pilotAttributeSyntax, null, LN_pilotAttributeSyntax, OBJ_pilotAttributeSyntax); // NID: 439 - addObject(NID_pilotObjectClass, null, LN_pilotObjectClass, OBJ_pilotObjectClass); // NID: 440 - addObject(NID_pilotGroups, null, LN_pilotGroups, OBJ_pilotGroups); // NID: 441 - addObject(NID_iA5StringSyntax, null, LN_iA5StringSyntax, OBJ_iA5StringSyntax); // NID: 442 - addObject(NID_caseIgnoreIA5StringSyntax, null, LN_caseIgnoreIA5StringSyntax, OBJ_caseIgnoreIA5StringSyntax); // NID: 443 - addObject(NID_pilotObject, null, LN_pilotObject, OBJ_pilotObject); // NID: 444 - addObject(NID_pilotPerson, null, LN_pilotPerson, OBJ_pilotPerson); // NID: 445 - addObject(NID_account, SN_account, null, OBJ_account); // NID: 446 - addObject(NID_document, SN_document, null, OBJ_document); // NID: 447 - addObject(NID_room, SN_room, null, OBJ_room); // NID: 448 - addObject(NID_documentSeries, null, LN_documentSeries, OBJ_documentSeries); // NID: 449 - addObject(NID_rFC822localPart, null, LN_rFC822localPart, OBJ_rFC822localPart); // NID: 450 - addObject(NID_dNSDomain, null, LN_dNSDomain, OBJ_dNSDomain); // NID: 451 - addObject(NID_domainRelatedObject, null, LN_domainRelatedObject, OBJ_domainRelatedObject); // NID: 452 - addObject(NID_friendlyCountry, null, LN_friendlyCountry, OBJ_friendlyCountry); // NID: 453 - addObject(NID_simpleSecurityObject, null, LN_simpleSecurityObject, OBJ_simpleSecurityObject); // NID: 454 - addObject(NID_pilotOrganization, null, LN_pilotOrganization, OBJ_pilotOrganization); // NID: 455 - addObject(NID_pilotDSA, null, LN_pilotDSA, OBJ_pilotDSA); // NID: 456 - addObject(NID_qualityLabelledData, null, LN_qualityLabelledData, OBJ_qualityLabelledData); // NID: 457 - addObject(NID_userId, SN_userId, LN_userId, OBJ_userId); // NID: 458 - addObject(NID_textEncodedORAddress, null, LN_textEncodedORAddress, OBJ_textEncodedORAddress); // NID: 459 - addObject(NID_rfc822Mailbox, SN_rfc822Mailbox, LN_rfc822Mailbox, OBJ_rfc822Mailbox); // NID: 460 - addObject(NID_info, SN_info, null, OBJ_info); // NID: 461 - addObject(NID_favouriteDrink, null, LN_favouriteDrink, OBJ_favouriteDrink); // NID: 462 - addObject(NID_roomNumber, null, LN_roomNumber, OBJ_roomNumber); // NID: 463 - addObject(NID_photo, SN_photo, null, OBJ_photo); // NID: 464 - addObject(NID_userClass, null, LN_userClass, OBJ_userClass); // NID: 465 - addObject(NID_host, SN_host, null, OBJ_host); // NID: 466 - addObject(NID_manager, SN_manager, null, OBJ_manager); // NID: 467 - addObject(NID_documentIdentifier, null, LN_documentIdentifier, OBJ_documentIdentifier); // NID: 468 - addObject(NID_documentTitle, null, LN_documentTitle, OBJ_documentTitle); // NID: 469 - addObject(NID_documentVersion, null, LN_documentVersion, OBJ_documentVersion); // NID: 470 - addObject(NID_documentAuthor, null, LN_documentAuthor, OBJ_documentAuthor); // NID: 471 - addObject(NID_documentLocation, null, LN_documentLocation, OBJ_documentLocation); // NID: 472 - addObject(NID_homeTelephoneNumber, null, LN_homeTelephoneNumber, OBJ_homeTelephoneNumber); // NID: 473 - addObject(NID_secretary, SN_secretary, null, OBJ_secretary); // NID: 474 - addObject(NID_otherMailbox, null, LN_otherMailbox, OBJ_otherMailbox); // NID: 475 - addObject(NID_lastModifiedTime, null, LN_lastModifiedTime, OBJ_lastModifiedTime); // NID: 476 - addObject(NID_lastModifiedBy, null, LN_lastModifiedBy, OBJ_lastModifiedBy); // NID: 477 - addObject(NID_aRecord, null, LN_aRecord, OBJ_aRecord); // NID: 478 - addObject(NID_pilotAttributeType27, null, LN_pilotAttributeType27, OBJ_pilotAttributeType27); // NID: 479 - addObject(NID_mXRecord, null, LN_mXRecord, OBJ_mXRecord); // NID: 480 - addObject(NID_nSRecord, null, LN_nSRecord, OBJ_nSRecord); // NID: 481 - addObject(NID_sOARecord, null, LN_sOARecord, OBJ_sOARecord); // NID: 482 - addObject(NID_cNAMERecord, null, LN_cNAMERecord, OBJ_cNAMERecord); // NID: 483 - addObject(NID_associatedDomain, null, LN_associatedDomain, OBJ_associatedDomain); // NID: 484 - addObject(NID_associatedName, null, LN_associatedName, OBJ_associatedName); // NID: 485 - addObject(NID_homePostalAddress, null, LN_homePostalAddress, OBJ_homePostalAddress); // NID: 486 - addObject(NID_personalTitle, null, LN_personalTitle, OBJ_personalTitle); // NID: 487 - addObject(NID_mobileTelephoneNumber, null, LN_mobileTelephoneNumber, OBJ_mobileTelephoneNumber); // NID: 488 - addObject(NID_pagerTelephoneNumber, null, LN_pagerTelephoneNumber, OBJ_pagerTelephoneNumber); // NID: 489 - addObject(NID_friendlyCountryName, null, LN_friendlyCountryName, OBJ_friendlyCountryName); // NID: 490 - addObject(NID_organizationalStatus, null, LN_organizationalStatus, OBJ_organizationalStatus); // NID: 491 - addObject(NID_janetMailbox, null, LN_janetMailbox, OBJ_janetMailbox); // NID: 492 - addObject(NID_mailPreferenceOption, null, LN_mailPreferenceOption, OBJ_mailPreferenceOption); // NID: 493 - addObject(NID_buildingName, null, LN_buildingName, OBJ_buildingName); // NID: 494 - addObject(NID_dSAQuality, null, LN_dSAQuality, OBJ_dSAQuality); // NID: 495 - addObject(NID_singleLevelQuality, null, LN_singleLevelQuality, OBJ_singleLevelQuality); // NID: 496 - addObject(NID_subtreeMinimumQuality, null, LN_subtreeMinimumQuality, OBJ_subtreeMinimumQuality); // NID: 497 - addObject(NID_subtreeMaximumQuality, null, LN_subtreeMaximumQuality, OBJ_subtreeMaximumQuality); // NID: 498 - addObject(NID_personalSignature, null, LN_personalSignature, OBJ_personalSignature); // NID: 499 - addObject(NID_dITRedirect, null, LN_dITRedirect, OBJ_dITRedirect); // NID: 500 - addObject(NID_audio, SN_audio, null, OBJ_audio); // NID: 501 - addObject(NID_documentPublisher, null, LN_documentPublisher, OBJ_documentPublisher); // NID: 502 - addObject(NID_x500UniqueIdentifier, null, LN_x500UniqueIdentifier, OBJ_x500UniqueIdentifier); // NID: 503 - addObject(NID_mime_mhs, SN_mime_mhs, LN_mime_mhs, OBJ_mime_mhs); // NID: 504 - addObject(NID_mime_mhs_headings, SN_mime_mhs_headings, LN_mime_mhs_headings, OBJ_mime_mhs_headings); // NID: 505 - addObject(NID_mime_mhs_bodies, SN_mime_mhs_bodies, LN_mime_mhs_bodies, OBJ_mime_mhs_bodies); // NID: 506 - addObject(NID_id_hex_partial_message, SN_id_hex_partial_message, LN_id_hex_partial_message, OBJ_id_hex_partial_message); // NID: 507 - addObject(NID_id_hex_multipart_message, SN_id_hex_multipart_message, LN_id_hex_multipart_message, OBJ_id_hex_multipart_message); // NID: 508 - addObject(NID_generationQualifier, null, LN_generationQualifier, OBJ_generationQualifier); // NID: 509 - addObject(NID_pseudonym, null, LN_pseudonym, OBJ_pseudonym); // NID: 510 - addObject(NID_id_set, SN_id_set, LN_id_set, OBJ_id_set); // NID: 512 - addObject(NID_set_ctype, SN_set_ctype, LN_set_ctype, OBJ_set_ctype); // NID: 513 - addObject(NID_set_msgExt, SN_set_msgExt, LN_set_msgExt, OBJ_set_msgExt); // NID: 514 - addObject(NID_set_attr, SN_set_attr, null, OBJ_set_attr); // NID: 515 - addObject(NID_set_policy, SN_set_policy, null, OBJ_set_policy); // NID: 516 - addObject(NID_set_certExt, SN_set_certExt, LN_set_certExt, OBJ_set_certExt); // NID: 517 - addObject(NID_set_brand, SN_set_brand, null, OBJ_set_brand); // NID: 518 - addObject(NID_setct_PANData, SN_setct_PANData, null, OBJ_setct_PANData); // NID: 519 - addObject(NID_setct_PANToken, SN_setct_PANToken, null, OBJ_setct_PANToken); // NID: 520 - addObject(NID_setct_PANOnly, SN_setct_PANOnly, null, OBJ_setct_PANOnly); // NID: 521 - addObject(NID_setct_OIData, SN_setct_OIData, null, OBJ_setct_OIData); // NID: 522 - addObject(NID_setct_PI, SN_setct_PI, null, OBJ_setct_PI); // NID: 523 - addObject(NID_setct_PIData, SN_setct_PIData, null, OBJ_setct_PIData); // NID: 524 - addObject(NID_setct_PIDataUnsigned, SN_setct_PIDataUnsigned, null, OBJ_setct_PIDataUnsigned); // NID: 525 - addObject(NID_setct_HODInput, SN_setct_HODInput, null, OBJ_setct_HODInput); // NID: 526 - addObject(NID_setct_AuthResBaggage, SN_setct_AuthResBaggage, null, OBJ_setct_AuthResBaggage); // NID: 527 - addObject(NID_setct_AuthRevReqBaggage, SN_setct_AuthRevReqBaggage, null, OBJ_setct_AuthRevReqBaggage); // NID: 528 - addObject(NID_setct_AuthRevResBaggage, SN_setct_AuthRevResBaggage, null, OBJ_setct_AuthRevResBaggage); // NID: 529 - addObject(NID_setct_CapTokenSeq, SN_setct_CapTokenSeq, null, OBJ_setct_CapTokenSeq); // NID: 530 - addObject(NID_setct_PInitResData, SN_setct_PInitResData, null, OBJ_setct_PInitResData); // NID: 531 - addObject(NID_setct_PI_TBS, SN_setct_PI_TBS, null, OBJ_setct_PI_TBS); // NID: 532 - addObject(NID_setct_PResData, SN_setct_PResData, null, OBJ_setct_PResData); // NID: 533 - addObject(NID_setct_AuthReqTBS, SN_setct_AuthReqTBS, null, OBJ_setct_AuthReqTBS); // NID: 534 - addObject(NID_setct_AuthResTBS, SN_setct_AuthResTBS, null, OBJ_setct_AuthResTBS); // NID: 535 - addObject(NID_setct_AuthResTBSX, SN_setct_AuthResTBSX, null, OBJ_setct_AuthResTBSX); // NID: 536 - addObject(NID_setct_AuthTokenTBS, SN_setct_AuthTokenTBS, null, OBJ_setct_AuthTokenTBS); // NID: 537 - addObject(NID_setct_CapTokenData, SN_setct_CapTokenData, null, OBJ_setct_CapTokenData); // NID: 538 - addObject(NID_setct_CapTokenTBS, SN_setct_CapTokenTBS, null, OBJ_setct_CapTokenTBS); // NID: 539 - addObject(NID_setct_AcqCardCodeMsg, SN_setct_AcqCardCodeMsg, null, OBJ_setct_AcqCardCodeMsg); // NID: 540 - addObject(NID_setct_AuthRevReqTBS, SN_setct_AuthRevReqTBS, null, OBJ_setct_AuthRevReqTBS); // NID: 541 - addObject(NID_setct_AuthRevResData, SN_setct_AuthRevResData, null, OBJ_setct_AuthRevResData); // NID: 542 - addObject(NID_setct_AuthRevResTBS, SN_setct_AuthRevResTBS, null, OBJ_setct_AuthRevResTBS); // NID: 543 - addObject(NID_setct_CapReqTBS, SN_setct_CapReqTBS, null, OBJ_setct_CapReqTBS); // NID: 544 - addObject(NID_setct_CapReqTBSX, SN_setct_CapReqTBSX, null, OBJ_setct_CapReqTBSX); // NID: 545 - addObject(NID_setct_CapResData, SN_setct_CapResData, null, OBJ_setct_CapResData); // NID: 546 - addObject(NID_setct_CapRevReqTBS, SN_setct_CapRevReqTBS, null, OBJ_setct_CapRevReqTBS); // NID: 547 - addObject(NID_setct_CapRevReqTBSX, SN_setct_CapRevReqTBSX, null, OBJ_setct_CapRevReqTBSX); // NID: 548 - addObject(NID_setct_CapRevResData, SN_setct_CapRevResData, null, OBJ_setct_CapRevResData); // NID: 549 - addObject(NID_setct_CredReqTBS, SN_setct_CredReqTBS, null, OBJ_setct_CredReqTBS); // NID: 550 - addObject(NID_setct_CredReqTBSX, SN_setct_CredReqTBSX, null, OBJ_setct_CredReqTBSX); // NID: 551 - addObject(NID_setct_CredResData, SN_setct_CredResData, null, OBJ_setct_CredResData); // NID: 552 - addObject(NID_setct_CredRevReqTBS, SN_setct_CredRevReqTBS, null, OBJ_setct_CredRevReqTBS); // NID: 553 - addObject(NID_setct_CredRevReqTBSX, SN_setct_CredRevReqTBSX, null, OBJ_setct_CredRevReqTBSX); // NID: 554 - addObject(NID_setct_CredRevResData, SN_setct_CredRevResData, null, OBJ_setct_CredRevResData); // NID: 555 - addObject(NID_setct_PCertReqData, SN_setct_PCertReqData, null, OBJ_setct_PCertReqData); // NID: 556 - addObject(NID_setct_PCertResTBS, SN_setct_PCertResTBS, null, OBJ_setct_PCertResTBS); // NID: 557 - addObject(NID_setct_BatchAdminReqData, SN_setct_BatchAdminReqData, null, OBJ_setct_BatchAdminReqData); // NID: 558 - addObject(NID_setct_BatchAdminResData, SN_setct_BatchAdminResData, null, OBJ_setct_BatchAdminResData); // NID: 559 - addObject(NID_setct_CardCInitResTBS, SN_setct_CardCInitResTBS, null, OBJ_setct_CardCInitResTBS); // NID: 560 - addObject(NID_setct_MeAqCInitResTBS, SN_setct_MeAqCInitResTBS, null, OBJ_setct_MeAqCInitResTBS); // NID: 561 - addObject(NID_setct_RegFormResTBS, SN_setct_RegFormResTBS, null, OBJ_setct_RegFormResTBS); // NID: 562 - addObject(NID_setct_CertReqData, SN_setct_CertReqData, null, OBJ_setct_CertReqData); // NID: 563 - addObject(NID_setct_CertReqTBS, SN_setct_CertReqTBS, null, OBJ_setct_CertReqTBS); // NID: 564 - addObject(NID_setct_CertResData, SN_setct_CertResData, null, OBJ_setct_CertResData); // NID: 565 - addObject(NID_setct_CertInqReqTBS, SN_setct_CertInqReqTBS, null, OBJ_setct_CertInqReqTBS); // NID: 566 - addObject(NID_setct_ErrorTBS, SN_setct_ErrorTBS, null, OBJ_setct_ErrorTBS); // NID: 567 - addObject(NID_setct_PIDualSignedTBE, SN_setct_PIDualSignedTBE, null, OBJ_setct_PIDualSignedTBE); // NID: 568 - addObject(NID_setct_PIUnsignedTBE, SN_setct_PIUnsignedTBE, null, OBJ_setct_PIUnsignedTBE); // NID: 569 - addObject(NID_setct_AuthReqTBE, SN_setct_AuthReqTBE, null, OBJ_setct_AuthReqTBE); // NID: 570 - addObject(NID_setct_AuthResTBE, SN_setct_AuthResTBE, null, OBJ_setct_AuthResTBE); // NID: 571 - addObject(NID_setct_AuthResTBEX, SN_setct_AuthResTBEX, null, OBJ_setct_AuthResTBEX); // NID: 572 - addObject(NID_setct_AuthTokenTBE, SN_setct_AuthTokenTBE, null, OBJ_setct_AuthTokenTBE); // NID: 573 - addObject(NID_setct_CapTokenTBE, SN_setct_CapTokenTBE, null, OBJ_setct_CapTokenTBE); // NID: 574 - addObject(NID_setct_CapTokenTBEX, SN_setct_CapTokenTBEX, null, OBJ_setct_CapTokenTBEX); // NID: 575 - addObject(NID_setct_AcqCardCodeMsgTBE, SN_setct_AcqCardCodeMsgTBE, null, OBJ_setct_AcqCardCodeMsgTBE); // NID: 576 - addObject(NID_setct_AuthRevReqTBE, SN_setct_AuthRevReqTBE, null, OBJ_setct_AuthRevReqTBE); // NID: 577 - addObject(NID_setct_AuthRevResTBE, SN_setct_AuthRevResTBE, null, OBJ_setct_AuthRevResTBE); // NID: 578 - addObject(NID_setct_AuthRevResTBEB, SN_setct_AuthRevResTBEB, null, OBJ_setct_AuthRevResTBEB); // NID: 579 - addObject(NID_setct_CapReqTBE, SN_setct_CapReqTBE, null, OBJ_setct_CapReqTBE); // NID: 580 - addObject(NID_setct_CapReqTBEX, SN_setct_CapReqTBEX, null, OBJ_setct_CapReqTBEX); // NID: 581 - addObject(NID_setct_CapResTBE, SN_setct_CapResTBE, null, OBJ_setct_CapResTBE); // NID: 582 - addObject(NID_setct_CapRevReqTBE, SN_setct_CapRevReqTBE, null, OBJ_setct_CapRevReqTBE); // NID: 583 - addObject(NID_setct_CapRevReqTBEX, SN_setct_CapRevReqTBEX, null, OBJ_setct_CapRevReqTBEX); // NID: 584 - addObject(NID_setct_CapRevResTBE, SN_setct_CapRevResTBE, null, OBJ_setct_CapRevResTBE); // NID: 585 - addObject(NID_setct_CredReqTBE, SN_setct_CredReqTBE, null, OBJ_setct_CredReqTBE); // NID: 586 - addObject(NID_setct_CredReqTBEX, SN_setct_CredReqTBEX, null, OBJ_setct_CredReqTBEX); // NID: 587 - addObject(NID_setct_CredResTBE, SN_setct_CredResTBE, null, OBJ_setct_CredResTBE); // NID: 588 - addObject(NID_setct_CredRevReqTBE, SN_setct_CredRevReqTBE, null, OBJ_setct_CredRevReqTBE); // NID: 589 - addObject(NID_setct_CredRevReqTBEX, SN_setct_CredRevReqTBEX, null, OBJ_setct_CredRevReqTBEX); // NID: 590 - addObject(NID_setct_CredRevResTBE, SN_setct_CredRevResTBE, null, OBJ_setct_CredRevResTBE); // NID: 591 - addObject(NID_setct_BatchAdminReqTBE, SN_setct_BatchAdminReqTBE, null, OBJ_setct_BatchAdminReqTBE); // NID: 592 - addObject(NID_setct_BatchAdminResTBE, SN_setct_BatchAdminResTBE, null, OBJ_setct_BatchAdminResTBE); // NID: 593 - addObject(NID_setct_RegFormReqTBE, SN_setct_RegFormReqTBE, null, OBJ_setct_RegFormReqTBE); // NID: 594 - addObject(NID_setct_CertReqTBE, SN_setct_CertReqTBE, null, OBJ_setct_CertReqTBE); // NID: 595 - addObject(NID_setct_CertReqTBEX, SN_setct_CertReqTBEX, null, OBJ_setct_CertReqTBEX); // NID: 596 - addObject(NID_setct_CertResTBE, SN_setct_CertResTBE, null, OBJ_setct_CertResTBE); // NID: 597 - addObject(NID_setct_CRLNotificationTBS, SN_setct_CRLNotificationTBS, null, OBJ_setct_CRLNotificationTBS); // NID: 598 - addObject(NID_setct_CRLNotificationResTBS, SN_setct_CRLNotificationResTBS, null, OBJ_setct_CRLNotificationResTBS); // NID: 599 - addObject(NID_setct_BCIDistributionTBS, SN_setct_BCIDistributionTBS, null, OBJ_setct_BCIDistributionTBS); // NID: 600 - addObject(NID_setext_genCrypt, SN_setext_genCrypt, LN_setext_genCrypt, OBJ_setext_genCrypt); // NID: 601 - addObject(NID_setext_miAuth, SN_setext_miAuth, LN_setext_miAuth, OBJ_setext_miAuth); // NID: 602 - addObject(NID_setext_pinSecure, SN_setext_pinSecure, null, OBJ_setext_pinSecure); // NID: 603 - addObject(NID_setext_pinAny, SN_setext_pinAny, null, OBJ_setext_pinAny); // NID: 604 - addObject(NID_setext_track2, SN_setext_track2, null, OBJ_setext_track2); // NID: 605 - addObject(NID_setext_cv, SN_setext_cv, LN_setext_cv, OBJ_setext_cv); // NID: 606 - addObject(NID_set_policy_root, SN_set_policy_root, null, OBJ_set_policy_root); // NID: 607 - addObject(NID_setCext_hashedRoot, SN_setCext_hashedRoot, null, OBJ_setCext_hashedRoot); // NID: 608 - addObject(NID_setCext_certType, SN_setCext_certType, null, OBJ_setCext_certType); // NID: 609 - addObject(NID_setCext_merchData, SN_setCext_merchData, null, OBJ_setCext_merchData); // NID: 610 - addObject(NID_setCext_cCertRequired, SN_setCext_cCertRequired, null, OBJ_setCext_cCertRequired); // NID: 611 - addObject(NID_setCext_tunneling, SN_setCext_tunneling, null, OBJ_setCext_tunneling); // NID: 612 - addObject(NID_setCext_setExt, SN_setCext_setExt, null, OBJ_setCext_setExt); // NID: 613 - addObject(NID_setCext_setQualf, SN_setCext_setQualf, null, OBJ_setCext_setQualf); // NID: 614 - addObject(NID_setCext_PGWYcapabilities, SN_setCext_PGWYcapabilities, null, OBJ_setCext_PGWYcapabilities); // NID: 615 - addObject(NID_setCext_TokenIdentifier, SN_setCext_TokenIdentifier, null, OBJ_setCext_TokenIdentifier); // NID: 616 - addObject(NID_setCext_Track2Data, SN_setCext_Track2Data, null, OBJ_setCext_Track2Data); // NID: 617 - addObject(NID_setCext_TokenType, SN_setCext_TokenType, null, OBJ_setCext_TokenType); // NID: 618 - addObject(NID_setCext_IssuerCapabilities, SN_setCext_IssuerCapabilities, null, OBJ_setCext_IssuerCapabilities); // NID: 619 - addObject(NID_setAttr_Cert, SN_setAttr_Cert, null, OBJ_setAttr_Cert); // NID: 620 - addObject(NID_setAttr_PGWYcap, SN_setAttr_PGWYcap, LN_setAttr_PGWYcap, OBJ_setAttr_PGWYcap); // NID: 621 - addObject(NID_setAttr_TokenType, SN_setAttr_TokenType, null, OBJ_setAttr_TokenType); // NID: 622 - addObject(NID_setAttr_IssCap, SN_setAttr_IssCap, LN_setAttr_IssCap, OBJ_setAttr_IssCap); // NID: 623 - addObject(NID_set_rootKeyThumb, SN_set_rootKeyThumb, null, OBJ_set_rootKeyThumb); // NID: 624 - addObject(NID_set_addPolicy, SN_set_addPolicy, null, OBJ_set_addPolicy); // NID: 625 - addObject(NID_setAttr_Token_EMV, SN_setAttr_Token_EMV, null, OBJ_setAttr_Token_EMV); // NID: 626 - addObject(NID_setAttr_Token_B0Prime, SN_setAttr_Token_B0Prime, null, OBJ_setAttr_Token_B0Prime); // NID: 627 - addObject(NID_setAttr_IssCap_CVM, SN_setAttr_IssCap_CVM, null, OBJ_setAttr_IssCap_CVM); // NID: 628 - addObject(NID_setAttr_IssCap_T2, SN_setAttr_IssCap_T2, null, OBJ_setAttr_IssCap_T2); // NID: 629 - addObject(NID_setAttr_IssCap_Sig, SN_setAttr_IssCap_Sig, null, OBJ_setAttr_IssCap_Sig); // NID: 630 - addObject(NID_setAttr_GenCryptgrm, SN_setAttr_GenCryptgrm, LN_setAttr_GenCryptgrm, OBJ_setAttr_GenCryptgrm); // NID: 631 - addObject(NID_setAttr_T2Enc, SN_setAttr_T2Enc, LN_setAttr_T2Enc, OBJ_setAttr_T2Enc); // NID: 632 - addObject(NID_setAttr_T2cleartxt, SN_setAttr_T2cleartxt, LN_setAttr_T2cleartxt, OBJ_setAttr_T2cleartxt); // NID: 633 - addObject(NID_setAttr_TokICCsig, SN_setAttr_TokICCsig, LN_setAttr_TokICCsig, OBJ_setAttr_TokICCsig); // NID: 634 - addObject(NID_setAttr_SecDevSig, SN_setAttr_SecDevSig, LN_setAttr_SecDevSig, OBJ_setAttr_SecDevSig); // NID: 635 - addObject(NID_set_brand_IATA_ATA, SN_set_brand_IATA_ATA, null, OBJ_set_brand_IATA_ATA); // NID: 636 - addObject(NID_set_brand_Diners, SN_set_brand_Diners, null, OBJ_set_brand_Diners); // NID: 637 - addObject(NID_set_brand_AmericanExpress, SN_set_brand_AmericanExpress, null, OBJ_set_brand_AmericanExpress); // NID: 638 - addObject(NID_set_brand_JCB, SN_set_brand_JCB, null, OBJ_set_brand_JCB); // NID: 639 - addObject(NID_set_brand_Visa, SN_set_brand_Visa, null, OBJ_set_brand_Visa); // NID: 640 - addObject(NID_set_brand_MasterCard, SN_set_brand_MasterCard, null, OBJ_set_brand_MasterCard); // NID: 641 - addObject(NID_set_brand_Novus, SN_set_brand_Novus, null, OBJ_set_brand_Novus); // NID: 642 - addObject(NID_des_cdmf, SN_des_cdmf, LN_des_cdmf, OBJ_des_cdmf); // NID: 643 - addObject(NID_rsaOAEPEncryptionSET, SN_rsaOAEPEncryptionSET, null, OBJ_rsaOAEPEncryptionSET); // NID: 644 - addObject(NID_itu_t, SN_itu_t, LN_itu_t, OBJ_itu_t); // NID: 645 - addObject(NID_joint_iso_itu_t, SN_joint_iso_itu_t, LN_joint_iso_itu_t, OBJ_joint_iso_itu_t); // NID: 646 - addObject(NID_international_organizations, SN_international_organizations, LN_international_organizations, OBJ_international_organizations); // NID: 647 - addObject(NID_ms_smartcard_login, SN_ms_smartcard_login, LN_ms_smartcard_login, OBJ_ms_smartcard_login); // NID: 648 - addObject(NID_ms_upn, SN_ms_upn, LN_ms_upn, OBJ_ms_upn); // NID: 649 - addObject(NID_aes_128_cfb1, SN_aes_128_cfb1, LN_aes_128_cfb1, null); // NID: 650 - addObject(NID_aes_192_cfb1, SN_aes_192_cfb1, LN_aes_192_cfb1, null); // NID: 651 - addObject(NID_aes_256_cfb1, SN_aes_256_cfb1, LN_aes_256_cfb1, null); // NID: 652 - addObject(NID_aes_128_cfb8, SN_aes_128_cfb8, LN_aes_128_cfb8, null); // NID: 653 - addObject(NID_aes_192_cfb8, SN_aes_192_cfb8, LN_aes_192_cfb8, null); // NID: 654 - addObject(NID_aes_256_cfb8, SN_aes_256_cfb8, LN_aes_256_cfb8, null); // NID: 655 - addObject(NID_des_cfb1, SN_des_cfb1, LN_des_cfb1, null); // NID: 656 - addObject(NID_des_cfb8, SN_des_cfb8, LN_des_cfb8, null); // NID: 657 - addObject(NID_des_ede3_cfb1, SN_des_ede3_cfb1, LN_des_ede3_cfb1, null); // NID: 658 - addObject(NID_des_ede3_cfb8, SN_des_ede3_cfb8, LN_des_ede3_cfb8, null); // NID: 659 - addObject(NID_streetAddress, null, LN_streetAddress, OBJ_streetAddress); // NID: 660 - addObject(NID_postalCode, null, LN_postalCode, OBJ_postalCode); // NID: 661 - addObject(NID_id_ppl, SN_id_ppl, null, OBJ_id_ppl); // NID: 662 - addObject(NID_proxyCertInfo, SN_proxyCertInfo, LN_proxyCertInfo, OBJ_proxyCertInfo); // NID: 663 - addObject(NID_id_ppl_anyLanguage, SN_id_ppl_anyLanguage, LN_id_ppl_anyLanguage, OBJ_id_ppl_anyLanguage); // NID: 664 - addObject(NID_id_ppl_inheritAll, SN_id_ppl_inheritAll, LN_id_ppl_inheritAll, OBJ_id_ppl_inheritAll); // NID: 665 - addObject(NID_name_constraints, SN_name_constraints, LN_name_constraints, OBJ_name_constraints); // NID: 666 - addObject(NID_Independent, SN_Independent, LN_Independent, OBJ_Independent); // NID: 667 - addObject(NID_sha256WithRSAEncryption, SN_sha256WithRSAEncryption, LN_sha256WithRSAEncryption, OBJ_sha256WithRSAEncryption); // NID: 668 - addObject(NID_sha384WithRSAEncryption, SN_sha384WithRSAEncryption, LN_sha384WithRSAEncryption, OBJ_sha384WithRSAEncryption); // NID: 669 - addObject(NID_sha512WithRSAEncryption, SN_sha512WithRSAEncryption, LN_sha512WithRSAEncryption, OBJ_sha512WithRSAEncryption); // NID: 670 - addObject(NID_sha224WithRSAEncryption, SN_sha224WithRSAEncryption, LN_sha224WithRSAEncryption, OBJ_sha224WithRSAEncryption); // NID: 671 - addObject(NID_sha256, SN_sha256, LN_sha256, OBJ_sha256); // NID: 672 - addObject(NID_sha384, SN_sha384, LN_sha384, OBJ_sha384); // NID: 673 - addObject(NID_sha512, SN_sha512, LN_sha512, OBJ_sha512); // NID: 674 - addObject(NID_sha224, SN_sha224, LN_sha224, OBJ_sha224); // NID: 675 - addObject(NID_identified_organization, SN_identified_organization, null, OBJ_identified_organization); // NID: 676 - addObject(NID_certicom_arc, SN_certicom_arc, null, OBJ_certicom_arc); // NID: 677 - addObject(NID_wap, SN_wap, null, OBJ_wap); // NID: 678 - addObject(NID_wap_wsg, SN_wap_wsg, null, OBJ_wap_wsg); // NID: 679 - addObject(NID_X9_62_id_characteristic_two_basis, SN_X9_62_id_characteristic_two_basis, null, OBJ_X9_62_id_characteristic_two_basis); // NID: 680 - addObject(NID_X9_62_onBasis, SN_X9_62_onBasis, null, OBJ_X9_62_onBasis); // NID: 681 - addObject(NID_X9_62_tpBasis, SN_X9_62_tpBasis, null, OBJ_X9_62_tpBasis); // NID: 682 - addObject(NID_X9_62_ppBasis, SN_X9_62_ppBasis, null, OBJ_X9_62_ppBasis); // NID: 683 - addObject(NID_X9_62_c2pnb163v1, SN_X9_62_c2pnb163v1, null, OBJ_X9_62_c2pnb163v1); // NID: 684 - addObject(NID_X9_62_c2pnb163v2, SN_X9_62_c2pnb163v2, null, OBJ_X9_62_c2pnb163v2); // NID: 685 - addObject(NID_X9_62_c2pnb163v3, SN_X9_62_c2pnb163v3, null, OBJ_X9_62_c2pnb163v3); // NID: 686 - addObject(NID_X9_62_c2pnb176v1, SN_X9_62_c2pnb176v1, null, OBJ_X9_62_c2pnb176v1); // NID: 687 - addObject(NID_X9_62_c2tnb191v1, SN_X9_62_c2tnb191v1, null, OBJ_X9_62_c2tnb191v1); // NID: 688 - addObject(NID_X9_62_c2tnb191v2, SN_X9_62_c2tnb191v2, null, OBJ_X9_62_c2tnb191v2); // NID: 689 - addObject(NID_X9_62_c2tnb191v3, SN_X9_62_c2tnb191v3, null, OBJ_X9_62_c2tnb191v3); // NID: 690 - addObject(NID_X9_62_c2onb191v4, SN_X9_62_c2onb191v4, null, OBJ_X9_62_c2onb191v4); // NID: 691 - addObject(NID_X9_62_c2onb191v5, SN_X9_62_c2onb191v5, null, OBJ_X9_62_c2onb191v5); // NID: 692 - addObject(NID_X9_62_c2pnb208w1, SN_X9_62_c2pnb208w1, null, OBJ_X9_62_c2pnb208w1); // NID: 693 - addObject(NID_X9_62_c2tnb239v1, SN_X9_62_c2tnb239v1, null, OBJ_X9_62_c2tnb239v1); // NID: 694 - addObject(NID_X9_62_c2tnb239v2, SN_X9_62_c2tnb239v2, null, OBJ_X9_62_c2tnb239v2); // NID: 695 - addObject(NID_X9_62_c2tnb239v3, SN_X9_62_c2tnb239v3, null, OBJ_X9_62_c2tnb239v3); // NID: 696 - addObject(NID_X9_62_c2onb239v4, SN_X9_62_c2onb239v4, null, OBJ_X9_62_c2onb239v4); // NID: 697 - addObject(NID_X9_62_c2onb239v5, SN_X9_62_c2onb239v5, null, OBJ_X9_62_c2onb239v5); // NID: 698 - addObject(NID_X9_62_c2pnb272w1, SN_X9_62_c2pnb272w1, null, OBJ_X9_62_c2pnb272w1); // NID: 699 - addObject(NID_X9_62_c2pnb304w1, SN_X9_62_c2pnb304w1, null, OBJ_X9_62_c2pnb304w1); // NID: 700 - addObject(NID_X9_62_c2tnb359v1, SN_X9_62_c2tnb359v1, null, OBJ_X9_62_c2tnb359v1); // NID: 701 - addObject(NID_X9_62_c2pnb368w1, SN_X9_62_c2pnb368w1, null, OBJ_X9_62_c2pnb368w1); // NID: 702 - addObject(NID_X9_62_c2tnb431r1, SN_X9_62_c2tnb431r1, null, OBJ_X9_62_c2tnb431r1); // NID: 703 - addObject(NID_secp112r1, SN_secp112r1, null, OBJ_secp112r1); // NID: 704 - addObject(NID_secp112r2, SN_secp112r2, null, OBJ_secp112r2); // NID: 705 - addObject(NID_secp128r1, SN_secp128r1, null, OBJ_secp128r1); // NID: 706 - addObject(NID_secp128r2, SN_secp128r2, null, OBJ_secp128r2); // NID: 707 - addObject(NID_secp160k1, SN_secp160k1, null, OBJ_secp160k1); // NID: 708 - addObject(NID_secp160r1, SN_secp160r1, null, OBJ_secp160r1); // NID: 709 - addObject(NID_secp160r2, SN_secp160r2, null, OBJ_secp160r2); // NID: 710 - addObject(NID_secp192k1, SN_secp192k1, null, OBJ_secp192k1); // NID: 711 - addObject(NID_secp224k1, SN_secp224k1, null, OBJ_secp224k1); // NID: 712 - addObject(NID_secp224r1, SN_secp224r1, null, OBJ_secp224r1); // NID: 713 - addObject(NID_secp256k1, SN_secp256k1, null, OBJ_secp256k1); // NID: 714 - addObject(NID_secp384r1, SN_secp384r1, null, OBJ_secp384r1); // NID: 715 - addObject(NID_secp521r1, SN_secp521r1, null, OBJ_secp521r1); // NID: 716 - addObject(NID_sect113r1, SN_sect113r1, null, OBJ_sect113r1); // NID: 717 - addObject(NID_sect113r2, SN_sect113r2, null, OBJ_sect113r2); // NID: 718 - addObject(NID_sect131r1, SN_sect131r1, null, OBJ_sect131r1); // NID: 719 - addObject(NID_sect131r2, SN_sect131r2, null, OBJ_sect131r2); // NID: 720 - addObject(NID_sect163k1, SN_sect163k1, null, OBJ_sect163k1); // NID: 721 - addObject(NID_sect163r1, SN_sect163r1, null, OBJ_sect163r1); // NID: 722 - addObject(NID_sect163r2, SN_sect163r2, null, OBJ_sect163r2); // NID: 723 - addObject(NID_sect193r1, SN_sect193r1, null, OBJ_sect193r1); // NID: 724 - addObject(NID_sect193r2, SN_sect193r2, null, OBJ_sect193r2); // NID: 725 - addObject(NID_sect233k1, SN_sect233k1, null, OBJ_sect233k1); // NID: 726 - addObject(NID_sect233r1, SN_sect233r1, null, OBJ_sect233r1); // NID: 727 - addObject(NID_sect239k1, SN_sect239k1, null, OBJ_sect239k1); // NID: 728 - addObject(NID_sect283k1, SN_sect283k1, null, OBJ_sect283k1); // NID: 729 - addObject(NID_sect283r1, SN_sect283r1, null, OBJ_sect283r1); // NID: 730 - addObject(NID_sect409k1, SN_sect409k1, null, OBJ_sect409k1); // NID: 731 - addObject(NID_sect409r1, SN_sect409r1, null, OBJ_sect409r1); // NID: 732 - addObject(NID_sect571k1, SN_sect571k1, null, OBJ_sect571k1); // NID: 733 - addObject(NID_sect571r1, SN_sect571r1, null, OBJ_sect571r1); // NID: 734 - addObject(NID_wap_wsg_idm_ecid_wtls1, SN_wap_wsg_idm_ecid_wtls1, null, OBJ_wap_wsg_idm_ecid_wtls1); // NID: 735 - addObject(NID_wap_wsg_idm_ecid_wtls3, SN_wap_wsg_idm_ecid_wtls3, null, OBJ_wap_wsg_idm_ecid_wtls3); // NID: 736 - addObject(NID_wap_wsg_idm_ecid_wtls4, SN_wap_wsg_idm_ecid_wtls4, null, OBJ_wap_wsg_idm_ecid_wtls4); // NID: 737 - addObject(NID_wap_wsg_idm_ecid_wtls5, SN_wap_wsg_idm_ecid_wtls5, null, OBJ_wap_wsg_idm_ecid_wtls5); // NID: 738 - addObject(NID_wap_wsg_idm_ecid_wtls6, SN_wap_wsg_idm_ecid_wtls6, null, OBJ_wap_wsg_idm_ecid_wtls6); // NID: 739 - addObject(NID_wap_wsg_idm_ecid_wtls7, SN_wap_wsg_idm_ecid_wtls7, null, OBJ_wap_wsg_idm_ecid_wtls7); // NID: 740 - addObject(NID_wap_wsg_idm_ecid_wtls8, SN_wap_wsg_idm_ecid_wtls8, null, OBJ_wap_wsg_idm_ecid_wtls8); // NID: 741 - addObject(NID_wap_wsg_idm_ecid_wtls9, SN_wap_wsg_idm_ecid_wtls9, null, OBJ_wap_wsg_idm_ecid_wtls9); // NID: 742 - addObject(NID_wap_wsg_idm_ecid_wtls10, SN_wap_wsg_idm_ecid_wtls10, null, OBJ_wap_wsg_idm_ecid_wtls10); // NID: 743 - addObject(NID_wap_wsg_idm_ecid_wtls11, SN_wap_wsg_idm_ecid_wtls11, null, OBJ_wap_wsg_idm_ecid_wtls11); // NID: 744 - addObject(NID_wap_wsg_idm_ecid_wtls12, SN_wap_wsg_idm_ecid_wtls12, null, OBJ_wap_wsg_idm_ecid_wtls12); // NID: 745 - addObject(NID_any_policy, SN_any_policy, LN_any_policy, OBJ_any_policy); // NID: 746 - addObject(NID_policy_mappings, SN_policy_mappings, LN_policy_mappings, OBJ_policy_mappings); // NID: 747 - addObject(NID_inhibit_any_policy, SN_inhibit_any_policy, LN_inhibit_any_policy, OBJ_inhibit_any_policy); // NID: 748 - addObject(NID_ipsec3, SN_ipsec3, LN_ipsec3, null); // NID: 749 - addObject(NID_ipsec4, SN_ipsec4, LN_ipsec4, null); // NID: 750 - addObject(NID_dsa_with_SHA224, SN_dsa_with_SHA224, null, OBJ_dsa_with_SHA224); // NID: 802 - addObject(NID_dsa_with_SHA256, SN_dsa_with_SHA256, null, OBJ_dsa_with_SHA256); // NID: 803 - } - - -// public final static String SN_undef = "UNDEF"; -// public final static String LN_undef = "undefined"; -// public final static int NID_undef = 0; -// public final static String OBJ_undef = "0"; - -// public final static String SN_Algorithm = "Algorithm"; -// public final static String LN_algorithm = "algorithm"; -// public final static int NID_algorithm = 38; -// public final static String OBJ_algorithm = "1.3.14.3.2"; - -// public final static String LN_rsadsi = "rsadsi"; -// public final static int NID_rsadsi = 1; -// public final static String OBJ_rsadsi = "1.2.840.113549"; - -// public final static String LN_pkcs = "pkcs"; -// public final static int NID_pkcs = 2; -// public final static String OBJ_pkcs = OBJ_rsadsi+".1"; - -// public final static String SN_md2 = "MD2"; -// public final static String LN_md2 = "md2"; -// public final static int NID_md2 = 3; -// public final static String OBJ_md2 = OBJ_rsadsi+".2.2"; - -// public final static String SN_md5 = "MD5"; -// public final static String LN_md5 = "md5"; -// public final static int NID_md5 = 4; -// public final static String OBJ_md5 = OBJ_rsadsi+".2.5"; - -// public final static String SN_rc4 = "RC4"; -// public final static String LN_rc4 = "rc4"; -// public final static int NID_rc4 = 5; -// public final static String OBJ_rc4 = OBJ_rsadsi+".3.4"; - -// public final static String LN_rsaEncryption = "rsaEncryption"; -// public final static int NID_rsaEncryption = 6; -// public final static String OBJ_rsaEncryption = OBJ_pkcs+".1.1"; - -// public final static String SN_md2WithRSAEncryption = "RSA-MD2"; -// public final static String LN_md2WithRSAEncryption = "md2WithRSAEncryption"; -// public final static int NID_md2WithRSAEncryption = 7; -// public final static String OBJ_md2WithRSAEncryption = OBJ_pkcs+".1.2"; - -// public final static String SN_md5WithRSAEncryption = "RSA-MD5"; -// public final static String LN_md5WithRSAEncryption = "md5WithRSAEncryption"; -// public final static int NID_md5WithRSAEncryption = 8; -// public final static String OBJ_md5WithRSAEncryption = OBJ_pkcs+".1.4"; - -// public final static String SN_pbeWithMD2AndDES_CBC = "PBE-MD2-DES"; -// public final static String LN_pbeWithMD2AndDES_CBC = "pbeWithMD2AndDES-CBC"; -// public final static int NID_pbeWithMD2AndDES_CBC = 9; -// public final static String OBJ_pbeWithMD2AndDES_CBC = OBJ_pkcs+".5.1"; - -// public final static String SN_pbeWithMD5AndDES_CBC = "PBE-MD5-DES"; -// public final static String LN_pbeWithMD5AndDES_CBC = "pbeWithMD5AndDES-CBC"; -// public final static int NID_pbeWithMD5AndDES_CBC = 10; -// public final static String OBJ_pbeWithMD5AndDES_CBC = OBJ_pkcs+".5.3"; - -// public final static String LN_X500 = "X500"; -// public final static int NID_X500 = 11; -// public final static String OBJ_X500 = "2.5"; - -// public final static String LN_X509 = "X509"; -// public final static int NID_X509 = 12; -// public final static String OBJ_X509 = OBJ_X500+".4"; - -// public final static String SN_commonName = "CN"; -// public final static String LN_commonName = "commonName"; -// public final static int NID_commonName = 13; -// public final static String OBJ_commonName = OBJ_X509+".3"; - -// public final static String SN_countryName = "C"; -// public final static String LN_countryName = "countryName"; -// public final static int NID_countryName = 14; -// public final static String OBJ_countryName = OBJ_X509+".6"; - -// public final static String SN_localityName = ""; -// public final static String LN_localityName = "localityName"; -// public final static int NID_localityName = 15; -// public final static String OBJ_localityName = OBJ_X509+".7"; - -// public final static String SN_stateOrProvinceName = "ST"; -// public final static String LN_stateOrProvinceName = "stateOrProvinceName"; -// public final static int NID_stateOrProvinceName = 16; -// public final static String OBJ_stateOrProvinceName = OBJ_X509+".8"; - -// public final static String SN_organizationName = "O"; -// public final static String LN_organizationName = "organizationName"; -// public final static int NID_organizationName = 17; -// public final static String OBJ_organizationName = OBJ_X509+".10"; - -// public final static String SN_organizationalUnitName = "OU"; -// public final static String LN_organizationalUnitName = "organizationalUnitName"; -// public final static int NID_organizationalUnitName = 18; -// public final static String OBJ_organizationalUnitName = OBJ_X509+".11"; - -// public final static String SN_rsa = "RSA"; -// public final static String LN_rsa = "rsa"; -// public final static int NID_rsa = 19; -// public final static String OBJ_rsa = OBJ_X500+".8.1.1"; - -// public final static String LN_pkcs7 = "pkcs7"; -// public final static int NID_pkcs7 = 20; -// public final static String OBJ_pkcs7 = OBJ_pkcs+".7"; - -// public final static String LN_pkcs7_data = "pkcs7-data"; -// public final static int NID_pkcs7_data = 21; -// public final static String OBJ_pkcs7_data = OBJ_pkcs7+".1"; - -// public final static String LN_pkcs7_signed = "pkcs7-signedData"; -// public final static int NID_pkcs7_signed = 22; -// public final static String OBJ_pkcs7_signed = OBJ_pkcs7+".2"; - -// public final static String LN_pkcs7_enveloped = "pkcs7-envelopedData"; -// public final static int NID_pkcs7_enveloped = 23; -// public final static String OBJ_pkcs7_enveloped = OBJ_pkcs7+".3"; - -// public final static String LN_pkcs7_signedAndEnveloped = "pkcs7-signedAndEnvelopedData"; -// public final static int NID_pkcs7_signedAndEnveloped = 24; -// public final static String OBJ_pkcs7_signedAndEnveloped = OBJ_pkcs7+".4"; - -// public final static String LN_pkcs7_digest = "pkcs7-digestData"; -// public final static int NID_pkcs7_digest = 25; -// public final static String OBJ_pkcs7_digest = OBJ_pkcs7+".5"; - -// public final static String LN_pkcs7_encrypted = "pkcs7-encryptedData"; -// public final static int NID_pkcs7_encrypted = 26; -// public final static String OBJ_pkcs7_encrypted = OBJ_pkcs7+".6"; - -// public final static String LN_pkcs3 = "pkcs3"; -// public final static int NID_pkcs3 = 27; -// public final static String OBJ_pkcs3 = OBJ_pkcs+".3"; - -// public final static String LN_dhKeyAgreement = "dhKeyAgreement"; -// public final static int NID_dhKeyAgreement = 28; -// public final static String OBJ_dhKeyAgreement = OBJ_pkcs3+".1"; - -// public final static String SN_des_ecb = "DES-ECB"; -// public final static String LN_des_ecb = "des-ecb"; -// public final static int NID_des_ecb = 29; -// public final static String OBJ_des_ecb = OBJ_algorithm+".6"; - -// public final static String SN_des_cfb64 = "DES-CFB"; -// public final static String LN_des_cfb64 = "des-cfb"; -// public final static int NID_des_cfb64 = 30; -// public final static String OBJ_des_cfb64 = OBJ_algorithm+".9"; - -// public final static String SN_des_cbc = "DES-CBC"; -// public final static String LN_des_cbc = "des-cbc"; -// public final static int NID_des_cbc = 31; -// public final static String OBJ_des_cbc = OBJ_algorithm+".7"; - -// public final static String SN_des_ede = "DES-EDE"; -// public final static String LN_des_ede = "des-ede"; -// public final static int NID_des_ede = 32; -// public final static String OBJ_des_ede = OBJ_algorithm+".17"; - -// public final static String SN_des_ede3 = "DES-EDE3"; -// public final static String LN_des_ede3 = "des-ede3"; -// public final static int NID_des_ede3 = 33; - -// public final static String SN_idea_cbc = "IDEA-CBC"; -// public final static String LN_idea_cbc = "idea-cbc"; -// public final static int NID_idea_cbc = 34; -// public final static String OBJ_idea_cbc = "1.3.6.1.4.1.188.7.1.1.2"; - -// public final static String SN_idea_cfb64 = "IDEA-CFB"; -// public final static String LN_idea_cfb64 = "idea-cfb"; -// public final static int NID_idea_cfb64 = 35; - -// public final static String SN_idea_ecb = "IDEA-ECB"; -// public final static String LN_idea_ecb = "idea-ecb"; -// public final static int NID_idea_ecb = 36; - -// public final static String SN_rc2_cbc = "RC2-CBC"; -// public final static String LN_rc2_cbc = "rc2-cbc"; -// public final static int NID_rc2_cbc = 37; -// public final static String OBJ_rc2_cbc = OBJ_rsadsi+".3.2"; - -// public final static String SN_rc2_ecb = "RC2-ECB"; -// public final static String LN_rc2_ecb = "rc2-ecb"; -// public final static int NID_rc2_ecb = 38; - -// public final static String SN_rc2_cfb64 = "RC2-CFB"; -// public final static String LN_rc2_cfb64 = "rc2-cfb"; -// public final static int NID_rc2_cfb64 = 39; - -// public final static String SN_rc2_ofb64 = "RC2-OFB"; -// public final static String LN_rc2_ofb64 = "rc2-ofb"; -// public final static int NID_rc2_ofb64 = 40; - -// public final static String SN_sha = "SHA"; -// public final static String LN_sha = "sha"; -// public final static int NID_sha = 41; -// public final static String OBJ_sha = OBJ_algorithm+".18"; - -// public final static String SN_shaWithRSAEncryption = "RSA-SHA"; -// public final static String LN_shaWithRSAEncryption = "shaWithRSAEncryption"; -// public final static int NID_shaWithRSAEncryption = 42; -// public final static String OBJ_shaWithRSAEncryption = OBJ_algorithm+".15"; - -// public final static String SN_des_ede_cbc = "DES-EDE-CBC"; -// public final static String LN_des_ede_cbc = "des-ede-cbc"; -// public final static int NID_des_ede_cbc = 43; - -// public final static String SN_des_ede3_cbc = "DES-EDE3-CBC"; -// public final static String LN_des_ede3_cbc = "des-ede3-cbc"; -// public final static int NID_des_ede3_cbc = 44; -// public final static String OBJ_des_ede3_cbc = OBJ_rsadsi+".3.7"; - -// public final static String SN_des_ofb64 = "DES-OFB"; -// public final static String LN_des_ofb64 = "des-ofb"; -// public final static int NID_des_ofb64 = 45; -// public final static String OBJ_des_ofb64 = OBJ_algorithm+".8"; - -// public final static String SN_idea_ofb64 = "IDEA-OFB"; -// public final static String LN_idea_ofb64 = "idea-ofb"; -// public final static int NID_idea_ofb64 = 46; - -// public final static String LN_pkcs9 = "pkcs9"; -// public final static int NID_pkcs9 = 47; -// public final static String OBJ_pkcs9 = OBJ_pkcs+".9"; - -// public final static String SN_pkcs9_emailAddress = "Email"; -// public final static String LN_pkcs9_emailAddress = "emailAddress"; -// public final static int NID_pkcs9_emailAddress = 48; -// public final static String OBJ_pkcs9_emailAddress = OBJ_pkcs9+".1"; - -// public final static String LN_pkcs9_unstructuredName = "unstructuredName"; -// public final static int NID_pkcs9_unstructuredName = 49; -// public final static String OBJ_pkcs9_unstructuredName = OBJ_pkcs9+".2"; - -// public final static String LN_pkcs9_contentType = "contentType"; -// public final static int NID_pkcs9_contentType = 50; -// public final static String OBJ_pkcs9_contentType = OBJ_pkcs9+".3"; - -// public final static String LN_pkcs9_messageDigest = "messageDigest"; -// public final static int NID_pkcs9_messageDigest = 51; -// public final static String OBJ_pkcs9_messageDigest = OBJ_pkcs9+".4"; - -// public final static String LN_pkcs9_signingTime = "signingTime"; -// public final static int NID_pkcs9_signingTime = 52; -// public final static String OBJ_pkcs9_signingTime = OBJ_pkcs9+".5"; - -// public final static String LN_pkcs9_countersignature = "countersignature"; -// public final static int NID_pkcs9_countersignature = 53; -// public final static String OBJ_pkcs9_countersignature = OBJ_pkcs9+".6"; - -// public final static String LN_pkcs9_challengePassword = "challengePassword"; -// public final static int NID_pkcs9_challengePassword = 54; -// public final static String OBJ_pkcs9_challengePassword = OBJ_pkcs9+".7"; - -// public final static String LN_pkcs9_unstructuredAddress = "unstructuredAddress"; -// public final static int NID_pkcs9_unstructuredAddress = 55; -// public final static String OBJ_pkcs9_unstructuredAddress = OBJ_pkcs9+".8"; - -// public final static String LN_pkcs9_extCertAttributes = "extendedCertificateAttributes"; -// public final static int NID_pkcs9_extCertAttributes = 56; -// public final static String OBJ_pkcs9_extCertAttributes = OBJ_pkcs9+".9"; - -// public final static String SN_netscape = "Netscape"; -// public final static String LN_netscape = "Netscape Communications Corp."; -// public final static int NID_netscape = 57; -// public final static String OBJ_netscape = "2.16.840.1.113730"; - -// public final static String SN_netscape_cert_extension = "nsCertExt"; -// public final static String LN_netscape_cert_extension = "Netscape Certificate Extension"; -// public final static int NID_netscape_cert_extension = 58; -// public final static String OBJ_netscape_cert_extension = OBJ_netscape+".1"; - -// public final static String SN_netscape_data_type = "nsDataType"; -// public final static String LN_netscape_data_type = "Netscape Data Type"; -// public final static int NID_netscape_data_type = 59; -// public final static String OBJ_netscape_data_type = OBJ_netscape+".2"; - -// public final static String SN_des_ede_cfb64 = "DES-EDE-CFB"; -// public final static String LN_des_ede_cfb64 = "des-ede-cfb"; -// public final static int NID_des_ede_cfb64 = 60; - -// public final static String SN_des_ede3_cfb64 = "DES-EDE3-CFB"; -// public final static String LN_des_ede3_cfb64 = "des-ede3-cfb"; -// public final static int NID_des_ede3_cfb64 = 61; - -// public final static String SN_des_ede_ofb64 = "DES-EDE-OFB"; -// public final static String LN_des_ede_ofb64 = "des-ede-ofb"; -// public final static int NID_des_ede_ofb64 = 62; - -// public final static String SN_des_ede3_ofb64 = "DES-EDE3-OFB"; -// public final static String LN_des_ede3_ofb64 = "des-ede3-ofb"; -// public final static int NID_des_ede3_ofb64 = 63; - -// public final static String SN_sha1 = "SHA1"; -// public final static String LN_sha1 = "sha1"; -// public final static int NID_sha1 = 64; -// public final static String OBJ_sha1 = OBJ_algorithm+".26"; - -// public final static String SN_sha1WithRSAEncryption = "RSA-SHA1"; -// public final static String LN_sha1WithRSAEncryption = "sha1WithRSAEncryption"; -// public final static int NID_sha1WithRSAEncryption = 65; -// public final static String OBJ_sha1WithRSAEncryption = OBJ_pkcs+".1.5"; - -// public final static String SN_dsaWithSHA = "DSA-SHA"; -// public final static String LN_dsaWithSHA = "dsaWithSHA"; -// public final static int NID_dsaWithSHA = 66; -// public final static String OBJ_dsaWithSHA = OBJ_algorithm+".13"; - -// public final static String SN_dsa_2 = "DSA-old"; -// public final static String LN_dsa_2 = "dsaEncryption-old"; -// public final static int NID_dsa_2 = 67; -// public final static String OBJ_dsa_2 = OBJ_algorithm+".12"; - -// public final static String SN_pbeWithSHA1AndRC2_CBC = "PBE-SHA1-RC2-64"; -// public final static String LN_pbeWithSHA1AndRC2_CBC = "pbeWithSHA1AndRC2-CBC"; -// public final static int NID_pbeWithSHA1AndRC2_CBC = 68; -// public final static String OBJ_pbeWithSHA1AndRC2_CBC = OBJ_pkcs+".5.11L "; - -// public final static String LN_id_pbkdf2 = "PBKDF2"; -// public final static int NID_id_pbkdf2 = 69; -// public final static String OBJ_id_pbkdf2 = OBJ_pkcs+".5.12L "; - -// public final static String SN_dsaWithSHA1_2 = "DSA-SHA1-old"; -// public final static String LN_dsaWithSHA1_2 = "dsaWithSHA1-old"; -// public final static int NID_dsaWithSHA1_2 = 70; -// public final static String OBJ_dsaWithSHA1_2 = OBJ_algorithm+".27"; - -// public final static String SN_netscape_cert_type = "nsCertType"; -// public final static String LN_netscape_cert_type = "Netscape Cert Type"; -// public final static int NID_netscape_cert_type = 71; -// public final static String OBJ_netscape_cert_type = OBJ_netscape_cert_extension+".1"; - -// public final static String SN_netscape_base_url = "nsBaseUrl"; -// public final static String LN_netscape_base_url = "Netscape Base Url"; -// public final static int NID_netscape_base_url = 72; -// public final static String OBJ_netscape_base_url = OBJ_netscape_cert_extension+".2"; - -// public final static String SN_netscape_revocation_url = "nsRevocationUrl"; -// public final static String LN_netscape_revocation_url = "Netscape Revocation Url"; -// public final static int NID_netscape_revocation_url = 73; -// public final static String OBJ_netscape_revocation_url = OBJ_netscape_cert_extension+".3"; - -// public final static String SN_netscape_ca_revocation_url = "nsCaRevocationUrl"; -// public final static String LN_netscape_ca_revocation_url = "Netscape CA Revocation Url"; -// public final static int NID_netscape_ca_revocation_url = 74; -// public final static String OBJ_netscape_ca_revocation_url = OBJ_netscape_cert_extension+".4"; - -// public final static String SN_netscape_renewal_url = "nsRenewalUrl"; -// public final static String LN_netscape_renewal_url = "Netscape Renewal Url"; -// public final static int NID_netscape_renewal_url = 75; -// public final static String OBJ_netscape_renewal_url = OBJ_netscape_cert_extension+".7"; - -// public final static String SN_netscape_ca_policy_url = "nsCaPolicyUrl"; -// public final static String LN_netscape_ca_policy_url = "Netscape CA Policy Url"; -// public final static int NID_netscape_ca_policy_url = 76; -// public final static String OBJ_netscape_ca_policy_url = OBJ_netscape_cert_extension+".8"; - -// public final static String SN_netscape_ssl_server_name = "nsSslServerName"; -// public final static String LN_netscape_ssl_server_name = "Netscape SSL Server Name"; -// public final static int NID_netscape_ssl_server_name = 77; -// public final static String OBJ_netscape_ssl_server_name = OBJ_netscape_cert_extension+".12"; - -// public final static String SN_netscape_comment = "nsComment"; -// public final static String LN_netscape_comment = "Netscape Comment"; -// public final static int NID_netscape_comment = 78; -// public final static String OBJ_netscape_comment = OBJ_netscape_cert_extension+".13"; - -// public final static String SN_netscape_cert_sequence = "nsCertSequence"; -// public final static String LN_netscape_cert_sequence = "Netscape Certificate Sequence"; -// public final static int NID_netscape_cert_sequence = 79; -// public final static String OBJ_netscape_cert_sequence = OBJ_netscape_data_type+".5"; - -// public final static String SN_desx_cbc = "DESX-CBC"; -// public final static String LN_desx_cbc = "desx-cbc"; -// public final static int NID_desx_cbc = 80; - -// public final static String SN_id_ce = "id-ce"; -// public final static int NID_id_ce = 81; -// public final static String OBJ_id_ce = "2.5.29"; - -// public final static String SN_subject_key_identifier = "subjectKeyIdentifier"; -// public final static String LN_subject_key_identifier = "X509v3 Subject Key Identifier"; -// public final static int NID_subject_key_identifier = 82; -// public final static String OBJ_subject_key_identifier = OBJ_id_ce+".14"; - -// public final static String SN_key_usage = "keyUsage"; -// public final static String LN_key_usage = "X509v3 Key Usage"; -// public final static int NID_key_usage = 83; -// public final static String OBJ_key_usage = OBJ_id_ce+".15"; - -// public final static String SN_private_key_usage_period = "privateKeyUsagePeriod"; -// public final static String LN_private_key_usage_period = "X509v3 Private Key Usage Period"; -// public final static int NID_private_key_usage_period = 84; -// public final static String OBJ_private_key_usage_period = OBJ_id_ce+".16"; - -// public final static String SN_subject_alt_name = "subjectAltName"; -// public final static String LN_subject_alt_name = "X509v3 Subject Alternative Name"; -// public final static int NID_subject_alt_name = 85; -// public final static String OBJ_subject_alt_name = OBJ_id_ce+".17"; - -// public final static String SN_issuer_alt_name = "issuerAltName"; -// public final static String LN_issuer_alt_name = "X509v3 Issuer Alternative Name"; -// public final static int NID_issuer_alt_name = 86; -// public final static String OBJ_issuer_alt_name = OBJ_id_ce+".18"; - -// public final static String SN_basic_constraints = "basicConstraints"; -// public final static String LN_basic_constraints = "X509v3 Basic Constraints"; -// public final static int NID_basic_constraints = 87; -// public final static String OBJ_basic_constraints = OBJ_id_ce+".19"; - -// public final static String SN_crl_number = "crlNumber"; -// public final static String LN_crl_number = "X509v3 CRL Number"; -// public final static int NID_crl_number = 88; -// public final static String OBJ_crl_number = OBJ_id_ce+".20"; - -// public final static String SN_certificate_policies = "certificatePolicies"; -// public final static String LN_certificate_policies = "X509v3 Certificate Policies"; -// public final static int NID_certificate_policies = 89; -// public final static String OBJ_certificate_policies = OBJ_id_ce+".32"; - -// public final static String SN_authority_key_identifier = "authorityKeyIdentifier"; -// public final static String LN_authority_key_identifier = "X509v3 Authority Key Identifier"; -// public final static int NID_authority_key_identifier = 90; -// public final static String OBJ_authority_key_identifier = OBJ_id_ce+".35"; - -// public final static String SN_bf_cbc = "BF-CBC"; -// public final static String LN_bf_cbc = "bf-cbc"; -// public final static int NID_bf_cbc = 91; -// public final static String OBJ_bf_cbc = "1.3.6.1.4.1.3029.1.2"; - -// public final static String SN_bf_ecb = "BF-ECB"; -// public final static String LN_bf_ecb = "bf-ecb"; -// public final static int NID_bf_ecb = 92; - -// public final static String SN_bf_cfb64 = "BF-CFB"; -// public final static String LN_bf_cfb64 = "bf-cfb"; -// public final static int NID_bf_cfb64 = 93; - -// public final static String SN_bf_ofb64 = "BF-OFB"; -// public final static String LN_bf_ofb64 = "bf-ofb"; -// public final static int NID_bf_ofb64 = 94; - -// public final static String SN_mdc2 = "MDC2"; -// public final static String LN_mdc2 = "mdc2"; -// public final static int NID_mdc2 = 95; -// public final static String OBJ_mdc2 = "2.5.8.3.101"; - -// public final static String SN_mdc2WithRSA = "RSA-MDC2"; -// public final static String LN_mdc2WithRSA = "mdc2withRSA"; -// public final static int NID_mdc2WithRSA = 96; -// public final static String OBJ_mdc2WithRSA = "2.5.8.3.100"; - -// public final static String SN_rc4_40 = "RC4-40"; -// public final static String LN_rc4_40 = "rc4-40"; -// public final static int NID_rc4_40 = 97; - -// public final static String SN_rc2_40_cbc = "RC2-40-CBC"; -// public final static String LN_rc2_40_cbc = "rc2-40-cbc"; -// public final static int NID_rc2_40_cbc = 98; - -// public final static String SN_givenName = "G"; -// public final static String LN_givenName = "givenName"; -// public final static int NID_givenName = 99; -// public final static String OBJ_givenName = OBJ_X509+".42"; - -// public final static String SN_surname = "S"; -// public final static String LN_surname = "surname"; -// public final static int NID_surname = 100; -// public final static String OBJ_surname = OBJ_X509+".4"; - -// public final static String SN_initials = "I"; -// public final static String LN_initials = "initials"; -// public final static int NID_initials = 101; -// public final static String OBJ_initials = OBJ_X509+".43"; - -// public final static String SN_uniqueIdentifier = "UID"; -// public final static String LN_uniqueIdentifier = "uniqueIdentifier"; -// public final static int NID_uniqueIdentifier = 102; -// public final static String OBJ_uniqueIdentifier = OBJ_X509+".45"; - -// public final static String SN_crl_distribution_points = "crlDistributionPoints"; -// public final static String LN_crl_distribution_points = "X509v3 CRL Distribution Points"; -// public final static int NID_crl_distribution_points = 103; -// public final static String OBJ_crl_distribution_points = OBJ_id_ce+".31"; - -// public final static String SN_md5WithRSA = "RSA-NP-MD5"; -// public final static String LN_md5WithRSA = "md5WithRSA"; -// public final static int NID_md5WithRSA = 104; -// public final static String OBJ_md5WithRSA = OBJ_algorithm+".3"; - -// public final static String SN_serialNumber = "SN"; -// public final static String LN_serialNumber = "serialNumber"; -// public final static int NID_serialNumber = 105; -// public final static String OBJ_serialNumber = OBJ_X509+".5"; - -// public final static String SN_title = "T"; -// public final static String LN_title = "title"; -// public final static int NID_title = 106; -// public final static String OBJ_title = OBJ_X509+".12"; - -// public final static String SN_description = "D"; -// public final static String LN_description = "description"; -// public final static int NID_description = 107; -// public final static String OBJ_description = OBJ_X509+".13"; - -// public final static String SN_cast5_cbc = "CAST5-CBC"; -// public final static String LN_cast5_cbc = "cast5-cbc"; -// public final static int NID_cast5_cbc = 108; -// public final static String OBJ_cast5_cbc = "1.2.840.113533.7.66.10"; - -// public final static String SN_cast5_ecb = "CAST5-ECB"; -// public final static String LN_cast5_ecb = "cast5-ecb"; -// public final static int NID_cast5_ecb = 109; - -// public final static String SN_cast5_cfb64 = "CAST5-CFB"; -// public final static String LN_cast5_cfb64 = "cast5-cfb"; -// public final static int NID_cast5_cfb64 = 110; - -// public final static String SN_cast5_ofb64 = "CAST5-OFB"; -// public final static String LN_cast5_ofb64 = "cast5-ofb"; -// public final static int NID_cast5_ofb64 = 111; - -// public final static String LN_pbeWithMD5AndCast5_CBC = "pbeWithMD5AndCast5CBC"; -// public final static int NID_pbeWithMD5AndCast5_CBC = 112; -// public final static String OBJ_pbeWithMD5AndCast5_CBC = "1.2.840.113533.7.66.12"; - -// public final static String SN_dsaWithSHA1 = "DSA-SHA1"; -// public final static String LN_dsaWithSHA1 = "dsaWithSHA1"; -// public final static int NID_dsaWithSHA1 = 113; -// public final static String OBJ_dsaWithSHA1 = "1.2.840.10040.4.3"; - -// public final static int NID_md5_sha1 = 114; -// public final static String SN_md5_sha1 = "MD5-SHA1"; -// public final static String LN_md5_sha1 = "md5-sha1"; - -// public final static String SN_sha1WithRSA = "RSA-SHA1-2"; -// public final static String LN_sha1WithRSA = "sha1WithRSA"; -// public final static int NID_sha1WithRSA = 115; -// public final static String OBJ_sha1WithRSA = OBJ_algorithm+".29"; - -// public final static String SN_dsa = "DSA"; -// public final static String LN_dsa = "dsaEncryption"; -// public final static int NID_dsa = 116; -// public final static String OBJ_dsa = "1.2.840.10040.4.1"; - -// public final static String SN_ripemd160 = "RIPEMD160"; -// public final static String LN_ripemd160 = "ripemd160"; -// public final static int NID_ripemd160 = 117; -// public final static String OBJ_ripemd160 = "1.3.36.3.2.1"; - -// public final static String SN_ripemd160WithRSA = "RSA-RIPEMD160"; -// public final static String LN_ripemd160WithRSA = "ripemd160WithRSA"; -// public final static int NID_ripemd160WithRSA = 119; -// public final static String OBJ_ripemd160WithRSA = "1.3.36.3.3.1.2"; - -// public final static String SN_rc5_cbc = "RC5-CBC"; -// public final static String LN_rc5_cbc = "rc5-cbc"; -// public final static int NID_rc5_cbc = 120; -// public final static String OBJ_rc5_cbc = OBJ_rsadsi+".3.8"; - -// public final static String SN_rc5_ecb = "RC5-ECB"; -// public final static String LN_rc5_ecb = "rc5-ecb"; -// public final static int NID_rc5_ecb = 121; - -// public final static String SN_rc5_cfb64 = "RC5-CFB"; -// public final static String LN_rc5_cfb64 = "rc5-cfb"; -// public final static int NID_rc5_cfb64 = 122; - -// public final static String SN_rc5_ofb64 = "RC5-OFB"; -// public final static String LN_rc5_ofb64 = "rc5-ofb"; -// public final static int NID_rc5_ofb64 = 123; - -// public final static String SN_rle_compression = "RLE"; -// public final static String LN_rle_compression = "run length compression"; -// public final static int NID_rle_compression = 124; -// public final static String OBJ_rle_compression = "1.1.1.1.666.1"; - -// public final static String SN_zlib_compression = "ZLIB"; -// public final static String LN_zlib_compression = "zlib compression"; -// public final static int NID_zlib_compression = 125; -// public final static String OBJ_zlib_compression = "1.1.1.1.666.2"; - -// public final static String SN_ext_key_usage = "extendedKeyUsage"; -// public final static String LN_ext_key_usage = "X509v3 Extended Key Usage"; -// public final static int NID_ext_key_usage = 126; -// public final static String OBJ_ext_key_usage = OBJ_id_ce+".37"; - -// public final static String SN_id_pkix = "PKIX"; -// public final static int NID_id_pkix = 127; -// public final static String OBJ_id_pkix = "1.3.6.1.5.5.7"; - -// public final static String SN_id_kp = "id-kp"; -// public final static int NID_id_kp = 128; -// public final static String OBJ_id_kp = OBJ_id_pkix+".3"; - -// public final static String SN_server_auth = "serverAuth"; -// public final static String LN_server_auth = "TLS Web Server Authentication"; -// public final static int NID_server_auth = 129; -// public final static String OBJ_server_auth = OBJ_id_kp+".1"; - -// public final static String SN_client_auth = "clientAuth"; -// public final static String LN_client_auth = "TLS Web Client Authentication"; -// public final static int NID_client_auth = 130; -// public final static String OBJ_client_auth = OBJ_id_kp+".2"; - -// public final static String SN_code_sign = "codeSigning"; -// public final static String LN_code_sign = "Code Signing"; -// public final static int NID_code_sign = 131; -// public final static String OBJ_code_sign = OBJ_id_kp+".3"; - -// public final static String SN_email_protect = "emailProtection"; -// public final static String LN_email_protect = "E-mail Protection"; -// public final static int NID_email_protect = 132; -// public final static String OBJ_email_protect = OBJ_id_kp+".4"; - -// public final static String SN_time_stamp = "timeStamping"; -// public final static String LN_time_stamp = "Time Stamping"; -// public final static int NID_time_stamp = 133; -// public final static String OBJ_time_stamp = OBJ_id_kp+".8"; - -// public final static String SN_ms_code_ind = "msCodeInd"; -// public final static String LN_ms_code_ind = "Microsoft Individual Code Signing"; -// public final static int NID_ms_code_ind = 134; -// public final static String OBJ_ms_code_ind = "1.3.6.1.4.1.311.2.1.21"; - -// public final static String SN_ms_code_com = "msCodeCom"; -// public final static String LN_ms_code_com = "Microsoft Commercial Code Signing"; -// public final static int NID_ms_code_com = 135; -// public final static String OBJ_ms_code_com = "1.3.6.1.4.1.311.2.1.22"; - -// public final static String SN_ms_ctl_sign = "msCTLSign"; -// public final static String LN_ms_ctl_sign = "Microsoft Trust List Signing"; -// public final static int NID_ms_ctl_sign = 136; -// public final static String OBJ_ms_ctl_sign = "1.3.6.1.4.1.311.10.3.1"; - -// public final static String SN_ms_sgc = "msSGC"; -// public final static String LN_ms_sgc = "Microsoft Server Gated Crypto"; -// public final static int NID_ms_sgc = 137; -// public final static String OBJ_ms_sgc = "1.3.6.1.4.1.311.10.3.3"; - -// public final static String SN_ms_efs = "msEFS"; -// public final static String LN_ms_efs = "Microsoft Encrypted File System"; -// public final static int NID_ms_efs = 138; -// public final static String OBJ_ms_efs = "1.3.6.1.4.1.311.10.3.4"; - -// public final static String SN_ns_sgc = "nsSGC"; -// public final static String LN_ns_sgc = "Netscape Server Gated Crypto"; -// public final static int NID_ns_sgc = 139; -// public final static String OBJ_ns_sgc = OBJ_netscape+".4.1"; - -// public final static String SN_delta_crl = "deltaCR"; -// public final static String LN_delta_crl = "X509v3 Delta CRL Indicator"; -// public final static int NID_delta_crl = 140; -// public final static String OBJ_delta_crl = OBJ_id_ce+".27"; - -// public final static String SN_crl_reason = "CRLReason"; -// public final static String LN_crl_reason = "CRL Reason Code"; -// public final static int NID_crl_reason = 141; -// public final static String OBJ_crl_reason = OBJ_id_ce+".21"; - -// public final static String SN_invalidity_date = "invalidityDate"; -// public final static String LN_invalidity_date = "Invalidity Date"; -// public final static int NID_invalidity_date = 142; -// public final static String OBJ_invalidity_date = OBJ_id_ce+".24"; - -// public final static String SN_sxnet = "SXNetID"; -// public final static String LN_sxnet = "Strong Extranet ID"; -// public final static int NID_sxnet = 143; -// public final static String OBJ_sxnet = "1.3.101.1.4.1"; - -// public final static String OBJ_pkcs12 = OBJ_pkcs+".12"; -// public final static String OBJ_pkcs12_pbeids = OBJ_pkcs12+".1"; - -// public final static String SN_pbe_WithSHA1And128BitRC4 = "PBE-SHA1-RC4-128"; -// public final static String LN_pbe_WithSHA1And128BitRC4 = "pbeWithSHA1And128BitRC4"; -// public final static int NID_pbe_WithSHA1And128BitRC4 = 144; -// public final static String OBJ_pbe_WithSHA1And128BitRC4 = OBJ_pkcs12_pbeids+".1"; - -// public final static String SN_pbe_WithSHA1And40BitRC4 = "PBE-SHA1-RC4-40"; -// public final static String LN_pbe_WithSHA1And40BitRC4 = "pbeWithSHA1And40BitRC4"; -// public final static int NID_pbe_WithSHA1And40BitRC4 = 145; -// public final static String OBJ_pbe_WithSHA1And40BitRC4 = OBJ_pkcs12_pbeids+".2"; - -// public final static String SN_pbe_WithSHA1And3_Key_TripleDES_CBC = "PBE-SHA1-3DES"; -// public final static String LN_pbe_WithSHA1And3_Key_TripleDES_CBC = "pbeWithSHA1And3-KeyTripleDES-CBC"; -// public final static int NID_pbe_WithSHA1And3_Key_TripleDES_CBC = 146; -// public final static String OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC = OBJ_pkcs12_pbeids+".3"; - -// public final static String SN_pbe_WithSHA1And2_Key_TripleDES_CBC = "PBE-SHA1-2DES"; -// public final static String LN_pbe_WithSHA1And2_Key_TripleDES_CBC = "pbeWithSHA1And2-KeyTripleDES-CBC"; -// public final static int NID_pbe_WithSHA1And2_Key_TripleDES_CBC = 147; -// public final static String OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC = OBJ_pkcs12_pbeids+".4"; - -// public final static String SN_pbe_WithSHA1And128BitRC2_CBC = "PBE-SHA1-RC2-128"; -// public final static String LN_pbe_WithSHA1And128BitRC2_CBC = "pbeWithSHA1And128BitRC2-CBC"; -// public final static int NID_pbe_WithSHA1And128BitRC2_CBC = 148; -// public final static String OBJ_pbe_WithSHA1And128BitRC2_CBC = OBJ_pkcs12_pbeids+".5"; - -// public final static String SN_pbe_WithSHA1And40BitRC2_CBC = "PBE-SHA1-RC2-40"; -// public final static String LN_pbe_WithSHA1And40BitRC2_CBC = "pbeWithSHA1And40BitRC2-CBC"; -// public final static int NID_pbe_WithSHA1And40BitRC2_CBC = 149; -// public final static String OBJ_pbe_WithSHA1And40BitRC2_CBC = OBJ_pkcs12_pbeids+".6"; - -// public final static String OBJ_pkcs12_Version1 = OBJ_pkcs12+".10"; - -// public final static String OBJ_pkcs12_BagIds = OBJ_pkcs12_Version1+".1"; - -// public final static String LN_keyBag = "keyBag"; -// public final static int NID_keyBag = 150; -// public final static String OBJ_keyBag = OBJ_pkcs12_BagIds+".1"; - -// public final static String LN_pkcs8ShroudedKeyBag = "pkcs8ShroudedKeyBag"; -// public final static int NID_pkcs8ShroudedKeyBag = 151; -// public final static String OBJ_pkcs8ShroudedKeyBag = OBJ_pkcs12_BagIds+".2"; - -// public final static String LN_certBag = "certBag"; -// public final static int NID_certBag = 152; -// public final static String OBJ_certBag = OBJ_pkcs12_BagIds+".3"; - -// public final static String LN_crlBag = "crlBag"; -// public final static int NID_crlBag = 153; -// public final static String OBJ_crlBag = OBJ_pkcs12_BagIds+".4"; - -// public final static String LN_secretBag = "secretBag"; -// public final static int NID_secretBag = 154; -// public final static String OBJ_secretBag = OBJ_pkcs12_BagIds+".5"; - -// public final static String LN_safeContentsBag = "safeContentsBag"; -// public final static int NID_safeContentsBag = 155; -// public final static String OBJ_safeContentsBag = OBJ_pkcs12_BagIds+".6"; - -// public final static String LN_friendlyName = "friendlyName"; -// public final static int NID_friendlyName = 156; -// public final static String OBJ_friendlyName = OBJ_pkcs9+".20"; - -// public final static String LN_localKeyID = "localKeyID"; -// public final static int NID_localKeyID = 157; -// public final static String OBJ_localKeyID = OBJ_pkcs9+".21"; - -// public final static String OBJ_certTypes = OBJ_pkcs9+".22"; - -// public final static String LN_x509Certificate = "x509Certificate"; -// public final static int NID_x509Certificate = 158; -// public final static String OBJ_x509Certificate = OBJ_certTypes+".1"; - -// public final static String LN_sdsiCertificate = "sdsiCertificate"; -// public final static int NID_sdsiCertificate = 159; -// public final static String OBJ_sdsiCertificate = OBJ_certTypes+".2"; - -// public final static String OBJ_crlTypes = OBJ_pkcs9+".23"; - -// public final static String LN_x509Crl = "x509Crl"; -// public final static int NID_x509Crl = 160; -// public final static String OBJ_x509Crl = OBJ_crlTypes+".1"; - -// public final static String LN_pbes2 = "PBES2"; -// public final static int NID_pbes2 = 161; -// public final static String OBJ_pbes2 = OBJ_pkcs+".5.13"; - -// public final static String LN_pbmac1 = "PBMAC1"; -// public final static int NID_pbmac1 = 162; -// public final static String OBJ_pbmac1 = OBJ_pkcs+".5.14"; - -// public final static String LN_hmacWithSHA1 = "hmacWithSHA1"; -// public final static int NID_hmacWithSHA1 = 163; -// public final static String OBJ_hmacWithSHA1 = OBJ_rsadsi+".2.7"; - -// public final static String LN_id_qt_cps = "Policy Qualifier CPS"; -// public final static String SN_id_qt_cps = "id-qt-cps"; -// public final static int NID_id_qt_cps = 164; -// public final static String OBJ_id_qt_cps = OBJ_id_pkix+".2.1"; - -// public final static String LN_id_qt_unotice = "Policy Qualifier User Notice"; -// public final static String SN_id_qt_unotice = "id-qt-unotice"; -// public final static int NID_id_qt_unotice = 165; -// public final static String OBJ_id_qt_unotice = OBJ_id_pkix+".2.2"; - -// public final static String SN_rc2_64_cbc = "RC2-64-CBC"; -// public final static String LN_rc2_64_cbc = "rc2-64-cbc"; -// public final static int NID_rc2_64_cbc = 166; - -// public final static String SN_SMIMECapabilities = "SMIME-CAPS"; -// public final static String LN_SMIMECapabilities = "S/MIME Capabilities"; -// public final static int NID_SMIMECapabilities = 167; -// public final static String OBJ_SMIMECapabilities = OBJ_pkcs9+".15"; - -// public final static String SN_pbeWithMD2AndRC2_CBC = "PBE-MD2-RC2-64"; -// public final static String LN_pbeWithMD2AndRC2_CBC = "pbeWithMD2AndRC2-CBC"; -// public final static int NID_pbeWithMD2AndRC2_CBC = 168; -// public final static String OBJ_pbeWithMD2AndRC2_CBC = OBJ_pkcs+".5.4"; - -// public final static String SN_pbeWithMD5AndRC2_CBC = "PBE-MD5-RC2-64"; -// public final static String LN_pbeWithMD5AndRC2_CBC = "pbeWithMD5AndRC2-CBC"; -// public final static int NID_pbeWithMD5AndRC2_CBC = 169; -// public final static String OBJ_pbeWithMD5AndRC2_CBC = OBJ_pkcs+".5.6"; - -// public final static String SN_pbeWithSHA1AndDES_CBC = "PBE-SHA1-DES"; -// public final static String LN_pbeWithSHA1AndDES_CBC = "pbeWithSHA1AndDES-CBC"; -// public final static int NID_pbeWithSHA1AndDES_CBC = 170; -// public final static String OBJ_pbeWithSHA1AndDES_CBC = OBJ_pkcs+".5.10"; - -// public final static String LN_ms_ext_req = "Microsoft Extension Request"; -// public final static String SN_ms_ext_req = "msExtReq"; -// public final static int NID_ms_ext_req = 171; -// public final static String OBJ_ms_ext_req = "1.3.6.1.4.1.311.2.1.14"; - -// public final static String LN_ext_req = "Extension Request"; -// public final static String SN_ext_req = "extReq"; -// public final static int NID_ext_req = 172; -// public final static String OBJ_ext_req = OBJ_pkcs9+".14"; - -// public final static String SN_name = "name"; -// public final static String LN_name = "name"; -// public final static int NID_name = 173; -// public final static String OBJ_name = OBJ_X509+".41"; - -// public final static String SN_dnQualifier = "dnQualifier"; -// public final static String LN_dnQualifier = "dnQualifier"; -// public final static int NID_dnQualifier = 174; -// public final static String OBJ_dnQualifier = OBJ_X509+".46"; - -// public final static String SN_id_pe = "id-pe"; -// public final static int NID_id_pe = 175; -// public final static String OBJ_id_pe = OBJ_id_pkix+".1"; - -// public final static String SN_id_ad = "id-ad"; -// public final static int NID_id_ad = 176; -// public final static String OBJ_id_ad = OBJ_id_pkix+".48"; - -// public final static String SN_info_access = "authorityInfoAccess"; -// public final static String LN_info_access = "Authority Information Access"; -// public final static int NID_info_access = 177; -// public final static String OBJ_info_access = OBJ_id_pe+".1"; - -// public final static String SN_ad_OCSP = "OCSP"; -// public final static String LN_ad_OCSP = "OCSP"; -// public final static int NID_ad_OCSP = 178; -// public final static String OBJ_ad_OCSP = OBJ_id_ad+".1"; - -// public final static String SN_ad_ca_issuers = "caIssuers"; -// public final static String LN_ad_ca_issuers = "CA Issuers"; -// public final static int NID_ad_ca_issuers = 179; -// public final static String OBJ_ad_ca_issuers = OBJ_id_ad+".2"; - -// public final static String SN_OCSP_sign = "OCSPSigning"; -// public final static String LN_OCSP_sign = "OCSP Signing"; -// public final static int NID_OCSP_sign = 180; -// public final static String OBJ_OCSP_sign = OBJ_id_kp+".9"; - -// static { -// addObject(NID_undef, SN_undef, LN_undef, OBJ_undef); -// addObject(NID_rsadsi, SN_rsadsi, LN_rsadsi, OBJ_rsadsi); -// addObject(NID_pkcs, SN_pkcs, LN_pkcs, OBJ_pkcs); -// addObject(NID_md2, SN_md2, LN_md2, OBJ_md2); -// addObject(NID_md5, SN_md5, LN_md5, OBJ_md5); -// addObject(NID_rc4, SN_rc4, LN_rc4, OBJ_rc4); -// addObject(NID_rsaEncryption, SN_rsaEncryption, LN_rsaEncryption, OBJ_rsaEncryption); -// addObject(NID_md2WithRSAEncryption, SN_md2WithRSAEncryption, LN_md2WithRSAEncryption, OBJ_md2WithRSAEncryption); -// addObject(NID_md5WithRSAEncryption, SN_md5WithRSAEncryption, LN_md5WithRSAEncryption, OBJ_md5WithRSAEncryption); -// addObject(NID_pbeWithMD2AndDES_CBC, SN_pbeWithMD2AndDES_CBC, LN_pbeWithMD2AndDES_CBC, OBJ_pbeWithMD2AndDES_CBC); -// addObject(NID_pbeWithMD5AndDES_CBC, SN_pbeWithMD5AndDES_CBC, LN_pbeWithMD5AndDES_CBC, OBJ_pbeWithMD5AndDES_CBC); -// addObject(NID_X500, SN_X500, LN_X500, OBJ_X500); -// addObject(NID_X509, SN_X509, LN_X509, OBJ_X509); -// addObject(NID_commonName, SN_commonName, LN_commonName, OBJ_commonName); -// addObject(NID_countryName, SN_countryName, LN_countryName, OBJ_countryName); -// addObject(NID_localityName, SN_localityName, LN_localityName, OBJ_localityName); -// addObject(NID_stateOrProvinceName, SN_stateOrProvinceName, LN_stateOrProvinceName, OBJ_stateOrProvinceName); -// addObject(NID_organizationName, SN_organizationName, LN_organizationName, OBJ_organizationName); -// addObject(NID_organizationalUnitName, SN_organizationalUnitName, LN_organizationalUnitName, OBJ_organizationalUnitName); -// addObject(NID_rsa, SN_rsa, LN_rsa, OBJ_rsa); -// addObject(NID_pkcs7, SN_pkcs7, LN_pkcs7, OBJ_pkcs7); -// addObject(NID_pkcs7_data, SN_pkcs7_data, LN_pkcs7_data, OBJ_pkcs7_data); -// addObject(NID_pkcs7_signed, SN_pkcs7_signed, LN_pkcs7_signed, OBJ_pkcs7_signed); -// addObject(NID_pkcs7_enveloped, SN_pkcs7_enveloped, LN_pkcs7_enveloped, OBJ_pkcs7_enveloped); -// addObject(NID_pkcs7_signedAndEnveloped, SN_pkcs7_signedAndEnveloped, LN_pkcs7_signedAndEnveloped, OBJ_pkcs7_signedAndEnveloped); -// addObject(NID_pkcs7_digest, SN_pkcs7_digest, LN_pkcs7_digest, OBJ_pkcs7_digest); -// addObject(NID_pkcs7_encrypted, SN_pkcs7_encrypted, LN_pkcs7_encrypted, OBJ_pkcs7_encrypted); -// addObject(NID_pkcs3, SN_pkcs3, LN_pkcs3, OBJ_pkcs3); -// addObject(NID_dhKeyAgreement, SN_dhKeyAgreement, LN_dhKeyAgreement, OBJ_dhKeyAgreement); -// addObject(NID_des_ecb, SN_des_ecb, LN_des_ecb, OBJ_des_ecb); -// addObject(NID_des_cfb64, SN_des_cfb64, LN_des_cfb64, OBJ_des_cfb64); -// addObject(NID_des_cbc, SN_des_cbc, LN_des_cbc, OBJ_des_cbc); -// addObject(NID_des_ede, SN_des_ede, LN_des_ede, OBJ_des_ede); -// addObject(NID_des_ede3, SN_des_ede3, LN_des_ede3, OBJ_des_ede3); -// addObject(NID_idea_cbc, SN_idea_cbc, LN_idea_cbc, OBJ_idea_cbc); -// addObject(NID_idea_cfb64, SN_idea_cfb64, LN_idea_cfb64, OBJ_idea_cfb64); -// addObject(NID_idea_ecb, SN_idea_ecb, LN_idea_ecb, OBJ_idea_ecb); -// addObject(NID_rc2_cbc, SN_rc2_cbc, LN_rc2_cbc, OBJ_rc2_cbc); -// addObject(NID_rc2_ecb, SN_rc2_ecb, LN_rc2_ecb, OBJ_rc2_ecb); -// addObject(NID_rc2_cfb64, SN_rc2_cfb64, LN_rc2_cfb64, OBJ_rc2_cfb64); -// addObject(NID_rc2_ofb64, SN_rc2_ofb64, LN_rc2_ofb64, OBJ_rc2_ofb64); -// addObject(NID_sha, SN_sha, LN_sha, OBJ_sha); -// addObject(NID_shaWithRSAEncryption, SN_shaWithRSAEncryption, LN_shaWithRSAEncryption, OBJ_shaWithRSAEncryption); -// addObject(NID_des_ede_cbc, SN_des_ede_cbc, LN_des_ede_cbc, OBJ_des_ede_cbc); -// addObject(NID_des_ede3_cbc, SN_des_ede3_cbc, LN_des_ede3_cbc, OBJ_des_ede3_cbc); -// addObject(NID_des_ofb64, SN_des_ofb64, LN_des_ofb64, OBJ_des_ofb64); -// addObject(NID_idea_ofb64, SN_idea_ofb64, LN_idea_ofb64, OBJ_idea_ofb64); -// addObject(NID_pkcs9, SN_pkcs9, LN_pkcs9, OBJ_pkcs9); -// addObject(NID_pkcs9_emailAddress, SN_pkcs9_emailAddress, LN_pkcs9_emailAddress, OBJ_pkcs9_emailAddress); -// addObject(NID_pkcs9_unstructuredName, SN_pkcs9_unstructuredName, LN_pkcs9_unstructuredName, OBJ_pkcs9_unstructuredName); -// addObject(NID_pkcs9_contentType, SN_pkcs9_contentType, LN_pkcs9_contentType, OBJ_pkcs9_contentType); -// addObject(NID_pkcs9_messageDigest, SN_pkcs9_messageDigest, LN_pkcs9_messageDigest, OBJ_pkcs9_messageDigest); -// addObject(NID_pkcs9_signingTime, SN_pkcs9_signingTime, LN_pkcs9_signingTime, OBJ_pkcs9_signingTime); -// addObject(NID_pkcs9_countersignature, SN_pkcs9_countersignature, LN_pkcs9_countersignature, OBJ_pkcs9_countersignature); -// addObject(NID_pkcs9_challengePassword, SN_pkcs9_challengePassword, LN_pkcs9_challengePassword, OBJ_pkcs9_challengePassword); -// addObject(NID_pkcs9_unstructuredAddress, SN_pkcs9_unstructuredAddress, LN_pkcs9_unstructuredAddress, OBJ_pkcs9_unstructuredAddress); -// addObject(NID_pkcs9_extCertAttributes, SN_pkcs9_extCertAttributes, LN_pkcs9_extCertAttributes, OBJ_pkcs9_extCertAttributes); -// addObject(NID_netscape, SN_netscape, LN_netscape, OBJ_netscape); -// addObject(NID_netscape_cert_extension, SN_netscape_cert_extension, LN_netscape_cert_extension, OBJ_netscape_cert_extension); -// addObject(NID_netscape_data_type, SN_netscape_data_type, LN_netscape_data_type, OBJ_netscape_data_type); -// addObject(NID_des_ede_cfb64, SN_des_ede_cfb64, LN_des_ede_cfb64, OBJ_des_ede_cfb64); -// addObject(NID_des_ede3_cfb64, SN_des_ede3_cfb64, LN_des_ede3_cfb64, OBJ_des_ede3_cfb64); -// addObject(NID_des_ede_ofb64, SN_des_ede_ofb64, LN_des_ede_ofb64, OBJ_des_ede_ofb64); -// addObject(NID_des_ede3_ofb64, SN_des_ede3_ofb64, LN_des_ede3_ofb64, OBJ_des_ede3_ofb64); -// addObject(NID_sha1, SN_sha1, LN_sha1, OBJ_sha1); -// addObject(NID_sha1WithRSAEncryption, SN_sha1WithRSAEncryption, LN_sha1WithRSAEncryption, OBJ_sha1WithRSAEncryption); -// addObject(NID_dsaWithSHA, SN_dsaWithSHA, LN_dsaWithSHA, OBJ_dsaWithSHA); -// addObject(NID_dsa_2, SN_dsa_2, LN_dsa_2, OBJ_dsa_2); -// addObject(NID_pbeWithSHA1AndRC2_CBC, SN_pbeWithSHA1AndRC2_CBC, LN_pbeWithSHA1AndRC2_CBC, OBJ_pbeWithSHA1AndRC2_CBC); -// addObject(NID_id_pbkdf2, SN_id_pbkdf2, LN_id_pbkdf2, OBJ_id_pbkdf2); -// addObject(NID_dsaWithSHA1_2, SN_dsaWithSHA1_2, LN_dsaWithSHA1_2, OBJ_dsaWithSHA1_2); -// addObject(NID_netscape_cert_type, SN_netscape_cert_type, LN_netscape_cert_type, OBJ_netscape_cert_type); -// addObject(NID_netscape_base_url, SN_netscape_base_url, LN_netscape_base_url, OBJ_netscape_base_url); -// addObject(NID_netscape_revocation_url, SN_netscape_revocation_url, LN_netscape_revocation_url, OBJ_netscape_revocation_url); -// addObject(NID_netscape_ca_revocation_url, SN_netscape_ca_revocation_url, LN_netscape_ca_revocation_url, OBJ_netscape_ca_revocation_url); -// addObject(NID_netscape_renewal_url, SN_netscape_renewal_url, LN_netscape_renewal_url, OBJ_netscape_renewal_url); -// addObject(NID_netscape_ca_policy_url, SN_netscape_ca_policy_url, LN_netscape_ca_policy_url, OBJ_netscape_ca_policy_url); -// addObject(NID_netscape_ssl_server_name, SN_netscape_ssl_server_name, LN_netscape_ssl_server_name, OBJ_netscape_ssl_server_name); -// addObject(NID_netscape_comment, SN_netscape_comment, LN_netscape_comment, OBJ_netscape_comment); -// addObject(NID_netscape_cert_sequence, SN_netscape_cert_sequence, LN_netscape_cert_sequence, OBJ_netscape_cert_sequence); -// addObject(NID_desx_cbc, SN_desx_cbc, LN_desx_cbc, OBJ_desx_cbc); -// addObject(NID_id_ce, SN_id_ce, LN_id_ce, OBJ_id_ce); -// addObject(NID_subject_key_identifier, SN_subject_key_identifier, LN_subject_key_identifier, OBJ_subject_key_identifier); -// addObject(NID_key_usage, SN_key_usage, LN_key_usage, OBJ_key_usage); -// addObject(NID_private_key_usage_period, SN_private_key_usage_period, LN_private_key_usage_period, OBJ_private_key_usage_period); -// addObject(NID_subject_alt_name, SN_subject_alt_name, LN_subject_alt_name, OBJ_subject_alt_name); -// addObject(NID_issuer_alt_name, SN_issuer_alt_name, LN_issuer_alt_name, OBJ_issuer_alt_name); -// addObject(NID_basic_constraints, SN_basic_constraints, LN_basic_constraints, OBJ_basic_constraints); -// addObject(NID_crl_number, SN_crl_number, LN_crl_number, OBJ_crl_number); -// addObject(NID_certificate_policies, SN_certificate_policies, LN_certificate_policies, OBJ_certificate_policies); -// addObject(NID_authority_key_identifier, SN_authority_key_identifier, LN_authority_key_identifier, OBJ_authority_key_identifier); -// addObject(NID_bf_cbc, SN_bf_cbc, LN_bf_cbc, OBJ_bf_cbc); -// addObject(NID_bf_ecb, SN_bf_ecb, LN_bf_ecb, OBJ_bf_ecb); -// addObject(NID_bf_cfb64, SN_bf_cfb64, LN_bf_cfb64, OBJ_bf_cfb64); -// addObject(NID_bf_ofb64, SN_bf_ofb64, LN_bf_ofb64, OBJ_bf_ofb64); -// addObject(NID_mdc2, SN_mdc2, LN_mdc2, OBJ_mdc2); -// addObject(NID_mdc2WithRSA, SN_mdc2WithRSA, LN_mdc2WithRSA, OBJ_mdc2WithRSA); -// addObject(NID_rc4_40, SN_rc4_40, LN_rc4_40, OBJ_rc4_40); -// addObject(NID_rc2_40_cbc, SN_rc2_40_cbc, LN_rc2_40_cbc, OBJ_rc2_40_cbc); -// addObject(NID_givenName, SN_givenName, LN_givenName, OBJ_givenName); -// addObject(NID_surname, SN_surname, LN_surname, OBJ_surname); -// addObject(NID_initials, SN_initials, LN_initials, OBJ_initials); -// addObject(NID_uniqueIdentifier, SN_uniqueIdentifier, LN_uniqueIdentifier, OBJ_uniqueIdentifier); -// addObject(NID_crl_distribution_points, SN_crl_distribution_points, LN_crl_distribution_points, OBJ_crl_distribution_points); -// addObject(NID_md5WithRSA, SN_md5WithRSA, LN_md5WithRSA, OBJ_md5WithRSA); -// addObject(NID_serialNumber, SN_serialNumber, LN_serialNumber, OBJ_serialNumber); -// addObject(NID_title, SN_title, LN_title, OBJ_title); -// addObject(NID_description, SN_description, LN_description, OBJ_description); -// addObject(NID_cast5_cbc, SN_cast5_cbc, LN_cast5_cbc, OBJ_cast5_cbc); -// addObject(NID_cast5_ecb, SN_cast5_ecb, LN_cast5_ecb, OBJ_cast5_ecb); -// addObject(NID_cast5_cfb64, SN_cast5_cfb64, LN_cast5_cfb64, OBJ_cast5_cfb64); -// addObject(NID_cast5_ofb64, SN_cast5_ofb64, LN_cast5_ofb64, OBJ_cast5_ofb64); -// addObject(NID_pbeWithMD5AndCast5_CBC, SN_pbeWithMD5AndCast5_CBC, LN_pbeWithMD5AndCast5_CBC, OBJ_pbeWithMD5AndCast5_CBC); -// addObject(NID_dsaWithSHA1, SN_dsaWithSHA1, LN_dsaWithSHA1, OBJ_dsaWithSHA1); -// addObject(NID_md5_sha1, SN_md5_sha1, LN_md5_sha1, OBJ_md5_sha1); -// addObject(NID_sha1WithRSA, SN_sha1WithRSA, LN_sha1WithRSA, OBJ_sha1WithRSA); -// addObject(NID_dsa, SN_dsa, LN_dsa, OBJ_dsa); -// addObject(NID_ripemd160, SN_ripemd160, LN_ripemd160, OBJ_ripemd160); -// addObject(NID_ripemd160WithRSA, SN_ripemd160WithRSA, LN_ripemd160WithRSA, OBJ_ripemd160WithRSA); -// addObject(NID_rc5_cbc, SN_rc5_cbc, LN_rc5_cbc, OBJ_rc5_cbc); -// addObject(NID_rc5_ecb, SN_rc5_ecb, LN_rc5_ecb, OBJ_rc5_ecb); -// addObject(NID_rc5_cfb64, SN_rc5_cfb64, LN_rc5_cfb64, OBJ_rc5_cfb64); -// addObject(NID_rc5_ofb64, SN_rc5_ofb64, LN_rc5_ofb64, OBJ_rc5_ofb64); -// addObject(NID_rle_compression, SN_rle_compression, LN_rle_compression, OBJ_rle_compression); -// addObject(NID_zlib_compression, SN_zlib_compression, LN_zlib_compression, OBJ_zlib_compression); -// addObject(NID_ext_key_usage, SN_ext_key_usage, LN_ext_key_usage, OBJ_ext_key_usage); -// addObject(NID_id_pkix, SN_id_pkix, LN_id_pkix, OBJ_id_pkix); -// addObject(NID_id_kp, SN_id_kp, LN_id_kp, OBJ_id_kp); -// addObject(NID_server_auth, SN_server_auth, LN_server_auth, OBJ_server_auth); -// addObject(NID_client_auth, SN_client_auth, LN_client_auth, OBJ_client_auth); -// addObject(NID_code_sign, SN_code_sign, LN_code_sign, OBJ_code_sign); -// addObject(NID_email_protect, SN_email_protect, LN_email_protect, OBJ_email_protect); -// addObject(NID_time_stamp, SN_time_stamp, LN_time_stamp, OBJ_time_stamp); -// addObject(NID_ms_code_ind, SN_ms_code_ind, LN_ms_code_ind, OBJ_ms_code_ind); -// addObject(NID_ms_code_com, SN_ms_code_com, LN_ms_code_com, OBJ_ms_code_com); -// addObject(NID_ms_ctl_sign, SN_ms_ctl_sign, LN_ms_ctl_sign, OBJ_ms_ctl_sign); -// addObject(NID_ms_sgc, SN_ms_sgc, LN_ms_sgc, OBJ_ms_sgc); -// addObject(NID_ms_efs, SN_ms_efs, LN_ms_efs, OBJ_ms_efs); -// addObject(NID_ns_sgc, SN_ns_sgc, LN_ns_sgc, OBJ_ns_sgc); -// addObject(NID_delta_crl, SN_delta_crl, LN_delta_crl, OBJ_delta_crl); -// addObject(NID_crl_reason, SN_crl_reason, LN_crl_reason, OBJ_crl_reason); -// addObject(NID_invalidity_date, SN_invalidity_date, LN_invalidity_date, OBJ_invalidity_date); -// addObject(NID_sxnet, SN_sxnet, LN_sxnet, OBJ_sxnet); -// addObject(NID_pbe_WithSHA1And128BitRC4, SN_pbe_WithSHA1And128BitRC4, LN_pbe_WithSHA1And128BitRC4, OBJ_pbe_WithSHA1And128BitRC4); -// addObject(NID_pbe_WithSHA1And40BitRC4, SN_pbe_WithSHA1And40BitRC4, LN_pbe_WithSHA1And40BitRC4, OBJ_pbe_WithSHA1And40BitRC4); -// addObject(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, SN_pbe_WithSHA1And3_Key_TripleDES_CBC, LN_pbe_WithSHA1And3_Key_TripleDES_CBC, OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC); -// addObject(NID_pbe_WithSHA1And2_Key_TripleDES_CBC, SN_pbe_WithSHA1And2_Key_TripleDES_CBC, LN_pbe_WithSHA1And2_Key_TripleDES_CBC, OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC); -// addObject(NID_pbe_WithSHA1And128BitRC2_CBC, SN_pbe_WithSHA1And128BitRC2_CBC, LN_pbe_WithSHA1And128BitRC2_CBC, OBJ_pbe_WithSHA1And128BitRC2_CBC); -// addObject(NID_pbe_WithSHA1And40BitRC2_CBC, SN_pbe_WithSHA1And40BitRC2_CBC, LN_pbe_WithSHA1And40BitRC2_CBC, OBJ_pbe_WithSHA1And40BitRC2_CBC); -// addObject(NID_keyBag, SN_keyBag, LN_keyBag, OBJ_keyBag); -// addObject(NID_pkcs8ShroudedKeyBag, SN_pkcs8ShroudedKeyBag, LN_pkcs8ShroudedKeyBag, OBJ_pkcs8ShroudedKeyBag); -// addObject(NID_certBag, SN_certBag, LN_certBag, OBJ_certBag); -// addObject(NID_crlBag, SN_crlBag, LN_crlBag, OBJ_crlBag); -// addObject(NID_secretBag, SN_secretBag, LN_secretBag, OBJ_secretBag); -// addObject(NID_safeContentsBag, SN_safeContentsBag, LN_safeContentsBag, OBJ_safeContentsBag); -// addObject(NID_friendlyName, SN_friendlyName, LN_friendlyName, OBJ_friendlyName); -// addObject(NID_localKeyID, SN_localKeyID, LN_localKeyID, OBJ_localKeyID); -// addObject(NID_x509Certificate, SN_x509Certificate, LN_x509Certificate, OBJ_x509Certificate); -// addObject(NID_sdsiCertificate, SN_sdsiCertificate, LN_sdsiCertificate, OBJ_sdsiCertificate); -// addObject(NID_x509Crl, SN_x509Crl, LN_x509Crl, OBJ_x509Crl); -// addObject(NID_pbes2, SN_pbes2, LN_pbes2, OBJ_pbes2); -// addObject(NID_pbmac1, SN_pbmac1, LN_pbmac1, OBJ_pbmac1); -// addObject(NID_hmacWithSHA1, SN_hmacWithSHA1, LN_hmacWithSHA1, OBJ_hmacWithSHA1); -// addObject(NID_id_qt_cps, SN_id_qt_cps, LN_id_qt_cps, OBJ_id_qt_cps); -// addObject(NID_id_qt_unotice, SN_id_qt_unotice, LN_id_qt_unotice, OBJ_id_qt_unotice); -// addObject(NID_rc2_64_cbc, SN_rc2_64_cbc, LN_rc2_64_cbc, OBJ_rc2_64_cbc); -// addObject(NID_SMIMECapabilities, SN_SMIMECapabilities, LN_SMIMECapabilities, OBJ_SMIMECapabilities); -// addObject(NID_pbeWithMD2AndRC2_CBC, SN_pbeWithMD2AndRC2_CBC, LN_pbeWithMD2AndRC2_CBC, OBJ_pbeWithMD2AndRC2_CBC); -// addObject(NID_pbeWithMD5AndRC2_CBC, SN_pbeWithMD5AndRC2_CBC, LN_pbeWithMD5AndRC2_CBC, OBJ_pbeWithMD5AndRC2_CBC); -// addObject(NID_pbeWithSHA1AndDES_CBC, SN_pbeWithSHA1AndDES_CBC, LN_pbeWithSHA1AndDES_CBC, OBJ_pbeWithSHA1AndDES_CBC); -// addObject(NID_ms_ext_req, SN_ms_ext_req, LN_ms_ext_req, OBJ_ms_ext_req); -// addObject(NID_ext_req, SN_ext_req, LN_ext_req, OBJ_ext_req); -// addObject(NID_name, SN_name, LN_name, OBJ_name); -// addObject(NID_dnQualifier, SN_dnQualifier, LN_dnQualifier, OBJ_dnQualifier); -// addObject(NID_id_pe, SN_id_pe, LN_id_pe, OBJ_id_pe); -// addObject(NID_id_ad, SN_id_ad, LN_id_ad, OBJ_id_ad); -// addObject(NID_info_access, SN_info_access, LN_info_access, OBJ_info_access); -// addObject(NID_ad_OCSP, SN_ad_OCSP, LN_ad_OCSP, OBJ_ad_OCSP); -// addObject(NID_ad_ca_issuers, SN_ad_ca_issuers, LN_ad_ca_issuers, OBJ_ad_ca_issuers); -// addObject(NID_OCSP_sign, SN_OCSP_sign, LN_OCSP_sign, OBJ_OCSP_sign); - -// addObject(181, "AES-192-OFB", "aes-192-ofb","2.16.840.1.101.3.4.1.23"); -// addObject(182, "AES-192-CFB", "aes-192-cfb","2.16.840.1.101.3.4.1.24"); -// addObject(183, "AES-256-EBC", "aes-256-ebc","2.16.840.1.101.3.4.1.41"); -// addObject(184, "AES-256-CBC", "aes-256-cbc","2.16.840.1.101.3.4.1.42"); -// addObject(185, "AES-256-OFB", "aes-256-ofb","2.16.840.1.101.3.4.1.43"); -// addObject(186, "AES-256-CFB", "aes-256-cfb","2.16.840.1.101.3.4.1.44"); -// } -}// ASN1Registry diff --git a/src/java/org/jruby/ext/openssl/impl/Attribute.java b/src/java/org/jruby/ext/openssl/impl/Attribute.java deleted file mode 100644 index c2528a7..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Attribute.java +++ /dev/null @@ -1,88 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import org.bouncycastle.asn1.ASN1Encodable; -import java.util.List; -import java.util.ArrayList; - -/** X509_ATTRIBUTE - * - * @author Ola Bini - */ -public class Attribute { - private int type; - private boolean single; - private List set; - - private Attribute() {} - - public static Attribute create(int nid, int atrtype, ASN1Encodable value) { - Attribute ret = new Attribute(); - - ret.type = nid; - ret.single = false; - ret.set = new ArrayList(); - ret.set.add(value); - - return ret; - } - - public int getType() { - return type; - } - - public List getSet() { - return set; - } - - public boolean isSingle() { - return this.single; - } - - @Override - public boolean equals(Object obj) { - boolean ret = this == obj; - if(!ret && (obj instanceof Attribute)) { - Attribute attr2 = (Attribute)obj; - ret = - this.type == attr2.type && - this.set.equals(attr2.set); - } - return ret; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((set == null) ? 0 : set.hashCode()); - result = prime * result + type; - return result; - } -}// Attribute diff --git a/src/java/org/jruby/ext/openssl/impl/BIO.java b/src/java/org/jruby/ext/openssl/impl/BIO.java deleted file mode 100644 index 875a602..0000000 --- a/src/java/org/jruby/ext/openssl/impl/BIO.java +++ /dev/null @@ -1,345 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.MessageDigest; -import javax.crypto.Cipher; - -/** c: BIO - * - * @author Ola Bini - */ -public class BIO { - public final static int TYPE_DESCRIPTOR = 0x0100; - public final static int TYPE_FILTER = 0x0200; - public final static int TYPE_SOURCE_SINK = 0x0400; - - public final static int TYPE_NONE = 0; - public final static int TYPE_MEM = 1 | TYPE_SOURCE_SINK; - public final static int TYPE_FILE = 2 | TYPE_SOURCE_SINK; - public final static int TYPE_FD = 4 | TYPE_SOURCE_SINK | TYPE_DESCRIPTOR; - public final static int TYPE_SOCKET = 5 | TYPE_SOURCE_SINK | TYPE_DESCRIPTOR; - public final static int TYPE_NULL = 6 | TYPE_SOURCE_SINK; - public final static int TYPE_SSL = 7 | TYPE_FILTER; - public final static int TYPE_MD = 8 | TYPE_FILTER; - public final static int TYPE_BUFFER = 9 | TYPE_FILTER; - public final static int TYPE_CIPHER = 10 | TYPE_FILTER; - public final static int TYPE_BASE64 = 11 | TYPE_FILTER; - public final static int TYPE_CONNECT = 12 | TYPE_SOURCE_SINK | TYPE_DESCRIPTOR; - public final static int TYPE_ACCEPT = 13 | TYPE_SOURCE_SINK | TYPE_DESCRIPTOR; - public final static int TYPE_PROXY_CLIENT = 14 | TYPE_FILTER; - public final static int TYPE_PROXY_SERVER = 15 | TYPE_FILTER; - public final static int TYPE_NBIO_TEST = 16 | TYPE_FILTER; - public final static int TYPE_NULL_FILTER = 17 | TYPE_FILTER; - public final static int TYPE_BER = 18 | TYPE_FILTER; - public final static int TYPE_BIO = 19 | TYPE_SOURCE_SINK; - - private static final class BIOInputStream extends InputStream { - private BIO bio; - - public BIOInputStream(BIO bio) { - this.bio = bio; - } - - @Override - public int read() throws IOException { - byte[] buffer = new byte[1]; - int read = bio.read(buffer, 0, 1); - if(read == 0) { - return -1; - } - return ((int)buffer[0])&0xFF; - } - - @Override - public int read(byte[] into) throws IOException { - return this.read(into, 0, into.length); - } - - @Override - public int read(byte[] into, int off, int len) throws IOException { - int read = bio.read(into, off, len); - if(read == 0) { - return -1; - } - return read; - } - } - - private static final class BIOOutputStream extends OutputStream { - private BIO bio; - - public BIOOutputStream(BIO bio) { - this.bio = bio; - } - - @Override - public void write(int b) throws IOException { - } - - @Override - public void write(byte[] out) throws IOException { - this.write(out, 0, out.length); - } - - @Override - public void write(byte[] out, int off, int len) throws IOException { - bio.write(out, off, len); - } - } - - public static InputStream asInputStream(BIO input) { - return new BIOInputStream(input); - } - - public static OutputStream asOutputStream(BIO output) { - return new BIOOutputStream(output); - } - - public static BIO base64Filter(BIO real) { - BIO b64 = new Base64BIOFilter(); - b64.push(real); - return b64; - } - - public static BIO mdFilter(MessageDigest md) { - return new MessageDigestBIOFilter(md); - } - - public static BIO cipherFilter(Cipher cipher) { - return new CipherBIOFilter(cipher); - } - - public static BIO fromString(String input) { - MemBIO bio = new MemBIO(); - byte[] buf = null; - try { - buf = input.getBytes("ISO8859-1"); - bio.write(buf, 0, buf.length); - } catch(Exception e) {} - return bio; - } - - /** c: BIO_new(BIO_f_buffered()) - * - */ - public static BIO buffered() { - return null; - } - - /** c: BIO_new(BIO_s_mem()) - * - */ - public static BIO mem() { - return new MemBIO(); - } - - /** c: BIO_new(BIO_s_null()) - * - */ - public static BIO nullSink() { - return new NullSinkBIO(); - } - - /** c: BIO_new_mem_buf - * - */ - public static BIO memBuf(byte[] arr) { - return memBuf(arr, 0, arr.length); - } - - /** c: BIO_new_mem_buf - * - */ - public static BIO memBuf(byte[] arr, int offset, int length) { - // TODO: create real readonly version of MemBIO. - try { - BIO bio = new MemBIO(); - bio.write(arr, offset, length); - return bio; - } catch(IOException e) { - return null; - } - } - - protected BIO nextBio; - protected BIO prevBio; - - - /** c: BIO_flush - * - */ - public void flush() throws IOException, PKCS7Exception { - } - - private final static byte[] CONTENT_TEXT; - static { - byte[] val = null; - try { - val = "Content-Type: text/plain\r\n\r\n".getBytes("ISO8859-1"); - } catch(Exception e) { - val = null; - } - CONTENT_TEXT = val; - } - - /** c: SMIME_crlf_copy - * - */ - public void crlfCopy(BIO out, int flags) throws IOException { - BIO in = this; - byte[] linebuf = new byte[SMIME.MAX_SMLEN]; - int[] len = new int[]{0}; - - if((flags & PKCS7.BINARY) > 0 ) { - while((len[0] = in.read(linebuf, 0, SMIME.MAX_SMLEN)) > 0) { - out.write(linebuf, 0, len[0]); - } - return; - } - if((flags & PKCS7.TEXT) > 0) { - out.write(CONTENT_TEXT, 0, CONTENT_TEXT.length); - } - while((len[0] = in.gets(linebuf, SMIME.MAX_SMLEN)) > 0) { - boolean eol = SMIME.stripEol(linebuf, len); - if(len[0] != 0) { - out.write(linebuf, 0, len[0]); - } - if(eol) { - out.write(SMIME.NEWLINE, 0, 2); - } - } - } - - /** c: BIO_gets - * - */ - public int gets(byte[] in, int len) throws IOException { - throw new UnsupportedOperationException("for " + this.getClass().getName()); - } - - /** c: BIO_write - * - */ - public int write(byte[] out, int offset, int len) throws IOException { - throw new UnsupportedOperationException("for " + this.getClass().getName()); - } - - /** c: BIO_read - * - */ - public int read(byte[] into, int offset, int len) throws IOException { - throw new UnsupportedOperationException("for " + this.getClass().getName()); - } - - /** c: BIO_set_mem_eof_return - * - */ - public void setMemEofReturn(int value) { - throw new UnsupportedOperationException("for " + this.getClass().getName()); - } - - /** c: BIO_push - * - */ - public BIO push(BIO bio) { - BIO lb = this; - while(lb.nextBio != null) { - lb = lb.nextBio; - } - if(bio != null) { - bio.prevBio = lb; - } - lb.nextBio = bio; - return this; - } - - /** c: BIO_pop - * - */ - public BIO pop() { - BIO ret = this.nextBio; - if(this.prevBio != null) { - this.prevBio.nextBio = this.nextBio; - } - if(this.nextBio != null) { - this.nextBio.prevBio = this.prevBio; - } - this.nextBio = null; - this.prevBio = null; - return ret; - } - - /** c: BIO_find_type - * - */ - public BIO findType(int type) { - int mask = type & 0xFF; - BIO bio = this; - do { - int mt = bio.getType(); - if(mask == 0) { - if((mt & type) != 0) { - return bio; - } - } else if(mt == type) { - return bio; - } - bio = bio.nextBio; - } while(bio != null); - - return null; - } - - /** c: BIO_next - * - */ - public BIO next() { - return this.nextBio; - } - - public int getType() { - return TYPE_BIO; - } - - /** c: BIO_reset - * - */ - public void reset() { - throw new UnsupportedOperationException(); - } - - @Override - public String toString() { - String[] names = getClass().getName().split("\\."); - return "#"; - } -}// BIO diff --git a/src/java/org/jruby/ext/openssl/impl/BIOFilter.java b/src/java/org/jruby/ext/openssl/impl/BIOFilter.java deleted file mode 100644 index be9b58f..0000000 --- a/src/java/org/jruby/ext/openssl/impl/BIOFilter.java +++ /dev/null @@ -1,38 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** - * - * @author Ola Bini - */ -public abstract class BIOFilter extends BIO { - public int getType() { - return TYPE_FILTER; - } -}// BIOFilter diff --git a/src/java/org/jruby/ext/openssl/impl/Base64.java b/src/java/org/jruby/ext/openssl/impl/Base64.java deleted file mode 100644 index ecf596f..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Base64.java +++ /dev/null @@ -1,2066 +0,0 @@ -package org.jruby.ext.openssl.impl; -@SuppressWarnings("rawtypes") - -/** - *

    Encodes and decodes to and from Base64 notation.

    - *

    Homepage: http://iharder.net/base64.

    - * - *

    Example:

    - * - * String encoded = Base64.encode( myByteArray ); - *
    - * byte[] myByteArray = Base64.decode( encoded ); - * - *

    The options parameter, which appears in a few places, is used to pass - * several pieces of information to the encoder. In the "higher level" methods such as - * encodeBytes( bytes, options ) the options parameter can be used to indicate such - * things as first gzipping the bytes before encoding them, not inserting linefeeds, - * and encoding using the URL-safe and Ordered dialects.

    - * - *

    Note, according to RFC3548, - * Section 2.1, implementations should not add line feeds unless explicitly told - * to do so. I've got Base64 set to this behavior now, although earlier versions - * broke lines by default.

    - * - *

    The constants defined in Base64 can be OR-ed together to combine options, so you - * might make a call like this:

    - * - * String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES ); - *

    to compress the data before encoding it and then making the output have newline characters.

    - *

    Also...

    - * String encoded = Base64.encodeBytes( crazyString.getBytes() ); - * - * - * - *

    - * Change Log: - *

    - *
      - *
    • v2.3.7 - Fixed subtle bug when base 64 input stream contained the - * value 01111111, which is an invalid base 64 character but should not - * throw an ArrayIndexOutOfBoundsException either. Led to discovery of - * mishandling (or potential for better handling) of other bad input - * characters. You should now get an IOException if you try decoding - * something that has bad characters in it.
    • - *
    • v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded - * string ended in the last column; the buffer was not properly shrunk and - * contained an extra (null) byte that made it into the string.
    • - *
    • v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size - * was wrong for files of size 31, 34, and 37 bytes.
    • - *
    • v2.3.4 - Fixed bug when working with gzipped streams whereby flushing - * the Base64.OutputStream closed the Base64 encoding (by padding with equals - * signs) too soon. Also added an option to suppress the automatic decoding - * of gzipped streams. Also added experimental support for specifying a - * class loader when using the - * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)} - * method.
    • - *
    • v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java - * footprint with its CharEncoders and so forth. Fixed some javadocs that were - * inconsistent. Removed imports and specified things like java.io.IOException - * explicitly inline.
    • - *
    • v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the - * final encoded data will be so that the code doesn't have to create two output - * arrays: an oversized initial one and then a final, exact-sized one. Big win - * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not - * using the gzip options which uses a different mechanism with streams and stuff).
    • - *
    • v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some - * similar helper methods to be more efficient with memory by not returning a - * String but just a byte array.
    • - *
    • v2.3 - This is not a drop-in replacement! This is two years of comments - * and bug fixes queued up and finally executed. Thanks to everyone who sent - * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else. - * Much bad coding was cleaned up including throwing exceptions where necessary - * instead of returning null values or something similar. Here are some changes - * that may affect you: - *
        - *
      • Does not break lines, by default. This is to keep in compliance with - * RFC3548.
      • - *
      • Throws exceptions instead of returning null values. Because some operations - * (especially those that may permit the GZIP option) use IO streams, there - * is a possiblity of an java.io.IOException being thrown. After some discussion and - * thought, I've changed the behavior of the methods to throw java.io.IOExceptions - * rather than return null if ever there's an error. I think this is more - * appropriate, though it will require some changes to your code. Sorry, - * it should have been done this way to begin with.
      • - *
      • Removed all references to System.out, System.err, and the like. - * Shame on me. All I can say is sorry they were ever there.
      • - *
      • Throws NullPointerExceptions and IllegalArgumentExceptions as needed - * such as when passed arrays are null or offsets are invalid.
      • - *
      • Cleaned up as much javadoc as I could to avoid any javadoc warnings. - * This was especially annoying before for people who were thorough in their - * own projects and then had gobs of javadoc warnings on this file.
      • - *
      - *
    • v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug - * when using very small files (~< 40 bytes).
    • - *
    • v2.2 - Added some helper methods for encoding/decoding directly from - * one file to the next. Also added a main() method to support command line - * encoding/decoding from one file to the next. Also added these Base64 dialects: - *
        - *
      1. The default is RFC3548 format.
      2. - *
      3. Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates - * URL and file name friendly format as described in Section 4 of RFC3548. - * http://www.faqs.org/rfcs/rfc3548.html
      4. - *
      5. Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates - * URL and file name friendly format that preserves lexical ordering as described - * in http://www.faqs.org/qa/rfcc-1940.html
      6. - *
      - * Special thanks to Jim Kellerman at http://www.powerset.com/ - * for contributing the new Base64 dialects. - *
    • - * - *
    • v2.1 - Cleaned up javadoc comments and unused variables and methods. Added - * some convenience methods for reading and writing to and from files.
    • - *
    • v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems - * with other encodings (like EBCDIC).
    • - *
    • v2.0.1 - Fixed an error when decoding a single byte, that is, when the - * encoded data was a single byte.
    • - *
    • v2.0 - I got rid of methods that used booleans to set options. - * Now everything is more consolidated and cleaner. The code now detects - * when data that's being decoded is gzip-compressed and will decompress it - * automatically. Generally things are cleaner. You'll probably have to - * change some method calls that you were making to support the new - * options format (ints that you "OR" together).
    • - *
    • v1.5.1 - Fixed bug when decompressing and decoding to a - * byte[] using decode( String s, boolean gzipCompressed ). - * Added the ability to "suspend" encoding in the Output Stream so - * you can turn on and off the encoding if you need to embed base64 - * data in an otherwise "normal" stream (like an XML file).
    • - *
    • v1.5 - Output stream pases on flush() command but doesn't do anything itself. - * This helps when using GZIP streams. - * Added the ability to GZip-compress objects before encoding them.
    • - *
    • v1.4 - Added helper methods to read/write files.
    • - *
    • v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.
    • - *
    • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream - * where last buffer being read, if not completely full, was not returned.
    • - *
    • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
    • - *
    • v1.3.3 - Fixed I/O streams which were totally messed up.
    • - *
    - * - *

    - * I am placing this code in the Public Domain. Do with it as you will. - * This software comes with no guarantees or warranties but with - * plenty of well-wishing instead! - * Please visit http://iharder.net/base64 - * periodically to check for updates or to contribute improvements. - *

    - * - * @author Robert Harder - * @author rob@iharder.net - * @version 2.3.7 - */ -public class Base64 -{ - -/* ******** P U B L I C F I E L D S ******** */ - - - /** No options specified. Value is zero. */ - public final static int NO_OPTIONS = 0; - - /** Specify encoding in first bit. Value is one. */ - public final static int ENCODE = 1; - - - /** Specify decoding in first bit. Value is zero. */ - public final static int DECODE = 0; - - - /** Specify that data should be gzip-compressed in second bit. Value is two. */ - public final static int GZIP = 2; - - /** Specify that gzipped data should not be automatically gunzipped. */ - public final static int DONT_GUNZIP = 4; - - - /** Do break lines when encoding. Value is 8. */ - public final static int DO_BREAK_LINES = 8; - - /** - * Encode using Base64-like encoding that is URL- and Filename-safe as described - * in Section 4 of RFC3548: - * http://www.faqs.org/rfcs/rfc3548.html. - * It is important to note that data encoded this way is not officially valid Base64, - * or at the very least should not be called Base64 without also specifying that is - * was encoded using the URL- and Filename-safe dialect. - */ - public final static int URL_SAFE = 16; - - - /** - * Encode using the special "ordered" dialect of Base64 described here: - * http://www.faqs.org/qa/rfcc-1940.html. - */ - public final static int ORDERED = 32; - - -/* ******** P R I V A T E F I E L D S ******** */ - - - /** Maximum line length (76) of Base64 output. */ - private final static int MAX_LINE_LENGTH = 76; - - - /** The equals sign (=) as a byte. */ - private final static byte EQUALS_SIGN = (byte)'='; - - - /** The new line character (\n) as a byte. */ - private final static byte NEW_LINE = (byte)'\n'; - - - /** Preferred encoding. */ - private final static String PREFERRED_ENCODING = "US-ASCII"; - - - private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding - private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding - - -/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ - - /** The 64 valid Base64 values. */ - /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ - private final static byte[] _STANDARD_ALPHABET = { - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', - (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' - }; - - - /** - * Translates a Base64 value to either its 6-bit reconstruction value - * or a negative number indicating some other meaning. - **/ - private final static byte[] _STANDARD_DECODABET = { - -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 - -5,-5, // Whitespace: Tab and Linefeed - -9,-9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 - -9,-9,-9,-9,-9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9,-9,-9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine - -9,-9,-9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9,-9,-9, // Decimal 62 - 64 - 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' - 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' - -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 - 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' - 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' - -9,-9,-9,-9,-9 // Decimal 123 - 127 - ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 - }; - - -/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ - - /** - * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: - * http://www.faqs.org/rfcs/rfc3548.html. - * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash." - */ - private final static byte[] _URL_SAFE_ALPHABET = { - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', - (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_' - }; - - /** - * Used in decoding URL- and Filename-safe dialects of Base64. - */ - private final static byte[] _URL_SAFE_DECODABET = { - -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 - -5,-5, // Whitespace: Tab and Linefeed - -9,-9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 - -9,-9,-9,-9,-9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 62, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine - -9,-9,-9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9,-9,-9, // Decimal 62 - 64 - 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' - 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' - -9,-9,-9,-9, // Decimal 91 - 94 - 63, // Underscore at decimal 95 - -9, // Decimal 96 - 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' - 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' - -9,-9,-9,-9,-9 // Decimal 123 - 127 - ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 - }; - - - -/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ - - /** - * I don't get the point of this technique, but someone requested it, - * and it is described here: - * http://www.faqs.org/qa/rfcc-1940.html. - */ - private final static byte[] _ORDERED_ALPHABET = { - (byte)'-', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', - (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'_', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z' - }; - - /** - * Used in decoding the "ordered" dialect of Base64. - */ - private final static byte[] _ORDERED_DECODABET = { - -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 - -5,-5, // Whitespace: Tab and Linefeed - -9,-9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 - -9,-9,-9,-9,-9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 0, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine - -9,-9,-9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9,-9,-9, // Decimal 62 - 64 - 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M' - 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z' - -9,-9,-9,-9, // Decimal 91 - 94 - 37, // Underscore at decimal 95 - -9, // Decimal 96 - 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm' - 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z' - -9,-9,-9,-9,-9 // Decimal 123 - 127 - ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 - }; - - -/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ - - - /** - * Returns one of the _SOMETHING_ALPHABET byte arrays depending on - * the options specified. - * It's possible, though silly, to specify ORDERED and URLSAFE - * in which case one of them will be picked, though there is - * no guarantee as to which one will be picked. - */ - private final static byte[] getAlphabet( int options ) { - if ((options & URL_SAFE) == URL_SAFE) { - return _URL_SAFE_ALPHABET; - } else if ((options & ORDERED) == ORDERED) { - return _ORDERED_ALPHABET; - } else { - return _STANDARD_ALPHABET; - } - } // end getAlphabet - - - /** - * Returns one of the _SOMETHING_DECODABET byte arrays depending on - * the options specified. - * It's possible, though silly, to specify ORDERED and URL_SAFE - * in which case one of them will be picked, though there is - * no guarantee as to which one will be picked. - */ - private final static byte[] getDecodabet( int options ) { - if( (options & URL_SAFE) == URL_SAFE) { - return _URL_SAFE_DECODABET; - } else if ((options & ORDERED) == ORDERED) { - return _ORDERED_DECODABET; - } else { - return _STANDARD_DECODABET; - } - } // end getAlphabet - - - - /** Defeats instantiation. */ - private Base64(){} - - - - -/* ******** E N C O D I N G M E T H O D S ******** */ - - - /** - * Encodes up to the first three bytes of array threeBytes - * and returns a four-byte array in Base64 notation. - * The actual number of significant bytes in your array is - * given by numSigBytes. - * The array threeBytes needs only be as big as - * numSigBytes. - * Code can reuse a byte array by passing a four-byte array as b4. - * - * @param b4 A reusable byte array to reduce array instantiation - * @param threeBytes the array to convert - * @param numSigBytes the number of significant bytes in your array - * @return four byte array in Base64 notation. - * @since 1.5.1 - */ - private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) { - encode3to4( threeBytes, 0, numSigBytes, b4, 0, options ); - return b4; - } // end encode3to4 - - - /** - *

    Encodes up to three bytes of the array source - * and writes the resulting four Base64 bytes to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accomodate srcOffset + 3 for - * the source array or destOffset + 4 for - * the destination array. - * The actual number of significant bytes in your array is - * given by numSigBytes.

    - *

    This is the lowest level of the encoding methods with - * all possible parameters.

    - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param numSigBytes the number of significant bytes in your array - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4( - byte[] source, int srcOffset, int numSigBytes, - byte[] destination, int destOffset, int options ) { - - byte[] ALPHABET = getAlphabet( options ); - - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index ALPHABET - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3f 0x3f 0x3f Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an int. - int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) - | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) - | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); - - switch( numSigBytes ) - { - case 3: - destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; - destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; - destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; - destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; - return destination; - - case 2: - destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; - destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; - destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; - destination[ destOffset + 3 ] = EQUALS_SIGN; - return destination; - - case 1: - destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; - destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; - destination[ destOffset + 2 ] = EQUALS_SIGN; - destination[ destOffset + 3 ] = EQUALS_SIGN; - return destination; - - default: - return destination; - } // end switch - } // end encode3to4 - - - - /** - * Performs Base64 encoding on the raw ByteBuffer, - * writing it to the encoded ByteBuffer. - * This is an experimental feature. Currently it does not - * pass along any options (such as {@link #DO_BREAK_LINES} - * or {@link #GZIP}. - * - * @param raw input buffer - * @param encoded output buffer - * @since 2.3 - */ - public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){ - byte[] raw3 = new byte[3]; - byte[] enc4 = new byte[4]; - - while( raw.hasRemaining() ){ - int rem = Math.min(3,raw.remaining()); - raw.get(raw3,0,rem); - Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS ); - encoded.put(enc4); - } // end input remaining - } - - - /** - * Performs Base64 encoding on the raw ByteBuffer, - * writing it to the encoded CharBuffer. - * This is an experimental feature. Currently it does not - * pass along any options (such as {@link #DO_BREAK_LINES} - * or {@link #GZIP}. - * - * @param raw input buffer - * @param encoded output buffer - * @since 2.3 - */ - public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){ - byte[] raw3 = new byte[3]; - byte[] enc4 = new byte[4]; - - while( raw.hasRemaining() ){ - int rem = Math.min(3,raw.remaining()); - raw.get(raw3,0,rem); - Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS ); - for( int i = 0; i < 4; i++ ){ - encoded.put( (char)(enc4[i] & 0xFF) ); - } - } // end input remaining - } - - - - - /** - * Serializes an object and returns the Base64-encoded - * version of that serialized object. - * - *

    As of v 2.3, if the object - * cannot be serialized or there is another error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned a null value, but - * in retrospect that's a pretty poor way to handle it.

    - * - * The object is not GZip-compressed before being encoded. - * - * @param serializableObject The object to encode - * @return The Base64-encoded object - * @throws java.io.IOException if there is an error - * @throws NullPointerException if serializedObject is null - * @since 1.4 - */ - public static String encodeObject( java.io.Serializable serializableObject ) - throws java.io.IOException { - return encodeObject( serializableObject, NO_OPTIONS ); - } // end encodeObject - - - - /** - * Serializes an object and returns the Base64-encoded - * version of that serialized object. - * - *

    As of v 2.3, if the object - * cannot be serialized or there is another error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned a null value, but - * in retrospect that's a pretty poor way to handle it.

    - * - * The object is not GZip-compressed before being encoded. - *

    - * Example options:

    -     *   GZIP: gzip-compresses object before encoding it.
    -     *   DO_BREAK_LINES: break lines at 76 characters
    -     * 
    - *

    - * Example: encodeObject( myObj, Base64.GZIP ) or - *

    - * Example: encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES ) - * - * @param serializableObject The object to encode - * @param options Specified options - * @return The Base64-encoded object - * @see Base64#GZIP - * @see Base64#DO_BREAK_LINES - * @throws java.io.IOException if there is an error - * @since 2.0 - */ - public static String encodeObject( java.io.Serializable serializableObject, int options ) - throws java.io.IOException { - - if( serializableObject == null ){ - throw new NullPointerException( "Cannot serialize a null object." ); - } // end if: null - - // Streams - java.io.ByteArrayOutputStream baos = null; - java.io.OutputStream b64os = null; - java.util.zip.GZIPOutputStream gzos = null; - java.io.ObjectOutputStream oos = null; - - - try { - // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream - baos = new java.io.ByteArrayOutputStream(); - b64os = new Base64.OutputStream( baos, ENCODE | options ); - if( (options & GZIP) != 0 ){ - // Gzip - gzos = new java.util.zip.GZIPOutputStream(b64os); - oos = new java.io.ObjectOutputStream( gzos ); - } else { - // Not gzipped - oos = new java.io.ObjectOutputStream( b64os ); - } - oos.writeObject( serializableObject ); - } // end try - catch( java.io.IOException e ) { - // Catch it and then throw it immediately so that - // the finally{} block is called for cleanup. - throw e; - } // end catch - finally { - try{ oos.close(); } catch( Exception e ){} - try{ gzos.close(); } catch( Exception e ){} - try{ b64os.close(); } catch( Exception e ){} - try{ baos.close(); } catch( Exception e ){} - } // end finally - - // Return value according to relevant encoding. - try { - return new String( baos.toByteArray(), PREFERRED_ENCODING ); - } // end try - catch (java.io.UnsupportedEncodingException uue){ - // Fall back to some Java default - return new String( baos.toByteArray() ); - } // end catch - - } // end encode - - - - /** - * Encodes a byte array into Base64 notation. - * Does not GZip-compress data. - * - * @param source The data to convert - * @return The data in Base64-encoded form - * @throws NullPointerException if source array is null - * @since 1.4 - */ - public static String encodeBytes( byte[] source ) { - // Since we're not going to have the GZIP encoding turned on, - // we're not going to have an java.io.IOException thrown, so - // we should not force the user to have to catch it. - String encoded = null; - try { - encoded = encodeBytes(source, 0, source.length, NO_OPTIONS); - } catch (java.io.IOException ex) { - assert false : ex.getMessage(); - } // end catch - assert encoded != null; - return encoded; - } // end encodeBytes - - - - /** - * Encodes a byte array into Base64 notation. - *

    - * Example options:

    -     *   GZIP: gzip-compresses object before encoding it.
    -     *   DO_BREAK_LINES: break lines at 76 characters
    -     *     Note: Technically, this makes your encoding non-compliant.
    -     * 
    - *

    - * Example: encodeBytes( myData, Base64.GZIP ) or - *

    - * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) - * - * - *

    As of v 2.3, if there is an error with the GZIP stream, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned a null value, but - * in retrospect that's a pretty poor way to handle it.

    - * - * - * @param source The data to convert - * @param options Specified options - * @return The Base64-encoded data as a String - * @see Base64#GZIP - * @see Base64#DO_BREAK_LINES - * @throws java.io.IOException if there is an error - * @throws NullPointerException if source array is null - * @since 2.0 - */ - public static String encodeBytes( byte[] source, int options ) throws java.io.IOException { - return encodeBytes( source, 0, source.length, options ); - } // end encodeBytes - - - /** - * Encodes a byte array into Base64 notation. - * Does not GZip-compress data. - * - *

    As of v 2.3, if there is an error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned a null value, but - * in retrospect that's a pretty poor way to handle it.

    - * - * - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @return The Base64-encoded data as a String - * @throws NullPointerException if source array is null - * @throws IllegalArgumentException if source array, offset, or length are invalid - * @since 1.4 - */ - public static String encodeBytes( byte[] source, int off, int len ) { - // Since we're not going to have the GZIP encoding turned on, - // we're not going to have an java.io.IOException thrown, so - // we should not force the user to have to catch it. - String encoded = null; - try { - encoded = encodeBytes( source, off, len, NO_OPTIONS ); - } catch (java.io.IOException ex) { - assert false : ex.getMessage(); - } // end catch - assert encoded != null; - return encoded; - } // end encodeBytes - - - - /** - * Encodes a byte array into Base64 notation. - *

    - * Example options:

    -     *   GZIP: gzip-compresses object before encoding it.
    -     *   DO_BREAK_LINES: break lines at 76 characters
    -     *     Note: Technically, this makes your encoding non-compliant.
    -     * 
    - *

    - * Example: encodeBytes( myData, Base64.GZIP ) or - *

    - * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) - * - * - *

    As of v 2.3, if there is an error with the GZIP stream, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned a null value, but - * in retrospect that's a pretty poor way to handle it.

    - * - * - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @param options Specified options - * @return The Base64-encoded data as a String - * @see Base64#GZIP - * @see Base64#DO_BREAK_LINES - * @throws java.io.IOException if there is an error - * @throws NullPointerException if source array is null - * @throws IllegalArgumentException if source array, offset, or length are invalid - * @since 2.0 - */ - public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException { - byte[] encoded = encodeBytesToBytes( source, off, len, options ); - - // Return value according to relevant encoding. - try { - return new String( encoded, PREFERRED_ENCODING ); - } // end try - catch (java.io.UnsupportedEncodingException uue) { - return new String( encoded ); - } // end catch - - } // end encodeBytes - - - - - /** - * Similar to {@link #encodeBytes(byte[])} but returns - * a byte array instead of instantiating a String. This is more efficient - * if you're working with I/O streams and have large data sets to encode. - * - * - * @param source The data to convert - * @return The Base64-encoded data as a byte[] (of ASCII characters) - * @throws NullPointerException if source array is null - * @since 2.3.1 - */ - public static byte[] encodeBytesToBytes( byte[] source ) { - byte[] encoded = null; - try { - encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS ); - } catch( java.io.IOException ex ) { - assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); - } - return encoded; - } - - - /** - * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns - * a byte array instead of instantiating a String. This is more efficient - * if you're working with I/O streams and have large data sets to encode. - * - * - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @param options Specified options - * @return The Base64-encoded data as a String - * @see Base64#GZIP - * @see Base64#DO_BREAK_LINES - * @throws java.io.IOException if there is an error - * @throws NullPointerException if source array is null - * @throws IllegalArgumentException if source array, offset, or length are invalid - * @since 2.3.1 - */ - public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException { - - if( source == null ){ - throw new NullPointerException( "Cannot serialize a null array." ); - } // end if: null - - if( off < 0 ){ - throw new IllegalArgumentException( "Cannot have negative offset: " + off ); - } // end if: off < 0 - - if( len < 0 ){ - throw new IllegalArgumentException( "Cannot have length offset: " + len ); - } // end if: len < 0 - - if( off + len > source.length ){ - throw new IllegalArgumentException( - String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length)); - } // end if: off < 0 - - - - // Compress? - if( (options & GZIP) != 0 ) { - java.io.ByteArrayOutputStream baos = null; - java.util.zip.GZIPOutputStream gzos = null; - Base64.OutputStream b64os = null; - - try { - // GZip -> Base64 -> ByteArray - baos = new java.io.ByteArrayOutputStream(); - b64os = new Base64.OutputStream( baos, ENCODE | options ); - gzos = new java.util.zip.GZIPOutputStream( b64os ); - - gzos.write( source, off, len ); - gzos.close(); - } // end try - catch( java.io.IOException e ) { - // Catch it and then throw it immediately so that - // the finally{} block is called for cleanup. - throw e; - } // end catch - finally { - try{ gzos.close(); } catch( Exception e ){} - try{ b64os.close(); } catch( Exception e ){} - try{ baos.close(); } catch( Exception e ){} - } // end finally - - return baos.toByteArray(); - } // end if: compress - - // Else, don't compress. Better not to use streams at all then. - else { - boolean breakLines = (options & DO_BREAK_LINES) != 0; - - //int len43 = len * 4 / 3; - //byte[] outBuff = new byte[ ( len43 ) // Main 4:3 - // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding - // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines - // Try to determine more precisely how big the array needs to be. - // If we get it right, we don't have to do an array copy, and - // we save a bunch of memory. - int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding - if( breakLines ){ - encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters - } - byte[] outBuff = new byte[ encLen ]; - - - int d = 0; - int e = 0; - int len2 = len - 2; - int lineLength = 0; - for( ; d < len2; d+=3, e+=4 ) { - encode3to4( source, d+off, 3, outBuff, e, options ); - - lineLength += 4; - if( breakLines && lineLength >= MAX_LINE_LENGTH ) - { - outBuff[e+4] = NEW_LINE; - e++; - lineLength = 0; - } // end if: end of line - } // en dfor: each piece of array - - if( d < len ) { - encode3to4( source, d+off, len - d, outBuff, e, options ); - e += 4; - } // end if: some padding needed - - - // Only resize array if we didn't guess it right. - if( e <= outBuff.length - 1 ){ - // If breaking lines and the last byte falls right at - // the line length (76 bytes per line), there will be - // one extra byte, and the array will need to be resized. - // Not too bad of an estimate on array size, I'd say. - byte[] finalOut = new byte[e]; - System.arraycopy(outBuff,0, finalOut,0,e); - //System.err.println("Having to resize array from " + outBuff.length + " to " + e ); - return finalOut; - } else { - //System.err.println("No need to resize array."); - return outBuff; - } - - } // end else: don't compress - - } // end encodeBytesToBytes - - - - - -/* ******** D E C O D I N G M E T H O D S ******** */ - - - /** - * Decodes four bytes from array source - * and writes the resulting bytes (up to three of them) - * to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accomodate srcOffset + 4 for - * the source array or destOffset + 3 for - * the destination array. - * This method returns the actual number of bytes that - * were converted from the Base64 encoding. - *

    This is the lowest level of the decoding methods with - * all possible parameters.

    - * - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param options alphabet type is pulled from this (standard, url-safe, ordered) - * @return the number of decoded bytes converted - * @throws NullPointerException if source or destination arrays are null - * @throws IllegalArgumentException if srcOffset or destOffset are invalid - * or there is not enough room in the array. - * @since 1.3 - */ - private static int decode4to3( - byte[] source, int srcOffset, - byte[] destination, int destOffset, int options ) { - - // Lots of error checking and exception throwing - if( source == null ){ - throw new NullPointerException( "Source array was null." ); - } // end if - if( destination == null ){ - throw new NullPointerException( "Destination array was null." ); - } // end if - if( srcOffset < 0 || srcOffset + 3 >= source.length ){ - throw new IllegalArgumentException( String.format( - "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) ); - } // end if - if( destOffset < 0 || destOffset +2 >= destination.length ){ - throw new IllegalArgumentException( String.format( - "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) ); - } // end if - - - byte[] DECODABET = getDecodabet( options ); - - // Example: Dk== - if( source[ srcOffset + 2] == EQUALS_SIGN ) { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); - int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) - | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); - - destination[ destOffset ] = (byte)( outBuff >>> 16 ); - return 1; - } - - // Example: DkL= - else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); - int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) - | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) - | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); - - destination[ destOffset ] = (byte)( outBuff >>> 16 ); - destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); - return 2; - } - - // Example: DkLE - else { - // Two ways to do the same thing. Don't know which way I like best. - //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) - // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); - int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) - | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) - | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) - | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); - - - destination[ destOffset ] = (byte)( outBuff >> 16 ); - destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); - destination[ destOffset + 2 ] = (byte)( outBuff ); - - return 3; - } - } // end decodeToBytes - - - - - - /** - * Low-level access to decoding ASCII characters in - * the form of a byte array. Ignores GUNZIP option, if - * it's set. This is not generally a recommended method, - * although it is used internally as part of the decoding process. - * Special case: if len = 0, an empty array is returned. Still, - * if you need more speed and reduced memory footprint (and aren't - * gzipping), consider this method. - * - * @param source The Base64 encoded data - * @return decoded data - * @since 2.3.1 - */ - public static byte[] decode( byte[] source ) - throws java.io.IOException { - byte[] decoded = null; -// try { - decoded = decode( source, 0, source.length, Base64.NO_OPTIONS ); -// } catch( java.io.IOException ex ) { -// assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); -// } - return decoded; - } - - - - /** - * Low-level access to decoding ASCII characters in - * the form of a byte array. Ignores GUNZIP option, if - * it's set. This is not generally a recommended method, - * although it is used internally as part of the decoding process. - * Special case: if len = 0, an empty array is returned. Still, - * if you need more speed and reduced memory footprint (and aren't - * gzipping), consider this method. - * - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @param options Can specify options such as alphabet type to use - * @return decoded data - * @throws java.io.IOException If bogus characters exist in source data - * @since 1.3 - */ - public static byte[] decode( byte[] source, int off, int len, int options ) - throws java.io.IOException { - - // Lots of error checking and exception throwing - if( source == null ){ - throw new NullPointerException( "Cannot decode null source array." ); - } // end if - if( off < 0 || off + len > source.length ){ - throw new IllegalArgumentException( String.format( - "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) ); - } // end if - - if( len == 0 ){ - return new byte[0]; - }else if( len < 4 ){ - throw new IllegalArgumentException( - "Base64-encoded string must have at least four characters, but length specified was " + len ); - } // end if - - byte[] DECODABET = getDecodabet( options ); - - int len34 = len * 3 / 4; // Estimate on array size - byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output - int outBuffPosn = 0; // Keep track of where we're writing - - byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space - int b4Posn = 0; // Keep track of four byte input buffer - int i = 0; // Source array counter - byte sbiDecode = 0; // Special value from DECODABET - - for( i = off; i < off+len; i++ ) { // Loop through source - - sbiDecode = DECODABET[ source[i]&0xFF ]; - - // White space, Equals sign, or legit Base64 character - // Note the values such as -5 and -9 in the - // DECODABETs at the top of the file. - if( sbiDecode >= WHITE_SPACE_ENC ) { - if( sbiDecode >= EQUALS_SIGN_ENC ) { - b4[ b4Posn++ ] = source[i]; // Save non-whitespace - if( b4Posn > 3 ) { // Time to decode? - outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options ); - b4Posn = 0; - - // If that was the equals sign, break out of 'for' loop - if( source[i] == EQUALS_SIGN ) { - break; - } // end if: equals sign - } // end if: quartet built - } // end if: equals sign or better - } // end if: white space, equals sign or better - else { - // There's a bad input character in the Base64 stream. - throw new java.io.IOException( String.format( - "Bad Base64 input character decimal %d in array position %d", ((int)source[i])&0xFF, i ) ); - } // end else: - } // each input character - - byte[] out = new byte[ outBuffPosn ]; - System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); - return out; - } // end decode - - - - - /** - * Decodes data from Base64 notation, automatically - * detecting gzip-compressed data and decompressing it. - * - * @param s the string to decode - * @return the decoded data - * @throws java.io.IOException If there is a problem - * @since 1.4 - */ - public static byte[] decode( String s ) throws java.io.IOException { - return decode( s, NO_OPTIONS ); - } - - - - /** - * Decodes data from Base64 notation, automatically - * detecting gzip-compressed data and decompressing it. - * - * @param s the string to decode - * @param options encode options such as URL_SAFE - * @return the decoded data - * @throws java.io.IOException if there is an error - * @throws NullPointerException if s is null - * @since 1.4 - */ - public static byte[] decode( String s, int options ) throws java.io.IOException { - - if( s == null ){ - throw new NullPointerException( "Input string was null." ); - } // end if - - byte[] bytes; - try { - bytes = s.getBytes( PREFERRED_ENCODING ); - } // end try - catch( java.io.UnsupportedEncodingException uee ) { - bytes = s.getBytes(); - } // end catch - // - - // Decode - bytes = decode( bytes, 0, bytes.length, options ); - - // Check to see if it's gzip-compressed - // GZIP Magic Two-Byte Number: 0x8b1f (35615) - boolean dontGunzip = (options & DONT_GUNZIP) != 0; - if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) { - - int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); - if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) { - java.io.ByteArrayInputStream bais = null; - java.util.zip.GZIPInputStream gzis = null; - java.io.ByteArrayOutputStream baos = null; - byte[] buffer = new byte[2048]; - int length = 0; - - try { - baos = new java.io.ByteArrayOutputStream(); - bais = new java.io.ByteArrayInputStream( bytes ); - gzis = new java.util.zip.GZIPInputStream( bais ); - - while( ( length = gzis.read( buffer ) ) >= 0 ) { - baos.write(buffer,0,length); - } // end while: reading input - - // No error? Get new bytes. - bytes = baos.toByteArray(); - - } // end try - catch( java.io.IOException e ) { - e.printStackTrace(); - // Just return originally-decoded bytes - } // end catch - finally { - try{ baos.close(); } catch( Exception e ){} - try{ gzis.close(); } catch( Exception e ){} - try{ bais.close(); } catch( Exception e ){} - } // end finally - - } // end if: gzipped - } // end if: bytes.length >= 2 - - return bytes; - } // end decode - - - - /** - * Attempts to decode Base64 data and deserialize a Java - * Object within. Returns null if there was an error. - * - * @param encodedObject The Base64 data to decode - * @return The decoded and deserialized object - * @throws NullPointerException if encodedObject is null - * @throws java.io.IOException if there is a general error - * @throws ClassNotFoundException if the decoded object is of a - * class that cannot be found by the JVM - * @since 1.5 - */ - public static Object decodeToObject( String encodedObject ) - throws java.io.IOException, java.lang.ClassNotFoundException { - return decodeToObject(encodedObject,NO_OPTIONS,null); - } - - - /** - * Attempts to decode Base64 data and deserialize a Java - * Object within. Returns null if there was an error. - * If loader is not null, it will be the class loader - * used when deserializing. - * - * @param encodedObject The Base64 data to decode - * @param options Various parameters related to decoding - * @param loader Optional class loader to use in deserializing classes. - * @return The decoded and deserialized object - * @throws NullPointerException if encodedObject is null - * @throws java.io.IOException if there is a general error - * @throws ClassNotFoundException if the decoded object is of a - * class that cannot be found by the JVM - * @since 2.3.4 - */ - public static Object decodeToObject( - String encodedObject, int options, final ClassLoader loader ) - throws java.io.IOException, java.lang.ClassNotFoundException { - - // Decode and gunzip if necessary - byte[] objBytes = decode( encodedObject, options ); - - java.io.ByteArrayInputStream bais = null; - java.io.ObjectInputStream ois = null; - Object obj = null; - - try { - bais = new java.io.ByteArrayInputStream( objBytes ); - - // If no custom class loader is provided, use Java's builtin OIS. - if( loader == null ){ - ois = new java.io.ObjectInputStream( bais ); - } // end if: no loader provided - - // Else make a customized object input stream that uses - // the provided class loader. - else { - ois = new java.io.ObjectInputStream(bais){ - @Override - public Class resolveClass(java.io.ObjectStreamClass streamClass) - throws java.io.IOException, ClassNotFoundException { - Class c = Class.forName(streamClass.getName(), false, loader); - if( c == null ){ - return super.resolveClass(streamClass); - } else { - return c; // Class loader knows of this class. - } // end else: not null - } // end resolveClass - }; // end ois - } // end else: no custom class loader - - obj = ois.readObject(); - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and throw in order to execute finally{} - } // end catch - catch( java.lang.ClassNotFoundException e ) { - throw e; // Catch and throw in order to execute finally{} - } // end catch - finally { - try{ bais.close(); } catch( Exception e ){} - try{ ois.close(); } catch( Exception e ){} - } // end finally - - return obj; - } // end decodeObject - - - - /** - * Convenience method for encoding data to a file. - * - *

    As of v 2.3, if there is a error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned false, but - * in retrospect that's a pretty poor way to handle it.

    - * - * @param dataToEncode byte array of data to encode in base64 form - * @param filename Filename for saving encoded data - * @throws java.io.IOException if there is an error - * @throws NullPointerException if dataToEncode is null - * @since 2.1 - */ - public static void encodeToFile( byte[] dataToEncode, String filename ) - throws java.io.IOException { - - if( dataToEncode == null ){ - throw new NullPointerException( "Data to encode was null." ); - } // end iff - - Base64.OutputStream bos = null; - try { - bos = new Base64.OutputStream( - new java.io.FileOutputStream( filename ), Base64.ENCODE ); - bos.write( dataToEncode ); - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and throw to execute finally{} block - } // end catch: java.io.IOException - finally { - try{ bos.close(); } catch( Exception e ){} - } // end finally - - } // end encodeToFile - - - /** - * Convenience method for decoding data to a file. - * - *

    As of v 2.3, if there is a error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned false, but - * in retrospect that's a pretty poor way to handle it.

    - * - * @param dataToDecode Base64-encoded data as a string - * @param filename Filename for saving decoded data - * @throws java.io.IOException if there is an error - * @since 2.1 - */ - public static void decodeToFile( String dataToDecode, String filename ) - throws java.io.IOException { - - Base64.OutputStream bos = null; - try{ - bos = new Base64.OutputStream( - new java.io.FileOutputStream( filename ), Base64.DECODE ); - bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) ); - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and throw to execute finally{} block - } // end catch: java.io.IOException - finally { - try{ bos.close(); } catch( Exception e ){} - } // end finally - - } // end decodeToFile - - - - - /** - * Convenience method for reading a base64-encoded - * file and decoding it. - * - *

    As of v 2.3, if there is a error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned false, but - * in retrospect that's a pretty poor way to handle it.

    - * - * @param filename Filename for reading encoded data - * @return decoded byte array - * @throws java.io.IOException if there is an error - * @since 2.1 - */ - public static byte[] decodeFromFile( String filename ) - throws java.io.IOException { - - byte[] decodedData = null; - Base64.InputStream bis = null; - try - { - // Set up some useful variables - java.io.File file = new java.io.File( filename ); - byte[] buffer = null; - int length = 0; - int numBytes = 0; - - // Check for size of file - if( file.length() > Integer.MAX_VALUE ) - { - throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." ); - } // end if: file too big for int index - buffer = new byte[ (int)file.length() ]; - - // Open a stream - bis = new Base64.InputStream( - new java.io.BufferedInputStream( - new java.io.FileInputStream( file ) ), Base64.DECODE ); - - // Read until done - while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) { - length += numBytes; - } // end while - - // Save in a variable to return - decodedData = new byte[ length ]; - System.arraycopy( buffer, 0, decodedData, 0, length ); - - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and release to execute finally{} - } // end catch: java.io.IOException - finally { - try{ bis.close(); } catch( Exception e) {} - } // end finally - - return decodedData; - } // end decodeFromFile - - - - /** - * Convenience method for reading a binary file - * and base64-encoding it. - * - *

    As of v 2.3, if there is a error, - * the method will throw an java.io.IOException. This is new to v2.3! - * In earlier versions, it just returned false, but - * in retrospect that's a pretty poor way to handle it.

    - * - * @param filename Filename for reading binary data - * @return base64-encoded string - * @throws java.io.IOException if there is an error - * @since 2.1 - */ - public static String encodeFromFile( String filename ) - throws java.io.IOException { - - String encodedData = null; - Base64.InputStream bis = null; - try - { - // Set up some useful variables - java.io.File file = new java.io.File( filename ); - byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4+1),40) ]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5) - int length = 0; - int numBytes = 0; - - // Open a stream - bis = new Base64.InputStream( - new java.io.BufferedInputStream( - new java.io.FileInputStream( file ) ), Base64.ENCODE ); - - // Read until done - while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) { - length += numBytes; - } // end while - - // Save in a variable to return - encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING ); - - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and release to execute finally{} - } // end catch: java.io.IOException - finally { - try{ bis.close(); } catch( Exception e) {} - } // end finally - - return encodedData; - } // end encodeFromFile - - /** - * Reads infile and encodes it to outfile. - * - * @param infile Input file - * @param outfile Output file - * @throws java.io.IOException if there is an error - * @since 2.2 - */ - public static void encodeFileToFile( String infile, String outfile ) - throws java.io.IOException { - - String encoded = Base64.encodeFromFile( infile ); - java.io.OutputStream out = null; - try{ - out = new java.io.BufferedOutputStream( - new java.io.FileOutputStream( outfile ) ); - out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output. - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and release to execute finally{} - } // end catch - finally { - try { out.close(); } - catch( Exception ex ){} - } // end finally - } // end encodeFileToFile - - - /** - * Reads infile and decodes it to outfile. - * - * @param infile Input file - * @param outfile Output file - * @throws java.io.IOException if there is an error - * @since 2.2 - */ - public static void decodeFileToFile( String infile, String outfile ) - throws java.io.IOException { - - byte[] decoded = Base64.decodeFromFile( infile ); - java.io.OutputStream out = null; - try{ - out = new java.io.BufferedOutputStream( - new java.io.FileOutputStream( outfile ) ); - out.write( decoded ); - } // end try - catch( java.io.IOException e ) { - throw e; // Catch and release to execute finally{} - } // end catch - finally { - try { out.close(); } - catch( Exception ex ){} - } // end finally - } // end decodeFileToFile - - - /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ - - - - /** - * A {@link Base64.InputStream} will read data from another - * java.io.InputStream, given in the constructor, - * and encode/decode to/from Base64 notation on the fly. - * - * @see Base64 - * @since 1.3 - */ - public static class InputStream extends java.io.FilterInputStream { - - private boolean encode; // Encoding or decoding - private int position; // Current position in the buffer - private byte[] buffer; // Small buffer holding converted data - private int bufferLength; // Length of buffer (3 or 4) - private int numSigBytes; // Number of meaningful bytes in the buffer - private int lineLength; - private boolean breakLines; // Break lines at less than 80 characters - private int options; // Record options used to create the stream. - private byte[] decodabet; // Local copies to avoid extra method calls - - - /** - * Constructs a {@link Base64.InputStream} in DECODE mode. - * - * @param in the java.io.InputStream from which to read data. - * @since 1.3 - */ - public InputStream( java.io.InputStream in ) { - this( in, DECODE ); - } // end constructor - - - /** - * Constructs a {@link Base64.InputStream} in - * either ENCODE or DECODE mode. - *

    - * Valid options:

    -         *   ENCODE or DECODE: Encode or Decode as data is read.
    -         *   DO_BREAK_LINES: break lines at 76 characters
    -         *     (only meaningful when encoding)
    -         * 
    - *

    - * Example: new Base64.InputStream( in, Base64.DECODE ) - * - * - * @param in the java.io.InputStream from which to read data. - * @param options Specified options - * @see Base64#ENCODE - * @see Base64#DECODE - * @see Base64#DO_BREAK_LINES - * @since 2.0 - */ - public InputStream( java.io.InputStream in, int options ) { - - super( in ); - this.options = options; // Record for later - this.breakLines = (options & DO_BREAK_LINES) > 0; - this.encode = (options & ENCODE) > 0; - this.bufferLength = encode ? 4 : 3; - this.buffer = new byte[ bufferLength ]; - this.position = -1; - this.lineLength = 0; - this.decodabet = getDecodabet(options); - } // end constructor - - /** - * Reads enough of the input stream to convert - * to/from Base64 and returns the next byte. - * - * @return next byte - * @since 1.3 - */ - @Override - public int read() throws java.io.IOException { - - // Do we need to get data? - if( position < 0 ) { - if( encode ) { - byte[] b3 = new byte[3]; - int numBinaryBytes = 0; - for( int i = 0; i < 3; i++ ) { - int b = in.read(); - - // If end of stream, b is -1. - if( b >= 0 ) { - b3[i] = (byte)b; - numBinaryBytes++; - } else { - break; // out of for loop - } // end else: end of stream - - } // end for: each needed input byte - - if( numBinaryBytes > 0 ) { - encode3to4( b3, 0, numBinaryBytes, buffer, 0, options ); - position = 0; - numSigBytes = 4; - } // end if: got data - else { - return -1; // Must be end of stream - } // end else - } // end if: encoding - - // Else decoding - else { - byte[] b4 = new byte[4]; - int i = 0; - for( i = 0; i < 4; i++ ) { - // Read four "meaningful" bytes: - int b = 0; - do{ b = in.read(); } - while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC ); - - if( b < 0 ) { - break; // Reads a -1 if end of stream - } // end if: end of stream - - b4[i] = (byte)b; - } // end for: each needed input byte - - if( i == 4 ) { - numSigBytes = decode4to3( b4, 0, buffer, 0, options ); - position = 0; - } // end if: got four characters - else if( i == 0 ){ - return -1; - } // end else if: also padded correctly - else { - // Must have broken out from above. - throw new java.io.IOException( "Improperly padded Base64 input." ); - } // end - - } // end else: decode - } // end else: get data - - // Got data? - if( position >= 0 ) { - // End of relevant data? - if( /*!encode &&*/ position >= numSigBytes ){ - return -1; - } // end if: got data - - if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) { - lineLength = 0; - return '\n'; - } // end if - else { - lineLength++; // This isn't important when decoding - // but throwing an extra "if" seems - // just as wasteful. - - int b = buffer[ position++ ]; - - if( position >= bufferLength ) { - position = -1; - } // end if: end - - return b & 0xFF; // This is how you "cast" a byte that's - // intended to be unsigned. - } // end else - } // end if: position >= 0 - - // Else error - else { - throw new java.io.IOException( "Error in Base64 code reading stream." ); - } // end else - } // end read - - - /** - * Calls {@link #read()} repeatedly until the end of stream - * is reached or len bytes are read. - * Returns number of bytes read into array or -1 if - * end of stream is encountered. - * - * @param dest array to hold values - * @param off offset for array - * @param len max number of bytes to read into array - * @return bytes read into array or -1 if end of stream is encountered. - * @since 1.3 - */ - @Override - public int read( byte[] dest, int off, int len ) - throws java.io.IOException { - int i; - int b; - for( i = 0; i < len; i++ ) { - b = read(); - - if( b >= 0 ) { - dest[off + i] = (byte) b; - } - else if( i == 0 ) { - return -1; - } - else { - break; // Out of 'for' loop - } // Out of 'for' loop - } // end for: each byte read - return i; - } // end read - - } // end inner class InputStream - - - - - - - /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ - - - - /** - * A {@link Base64.OutputStream} will write data to another - * java.io.OutputStream, given in the constructor, - * and encode/decode to/from Base64 notation on the fly. - * - * @see Base64 - * @since 1.3 - */ - public static class OutputStream extends java.io.FilterOutputStream { - - private boolean encode; - private int position; - private byte[] buffer; - private int bufferLength; - private int lineLength; - private boolean breakLines; - private byte[] b4; // Scratch used in a few places - private boolean suspendEncoding; - private int options; // Record for later - private byte[] decodabet; // Local copies to avoid extra method calls - - /** - * Constructs a {@link Base64.OutputStream} in ENCODE mode. - * - * @param out the java.io.OutputStream to which data will be written. - * @since 1.3 - */ - public OutputStream( java.io.OutputStream out ) { - this( out, ENCODE ); - } // end constructor - - - /** - * Constructs a {@link Base64.OutputStream} in - * either ENCODE or DECODE mode. - *

    - * Valid options:

    -         *   ENCODE or DECODE: Encode or Decode as data is read.
    -         *   DO_BREAK_LINES: don't break lines at 76 characters
    -         *     (only meaningful when encoding)
    -         * 
    - *

    - * Example: new Base64.OutputStream( out, Base64.ENCODE ) - * - * @param out the java.io.OutputStream to which data will be written. - * @param options Specified options. - * @see Base64#ENCODE - * @see Base64#DECODE - * @see Base64#DO_BREAK_LINES - * @since 1.3 - */ - public OutputStream( java.io.OutputStream out, int options ) { - super( out ); - this.breakLines = (options & DO_BREAK_LINES) != 0; - this.encode = (options & ENCODE) != 0; - this.bufferLength = encode ? 3 : 4; - this.buffer = new byte[ bufferLength ]; - this.position = 0; - this.lineLength = 0; - this.suspendEncoding = false; - this.b4 = new byte[4]; - this.options = options; - this.decodabet = getDecodabet(options); - } // end constructor - - - /** - * Writes the byte to the output stream after - * converting to/from Base64 notation. - * When encoding, bytes are buffered three - * at a time before the output stream actually - * gets a write() call. - * When decoding, bytes are buffered four - * at a time. - * - * @param theByte the byte to write - * @since 1.3 - */ - @Override - public void write(int theByte) - throws java.io.IOException { - // Encoding suspended? - if( suspendEncoding ) { - this.out.write( theByte ); - return; - } // end if: supsended - - // Encode? - if( encode ) { - buffer[ position++ ] = (byte)theByte; - if( position >= bufferLength ) { // Enough to encode. - - this.out.write( encode3to4( b4, buffer, bufferLength, options ) ); - - lineLength += 4; - if( breakLines && lineLength >= MAX_LINE_LENGTH ) { - this.out.write( NEW_LINE ); - lineLength = 0; - } // end if: end of line - - position = 0; - } // end if: enough to output - } // end if: encoding - - // Else, Decoding - else { - // Meaningful Base64 character? - if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) { - buffer[ position++ ] = (byte)theByte; - if( position >= bufferLength ) { // Enough to output. - - int len = Base64.decode4to3( buffer, 0, b4, 0, options ); - out.write( b4, 0, len ); - position = 0; - } // end if: enough to output - } // end if: meaningful base64 character - else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) { - throw new java.io.IOException( "Invalid character in Base64 data." ); - } // end else: not white space either - } // end else: decoding - } // end write - - - - /** - * Calls {@link #write(int)} repeatedly until len - * bytes are written. - * - * @param theBytes array from which to read bytes - * @param off offset for array - * @param len max number of bytes to read into array - * @since 1.3 - */ - @Override - public void write( byte[] theBytes, int off, int len ) - throws java.io.IOException { - // Encoding suspended? - if( suspendEncoding ) { - this.out.write( theBytes, off, len ); - return; - } // end if: supsended - - for( int i = 0; i < len; i++ ) { - write( theBytes[ off + i ] ); - } // end for: each byte written - - } // end write - - - - /** - * Method added by PHIL. [Thanks, PHIL. -Rob] - * This pads the buffer without closing the stream. - * @throws java.io.IOException if there's an error. - */ - public void flushBase64() throws java.io.IOException { - if( position > 0 ) { - if( encode ) { - out.write( encode3to4( b4, buffer, position, options ) ); - position = 0; - } // end if: encoding - else { - throw new java.io.IOException( "Base64 input not properly padded." ); - } // end else: decoding - } // end if: buffer partially full - - } // end flush - - - /** - * Flushes and closes (I think, in the superclass) the stream. - * - * @since 1.3 - */ - @Override - public void close() throws java.io.IOException { - // 1. Ensure that pending characters are written - flushBase64(); - - // 2. Actually close the stream - // Base class both flushes and closes. - super.close(); - - buffer = null; - out = null; - } // end close - - - - /** - * Suspends encoding of the stream. - * May be helpful if you need to embed a piece of - * base64-encoded data in a stream. - * - * @throws java.io.IOException if there's an error flushing - * @since 1.5.1 - */ - public void suspendEncoding() throws java.io.IOException { - flushBase64(); - this.suspendEncoding = true; - } // end suspendEncoding - - - /** - * Resumes encoding of the stream. - * May be helpful if you need to embed a piece of - * base64-encoded data in a stream. - * - * @since 1.5.1 - */ - public void resumeEncoding() { - this.suspendEncoding = false; - } // end resumeEncoding - - - - } // end inner class OutputStream - - -} // end class Base64 diff --git a/src/java/org/jruby/ext/openssl/impl/Base64BIOFilter.java b/src/java/org/jruby/ext/openssl/impl/Base64BIOFilter.java deleted file mode 100644 index 99febed..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Base64BIOFilter.java +++ /dev/null @@ -1,74 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * - * @author Ola Bini - */ -public class Base64BIOFilter extends BIOFilter { - private OutputStream nextOutput; - private InputStream nextInput; - - @Override - public int write(byte[] out, int offset, int len) throws IOException { - this.nextOutput.write(out, offset, len); - return len; - } - - @Override - public int read(byte[] into, int offset, int len) throws IOException { - int read = this.nextInput.read(into, offset, len); - if(read == -1) { - return 0; - } - return read; - } - - @Override - public void flush() throws IOException { - this.nextOutput.flush(); - } - - @Override - public BIO push(BIO bio) { - BIO ret = super.push(bio); - this.nextOutput = new Base64.OutputStream(BIO.asOutputStream(this.nextBio)); - this.nextInput = new Base64.InputStream(BIO.asInputStream(this.nextBio)); - return ret; - } - - @Override - public int getType() { - return TYPE_BASE64; - } -}// Base64BIOFilter diff --git a/src/java/org/jruby/ext/openssl/impl/CipherBIOFilter.java b/src/java/org/jruby/ext/openssl/impl/CipherBIOFilter.java deleted file mode 100644 index 14ed54e..0000000 --- a/src/java/org/jruby/ext/openssl/impl/CipherBIOFilter.java +++ /dev/null @@ -1,158 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; - -/** - * - * @author Ola Bini - */ -public class CipherBIOFilter extends BIOFilter { - private Cipher cipher; - - private byte[] bufRead = new byte[4096]; - private int fillLen = 0; - private int fillOffset = 0; - - private byte[] tmpBuf = new byte[1024]; - - private boolean finalized = false; - - public CipherBIOFilter(Cipher cipher) { - this.cipher = cipher; - } - - @Override - public void flush() throws IOException, PKCS7Exception { - try { - byte[] result = cipher.doFinal(); - if(result == null) { - return; - } - next().write(result, 0, result.length); - } catch(IllegalBlockSizeException e) { - throw new PKCS7Exception(-1, -1, e); - } catch(BadPaddingException e) { - throw new PKCS7Exception(-1, -1, e); - } - } - - public int read(byte[] into, int offset, int len) throws IOException { - try { - int read = 0; - if(fillLen > 0) { - read = Math.min(fillLen, len); - System.arraycopy(bufRead, fillOffset, into, offset, read); - fillOffset += read; - fillLen -= read; - if(fillLen == 0) { - fillOffset = 0; - } - if(read == len) { - return read; - } - } - - int req = len - read; - int off = offset + read; - - if(finalized) { - return 0; - } - - while(req > 0) { - int readFromNext = next().read(tmpBuf, 0, 1024); - if(readFromNext > 0) { - int required = cipher.getOutputSize(readFromNext); - if(required > (bufRead.length - (fillOffset + fillLen))) { - byte[] newBuf = new byte[required + fillOffset + fillLen]; - System.arraycopy(bufRead, fillOffset, newBuf, 0, fillLen); - fillOffset = 0; - bufRead = newBuf; - } - int outputted = cipher.update(tmpBuf, 0, readFromNext, bufRead, fillOffset + fillLen); - fillLen += outputted; - - read = Math.min(fillLen, req); - System.arraycopy(bufRead, fillOffset, into, off, read); - fillOffset += read; - fillLen -= read; - if(fillLen == 0) { - fillOffset = 0; - } - - req -= read; - off += read; - } else { - int required = cipher.getOutputSize(0); - if(required > (bufRead.length - (fillOffset + fillLen))) { - byte[] newBuf = new byte[required + fillOffset + fillLen]; - System.arraycopy(bufRead, fillOffset, newBuf, 0, fillLen); - fillOffset = 0; - bufRead = newBuf; - } - int outputted = cipher.doFinal(bufRead, fillOffset + fillLen); - finalized = true; - fillLen += outputted; - - read = Math.min(fillLen, req); - System.arraycopy(bufRead, fillOffset, into, off, read); - fillOffset += read; - fillLen -= read; - if(fillLen == 0) { - fillOffset = 0; - } - - req -= read; - return len-req; - } - } - - return len; - } catch(Exception e) { - throw new IllegalArgumentException(e); - } - } - - public int write(byte[] out, int offset, int len) throws IOException { - byte[] result = cipher.update(out, offset, len); - if(result == null) { - return len; - } - next().write(result, 0, result.length); - return len; - } - - public int getType() { - return TYPE_CIPHER; - } -}// CipherBIOFilter diff --git a/src/java/org/jruby/ext/openssl/impl/CipherSpec.java b/src/java/org/jruby/ext/openssl/impl/CipherSpec.java deleted file mode 100644 index 1891cd9..0000000 --- a/src/java/org/jruby/ext/openssl/impl/CipherSpec.java +++ /dev/null @@ -1,78 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2009 Hiroshi Nakamura - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import javax.crypto.Cipher; - -/** - * - * @author Ola Bini - */ -public class CipherSpec extends BIOFilter { - private final Cipher cipher; - private final String osslName; - private final int keyLenInBits; - - public CipherSpec(Cipher cipher, String osslName, int keyLenInBits) { - this.cipher = cipher; - this.osslName = osslName; - this.keyLenInBits = keyLenInBits; - } - - public Cipher getCipher() { - return cipher; - } - - public String getOsslName() { - return osslName; - } - - public int getKeyLenInBits() { - return keyLenInBits; - } - - public String getAlgorithm() { - return getCipher().getAlgorithm(); - } - - public String getWrappingAlgorithm() { - return getWrappingAlgorithm(getAlgorithm()); - } - - public static String getWrappingAlgorithm(String algorithm) { - if (algorithm == null) { - return null; - } - if (algorithm.equalsIgnoreCase("RSA")) { - return "RSA/ECB/PKCS1Padding"; - } else { - return algorithm; - } - } - -}// CipherSpec diff --git a/src/java/org/jruby/ext/openssl/impl/Digest.java b/src/java/org/jruby/ext/openssl/impl/Digest.java deleted file mode 100644 index 9de032e..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Digest.java +++ /dev/null @@ -1,126 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** PKCS7_DIGEST - * - * @author Ola Bini - */ -public class Digest { - /** - * Describe version here. - */ - private int version; - - /** - * Describe md here. - */ - private AlgorithmIdentifier md; - - /** - * Describe digest here. - */ - private ASN1OctetString digest; - - PKCS7 contents; - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the Contents value. - * - * @return a PKCS7 value - */ - public final PKCS7 getContents() { - return contents; - } - - /** - * Set the Contents value. - * - * @param newContents The new Contents value. - */ - public final void setContents(final PKCS7 newContents) { - this.contents = newContents; - } - - /** - * Get the Md value. - * - * @return an AlgorithmIdentifier value - */ - public final AlgorithmIdentifier getMd() { - return md; - } - - /** - * Set the Md value. - * - * @param newMd The new Md value. - */ - public final void setMd(final AlgorithmIdentifier newMd) { - this.md = newMd; - } - - /** - * Get the Digest value. - * - * @return an ASN1OctetString value - */ - public final ASN1OctetString getDigest() { - return digest; - } - - /** - * Set the Digest value. - * - * @param newDigest The new Digest value. - */ - public final void setDigest(final ASN1OctetString newDigest) { - this.digest = newDigest; - } -}// Digest diff --git a/src/java/org/jruby/ext/openssl/impl/EVP.java b/src/java/org/jruby/ext/openssl/impl/EVP.java deleted file mode 100644 index b46060f..0000000 --- a/src/java/org/jruby/ext/openssl/impl/EVP.java +++ /dev/null @@ -1,147 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import org.bouncycastle.asn1.DERObjectIdentifier; - -/** - * - * @author Ola Bini - */ -public class EVP { - // This is a class that will collect mappings from ASN1 stuff to - // matching Cipher and other algorithms. - - // Typical examples: - // EVP_get_cipherbyobj - // EVP_get_digestbynid - - /* c: EVP_get_cipherbyobj - * - */ - public static Cipher getCipher(DERObjectIdentifier oid) throws GeneralSecurityException { - String algorithm = getAlgorithmName(oid); - String[] cipher = org.jruby.ext.openssl.Cipher.Algorithm.osslToJsse(algorithm); - String realName = cipher[3]; - return Cipher.getInstance(realName); - } - - /* c: EVP_get_cipherbynid - * - */ - public static Cipher getCipher(int nid) throws GeneralSecurityException { - return getCipher(ASN1Registry.nid2obj(nid)); - } - - /* c: EVP_get_digestbyobj - * - */ - public static MessageDigest getDigest(DERObjectIdentifier oid) throws GeneralSecurityException { - String algorithm = getAlgorithmName(oid); - return MessageDigest.getInstance(algorithm); - } - - /* c: EVP_get_digestbynid - * - */ - public static MessageDigest getDigest(int nid) throws GeneralSecurityException { - return getDigest(ASN1Registry.nid2obj(nid)); - } - - /* c: EVP_sha1 - * - */ - public static MessageDigest sha1() { - try { - return MessageDigest.getInstance("SHA1"); - } catch(Exception e) { - return null; - } - } - - public static int type(MessageDigest digest) { - String name = digest.getAlgorithm(); - DERObjectIdentifier obj = ASN1Registry.sym2oid(name); - if(obj == null) { - name = name.toLowerCase().replace("sha-", "sha"); - obj = ASN1Registry.sym2oid(name); - } - return ASN1Registry.obj2nid(obj); - } - - public static String signatureAlgorithm(MessageDigest digest, Key key) { - String sig = digest.getAlgorithm().toLowerCase().replace("sha-", "sha"); - String type = key.getAlgorithm().toLowerCase(); - if(sig == null) { - sig = "none"; - } - return sig + "with" + type; - } - - /* c: EVP_PKEY_decrypt - * - */ - public static byte[] decrypt(byte[] input, int offset, int len, Key key) throws InvalidKeyException, - NoSuchAlgorithmException, - NoSuchPaddingException, - IllegalBlockSizeException, - BadPaddingException { - Cipher cipher = Cipher.getInstance(key.getAlgorithm()); - cipher.init(Cipher.DECRYPT_MODE, key); - return cipher.doFinal(input, offset, len); - } - - /* c: EVP_PKEY_decrypt - * - */ - public static byte[] decrypt(byte[] input, Key key) throws InvalidKeyException, - NoSuchAlgorithmException, - NoSuchPaddingException, - IllegalBlockSizeException, - BadPaddingException { - return decrypt(input, 0, input.length, key); - } - - private static String getAlgorithmName(DERObjectIdentifier oid) { - String algorithm = ASN1Registry.o2a(oid); - if (algorithm != null) { - return algorithm.toUpperCase(); - } else { - return oid.getId(); - } - } -}// EVP diff --git a/src/java/org/jruby/ext/openssl/impl/EncContent.java b/src/java/org/jruby/ext/openssl/impl/EncContent.java deleted file mode 100644 index dfa7767..0000000 --- a/src/java/org/jruby/ext/openssl/impl/EncContent.java +++ /dev/null @@ -1,188 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.util.Enumeration; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.jruby.util.ByteList; - -/** PKCS7_ENC_CONTENT - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class EncContent { - /** - * Describe contentType here. - */ - private int contentType; - - /** - * Describe cipher here. - */ - private CipherSpec cipher; - - /** - * Describe algorithm here. - */ - private AlgorithmIdentifier algorithm; - - /** - * Describe encData here. - */ - private ASN1OctetString encData; - - /** - * Get the ContentType value. - * - * @return an int value - */ - public final int getContentType() { - return contentType; - } - - /** - * Set the ContentType value. - * - * @param newContentType The new ContentType value. - */ - public final void setContentType(final int newContentType) { - this.contentType = newContentType; - } - - /** - * Get the Cipher value. - * - * @return a Cipher value - */ - public final CipherSpec getCipher() { - return cipher; - } - - /** - * Set the Cipher value. - * - * @param newCipher The new Cipher value. - */ - public final void setCipher(final CipherSpec newCipher) { - this.cipher = newCipher; - } - - /** - * Get the Algorithm value. - * - * @return an AlgorithmIdentifier value - */ - public final AlgorithmIdentifier getAlgorithm() { - return algorithm; - } - - /** - * Set the Algorithm value. - * - * @param newAlgorithm The new Algorithm value. - */ - public final void setAlgorithm(final AlgorithmIdentifier newAlgorithm) { - this.algorithm = newAlgorithm; - } - - /** - * Get the EncData value. - * - * @return an ASN1OctetString value - */ - public final ASN1OctetString getEncData() { - return encData; - } - - /** - * Set the EncData value. - * - * @param newEncData The new EncData value. - */ - public final void setEncData(final ASN1OctetString newEncData) { - this.encData = newEncData; - } - - @Override - public String toString() { - return "#"; - } - - /** - * EncryptedContentInfo ::= SEQUENCE { - * contentType ContentType, - * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, - * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } - * - * EncryptedContent ::= OCTET STRING - */ - public static EncContent fromASN1(DEREncodable content) { - ASN1Sequence sequence = (ASN1Sequence)content; - DERObjectIdentifier contentType = (DERObjectIdentifier)(sequence.getObjectAt(0)); - int nid = ASN1Registry.obj2nid(contentType); - - EncContent ec = new EncContent(); - ec.setContentType(nid); - ec.setAlgorithm(AlgorithmIdentifier.getInstance(sequence.getObjectAt(1))); - if(sequence.size() > 2 && sequence.getObjectAt(2) instanceof DERTaggedObject && ((DERTaggedObject)(sequence.getObjectAt(2))).getTagNo() == 0) { - DEREncodable ee = ((DERTaggedObject)(sequence.getObjectAt(2))).getObject(); - if(ee instanceof ASN1Sequence && ((ASN1Sequence)ee).size() > 0) { - ByteList combinedOctets = new ByteList(); - Enumeration enm = ((ASN1Sequence)ee).getObjects(); - while (enm.hasMoreElements()) { - byte[] octets = ((ASN1OctetString)enm.nextElement()).getOctets(); - combinedOctets.append(octets); - } - ec.setEncData(new DEROctetString(combinedOctets.bytes())); - } else { - ec.setEncData((ASN1OctetString)ee); - } - } - return ec; - } - - public ASN1Encodable asASN1() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - vector.add(ASN1Registry.nid2obj(contentType).toASN1Object()); - vector.add(algorithm.toASN1Object()); - if(encData != null) { - vector.add(new DERTaggedObject(false, 0, encData)); - } - return new DERSequence(vector); - } -}// EncContent diff --git a/src/java/org/jruby/ext/openssl/impl/Encrypt.java b/src/java/org/jruby/ext/openssl/impl/Encrypt.java deleted file mode 100644 index 00b0a97..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Encrypt.java +++ /dev/null @@ -1,77 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** PKCS7_ENCRYPT - * - * @author Ola Bini - */ -public class Encrypt { - private int version; - - /** - * Describe encContent here. - */ - private EncContent encData = new EncContent(); - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the EncData value. - * - * @return an EncContent value - */ - public final EncContent getEncData() { - return encData; - } - - /** - * Set the EncData value. - * - * @param newEncContent The new EncContent value. - */ - public final void setEncData(final EncContent newEncData) { - this.encData = newEncData; - } -}// Encrypt diff --git a/src/java/org/jruby/ext/openssl/impl/Envelope.java b/src/java/org/jruby/ext/openssl/impl/Envelope.java deleted file mode 100644 index b508bfb..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Envelope.java +++ /dev/null @@ -1,167 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; - -/** PKCS7_ENVELOPE - * - * @author Ola Bini - */ -public class Envelope { - private int version; - - /** - * Describe encContent here. - */ - private EncContent encData = new EncContent(); - - /** - * Describe recipientInfo here. - */ - private Collection recipientInfo = new ArrayList(); - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the EncData value. - * - * @return an EncContent value - */ - public final EncContent getEncData() { - return encData; - } - - /** - * Set the EncData value. - * - * @param newEncContent The new EncContent value. - */ - public final void setEncData(final EncContent newEncData) { - this.encData = newEncData; - } - - /** - * Get the RecipientInfo value. - * - * @return a Collection value - */ - public final Collection getRecipientInfo() { - return recipientInfo; - } - - /** - * Set the RecipientInfo value. - * - * @param newRecipientInfo The new RecipientInfo value. - */ - public final void setRecipientInfo(final Collection newRecipientInfo) { - this.recipientInfo = newRecipientInfo; - } - - @Override - public String toString() { - return "#"; - } - - /** - * EnvelopedData ::= SEQUENCE { - * version Version, - * recipientInfos RecipientInfos, - * encryptedContentInfo EncryptedContentInfo } - * - * Version ::= INTEGER - * - * RecipientInfos ::= SET OF RecipientInfo - * - */ - public static Envelope fromASN1(DEREncodable content) { - ASN1Sequence sequence = (ASN1Sequence)content; - DERInteger version = (DERInteger)sequence.getObjectAt(0); - ASN1Set recipients = (ASN1Set)sequence.getObjectAt(1); - DEREncodable encContent = sequence.getObjectAt(2); - - Envelope envelope = new Envelope(); - envelope.setVersion(version.getValue().intValue()); - envelope.setRecipientInfo(recipientInfosFromASN1Set(recipients)); - envelope.setEncData(EncContent.fromASN1(encContent)); - - return envelope; - } - - public ASN1Encodable asASN1() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - vector.add(new DERInteger(version)); - vector.add(receipientInfosToASN1Set()); - vector.add(encData.asASN1()); - return new DERSequence(vector); - } - - private ASN1Set receipientInfosToASN1Set() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - for(RecipInfo ri : getRecipientInfo()) { - vector.add(ri.asASN1()); - } - return new DERSet(vector); - } - - private static Collection recipientInfosFromASN1Set(DEREncodable content) { - ASN1Set set = (ASN1Set)content; - Collection result = new ArrayList(); - for(Enumeration e = set.getObjects(); e.hasMoreElements();) { - result.add(RecipInfo.fromASN1((DEREncodable)e.nextElement())); - } - return result; - } -}// Envelope diff --git a/src/java/org/jruby/ext/openssl/impl/IssuerAndSerial.java b/src/java/org/jruby/ext/openssl/impl/IssuerAndSerial.java deleted file mode 100644 index f6dc109..0000000 --- a/src/java/org/jruby/ext/openssl/impl/IssuerAndSerial.java +++ /dev/null @@ -1,35 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** PKCS7_ISSUER_AND_SERIAL - * - * @author Ola Bini - */ -public class IssuerAndSerial { -}// IssuerAndSerial diff --git a/src/java/org/jruby/ext/openssl/impl/MemBIO.java b/src/java/org/jruby/ext/openssl/impl/MemBIO.java deleted file mode 100644 index eab205e..0000000 --- a/src/java/org/jruby/ext/openssl/impl/MemBIO.java +++ /dev/null @@ -1,117 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; - -/** - * - * @author Ola Bini - */ -public class MemBIO extends BIO { - private byte[] buffer = new byte[1024]; - private int wpointer = 0; - private int rpointer = 0; - private int slen = 0; - - private void realloc() { - byte[] newBuffer = new byte[buffer.length*2]; - System.arraycopy(buffer, 0, newBuffer, 0, wpointer); - buffer = newBuffer; - } - - @Override - public int gets(byte[] in, int len) throws IOException { - if(rpointer == slen) { - return 0; - } - - int i=0; - for(;i buffer.length) { - realloc(); - } - - System.arraycopy(out, offset, buffer, wpointer, len); - wpointer += len; - slen += len; - - return len; - } - - @Override - public String toString() { - try { - return ""; - } catch(Exception e) {} - - return null; - } - - @Override - public void setMemEofReturn(int value) { - } - - public int getType() { - return TYPE_MEM; - } - - public byte[] getMemCopy() { - byte[] nbuf = new byte[slen]; - System.arraycopy(buffer, 0, nbuf, 0, slen); - return nbuf; - } - - public void reset() { - this.rpointer = 0; - } -}// MemBIO diff --git a/src/java/org/jruby/ext/openssl/impl/MessageDigestBIOFilter.java b/src/java/org/jruby/ext/openssl/impl/MessageDigestBIOFilter.java deleted file mode 100644 index 68462fe..0000000 --- a/src/java/org/jruby/ext/openssl/impl/MessageDigestBIOFilter.java +++ /dev/null @@ -1,76 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.security.MessageDigest; - -/** - * - * @author Ola Bini - */ -public class MessageDigestBIOFilter extends BIOFilter { - private MessageDigest md; - - public MessageDigestBIOFilter(MessageDigest md) { - this.md = md; - } - - public int gets(byte[] in, int len) throws IOException { - int read = next().gets(in, len); - if(read > 0) { - md.update(in, 0, read); - } - return read; - } - - public int read(byte[] into, int offset, int len) throws IOException { - int read = next().read(into, offset, len); - if(read > 0) { - md.update(into, offset, read); - } - return read; - } - - public int write(byte[] out, int offset, int len) throws IOException { - int written = next().write(out, offset, len); - md.update(out, offset, written); - return written; - } - - public int getType() { - return TYPE_MD; - } - - /** c: BIO_get_md_ctx - * - */ - public MessageDigest getMessageDigest() { - return md; - } -}// MessageDigestBIOFilter diff --git a/src/java/org/jruby/ext/openssl/impl/Mime.java b/src/java/org/jruby/ext/openssl/impl/Mime.java deleted file mode 100644 index 4d0cd6c..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Mime.java +++ /dev/null @@ -1,244 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Ola Bini - */ -public interface Mime { - Mime DEFAULT = new Mime() { - private final static int MIME_START = 1; - private final static int MIME_TYPE = 2; - private final static int MIME_NAME = 3; - private final static int MIME_VALUE = 4; - private final static int MIME_QUOTE = 5; - private final static int MIME_COMMENT = 6; - - private final static int MAX_SMLEN = 1024; - - /* c: static strip_start - */ - private int stripStart(byte[] buffer, int start, int end) { - byte c; - for(int p = start; p= start; p--) { - mimeDebug(" p = "+p+", c = "+(char)buffer[p] + "(" + buffer[p] + ")"); - c = buffer[p]; - if(c == '"') { - if(p - 1 == start) { - return -1; - } - return p; - } - if(!Character.isWhitespace((char)c)) { - return p+1; - } - } - - return -1; - } - - /* c: static strip_ends - */ - private String stripEnds(byte[] buffer, int start, int end) { - start = stripStart(buffer, start, end); - end = stripEnd(buffer, start, end); - - try { - return new String(buffer, start, end-start, "ISO8859-1"); - } catch(Exception e) { - return null; - } - } - - public void mimeDebug(String str) { - // System.err.println(str); - } - - public List parseHeaders(BIO bio) throws IOException { - mimeDebug("\n!!!!!!!!!!!!!!!!!\n" + bio + "\n^^^^^^^^^^^^^^^^^^^^^^^^\n"); - int state = 0; - byte[] linebuf = new byte[MAX_SMLEN]; - int len = 0; - String ntmp = null; - int p, q; - byte c; - MimeHeader mhdr = null; - int saveState = -1; - - List headers = new ArrayList(); - - while((len = bio.gets(linebuf, MAX_SMLEN)) > 0) { - if(mhdr != null && Character.isWhitespace((char)linebuf[0])) { - state = MIME_NAME; - } else { - state = MIME_START; - } - - for(p = 0, q = 0; p headers, String key) { - for(MimeHeader hdr : headers) { - if(hdr.getName().equals(key)) { - return hdr; - } - } - - return null; - } - - public MimeParam findParam(MimeHeader header, String key) { - for(MimeParam par : header.getParams()) { - if(par.getParamName().equals(key)) { - return par; - } - } - - return null; - } - }; - - - /* c: mime_parse_hdr - * - */ - List parseHeaders(BIO bio) throws IOException; - - /* c: mime_hdr_find - * - */ - MimeHeader findHeader(List headers, String key); - - /* c: mime_param_find - * - */ - MimeParam findParam(MimeHeader header, String key); -}// Mime diff --git a/src/java/org/jruby/ext/openssl/impl/MimeHeader.java b/src/java/org/jruby/ext/openssl/impl/MimeHeader.java deleted file mode 100644 index ce7c37c..0000000 --- a/src/java/org/jruby/ext/openssl/impl/MimeHeader.java +++ /dev/null @@ -1,113 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.util.ArrayList; -import java.util.List; - -/** MIME_HEADER - * - * @author Ola Bini - */ -public class MimeHeader { - private String name; - private String value; - - /** - * Describe params here. - */ - private List params; - - public MimeHeader(String name, String value) { - this(name, value, new ArrayList()); - } - - public MimeHeader(String name, String value, List params) { - this.name = (name == null) ? - null : - name.toLowerCase(); - this.value = (value == null) ? - null : - value.toLowerCase(); - this.params = params; - } - - public String getName() { - return this.name; - } - - public String getValue() { - return this.value; - } - - /** - * Get the Params value. - * - * @return a List value - */ - public final List getParams() { - return params; - } - - /** - * Set the Params value. - * - * @param newParams The new Params value. - */ - public final void setParams(final List newParams) { - this.params = newParams; - } - - @Override - public boolean equals(Object other) { - boolean ret = this == other; - if(!ret && (other instanceof MimeHeader)) { - MimeHeader mh = (MimeHeader)other; - ret = - ((this.name == null) ? mh.name == null : this.name.equals(mh.name)) && - ((this.value == null) ? mh.value == null : this.value.equals(mh.value)) && - ((this.params == null) ? mh.params == null : this.params.equals(mh.params)); - } - return ret; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override - public String toString() { - return "#"; - } -}// MimeHeader diff --git a/src/java/org/jruby/ext/openssl/impl/MimeParam.java b/src/java/org/jruby/ext/openssl/impl/MimeParam.java deleted file mode 100644 index b34e528..0000000 --- a/src/java/org/jruby/ext/openssl/impl/MimeParam.java +++ /dev/null @@ -1,80 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** MIME_PARAM - * - * @author Ola Bini - */ -public class MimeParam { - private String paramName; - private String paramValue; - - public MimeParam(String name, String value) { - this.paramName = (name == null) ? - null : - name.toLowerCase(); - this.paramValue = value; - } - - public String getParamName() { - return this.paramName; - } - - public String getParamValue() { - return this.paramValue; - } - - @Override - public boolean equals(Object other) { - boolean ret = this == other; - if(!ret && (other instanceof MimeParam)) { - MimeParam mh = (MimeParam)other; - ret = - ((this.paramName == null) ? mh.paramName == null : this.paramName.equals(mh.paramName)) && - ((this.paramValue == null) ? mh.paramValue == null : this.paramValue.equals(mh.paramValue)); - } - return ret; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((paramName == null) ? 0 : paramName.hashCode()); - result = prime * result - + ((paramValue == null) ? 0 : paramValue.hashCode()); - return result; - } - - @Override - public String toString() { - return "#"; - } -}// MimeParam diff --git a/src/java/org/jruby/ext/openssl/impl/NotVerifiedPKCS7Exception.java b/src/java/org/jruby/ext/openssl/impl/NotVerifiedPKCS7Exception.java deleted file mode 100644 index 12d5b0f..0000000 --- a/src/java/org/jruby/ext/openssl/impl/NotVerifiedPKCS7Exception.java +++ /dev/null @@ -1,40 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** - * - * @author Ola Bini - */ -public class NotVerifiedPKCS7Exception extends PKCS7Exception { - private static final long serialVersionUID = 1L; - - public NotVerifiedPKCS7Exception() { - super(-1, -1); - } -}// NotVerifiedPKCS7Exception diff --git a/src/java/org/jruby/ext/openssl/impl/NullSinkBIO.java b/src/java/org/jruby/ext/openssl/impl/NullSinkBIO.java deleted file mode 100644 index f75dd27..0000000 --- a/src/java/org/jruby/ext/openssl/impl/NullSinkBIO.java +++ /dev/null @@ -1,52 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; - -/** - * - * @author Ola Bini - */ -public class NullSinkBIO extends BIO { - public int gets(byte[] in, int len) throws IOException { - return 0; - } - - public int write(byte[] out, int offset, int len) throws IOException { - return len; - } - - public int read(byte[] into, int offset, int len) throws IOException { - return 0; - } - - public int getType() { - return TYPE_NULL; - } -}// NullSinkBIO diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7.java b/src/java/org/jruby/ext/openssl/impl/PKCS7.java deleted file mode 100644 index 559a993..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7.java +++ /dev/null @@ -1,1277 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.cert.X509CRL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.TimeZone; -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.DERUTCTime; -import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.X509Name; -import org.jruby.ext.openssl.x509store.Name; -import org.jruby.ext.openssl.x509store.Store; -import org.jruby.ext.openssl.x509store.StoreContext; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; -import org.jruby.ext.openssl.x509store.X509Utils; - -/** c: PKCS7 - * - * Basically equivalent of the ContentInfo structures in PKCS#7. - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class PKCS7 { - // OpenSSL behavior: PKCS#7 ObjectId for "ITU-T" + "0" - private static final String EMPTY_PKCS7_OID = "0.0"; - - /* content as defined by the type */ - /* all encryption/message digests are applied to the 'contents', - * leaving out the 'type' field. */ - private PKCS7Data data; - - public Object ctrl(int cmd, Object v, Object ignored) throws PKCS7Exception { - return this.data.ctrl(cmd, v, ignored); - } - - public void setDetached(int v) throws PKCS7Exception { - ctrl(OP_SET_DETACHED_SIGNATURE, Integer.valueOf(v), null); - } - - public int getDetached() throws PKCS7Exception { - return ((Integer)ctrl(OP_GET_DETACHED_SIGNATURE, null, null)).intValue(); - } - - public boolean isDetached() throws PKCS7Exception { - return isSigned() && getDetached() != 0; - } - - private void initiateWith(Integer nid, DEREncodable content) throws PKCS7Exception { - this.data = PKCS7Data.fromASN1(nid, content); - } - - /** - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } - * - * ContentType ::= OBJECT IDENTIFIER - */ - public static PKCS7 fromASN1(DEREncodable obj) throws PKCS7Exception { - PKCS7 p7 = new PKCS7(); - - int size = ((ASN1Sequence) obj).size(); - if (size == 0) { - return p7; - } - - DERObjectIdentifier contentType = (DERObjectIdentifier) (((ASN1Sequence) obj).getObjectAt(0)); - if (EMPTY_PKCS7_OID.equals(contentType.getId())) { - // OpenSSL behavior - p7.setType(ASN1Registry.NID_undef); - } else { - Integer nid = ASN1Registry.obj2nid(contentType); - - DEREncodable content = size == 1 ? (DEREncodable) null : ((ASN1Sequence) obj).getObjectAt(1); - - if (content != null && content instanceof DERTaggedObject && ((DERTaggedObject) content).getTagNo() == 0) { - content = ((DERTaggedObject) content).getObject(); - } - p7.initiateWith(nid, content); - } - return p7; - } - - /* c: d2i_PKCS7_bio - * - */ - public static PKCS7 fromASN1(BIO bio) throws IOException, PKCS7Exception { - ASN1InputStream ais = new ASN1InputStream(BIO.asInputStream(bio)); - return fromASN1(ais.readObject()); - } - - public ASN1Encodable asASN1() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - DERObjectIdentifier contentType; - if (data == null) { - // OpenSSL behavior - contentType = new DERObjectIdentifier(EMPTY_PKCS7_OID); - } else { - contentType = ASN1Registry.nid2obj(getType()); - } - vector.add(contentType); - if (data != null) { - vector.add(new DERTaggedObject(0, data.asASN1())); - } - return new DERSequence(vector); - } - - /* c: i2d_PKCS7 - * - */ - public byte[] toASN1() throws IOException { - return asASN1().getEncoded(); - } - - /* c: PKCS7_add_signature - * - */ - public SignerInfoWithPkey addSignature(X509AuxCertificate x509, PrivateKey pkey, MessageDigest dgst) throws PKCS7Exception{ - SignerInfoWithPkey si = new SignerInfoWithPkey(); - si.set(x509, pkey, dgst); - addSigner(si); - return si; - } - - /* c: X509_find_by_issuer_and_serial - * - */ - public static X509AuxCertificate findByIssuerAndSerial(Collection certs, X509Name issuer, BigInteger serial) { - Name name = new Name(issuer); - for(X509AuxCertificate cert : certs) { - if(name.isEqual(cert.getIssuerX500Principal()) && serial.equals(cert.getSerialNumber())) { - return cert; - } - } - return null; - } - - - /* c: PKCS7_get0_signers - * - */ - public List getSigners(Collection certs, List sinfos, int flags) throws PKCS7Exception { - List signers = new ArrayList(); - - if(!isSigned()) { - throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_WRONG_CONTENT_TYPE); - } - - if(sinfos.size() == 0) { - throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_NO_SIGNERS); - } - - for(SignerInfoWithPkey si : sinfos) { - IssuerAndSerialNumber ias = si.getIssuerAndSerialNumber(); - X509AuxCertificate signer = null; -// System.err.println("looking for: " + ias.getName() + " and " + ias.getCertificateSerialNumber()); -// System.err.println(" in: " + certs); -// System.err.println(" in: " + getSign().getCert()); - if(certs != null) { - signer = findByIssuerAndSerial(certs, ias.getName(), ias.getCertificateSerialNumber().getValue()); - } - if(signer == null && (flags & NOINTERN) == 0 && getSign().getCert() != null) { - signer = findByIssuerAndSerial(getSign().getCert(), ias.getName(), ias.getCertificateSerialNumber().getValue()); - } - if(signer == null) { - throw new PKCS7Exception(F_PKCS7_GET0_SIGNERS,R_SIGNER_CERTIFICATE_NOT_FOUND); - } - signers.add(signer); - } - return signers; - } - - /* c: PKCS7_digest_from_attributes - * - */ - public ASN1OctetString digestFromAttributes(ASN1Set attributes) { - return (ASN1OctetString)SignerInfoWithPkey.getAttribute(attributes, ASN1Registry.NID_pkcs9_messageDigest); - } - - /* c: PKCS7_signatureVerify - * - */ - public void signatureVerify(BIO bio, SignerInfoWithPkey si, X509AuxCertificate x509) throws PKCS7Exception { - if(!isSigned() && !isSignedAndEnveloped()) { - throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_WRONG_PKCS7_TYPE); - } - - int md_type = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId()).intValue(); - BIO btmp = bio; - MessageDigest mdc = null; - - for(;;) { - if(btmp == null || (btmp = bio.findType(BIO.TYPE_MD)) == null) { - throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_UNABLE_TO_FIND_MESSAGE_DIGEST); - } - - mdc = ((MessageDigestBIOFilter)btmp).getMessageDigest(); - if(null == mdc) { - throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, -1); - } - - if(EVP.type(mdc) == md_type) { - break; - } - - btmp = btmp.next(); - } - - MessageDigest mdc_tmp = null; - try { - mdc_tmp = (MessageDigest)mdc.clone(); - } catch(Exception e) {} - - byte[] currentData = new byte[0]; - - ASN1Set sk = si.getAuthenticatedAttributes(); - try { - if(sk != null && sk.size() > 0) { - byte[] md_dat = mdc_tmp.digest(); - ASN1OctetString message_digest = digestFromAttributes(sk); - if(message_digest == null) { - throw new PKCS7Exception(F_PKCS7_SIGNATUREVERIFY, R_UNABLE_TO_FIND_MESSAGE_DIGEST); - } - if(!Arrays.equals(md_dat, message_digest.getOctets())) { - throw new NotVerifiedPKCS7Exception(); - } - - currentData = sk.getEncoded(); - } - - ASN1OctetString os = si.getEncryptedDigest(); - PublicKey pkey = x509.getPublicKey(); - - Signature sign = Signature.getInstance(EVP.signatureAlgorithm(mdc_tmp, pkey)); - sign.initVerify(pkey); - if(currentData.length > 0) { - sign.update(currentData); - } - if(!sign.verify(os.getOctets())) { - throw new NotVerifiedPKCS7Exception(); - } - } catch(NotVerifiedPKCS7Exception e) { - throw e; - } catch(Exception e) { - System.err.println("Other exception"); - e.printStackTrace(); - throw new NotVerifiedPKCS7Exception(); - } - } - - /* c: PKCS7_verify - * - */ - public void verify(Collection certs, Store store, BIO indata, BIO out, int flags) throws PKCS7Exception { - if(!isSigned()) { - throw new PKCS7Exception(F_PKCS7_VERIFY, R_WRONG_CONTENT_TYPE); - } - - if(getDetached() != 0 && indata == null) { - throw new PKCS7Exception(F_PKCS7_VERIFY, R_NO_CONTENT); - } - - List sinfos = new ArrayList(getSignerInfo()); - if(sinfos.size() == 0) { - throw new PKCS7Exception(F_PKCS7_VERIFY, R_NO_SIGNATURES_ON_DATA); - } - - List signers = getSigners(certs, sinfos, flags); - if(signers == null) { - throw new NotVerifiedPKCS7Exception(); - } - - /* Now verify the certificates */ - if((flags & NOVERIFY) == 0) { - for(X509AuxCertificate signer : signers) { - StoreContext cert_ctx = new StoreContext(); - if((flags & NOCHAIN) == 0) { - if(cert_ctx.init(store, signer, new ArrayList(getSign().getCert())) == 0) { - throw new PKCS7Exception(F_PKCS7_VERIFY, -1); - } - cert_ctx.setPurpose(X509Utils.X509_PURPOSE_SMIME_SIGN); - } else if(cert_ctx.init(store, signer, null) == 0) { - throw new PKCS7Exception(F_PKCS7_VERIFY, -1); - } - cert_ctx.setExtraData(1, store.getExtraData(1)); - if((flags & NOCRL) == 0) { - cert_ctx.setCRLs((List)getSign().getCrl()); - } - try { - int i = cert_ctx.verifyCertificate(); - int j = 0; - if(i <= 0) { - j = cert_ctx.getError(); - } - cert_ctx.cleanup(); - if(i <= 0) { - throw new PKCS7Exception(F_PKCS7_VERIFY, R_CERTIFICATE_VERIFY_ERROR, "Verify error:" + X509Utils.verifyCertificateErrorString(j)); - } - } catch(PKCS7Exception e) { - throw e; - } catch(Exception e) { - throw new PKCS7Exception(F_PKCS7_VERIFY, R_CERTIFICATE_VERIFY_ERROR, e); - } - } - } - - BIO tmpin = indata; - BIO p7bio = dataInit(tmpin); - BIO tmpout = null; - if((flags & TEXT) != 0) { - tmpout = BIO.mem(); - } else { - tmpout = out; - } - - byte[] buf = new byte[4096]; - for(;;) { - try { - int i = p7bio.read(buf, 0, buf.length); - if(i <= 0) { - break; - } - if(tmpout != null) { - tmpout.write(buf, 0, i); - } - } catch(IOException e) { - throw new PKCS7Exception(F_PKCS7_VERIFY, -1, e); - } - } - - if((flags & TEXT) != 0) { - new SMIME(Mime.DEFAULT).text(tmpout, out); - } - - if((flags & NOSIGS) == 0) { - for(int i=0; i certs, BIO data, int flags) throws PKCS7Exception { - PKCS7 p7 = new PKCS7(); - p7.setType(ASN1Registry.NID_pkcs7_signed); - p7.contentNew(ASN1Registry.NID_pkcs7_data); - SignerInfoWithPkey si = p7.addSignature(signcert, pkey, EVP.sha1()); - if((flags & NOCERTS) == 0) { - p7.addCertificate(signcert); - if(certs != null) { - for(X509AuxCertificate c : certs) { - p7.addCertificate(c); - } - } - } - - if((flags & NOATTR) == 0) { - si.addSignedAttribute(ASN1Registry.NID_pkcs9_contentType, ASN1Registry.nid2obj(ASN1Registry.NID_pkcs7_data)); - if((flags & NOSMIMECAP) == 0) { - ASN1EncodableVector smcap = new ASN1EncodableVector(); - smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_des_ede3_cbc))); - smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(128))); - smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(64))); - smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rc2_cbc), new DERInteger(40))); - smcap.add(new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_des_cbc))); - si.addSignedAttribute(ASN1Registry.NID_SMIMECapabilities, new DERSequence(smcap)); - } - } - - if((flags & STREAM) != 0) { - return p7; - } - - BIO p7bio = p7.dataInit(null); - - try { - data.crlfCopy(p7bio, flags); - } catch(IOException e) { - throw new PKCS7Exception(F_PKCS7_SIGN, R_PKCS7_DATAFINAL_ERROR, e); - } - - if((flags & DETACHED) != 0) { - p7.setDetached(1); - } - - p7.dataFinal(p7bio); - - return p7; - } - - /* c: PKCS7_encrypt - * - */ - public static PKCS7 encrypt(Collection certs, byte[] in, CipherSpec cipher, int flags) throws PKCS7Exception { - PKCS7 p7 = new PKCS7(); - - p7.setType(ASN1Registry.NID_pkcs7_enveloped); - - try { - p7.setCipher(cipher); - - for(X509AuxCertificate x509 : certs) { - p7.addRecipient(x509); - } - - BIO p7bio = p7.dataInit(null); - - BIO.memBuf(in).crlfCopy(p7bio, flags); - p7bio.flush(); - p7.dataFinal(p7bio); - - return p7; - } catch(IOException e) { - throw new PKCS7Exception(F_PKCS7_ENCRYPT, R_PKCS7_DATAFINAL_ERROR, e); - } - } - - /* c: PKCS7_decrypt - * - */ - public void decrypt(PrivateKey pkey, X509AuxCertificate cert, BIO data, int flags) throws PKCS7Exception { - if(!isEnveloped()) { - throw new PKCS7Exception(F_PKCS7_DECRYPT, R_WRONG_CONTENT_TYPE); - } - try { - BIO tmpmem = dataDecode(pkey, null, cert); - if((flags & TEXT) == TEXT) { - BIO tmpbuf = BIO.buffered(); - BIO bread = tmpbuf.push(tmpmem); - new SMIME(Mime.DEFAULT).text(bread, data); - } else { - int i; - byte[] buf = new byte[4096]; - while((i = tmpmem.read(buf, 0, 4096)) > 0) { - data.write(buf, 0, i); - } - } - } catch(IOException e) { - throw new PKCS7Exception(F_PKCS7_DECRYPT, R_DECRYPT_ERROR, e); - } - } - - /** c: PKCS7_set_type - * - */ - public void setType(int type) throws PKCS7Exception { - switch(type) { - case ASN1Registry.NID_undef: - this.data = null; - break; - case ASN1Registry.NID_pkcs7_signed: - this.data = new PKCS7DataSigned(); - break; - case ASN1Registry.NID_pkcs7_data: - this.data = new PKCS7DataData(); - break; - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - this.data = new PKCS7DataSignedAndEnveloped(); - break; - case ASN1Registry.NID_pkcs7_enveloped: - this.data = new PKCS7DataEnveloped(); - break; - case ASN1Registry.NID_pkcs7_encrypted: - this.data = new PKCS7DataEncrypted(); - break; - case ASN1Registry.NID_pkcs7_digest: - this.data = new PKCS7DataDigest(); - break; - default: - throw new PKCS7Exception(F_PKCS7_SET_TYPE,R_UNSUPPORTED_CONTENT_TYPE); - } - } - - /** c: PKCS7_set_cipher - * - */ - public void setCipher(CipherSpec cipher) throws PKCS7Exception { - this.data.setCipher(cipher); - } - - /** c: PKCS7_add_recipient - * - */ - public RecipInfo addRecipient(X509AuxCertificate recip) throws PKCS7Exception { - RecipInfo ri = new RecipInfo(); - ri.set(recip); - addRecipientInfo(ri); - return ri; - } - - /** c: PKCS7_content_new - * - */ - public void contentNew(int nid) throws PKCS7Exception { - PKCS7 ret = new PKCS7(); - ret.setType(nid); - this.setContent(ret); - } - - /** c: PKCS7_add_signer - * - */ - public void addSigner(SignerInfoWithPkey psi) throws PKCS7Exception { - this.data.addSigner(psi); - } - - /** c: PKCS7_add_certificate - * - */ - public void addCertificate(X509AuxCertificate cert) throws PKCS7Exception { - this.data.addCertificate(cert); - } - - /** c: PKCS7_add_crl - * - */ - public void addCRL(X509CRL crl) throws PKCS7Exception { - this.data.addCRL(crl); - } - - /** c: PKCS7_add_recipient_info - * - */ - public void addRecipientInfo(RecipInfo ri) throws PKCS7Exception { - this.data.addRecipientInfo(ri); - } - - /** c: PKCS7_set_content - * - */ - public void setContent(PKCS7 p7) throws PKCS7Exception { - this.data.setContent(p7); - } - - /** c: PKCS7_get_signer_info - * - */ - public Collection getSignerInfo() { - return this.data.getSignerInfo(); - } - - private final static byte[] PEM_STRING_PKCS7_START = "-----BEGIN PKCS7-----".getBytes(); - - /** c: PEM_read_bio_PKCS7 - * - */ - public static PKCS7 readPEM(BIO input) throws PKCS7Exception { - try { - byte[] buffer = new byte[SMIME.MAX_SMLEN]; - int read = -1; - read = input.gets(buffer, SMIME.MAX_SMLEN); - if(read > PEM_STRING_PKCS7_START.length) { - byte[] tmp = new byte[PEM_STRING_PKCS7_START.length]; - System.arraycopy(buffer, 0, tmp, 0, tmp.length); - if(Arrays.equals(PEM_STRING_PKCS7_START, tmp)) { - return fromASN1(BIO.base64Filter(input)); - } else { - return null; - } - } else { - return null; - } - } catch(IOException e) { - return null; - } - } - - /** c: stati PKCS7_bio_add_digest - * - */ - public BIO bioAddDigest(BIO pbio, AlgorithmIdentifier alg) throws PKCS7Exception { - try { - MessageDigest md = EVP.getDigest(alg.getObjectId()); - BIO btmp = BIO.mdFilter(md); - if(pbio == null) { - return btmp; - } else { - pbio.push(btmp); - return pbio; - } - } catch(Exception e) { - throw new PKCS7Exception(F_PKCS7_BIO_ADD_DIGEST, R_UNKNOWN_DIGEST_TYPE, e); - } - } - - /** c: PKCS7_dataDecode - * - */ - public BIO dataDecode(PrivateKey pkey, BIO inBio, X509AuxCertificate pcert) throws PKCS7Exception { - BIO out = null; - BIO btmp = null; - BIO etmp = null; - BIO bio = null; - byte[] dataBody = null; - Collection mdSk = null; - Collection rsk = null; - AlgorithmIdentifier encAlg = null; - Cipher evpCipher = null; - RecipInfo ri = null; - - int i = getType(); - switch(i) { - case ASN1Registry.NID_pkcs7_signed: - dataBody = getSign().getContents().getOctetString().getOctets(); - mdSk = getSign().getMdAlgs(); - break; - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - rsk = getSignedAndEnveloped().getRecipientInfo(); - mdSk = getSignedAndEnveloped().getMdAlgs(); - dataBody = getSignedAndEnveloped().getEncData().getEncData().getOctets(); - encAlg = getSignedAndEnveloped().getEncData().getAlgorithm(); - try { - evpCipher = EVP.getCipher(encAlg.getAlgorithm()); - } catch(Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e); - } - break; - case ASN1Registry.NID_pkcs7_enveloped: - rsk = getEnveloped().getRecipientInfo(); - dataBody = getEnveloped().getEncData().getEncData().getOctets(); - encAlg = getEnveloped().getEncData().getAlgorithm(); - try { - evpCipher = EVP.getCipher(encAlg.getAlgorithm()); - } catch(Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CIPHER_TYPE, e); - } - break; - default: - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNSUPPORTED_CONTENT_TYPE); - } - - /* We will be checking the signature */ - if(mdSk != null) { - for(AlgorithmIdentifier xa : mdSk) { - try { - MessageDigest evpMd = EVP.getDigest(xa.getAlgorithm()); - btmp = BIO.mdFilter(evpMd); - if(out == null) { - out = btmp; - } else { - out.push(btmp); - } - btmp = null; - } catch(Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_UNKNOWN_DIGEST_TYPE, e); - } - } - } - - - if(evpCipher != null) { - - /* It was encrypted, we need to decrypt the secret key - * with the private key */ - - /* Find the recipientInfo which matches the passed certificate - * (if any) - */ - if(pcert != null) { - for(Iterator iter = rsk.iterator(); iter.hasNext();) { - ri = iter.next(); - if(ri.compare(pcert)) { - break; - } - ri = null; - } - if(null == ri) { - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_NO_RECIPIENT_MATCHES_CERTIFICATE); - } - } - - byte[] tmp = null; - /* If we haven't got a certificate try each ri in turn */ - if(null == pcert) { - for(Iterator iter = rsk.iterator(); iter.hasNext();) { - ri = iter.next(); - try { - tmp = EVP.decrypt(ri.getEncKey().getOctets(), pkey); - if(tmp != null) { - break; - } - } catch(Exception e) { - tmp = null; - } - ri = null; - } - if(ri == null) { - throw new PKCS7Exception(F_PKCS7_DATADECODE, R_NO_RECIPIENT_MATCHES_KEY); - } - } else { - try { - Cipher cipher = Cipher.getInstance(CipherSpec.getWrappingAlgorithm(pkey.getAlgorithm())); - cipher.init(Cipher.DECRYPT_MODE, pkey); - tmp = cipher.doFinal(ri.getEncKey().getOctets()); - } catch (Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e); - } - } - - DEREncodable params = encAlg.getParameters(); - try { - String algo = org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(evpCipher); - if(params != null && params instanceof ASN1OctetString) { - if (algo.startsWith("RC2")) { - // J9's IBMJCE needs this exceptional RC2 support. - // Giving IvParameterSpec throws 'Illegal parameter' on IBMJCE. - SecretKeySpec sks = new SecretKeySpec(tmp, algo); - RC2ParameterSpec s = new RC2ParameterSpec(tmp.length * 8, ((ASN1OctetString) params).getOctets()); - evpCipher.init(Cipher.DECRYPT_MODE, sks, s); - } else { - SecretKeySpec sks = new SecretKeySpec(tmp, algo); - IvParameterSpec iv = new IvParameterSpec(((ASN1OctetString) params).getOctets()); - evpCipher.init(Cipher.DECRYPT_MODE, sks, iv); - } - } else { - evpCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(tmp, algo)); - } - } catch(Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATADECODE, -1, e); - } - - etmp = BIO.cipherFilter(evpCipher); - if(out == null) { - out = etmp; - } else { - out.push(etmp); - } - etmp = null; - } - - if(isDetached() || inBio != null) { - bio = inBio; - } else { - if(dataBody != null && dataBody.length > 0) { - bio = BIO.memBuf(dataBody); - } else { - bio = BIO.mem(); - } - } - out.push(bio); - bio = null; - return out; - } - - /** c: PKCS7_dataInit - * - */ - public BIO dataInit(BIO bio) throws PKCS7Exception { - Collection mdSk = null; - ASN1OctetString os = null; - int i = this.data.getType(); - Collection rsk = null; - AlgorithmIdentifier xa = null; - CipherSpec evpCipher = null; - BIO out = null; - BIO btmp = null; - EncContent enc = null; - switch (i) { - case ASN1Registry.NID_pkcs7_signed: - mdSk = getSign().getMdAlgs(); - os = getSign().getContents().getOctetString(); - break; - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - rsk = getSignedAndEnveloped().getRecipientInfo(); - mdSk = getSignedAndEnveloped().getMdAlgs(); - enc = getSignedAndEnveloped().getEncData(); - evpCipher = getSignedAndEnveloped().getEncData().getCipher(); - if (null == evpCipher) { - throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED); - } - break; - case ASN1Registry.NID_pkcs7_enveloped: - rsk = getEnveloped().getRecipientInfo(); - enc = getEnveloped().getEncData(); - evpCipher = getEnveloped().getEncData().getCipher(); - if (null == evpCipher) { - throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_NOT_INITIALIZED); - } - break; - case ASN1Registry.NID_pkcs7_digest: - xa = getDigest().getMd(); - os = getDigest().getContents().getOctetString(); - break; - default: - throw new PKCS7Exception(F_PKCS7_DATAINIT, R_UNSUPPORTED_CONTENT_TYPE); - } - - if (mdSk != null) { - for (AlgorithmIdentifier ai : mdSk) { - if ((out = bioAddDigest(out, ai)) == null) { - return null; - } - } - } - - if (xa != null && (out = bioAddDigest(out, xa)) == null) { - return null; - } - - if (evpCipher != null) { - byte[] tmp; - btmp = BIO.cipherFilter(evpCipher.getCipher()); - String algoBase = evpCipher.getCipher().getAlgorithm(); - if (algoBase.indexOf('/') != -1) { - algoBase = algoBase.split("/")[0]; - } - try { - KeyGenerator gen = KeyGenerator.getInstance(algoBase); - gen.init(evpCipher.getKeyLenInBits(), new SecureRandom()); - SecretKey key = gen.generateKey(); - evpCipher.getCipher().init(Cipher.ENCRYPT_MODE, key); - if (null != rsk) { - for (RecipInfo ri : rsk) { - PublicKey pkey = ri.getCert().getPublicKey(); - Cipher cipher = Cipher.getInstance(CipherSpec.getWrappingAlgorithm(pkey.getAlgorithm())); - cipher.init(Cipher.ENCRYPT_MODE, pkey); - tmp = cipher.doFinal(key.getEncoded()); - ri.setEncKey(new DEROctetString(tmp)); - } - } - } catch (Exception e) { - e.printStackTrace(System.err); - throw new PKCS7Exception(F_PKCS7_DATAINIT, R_ERROR_SETTING_CIPHER, e); - } - - DERObjectIdentifier encAlgo = ASN1Registry.sym2oid(evpCipher.getOsslName()); - if (encAlgo == null) { - throw new PKCS7Exception(F_PKCS7_DATAINIT, R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); - } - if (evpCipher.getCipher().getIV() != null) { - enc.setAlgorithm(new AlgorithmIdentifier(encAlgo, new DEROctetString(evpCipher.getCipher().getIV()))); - } else { - enc.setAlgorithm(new AlgorithmIdentifier(encAlgo)); - } - - if (out == null) { - out = btmp; - } else { - out.push(btmp); - } - btmp = null; - } - - if (bio == null) { - if (isDetached()) { - bio = BIO.nullSink(); - } else if (os != null && os.getOctets().length > 0) { - bio = BIO.memBuf(os.getOctets()); - } - if (bio == null) { - bio = BIO.mem(); - bio.setMemEofReturn(0); - } - } - - if (out != null) { - out.push(bio); - } else { - out = bio; - } - bio = null; - return out; - } - - /** c: static PKCS7_find_digest - * - */ - public BIO findDigest(MessageDigest[] pmd, BIO bio, int nid) throws PKCS7Exception { - while(true) { - bio = bio.findType(BIO.TYPE_MD); - if(bio == null) { - throw new PKCS7Exception(F_PKCS7_FIND_DIGEST, R_UNABLE_TO_FIND_MESSAGE_DIGEST); - } - pmd[0] = ((MessageDigestBIOFilter)bio).getMessageDigest(); - if(pmd[0] == null) { - throw new PKCS7Exception(F_PKCS7_FIND_DIGEST, -1); - } - - if(nid == EVP.type(pmd[0])) { - return bio; - } - - bio = bio.next(); - } - } - - /** c: PKCS7_dataFinal - * - */ - public int dataFinal(BIO bio) throws PKCS7Exception { - Collection siSk = null; - BIO btmp; - byte[] buf; - MessageDigest mdc = null; - MessageDigest ctx_tmp = null; - ASN1Set sk; - - int i = this.data.getType(); - - switch(i) { - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - siSk = getSignedAndEnveloped().getSignerInfo(); - break; - case ASN1Registry.NID_pkcs7_signed: - siSk = getSign().getSignerInfo(); - break; - case ASN1Registry.NID_pkcs7_digest: - break; - default: - break; - } - - if(siSk != null) { - for(SignerInfoWithPkey si : siSk) { - if(si.getPkey() == null) { - continue; - } - int j = ASN1Registry.obj2nid(si.getDigestAlgorithm().getObjectId()); - btmp = bio; - MessageDigest[] _mdc = new MessageDigest[] {mdc}; - btmp = findDigest(_mdc, btmp, j); - mdc = _mdc[0]; - if(btmp == null) { - return 0; - } - - try { - ctx_tmp = (MessageDigest)mdc.clone(); - } catch(CloneNotSupportedException e) { - throw new RuntimeException(e); - } - - sk = si.getAuthenticatedAttributes(); - - Signature sign = null; - - try { - if(sk != null && sk.size() > 0) { - /* Add signing time if not already present */ - if(null == si.getSignedAttribute(ASN1Registry.NID_pkcs9_signingTime)) { - DERUTCTime signTime = new DERUTCTime(Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime()); - si.addSignedAttribute(ASN1Registry.NID_pkcs9_signingTime, signTime); - } - - byte[] md_data = ctx_tmp.digest(); - ASN1OctetString digest = new DEROctetString(md_data); - si.addSignedAttribute(ASN1Registry.NID_pkcs9_messageDigest, digest); - - sk = si.getAuthenticatedAttributes(); - sign = Signature.getInstance(EVP.signatureAlgorithm(ctx_tmp, si.getPkey())); - sign.initSign(si.getPkey()); - - byte[] abuf = sk.getEncoded(); - sign.update(abuf); - } - - if(sign != null) { - byte[] out = sign.sign(); - si.setEncryptedDigest(new DEROctetString(out)); - } - } catch(Exception e) { - throw new PKCS7Exception(F_PKCS7_DATAFINAL, -1, e); - } - } - } else if(i == ASN1Registry.NID_pkcs7_digest) { - int nid = ASN1Registry.obj2nid(getDigest().getMd().getObjectId()); - MessageDigest[] _mdc = new MessageDigest[] {mdc}; - bio = findDigest(_mdc, bio, nid); - mdc = _mdc[0]; - byte[] md_data = mdc.digest(); - ASN1OctetString digest = new DEROctetString(md_data); - getDigest().setDigest(digest); - } - - if(!isDetached()) { - btmp = bio.findType(BIO.TYPE_MEM); - if(null == btmp) { - throw new PKCS7Exception(F_PKCS7_DATAFINAL, R_UNABLE_TO_FIND_MEM_BIO); - } - buf = ((MemBIO)btmp).getMemCopy(); - switch(i) { - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - getSignedAndEnveloped().getEncData().setEncData(new DEROctetString(buf)); - break; - case ASN1Registry.NID_pkcs7_enveloped: - getEnveloped().getEncData().setEncData(new DEROctetString(buf)); - break; - case ASN1Registry.NID_pkcs7_signed: - if(getSign().getContents().isData() && getDetached() != 0) { - getSign().getContents().setData(null); - } else { - getSign().getContents().setData(new DEROctetString(buf)); - } - break; - case ASN1Registry.NID_pkcs7_digest: - if(getDigest().getContents().isData() && getDetached() != 0) { - getDigest().getContents().setData(null); - } else { - getDigest().getContents().setData(new DEROctetString(buf)); - } - break; - } - } - - return 1; - } - - @Override - public String toString() { - return "#"; - } - - public static final int S_HEADER = 0; - public static final int S_BODY = 1; - public static final int S_TAIL = 2; - - public static final int OP_SET_DETACHED_SIGNATURE = 1; - public static final int OP_GET_DETACHED_SIGNATURE = 2; - - /* S/MIME related flags */ - public static final int TEXT = 0x1; - public static final int NOCERTS = 0x2; - public static final int NOSIGS = 0x4; - public static final int NOCHAIN = 0x8; - public static final int NOINTERN = 0x10; - public static final int NOVERIFY = 0x20; - public static final int DETACHED = 0x40; - public static final int BINARY = 0x80; - public static final int NOATTR = 0x100; - public static final int NOSMIMECAP = 0x200; - public static final int NOOLDMIMETYPE = 0x400; - public static final int CRLFEOL = 0x800; - public static final int STREAM = 0x1000; - public static final int NOCRL = 0x2000; - - /* Flags: for compatibility with older code */ - public static final int SMIME_TEXT = TEXT; - public static final int SMIME_NOCERTS = NOCERTS; - public static final int SMIME_NOSIGS = NOSIGS; - public static final int SMIME_NOCHAIN = NOCHAIN; - public static final int SMIME_NOINTERN = NOINTERN; - public static final int SMIME_NOVERIFY = NOVERIFY; - public static final int SMIME_DETACHED = DETACHED; - public static final int SMIME_BINARY = BINARY; - public static final int SMIME_NOATTR = NOATTR; - - /* Function codes. */ - public static final int F_B64_READ_PKCS7 = 120; - public static final int F_B64_WRITE_PKCS7 = 121; - public static final int F_PKCS7_ADD_ATTRIB_SMIMECAP = 118; - public static final int F_PKCS7_ADD_CERTIFICATE = 100; - public static final int F_PKCS7_ADD_CRL = 101; - public static final int F_PKCS7_ADD_RECIPIENT_INFO = 102; - public static final int F_PKCS7_ADD_SIGNER = 103; - public static final int F_PKCS7_BIO_ADD_DIGEST = 125; - public static final int F_PKCS7_CTRL = 104; - public static final int F_PKCS7_DATADECODE = 112; - public static final int F_PKCS7_DATAFINAL = 128; - public static final int F_PKCS7_DATAINIT = 105; - public static final int F_PKCS7_DATASIGN = 106; - public static final int F_PKCS7_DATAVERIFY = 107; - public static final int F_PKCS7_DECRYPT = 114; - public static final int F_PKCS7_ENCRYPT = 115; - public static final int F_PKCS7_FIND_DIGEST = 127; - public static final int F_PKCS7_GET0_SIGNERS = 124; - public static final int F_PKCS7_SET_CIPHER = 108; - public static final int F_PKCS7_SET_CONTENT = 109; - public static final int F_PKCS7_SET_DIGEST = 126; - public static final int F_PKCS7_SET_TYPE = 110; - public static final int F_PKCS7_SIGN = 116; - public static final int F_PKCS7_SIGNATUREVERIFY = 113; - public static final int F_PKCS7_SIMPLE_SMIMECAP = 119; - public static final int F_PKCS7_VERIFY = 117; - public static final int F_SMIME_READ_PKCS7 = 122; - public static final int F_SMIME_TEXT = 123; - - /* Reason codes. */ - public static final int R_CERTIFICATE_VERIFY_ERROR = 117; - public static final int R_CIPHER_HAS_NO_OBJECT_IDENTIFIER = 144; - public static final int R_CIPHER_NOT_INITIALIZED = 116; - public static final int R_CONTENT_AND_DATA_PRESENT = 118; - public static final int R_DECODE_ERROR = 130; - public static final int R_DECRYPTED_KEY_IS_WRONG_LENGTH = 100; - public static final int R_DECRYPT_ERROR = 119; - public static final int R_DIGEST_FAILURE = 101; - public static final int R_ERROR_ADDING_RECIPIENT = 120; - public static final int R_ERROR_SETTING_CIPHER = 121; - public static final int R_INVALID_MIME_TYPE = 131; - public static final int R_INVALID_NULL_POINTER = 143; - public static final int R_MIME_NO_CONTENT_TYPE = 132; - public static final int R_MIME_PARSE_ERROR = 133; - public static final int R_MIME_SIG_PARSE_ERROR = 134; - public static final int R_MISSING_CERIPEND_INFO = 103; - public static final int R_NO_CONTENT = 122; - public static final int R_NO_CONTENT_TYPE = 135; - public static final int R_NO_MULTIPART_BODY_FAILURE = 136; - public static final int R_NO_MULTIPART_BOUNDARY = 137; - public static final int R_NO_RECIPIENT_MATCHES_CERTIFICATE = 115; - public static final int R_NO_RECIPIENT_MATCHES_KEY = 146; - public static final int R_NO_SIGNATURES_ON_DATA = 123; - public static final int R_NO_SIGNERS = 142; - public static final int R_NO_SIG_CONTENT_TYPE = 138; - public static final int R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE = 104; - public static final int R_PKCS7_ADD_SIGNATURE_ERROR = 124; - public static final int R_PKCS7_DATAFINAL = 126; - public static final int R_PKCS7_DATAFINAL_ERROR = 125; - public static final int R_PKCS7_DATASIGN = 145; - public static final int R_PKCS7_PARSE_ERROR = 139; - public static final int R_PKCS7_SIG_PARSE_ERROR = 140; - public static final int R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE = 127; - public static final int R_SIGNATURE_FAILURE = 105; - public static final int R_SIGNER_CERTIFICATE_NOT_FOUND = 128; - public static final int R_SIG_INVALID_MIME_TYPE = 141; - public static final int R_SMIME_TEXT_ERROR = 129; - public static final int R_UNABLE_TO_FIND_CERTIFICATE = 106; - public static final int R_UNABLE_TO_FIND_MEM_BIO = 107; - public static final int R_UNABLE_TO_FIND_MESSAGE_DIGEST = 108; - public static final int R_UNKNOWN_DIGEST_TYPE = 109; - public static final int R_UNKNOWN_OPERATION = 110; - public static final int R_UNSUPPORTED_CIPHER_TYPE = 111; - public static final int R_UNSUPPORTED_CONTENT_TYPE = 112; - public static final int R_WRONG_CONTENT_TYPE = 113; - public static final int R_WRONG_PKCS7_TYPE = 114; - - public Envelope getEnveloped() { - return this.data.getEnveloped(); - } - - public SignEnvelope getSignedAndEnveloped() { - return this.data.getSignedAndEnveloped(); - } - - public Digest getDigest() { - return this.data.getDigest(); - } - - public Encrypt getEncrypted() { - return this.data.getEncrypted(); - } - - public ASN1Encodable getOther() { - return this.data.getOther(); - } - - public void setSign(Signed sign) { - this.data.setSign(sign); - } - - public Signed getSign() { - return this.data.getSign(); - } - - public void setData(ASN1OctetString data) { - this.data.setData(data); - } - - public ASN1OctetString getData() { - return this.data.getData(); - } - - public boolean isSigned() { - return this.data.isSigned(); - } - - public boolean isEncrypted() { - return this.data.isEncrypted(); - } - - public boolean isEnveloped() { - return this.data.isEnveloped(); - } - - public boolean isSignedAndEnveloped() { - return this.data.isSignedAndEnveloped(); - } - - public boolean isData() { - return this.data.isData(); - } - - public boolean isDigest() { - return this.data.isDigest(); - } - - public boolean isOther() { - return this.data.isOther(); - } - - public int getType() { - return this.data.getType(); - } - - /* c: static PKCS7_get_octet_string - * - */ - public ASN1OctetString getOctetString() { - if(isData()) { - return getData(); - } else if(isOther() && getOther() != null && getOther() instanceof ASN1OctetString) { - return (ASN1OctetString)getOther(); - } - return null; - } -}// PKCS7 - diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7Data.java b/src/java/org/jruby/ext/openssl/impl/PKCS7Data.java deleted file mode 100644 index ad34a56..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7Data.java +++ /dev/null @@ -1,166 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.security.cert.X509CRL; -import java.util.Collection; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEREncodable; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** - * @author Ola Bini - */ -public abstract class PKCS7Data { - public abstract int getType(); - - public Object ctrl(int cmd, Object v, Object ignored) throws PKCS7Exception { - switch(cmd) { - case PKCS7.OP_SET_DETACHED_SIGNATURE: - throw new PKCS7Exception(PKCS7.F_PKCS7_CTRL,PKCS7.R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); - case PKCS7.OP_GET_DETACHED_SIGNATURE: - throw new PKCS7Exception(PKCS7.F_PKCS7_CTRL,PKCS7.R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE); - default: - throw new PKCS7Exception(PKCS7.F_PKCS7_CTRL,PKCS7.R_UNKNOWN_OPERATION); - } - } - - public Envelope getEnveloped() { - return null; - } - - public SignEnvelope getSignedAndEnveloped() { - return null; - } - - public Digest getDigest() { - return null; - } - - public Encrypt getEncrypted() { - return null; - } - - public ASN1Encodable getOther() { - return null; - } - - public void setSign(Signed sign) { - } - - public Signed getSign() { - return null; - } - - public void setData(ASN1OctetString data) { - } - - public ASN1OctetString getData() { - return null; - } - - public boolean isSigned() { - return false; - } - - public boolean isEncrypted() { - return false; - } - - public boolean isEnveloped() { - return false; - } - - public boolean isSignedAndEnveloped() { - return false; - } - - public boolean isData() { - return false; - } - - public boolean isDigest() { - return false; - } - - public boolean isOther() { - return false; - } - - public void setCipher(CipherSpec cipher) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_SET_CIPHER,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public void addRecipientInfo(RecipInfo ri) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_ADD_RECIPIENT_INFO,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public void addSigner(SignerInfoWithPkey psi) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_ADD_SIGNER,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public void setContent(PKCS7 p7) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_SET_CONTENT,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public Collection getSignerInfo() { - return null; - } - - public void addCertificate(X509AuxCertificate cert) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_ADD_CERTIFICATE,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public void addCRL(X509CRL crl) throws PKCS7Exception { - throw new PKCS7Exception(PKCS7.F_PKCS7_ADD_CRL,PKCS7.R_WRONG_CONTENT_TYPE); - } - - public static PKCS7Data fromASN1(Integer nid, DEREncodable content) throws PKCS7Exception { - switch(nid) { - case ASN1Registry.NID_pkcs7_data: - return PKCS7DataData.fromASN1(content); - case ASN1Registry.NID_pkcs7_signed: - return PKCS7DataSigned.fromASN1(content); - case ASN1Registry.NID_pkcs7_enveloped: - return PKCS7DataEnveloped.fromASN1(content); - case ASN1Registry.NID_pkcs7_signedAndEnveloped: - return PKCS7DataSignedAndEnveloped.fromASN1(content); - case ASN1Registry.NID_pkcs7_digest: - return PKCS7DataDigest.fromASN1(content); - case ASN1Registry.NID_pkcs7_encrypted: - return PKCS7DataEncrypted.fromASN1(content); - default: - throw new UnsupportedOperationException("can't handle PKCS#7 with content type " + ASN1Registry.nid2ln(nid)); - } - } - - public ASN1Encodable asASN1() { - throw new UnsupportedOperationException("can't ASN1 PKCS#7 with content type " + ASN1Registry.nid2ln(getType())); - } -}// PKCS7Data diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataData.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataData.java deleted file mode 100644 index fc92a6c..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataData.java +++ /dev/null @@ -1,92 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DEROctetString; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataData extends PKCS7Data { - /* NID_pkcs7_data */ - private ASN1OctetString data; - - public PKCS7DataData() { - this(new DEROctetString(new byte[0])); - } - - public PKCS7DataData(ASN1OctetString data) { - this.data = data; - } - - public int getType() { - return ASN1Registry.NID_pkcs7_data; - } - - @Override - public void setData(ASN1OctetString data) { - this.data = data; - } - - @Override - public ASN1OctetString getData() { - return this.data; - } - - @Override - public boolean isData() { - return true; - } - - @Override - public String toString() { - return "#"; - } - - /** - * Data ::= OCTET STRING - */ - public static PKCS7DataData fromASN1(DEREncodable content) { - if(content == null) { - return new PKCS7DataData(); - } - return new PKCS7DataData((ASN1OctetString)content); - } - - @Override - public ASN1Encodable asASN1() { - if(data == null) { - return new DEROctetString(new byte[0]).toASN1Object(); - } - return data.toASN1Object(); - } -}// PKCS7DataData diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataDigest.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataDigest.java deleted file mode 100644 index 7395d23..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataDigest.java +++ /dev/null @@ -1,64 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import org.bouncycastle.asn1.DEREncodable; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataDigest extends PKCS7Data { - /* NID_pkcs7_digest */ - private Digest digest; - - public PKCS7DataDigest() { - this.digest = new Digest(); - this.digest.setVersion(0); - } - - public int getType() { - return ASN1Registry.NID_pkcs7_digest; - } - - public Digest getDigest() { - return this.digest; - } - - public boolean isDigest() { - return true; - } - - public void setContent(PKCS7 p7) { - this.digest.setContents(p7); - } - - public static PKCS7DataDigest fromASN1(DEREncodable content) { - throw new UnsupportedOperationException("TODO: can't create DataDigest from ASN1 yet"); - } -}// PKCS7DataDigest diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataEncrypted.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataEncrypted.java deleted file mode 100644 index 2a685ea..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataEncrypted.java +++ /dev/null @@ -1,61 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import org.bouncycastle.asn1.DEREncodable; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataEncrypted extends PKCS7Data { - /* NID_pkcs7_encrypted */ - private Encrypt encrypted; - - public PKCS7DataEncrypted() { - this.encrypted = new Encrypt(); - this.encrypted.setVersion(0); - this.encrypted.getEncData().setContentType(ASN1Registry.NID_pkcs7_data); - } - - public int getType() { - return ASN1Registry.NID_pkcs7_encrypted; - } - - public Encrypt getEncrypted() { - return this.encrypted; - } - - public boolean isEncrypted() { - return true; - } - - public static PKCS7DataEncrypted fromASN1(DEREncodable content) { - throw new UnsupportedOperationException("TODO: can't create DataEncrypted from ASN1 yet"); - } -}// PKCS7DataEncrypted diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataEnveloped.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataEnveloped.java deleted file mode 100644 index 84d099e..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataEnveloped.java +++ /dev/null @@ -1,89 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.DEREncodable; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataEnveloped extends PKCS7Data { - /* NID_pkcs7_enveloped */ - private Envelope enveloped; - - public PKCS7DataEnveloped() { - this.enveloped = new Envelope(); - this.enveloped.setVersion(0); - this.enveloped.getEncData().setContentType(ASN1Registry.NID_pkcs7_data); - } - - public PKCS7DataEnveloped(Envelope enveloped) { - this.enveloped = enveloped; - } - - public int getType() { - return ASN1Registry.NID_pkcs7_enveloped; - } - - @Override - public Envelope getEnveloped() { - return this.enveloped; - } - - @Override - public boolean isEnveloped() { - return true; - } - - @Override - public void setCipher(CipherSpec cipher) { - this.enveloped.getEncData().setCipher(cipher); - } - - @Override - public void addRecipientInfo(RecipInfo ri) { - this.enveloped.getRecipientInfo().add(ri); - } - - @Override - public String toString() { - return this.enveloped.toString(); - } - - public static PKCS7DataEnveloped fromASN1(DEREncodable content) { - return new PKCS7DataEnveloped(Envelope.fromASN1(content)); - } - - @Override - public ASN1Encodable asASN1() { - return enveloped.asASN1(); - } -}// PKCS7DataEnveloped diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataSigned.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataSigned.java deleted file mode 100644 index fb41f1d..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataSigned.java +++ /dev/null @@ -1,134 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.security.cert.X509CRL; -import java.util.Collection; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.DEREncodable; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataSigned extends PKCS7Data { - /* NID_pkcs7_signed */ - private Signed sign; - - public PKCS7DataSigned() { - this.sign = new Signed(); - this.sign.setVersion(1); - } - - public PKCS7DataSigned(Signed sign) { - this.sign = sign; - } - - public int getType() { - return ASN1Registry.NID_pkcs7_signed; - } - - @Override - public Object ctrl(int cmd, Object v, Object ignored) { - int ret = 0; - switch(cmd) { - case PKCS7.OP_SET_DETACHED_SIGNATURE: - ret = ((Integer)v).intValue(); - if(ret != 0 && sign.contents.isData()) { - sign.contents.setData(null); - } - break; - case PKCS7.OP_GET_DETACHED_SIGNATURE: - if(sign == null || sign.contents.getData() == null) { - ret = 1; - } else { - ret = 0; - } - break; - default: - throw new RuntimeException("TODO: implement error handling"); - } - return Integer.valueOf(ret); - } - - @Override - public void setSign(Signed sign) { - this.sign = sign; - } - - @Override - public Signed getSign() { - return this.sign; - } - - @Override - public boolean isSigned() { - return true; - } - - @Override - public void addSigner(SignerInfoWithPkey psi) { - this.sign.getMdAlgs().add(psi.getDigestAlgorithm()); - this.sign.getSignerInfo().add(psi); - } - - @Override - public void setContent(PKCS7 p7) { - this.sign.setContents(p7); - } - - @Override - public Collection getSignerInfo() { - return this.sign.getSignerInfo(); - } - - @Override - public void addCertificate(X509AuxCertificate cert) { - this.sign.getCert().add(cert); - } - - @Override - public void addCRL(X509CRL crl) { - this.sign.getCrl().add(crl); - } - - @Override - public String toString() { - return this.sign.toString(); - } - - public static PKCS7DataSigned fromASN1(DEREncodable content) throws PKCS7Exception { - return new PKCS7DataSigned(Signed.fromASN1(content)); - } - - @Override - public ASN1Encodable asASN1() { - return sign.asASN1(); - } -}// PKCS7DataSigned diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7DataSignedAndEnveloped.java b/src/java/org/jruby/ext/openssl/impl/PKCS7DataSignedAndEnveloped.java deleted file mode 100644 index 9664da0..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7DataSignedAndEnveloped.java +++ /dev/null @@ -1,97 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.security.cert.X509CRL; -import java.util.Collection; -import org.bouncycastle.asn1.DEREncodable; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** - * - * @author Ola Bini - */ -public class PKCS7DataSignedAndEnveloped extends PKCS7Data { - /* NID_pkcs7_signedAndEnveloped */ - private SignEnvelope signedAndEnveloped; - - public PKCS7DataSignedAndEnveloped() { - this.signedAndEnveloped = new SignEnvelope(); - this.signedAndEnveloped.setVersion(1); - this.signedAndEnveloped.getEncData().setContentType(ASN1Registry.NID_pkcs7_data); - } - - public int getType() { - return ASN1Registry.NID_pkcs7_signedAndEnveloped; - } - - @Override - public boolean isSignedAndEnveloped() { - return true; - } - - @Override - public SignEnvelope getSignedAndEnveloped() { - return signedAndEnveloped; - } - - @Override - public void setCipher(CipherSpec cipher) { - this.signedAndEnveloped.getEncData().setCipher(cipher); - } - - @Override - public void addRecipientInfo(RecipInfo ri) { - this.signedAndEnveloped.getRecipientInfo().add(ri); - } - - @Override - public void addSigner(SignerInfoWithPkey psi) { - this.signedAndEnveloped.getMdAlgs().add(psi.getDigestAlgorithm()); - this.signedAndEnveloped.getSignerInfo().add(psi); - } - - @Override - public Collection getSignerInfo() { - return this.signedAndEnveloped.getSignerInfo(); - } - - @Override - public void addCertificate(X509AuxCertificate cert) { - this.signedAndEnveloped.getCert().add(cert); - } - - @Override - public void addCRL(X509CRL crl) { - this.signedAndEnveloped.getCrl().add(crl); - } - - public static PKCS7DataSignedAndEnveloped fromASN1(DEREncodable content) { - throw new UnsupportedOperationException("TODO: can't create DataSignedAndEnveloped from ASN1 yet"); - } -}// PKCS7DataSignedAndEnveloped diff --git a/src/java/org/jruby/ext/openssl/impl/PKCS7Exception.java b/src/java/org/jruby/ext/openssl/impl/PKCS7Exception.java deleted file mode 100644 index 3efcaff..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKCS7Exception.java +++ /dev/null @@ -1,70 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** - * - * @author Ola Bini - */ -public class PKCS7Exception extends Exception { - private static final long serialVersionUID = 1L; - - private int method; - private int reason; - private String errorData; - - public PKCS7Exception(int method, int reason) { - this(method, reason, ""+null); - } - - public PKCS7Exception(int method, int reason, String errorData) { - super("PKCS7[Method: " + method + ", Reason: " + reason + ", Data: " + errorData + "]"); - this.method = method; - this.reason = reason; - this.errorData = errorData; - } - - public PKCS7Exception(int method, int reason, Throwable cause) { - super("PKCS7[Method: " + method + ", Reason: " + reason + "]", cause); - this.method = method; - this.reason = reason; - this.errorData = cause.getMessage(); - } - - public int getMethod() { - return this.method; - } - - public int getReason() { - return this.reason; - } - - public String getErrorData() { - return this.errorData; - } -}// PKCS7Exception diff --git a/src/java/org/jruby/ext/openssl/impl/PKey.java b/src/java/org/jruby/ext/openssl/impl/PKey.java deleted file mode 100644 index 02396ce..0000000 --- a/src/java/org/jruby/ext/openssl/impl/PKey.java +++ /dev/null @@ -1,257 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2010 Hiroshi Nakamura - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.KeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPublicKeySpec; - -import javax.crypto.spec.DHParameterSpec; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERSequence; -import org.jruby.util.ByteList; - -/** - * - * Handles PKey related ASN.1 handling. - * - * @author Hiroshi Nakamura - */ -public class PKey { - - public static KeyPair readPrivateKey(byte[] input, String type) throws IOException, GeneralSecurityException { - KeySpec pubSpec = null; - KeySpec privSpec = null; - ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(input).readObject(); - if (type.equals("RSA")) { - DERInteger mod = (DERInteger) seq.getObjectAt(1); - DERInteger pubExp = (DERInteger) seq.getObjectAt(2); - DERInteger privExp = (DERInteger) seq.getObjectAt(3); - DERInteger p1 = (DERInteger) seq.getObjectAt(4); - DERInteger p2 = (DERInteger) seq.getObjectAt(5); - DERInteger exp1 = (DERInteger) seq.getObjectAt(6); - DERInteger exp2 = (DERInteger) seq.getObjectAt(7); - DERInteger crtCoef = (DERInteger) seq.getObjectAt(8); - pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue()); - privSpec = new RSAPrivateCrtKeySpec(mod.getValue(), pubExp.getValue(), privExp.getValue(), p1.getValue(), p2.getValue(), exp1.getValue(), - exp2.getValue(), crtCoef.getValue()); - } else { // assume "DSA" for now. - DERInteger p = (DERInteger) seq.getObjectAt(1); - DERInteger q = (DERInteger) seq.getObjectAt(2); - DERInteger g = (DERInteger) seq.getObjectAt(3); - DERInteger y = (DERInteger) seq.getObjectAt(4); - DERInteger x = (DERInteger) seq.getObjectAt(5); - privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue()); - pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue()); - } - KeyFactory fact = KeyFactory.getInstance(type); - return new KeyPair(fact.generatePublic(pubSpec), fact.generatePrivate(privSpec)); - } - - // d2i_PrivateKey_bio - public static KeyPair readPrivateKey(byte[] input) throws IOException, GeneralSecurityException { - KeyPair key = null; - try { - key = readRSAPrivateKey(input); - } catch (Exception e) { - // ignore - } - if (key == null) { - try { - key = readDSAPrivateKey(input); - } catch (Exception e) { - // ignore - } - } - return key; - } - - // d2i_PUBKEY_bio - public static PublicKey readPublicKey(byte[] input) throws IOException, GeneralSecurityException { - PublicKey key = null; - try { - key = readRSAPublicKey(input); - } catch (Exception e) { - // ignore - } - if (key == null) { - try { - key = readDSAPublicKey(input); - } catch (Exception e) { - // ignore - } - } - return key; - } - - // d2i_RSAPrivateKey_bio - public static KeyPair readRSAPrivateKey(byte[] input) throws IOException, GeneralSecurityException { - KeyFactory fact = KeyFactory.getInstance("RSA"); - DERSequence seq = (DERSequence) (new ASN1InputStream(input).readObject()); - if (seq.size() == 9) { - BigInteger mod = ((DERInteger) seq.getObjectAt(1)).getValue(); - BigInteger pubexp = ((DERInteger) seq.getObjectAt(2)).getValue(); - BigInteger privexp = ((DERInteger) seq.getObjectAt(3)).getValue(); - BigInteger primep = ((DERInteger) seq.getObjectAt(4)).getValue(); - BigInteger primeq = ((DERInteger) seq.getObjectAt(5)).getValue(); - BigInteger primeep = ((DERInteger) seq.getObjectAt(6)).getValue(); - BigInteger primeeq = ((DERInteger) seq.getObjectAt(7)).getValue(); - BigInteger crtcoeff = ((DERInteger) seq.getObjectAt(8)).getValue(); - PrivateKey priv = fact.generatePrivate(new RSAPrivateCrtKeySpec(mod, pubexp, privexp, primep, primeq, primeep, primeeq, crtcoeff)); - PublicKey pub = fact.generatePublic(new RSAPublicKeySpec(mod, pubexp)); - return new KeyPair(pub, priv); - } else { - return null; - } - } - - // d2i_RSAPublicKey_bio - public static PublicKey readRSAPublicKey(byte[] input) throws IOException, GeneralSecurityException { - KeyFactory fact = KeyFactory.getInstance("RSA"); - DERSequence seq = (DERSequence) (new ASN1InputStream(input).readObject()); - if (seq.size() == 2) { - BigInteger mod = ((DERInteger) seq.getObjectAt(0)).getValue(); - BigInteger pubexp = ((DERInteger) seq.getObjectAt(1)).getValue(); - return fact.generatePublic(new RSAPublicKeySpec(mod, pubexp)); - } else { - return null; - } - } - - // d2i_DSAPrivateKey_bio - public static KeyPair readDSAPrivateKey(byte[] input) throws IOException, GeneralSecurityException { - KeyFactory fact = KeyFactory.getInstance("DSA"); - DERSequence seq = (DERSequence) (new ASN1InputStream(input).readObject()); - if (seq.size() == 6) { - BigInteger p = ((DERInteger) seq.getObjectAt(1)).getValue(); - BigInteger q = ((DERInteger) seq.getObjectAt(2)).getValue(); - BigInteger g = ((DERInteger) seq.getObjectAt(3)).getValue(); - BigInteger y = ((DERInteger) seq.getObjectAt(4)).getValue(); - BigInteger x = ((DERInteger) seq.getObjectAt(5)).getValue(); - PrivateKey priv = fact.generatePrivate(new DSAPrivateKeySpec(x, p, q, g)); - PublicKey pub = fact.generatePublic(new DSAPublicKeySpec(y, p, q, g)); - return new KeyPair(pub, priv); - } else { - return null; - } - } - - // d2i_DSA_PUBKEY_bio - public static PublicKey readDSAPublicKey(byte[] input) throws IOException, GeneralSecurityException { - KeyFactory fact = KeyFactory.getInstance("RSA"); - DERSequence seq = (DERSequence) (new ASN1InputStream(input).readObject()); - if (seq.size() == 4) { - BigInteger y = ((DERInteger) seq.getObjectAt(0)).getValue(); - BigInteger p = ((DERInteger) seq.getObjectAt(1)).getValue(); - BigInteger q = ((DERInteger) seq.getObjectAt(2)).getValue(); - BigInteger g = ((DERInteger) seq.getObjectAt(3)).getValue(); - return fact.generatePublic(new DSAPublicKeySpec(y, p, q, g)); - } else { - return null; - } - } - - // d2i_DHparams_bio - public static DHParameterSpec readDHParameter(byte[] input) throws IOException { - ASN1InputStream aIn = new ASN1InputStream(input); - ASN1Sequence seq = (ASN1Sequence) aIn.readObject(); - BigInteger p = ((DERInteger) seq.getObjectAt(0)).getValue(); - BigInteger g = ((DERInteger) seq.getObjectAt(1)).getValue(); - return new DHParameterSpec(p, g); - } - - public static byte[] toDerRSAKey(RSAPublicKey pubKey, RSAPrivateCrtKey privKey) throws IOException { - ASN1EncodableVector v1 = new ASN1EncodableVector(); - if (pubKey != null && privKey == null) { - v1.add(new DERInteger(pubKey.getModulus())); - v1.add(new DERInteger(pubKey.getPublicExponent())); - } else { - v1.add(new DERInteger(0)); - v1.add(new DERInteger(privKey.getModulus())); - v1.add(new DERInteger(privKey.getPublicExponent())); - v1.add(new DERInteger(privKey.getPrivateExponent())); - v1.add(new DERInteger(privKey.getPrimeP())); - v1.add(new DERInteger(privKey.getPrimeQ())); - v1.add(new DERInteger(privKey.getPrimeExponentP())); - v1.add(new DERInteger(privKey.getPrimeExponentQ())); - v1.add(new DERInteger(privKey.getCrtCoefficient())); - } - return new DERSequence(v1).getEncoded(); - } - - public static byte[] toDerDSAKey(DSAPublicKey pubKey, DSAPrivateKey privKey) throws IOException { - if (pubKey != null && privKey == null) { - return pubKey.getEncoded(); - } else if (privKey != null && pubKey != null) { - DSAParams params = privKey.getParams(); - ASN1EncodableVector v1 = new ASN1EncodableVector(); - v1.add(new DERInteger(0)); - v1.add(new DERInteger(params.getP())); - v1.add(new DERInteger(params.getQ())); - v1.add(new DERInteger(params.getG())); - v1.add(new DERInteger(pubKey.getY())); - v1.add(new DERInteger(privKey.getX())); - return new DERSequence(v1).getEncoded(); - } else { - return privKey.getEncoded(); - } - } - - public static byte[] toDerDHKey(BigInteger p, BigInteger g) throws IOException { - ASN1EncodableVector v = new ASN1EncodableVector(); - if (p != null) { - v.add(new DERInteger(p)); - } - if (g != null) { - v.add(new DERInteger(g)); - } - return new DERSequence(v).getEncoded(); - } -} - - diff --git a/src/java/org/jruby/ext/openssl/impl/RecipInfo.java b/src/java/org/jruby/ext/openssl/impl/RecipInfo.java deleted file mode 100644 index 008c833..0000000 --- a/src/java/org/jruby/ext/openssl/impl/RecipInfo.java +++ /dev/null @@ -1,245 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.X509Name; -import org.jruby.ext.openssl.x509store.Name; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** PKCS7_RECIP_INFO - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class RecipInfo { - private int version; - private IssuerAndSerialNumber issuerAndSerial; - private AlgorithmIdentifier keyEncAlgor; - private ASN1OctetString encKey; - - /** - * Describe cert here. - */ - private X509AuxCertificate cert; - - /** c: PKCS7_RECIP_INFO_set - * - */ - public void set(X509AuxCertificate cert) throws PKCS7Exception { - version = 0; - try { - X509Name issuer = X509Name.getInstance(new ASN1InputStream(new ByteArrayInputStream(cert.getIssuerX500Principal().getEncoded())).readObject()); - BigInteger serial = cert.getSerialNumber(); - issuerAndSerial = new IssuerAndSerialNumber(issuer, serial); - String algo = addEncryptionIfNeeded(cert.getPublicKey().getAlgorithm()); - keyEncAlgor = new AlgorithmIdentifier(ASN1Registry.sym2oid(algo)); - this.cert = cert; - } catch(IOException e) { - throw new PKCS7Exception(-1, -1, e); - } - } - - private String addEncryptionIfNeeded(String input) { - input = input.toLowerCase(); - if(input.equals("rsa")) { - return input + "Encryption"; - } else if(input.equals("dsa")) { - return input + "Encryption"; - } - return input; - } - - @Override - public boolean equals(Object other) { - boolean ret = this == other; - if(!ret && (other instanceof RecipInfo)) { - RecipInfo o = (RecipInfo)other; - ret = - this.version == o.version && - (this.issuerAndSerial == null ? o.issuerAndSerial == null : (this.issuerAndSerial.equals(o.issuerAndSerial))) && - (this.keyEncAlgor == null ? o.keyEncAlgor == null : (this.keyEncAlgor.equals(o.keyEncAlgor))) && - (this.encKey == null ? o.encKey == null : (this.encKey.equals(o.encKey))); - } - return ret; - } - - @Override - public int hashCode() { - int result = 31; - result = result + 13 * version; - result = result + ((issuerAndSerial == null) ? 0 : 13 * issuerAndSerial.hashCode()); - result = result + ((keyEncAlgor == null) ? 0 : 13 * keyEncAlgor.hashCode()); - result = result + ((encKey == null) ? 0 : 13 * encKey.hashCode()); - return result; - } - - @Override - public String toString() { - return "#"; - } - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the IssuerAndSerial value. - * - * @return an IssuerAndSerialNumber value - */ - public final IssuerAndSerialNumber getIssuerAndSerial() { - return issuerAndSerial; - } - - /** - * Set the IssuerAndSerial value. - * - * @param newIssuerAndSerial The new IssuerAndSerial value. - */ - public final void setIssuerAndSerial(final IssuerAndSerialNumber newIssuerAndSerial) { - this.issuerAndSerial = newIssuerAndSerial; - } - - /** - * Get the KeyEncAlgor value. - * - * @return an AlgorithmIdentifier value - */ - public final AlgorithmIdentifier getKeyEncAlgor() { - return keyEncAlgor; - } - - /** - * Set the KeyEncAlgor value. - * - * @param newKeyEncAlgor The new KeyEncAlgor value. - */ - public final void setKeyEncAlgor(final AlgorithmIdentifier newKeyEncAlgor) { - this.keyEncAlgor = newKeyEncAlgor; - } - - /** - * Get the EncKey value. - * - * @return an ASN1OctetString value - */ - public final ASN1OctetString getEncKey() { - return encKey; - } - - /** - * Set the EncKey value. - * - * @param newEncKey The new EncKey value. - */ - public final void setEncKey(final ASN1OctetString newEncKey) { - this.encKey = newEncKey; - } - - /** - * Get the Cert value. - * - * @return a X509AuxCertificate value - */ - public final X509AuxCertificate getCert() { - return cert; - } - - /** - * Set the Cert value. - * - * @param newCert The new Cert value. - */ - public final void setCert(final X509AuxCertificate newCert) { - this.cert = newCert; - } - - /* c: static pkcs7_cmp_ri - * - */ - public boolean compare(X509AuxCertificate pcert) { - if(!new Name(issuerAndSerial.getName()).isEqual(pcert.getIssuerX500Principal())) { - return false; - } - return pcert.getSerialNumber().compareTo(issuerAndSerial.getCertificateSerialNumber().getValue()) == 0; - } - - /** - * RecipientInfo ::= SEQUENCE { - * version Version, - * issuerAndSerialNumber IssuerAndSerialNumber, - * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * encryptedKey EncryptedKey } - * - * EncryptedKey ::= OCTET STRING - */ - public static RecipInfo fromASN1(DEREncodable content) { - DERSequence sequence = (DERSequence)content; - RecipInfo ri = new RecipInfo(); - ri.setVersion(((DERInteger)sequence.getObjectAt(0)).getValue().intValue()); - ri.setIssuerAndSerial(IssuerAndSerialNumber.getInstance(sequence.getObjectAt(1))); - ri.setKeyEncAlgor(AlgorithmIdentifier.getInstance(sequence.getObjectAt(2))); - ri.setEncKey((ASN1OctetString)sequence.getObjectAt(3)); - return ri; - } - - public ASN1Encodable asASN1() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - vector.add(new DERInteger(getVersion())); - vector.add(issuerAndSerial.toASN1Object()); - vector.add(keyEncAlgor.toASN1Object()); - vector.add(encKey.toASN1Object()); - return new DERSequence(vector); - } -}// RecipInfo diff --git a/src/java/org/jruby/ext/openssl/impl/SMIME.java b/src/java/org/jruby/ext/openssl/impl/SMIME.java deleted file mode 100644 index c18ecec..0000000 --- a/src/java/org/jruby/ext/openssl/impl/SMIME.java +++ /dev/null @@ -1,280 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** SMIME methods for PKCS7 - * - * @author Ola Bini - */ -public class SMIME { - public final static int MAX_SMLEN = 1024; - public final static byte[] NEWLINE = new byte[]{'\r','\n'}; - - private Mime mime; - - public SMIME() { - this(Mime.DEFAULT); - } - - public SMIME(Mime mime) { - this.mime = mime; - } - - private static boolean equals(byte[] first, int firstIndex, byte[] second, int secondIndex, int length) { - int len = length; - for(int i=firstIndex, - j=secondIndex, - flen=first.length, - slen=second.length; - i0; - i++, j++, len--) { - - if(first[i] != second[j]) { - return false; - } - } - return len == 0; - } - - /* c: static strip_eol - * - */ - public static boolean stripEol(byte[] linebuf, int[] plen) { - int len = plen[0]; - boolean isEol = false; - - for(int p = len - 1; len > 0; len--, p--) { - byte c = linebuf[p]; - if(c == '\n') { - isEol = true; - } else if(c != '\r') { - break; - } - - } - plen[0] = len; - return isEol; - } - - - /* c: SMIME_text - * - */ - public void text(BIO input, BIO output) { -// char iobuf[4096]; -// int len; -// STACK_OF(MIME_HEADER) *headers; -// MIME_HEADER *hdr; - -// if (!(headers = mime_parse_hdr(in))) { -// PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_PARSE_ERROR); -// return 0; -// } -// if(!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) { -// PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_MIME_NO_CONTENT_TYPE); -// sk_MIME_HEADER_pop_free(headers, mime_hdr_free); -// return 0; -// } -// if (strcmp (hdr->value, "text/plain")) { -// PKCS7err(PKCS7_F_SMIME_TEXT,PKCS7_R_INVALID_MIME_TYPE); -// ERR_add_error_data(2, "type: ", hdr->value); -// sk_MIME_HEADER_pop_free(headers, mime_hdr_free); -// return 0; -// } -// sk_MIME_HEADER_pop_free(headers, mime_hdr_free); -// while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0) -// BIO_write(out, iobuf, len); -// return 1; - } - - /* c: static mime_bound_check - * - */ - private int boundCheck(byte[] line, int linelen, byte[] bound, int blen) { - if(linelen == -1) { - linelen = line.length; - } - - if(blen == -1) { - blen = bound.length; - } - - // Quickly eliminate if line length too short - if(blen + 2 > linelen) { - return 0; - } - - if(line[0] == '-' && - line[1] == '-' && - equals(line, 2, bound, 0, blen)) { - if(line.length>=(blen+4) && - line[2 + blen] == '-' && - line[2 + blen + 1] == '-') { - return 2; - } else { - return 1; - } - } - return 0; - } - - /* c: B64_read_PKCS7 - * - */ - public PKCS7 readPKCS7Base64(BIO bio) throws IOException, PKCS7Exception { - BIO bio64 = BIO.base64Filter(bio); - return PKCS7.fromASN1(bio64); - } - - /* c: static multi_split - * - */ - private List multiSplit(BIO bio, byte[] bound) throws IOException { - List parts = new ArrayList(); - byte[] linebuf = new byte[MAX_SMLEN]; - int blen = bound.length; - boolean eol = false; - int len = 0; - int part = 0; - int state = 0; - boolean first = true; - BIO bpart = null; - - while((len = bio.gets(linebuf, MAX_SMLEN)) > 0) { - state = boundCheck(linebuf, len, bound, blen); - if(state == 1) { - first = true; - part++; - } else if(state == 2) { - parts.add(bpart); - return parts; - } else if(part != 0) { - // strip CR+LF from linebuf - int[] tmp = new int[] {len}; - boolean nextEol = stripEol(linebuf, tmp); - len = tmp[0]; - - if(first) { - first = false; - if(bpart != null) { - parts.add(bpart); - } - bpart = BIO.mem(); - bpart.setMemEofReturn(0); - } else if(eol) { - bpart.write(NEWLINE, 0, 2); - } - eol = nextEol; - if(len != 0) { - bpart.write(linebuf, 0, len); - } - } - } - - return parts; - } - - /* c: SMIME_read_PKCS7 - * - */ - public PKCS7 readPKCS7(BIO bio, BIO[] bcont) throws IOException, PKCS7Exception { - if(bcont != null && bcont.length > 0) { - bcont[0] = null; - } - - List headers = mime.parseHeaders(bio); - if(headers == null) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_MIME_PARSE_ERROR); - } - - MimeHeader hdr = mime.findHeader(headers, "content-type"); - if(hdr == null || hdr.getValue() == null) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_NO_CONTENT_TYPE); - } - - if("multipart/signed".equals(hdr.getValue())) { - MimeParam prm = mime.findParam(hdr, "boundary"); - if(prm == null || prm.getParamValue() == null) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_NO_MULTIPART_BOUNDARY); - } - - byte[] boundary = null; - try { - boundary = prm.getParamValue().getBytes("ISO8859-1"); - } catch(Exception e) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_NO_MULTIPART_BOUNDARY, e); - } - - List parts = multiSplit(bio, boundary); - if(parts == null || parts.size() != 2) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_NO_MULTIPART_BODY_FAILURE); - } - - BIO p7in = parts.get(1); - - headers = mime.parseHeaders(p7in); - - if(headers == null) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_MIME_SIG_PARSE_ERROR); - } - - hdr = mime.findHeader(headers, "content-type"); - if(hdr == null || hdr.getValue() == null) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_NO_SIG_CONTENT_TYPE); - } - - if(!"application/x-pkcs7-signature".equals(hdr.getValue()) && - !"application/pkcs7-signature".equals(hdr.getValue()) && - !"application/x-pkcs7-mime".equals(hdr.getValue()) && - !"application/pkcs7-mime".equals(hdr.getValue())) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_SIG_INVALID_MIME_TYPE, "type: " + hdr.getValue()); - } - - PKCS7 p7 = readPKCS7Base64(p7in); - - if(bcont != null && bcont.length>0) { - bcont[0] = parts.get(0); - } - - return p7; - } - - if(!"application/x-pkcs7-mime".equals(hdr.getValue()) && - !"application/pkcs7-mime".equals(hdr.getValue())) { - throw new PKCS7Exception(PKCS7.F_SMIME_READ_PKCS7, PKCS7.R_INVALID_MIME_TYPE, "type: " + hdr.getValue()); - } - - return readPKCS7Base64(bio); - } -} diff --git a/src/java/org/jruby/ext/openssl/impl/SignEnvelope.java b/src/java/org/jruby/ext/openssl/impl/SignEnvelope.java deleted file mode 100644 index 42dde27..0000000 --- a/src/java/org/jruby/ext/openssl/impl/SignEnvelope.java +++ /dev/null @@ -1,200 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.security.cert.X509CRL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** PKCS7_SIGN_ENVELOPE - * - * @author Ola Bini - */ -public class SignEnvelope { - private int version; - - /** - * Describe encContent here. - */ - private EncContent encData = new EncContent(); - - /** - * Describe crl here. - */ - private Collection crl = new ArrayList(); - - /** - * Describe cert here. - */ - private Collection cert = new ArrayList(); - - /** - * Describe mdAlgs here. - */ - private Set mdAlgs = new HashSet(); - - /** - * Describe signerInfo here. - */ - private Collection signerInfo = new ArrayList(); - - /** - * Describe recipientInfo here. - */ - private Collection recipientInfo = new ArrayList(); - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the EncData value. - * - * @return an EncContent value - */ - public final EncContent getEncData() { - return encData; - } - - /** - * Set the EncData value. - * - * @param newEncContent The new EncContent value. - */ - public final void setEncData(final EncContent newEncData) { - this.encData = newEncData; - } - - /** - * Get the RecipientInfo value. - * - * @return a Collection value - */ - public final Collection getRecipientInfo() { - return recipientInfo; - } - - /** - * Set the RecipientInfo value. - * - * @param newRecipientInfo The new RecipientInfo value. - */ - public final void setRecipientInfo(final Collection newRecipientInfo) { - this.recipientInfo = newRecipientInfo; - } - - /** - * Get the SignerInfoWithPkey value. - * - * @return a Collection value - */ - public final Collection getSignerInfo() { - return signerInfo; - } - - /** - * Set the SignerInfoWithPkey value. - * - * @param newSignerInfo The new SignerInfo value. - */ - public final void setSignerInfo(final Collection newSignerInfo) { - this.signerInfo = newSignerInfo; - } - - /** - * Get the MdAlgs value. - * - * @return a Set value - */ - public final Set getMdAlgs() { - return mdAlgs; - } - - /** - * Set the MdAlgs value. - * - * @param newMdAlgs The new MdAlgs value. - */ - public final void setMdAlgs(final Set newMdAlgs) { - this.mdAlgs = newMdAlgs; - } - - /** - * Get the Cert value. - * - * @return a Collection value - */ - public final Collection getCert() { - return cert; - } - - /** - * Set the Cert value. - * - * @param newCert The new Cert value. - */ - public final void setCert(final Collection newCert) { - this.cert = newCert; - } - - /** - * Get the Crl value. - * - * @return a Collection value - */ - public final Collection getCrl() { - return crl; - } - - /** - * Set the Crl value. - * - * @param newCrl The new Crl value. - */ - public final void setCrl(final Collection newCrl) { - this.crl = newCrl; - } -}// SignEnvelope diff --git a/src/java/org/jruby/ext/openssl/impl/Signed.java b/src/java/org/jruby/ext/openssl/impl/Signed.java deleted file mode 100644 index 2adac0d..0000000 --- a/src/java/org/jruby/ext/openssl/impl/Signed.java +++ /dev/null @@ -1,364 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.ByteArrayInputStream; -import java.security.cert.CertificateParsingException; -import java.security.cert.X509CRL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.X509CertificateStructure; -import org.bouncycastle.jce.provider.X509CertificateObject; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** PKCS7_SIGNED - * - * @author Ola Bini - */ -public class Signed { - /** - * Describe version here. - */ - private int version; - - /** - * Describe crl here. - */ - private Collection crl = new ArrayList(); - - /** - * Describe cert here. - */ - private Collection cert = new ArrayList(); - - /** - * Describe mdAlgs here. - */ - private Set mdAlgs = new HashSet(); - - /** - * Describe signerInfo here. - */ - private Collection signerInfo = new ArrayList(); - - PKCS7 contents; - - /** - * Get the Version value. - * - * @return an int value - */ - public final int getVersion() { - return version; - } - - /** - * Set the Version value. - * - * @param newVersion The new Version value. - */ - public final void setVersion(final int newVersion) { - this.version = newVersion; - } - - /** - * Get the SignerInfo value. - * - * @return a Collection value - */ - public final Collection getSignerInfo() { - return signerInfo; - } - - /** - * Set the SignerInfo value. - * - * @param newSignerInfo The new SignerInfo value. - */ - public final void setSignerInfo(final Collection newSignerInfo) { - this.signerInfo = newSignerInfo; - } - - /** - * Get the MdAlgs value. - * - * @return a Set value - */ - public final Set getMdAlgs() { - return mdAlgs; - } - - /** - * Set the MdAlgs value. - * - * @param newMdAlgs The new MdAlgs value. - */ - public final void setMdAlgs(final Set newMdAlgs) { - this.mdAlgs = newMdAlgs; - } - - /** - * Get the Contents value. - * - * @return a PKCS7 value - */ - public final PKCS7 getContents() { - return contents; - } - - /** - * Set the Contents value. - * - * @param newContents The new Contents value. - */ - public final void setContents(final PKCS7 newContents) { - this.contents = newContents; - } - - /** - * Get the Cert value. - * - * @return a Collection value - */ - public final Collection getCert() { - return cert; - } - - /** - * Set the Cert value. - * - * @param newCert The new Cert value. - */ - public final void setCert(final Collection newCert) { - this.cert = newCert; - } - - /** - * Get the Crl value. - * - * @return a Set value - */ - public final Collection getCrl() { - return crl; - } - - /** - * Set the Crl value. - * - * @param newCrl The new Crl value. - */ - public final void setCrl(final Collection newCrl) { - this.crl = newCrl; - } - - @Override - public String toString() { - return "#"; - } - - public ASN1Encodable asASN1() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - vector.add(new DERInteger(version)); - vector.add(digestAlgorithmsToASN1Set()); - vector.add(contents.asASN1()); - if (cert != null && cert.size() > 0) { - if (cert.size() > 1) { - vector.add(new DERTaggedObject(false, 0, certificatesToASN1Set())); - } else { - // Encode the signer certificate directly for OpenSSL compatibility. - // OpenSSL does not support multiple signer signature. - // And OpenSSL requires EXPLICIT tagging. - vector.add(new DERTaggedObject(true, 0, firstCertificatesToASN1())); - } - } - if (crl != null && crl.size() > 0) { - vector.add(new DERTaggedObject(false, 1, crlsToASN1Set())); - } - vector.add(signerInfosToASN1Set()); - return new DERSequence(vector); - } - - private ASN1Set digestAlgorithmsToASN1Set() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - for(AlgorithmIdentifier ai : mdAlgs) { - vector.add(ai.toASN1Object()); - } - return new DERSet(vector); - } - - // This imlementation is stupid and wasteful. Ouch. - private ASN1Set certificatesToASN1Set() { - try { - ASN1EncodableVector vector = new ASN1EncodableVector(); - for(X509AuxCertificate c : cert) { - vector.add(new ASN1InputStream(new ByteArrayInputStream(c.getEncoded())).readObject()); - } - return new DERSet(vector); - } catch(Exception e) { - return null; - } - } - - private DERSequence firstCertificatesToASN1() { - try { - X509AuxCertificate c = cert.iterator().next(); - return (DERSequence) (new ASN1InputStream(new ByteArrayInputStream(c.getEncoded())).readObject()); - } catch (Exception e) {} - return null; - } - - private ASN1Set crlsToASN1Set() { - throw new RuntimeException("TODO: implement CRL part"); - } - - private ASN1Set signerInfosToASN1Set() { - ASN1EncodableVector vector = new ASN1EncodableVector(); - for(SignerInfoWithPkey si : signerInfo) { - vector.add(si.toASN1Object()); - } - return new DERSet(vector); - } - - /** - * SignedData ::= SEQUENCE { - * version Version, - * digestAlgorithms DigestAlgorithmIdentifiers, - * contentInfo ContentInfo, - * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, - * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - * signerInfos SignerInfos } - * - * Version ::= INTEGER - * - * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - * - * SignerInfos ::= SET OF SignerInfo - */ - public static Signed fromASN1(DEREncodable content) throws PKCS7Exception{ - ASN1Sequence sequence = (ASN1Sequence)content; - DERInteger version = (DERInteger)sequence.getObjectAt(0); - ASN1Set digestAlgos = (ASN1Set)sequence.getObjectAt(1); - DEREncodable contentInfo = sequence.getObjectAt(2); - - DEREncodable certificates = null; - DEREncodable crls = null; - - int index = 3; - DEREncodable tmp = sequence.getObjectAt(index); - if((tmp instanceof DERTaggedObject) && ((DERTaggedObject)tmp).getTagNo() == 0) { - certificates = ((DERTaggedObject)tmp).getObject(); - index++; - } - - tmp = sequence.getObjectAt(index); - if((tmp instanceof DERTaggedObject) && ((DERTaggedObject)tmp).getTagNo() == 1) { - crls = ((DERTaggedObject)tmp).getObject(); - index++; - } - - ASN1Set signerInfos = (ASN1Set)sequence.getObjectAt(index); - - Signed signed = new Signed(); - signed.setVersion(version.getValue().intValue()); - signed.setMdAlgs(algorithmIdentifiersFromASN1Set(digestAlgos)); - signed.setContents(PKCS7.fromASN1(contentInfo)); - if(certificates != null) { - signed.setCert(certificatesFromASN1Set(certificates)); - } - if(crls != null) { - throw new RuntimeException("TODO: implement CRL part"); - } - signed.setSignerInfo(signerInfosFromASN1Set(signerInfos)); - - return signed; - } - - private static Collection certificatesFromASN1Set(DEREncodable content) throws PKCS7Exception { - Collection result = new ArrayList(); - if (content instanceof DERSequence) { - try { - for (Enumeration enm = ((DERSequence) content).getObjects(); enm.hasMoreElements();) { - DEREncodable current = (DEREncodable) enm.nextElement(); - result.add(certificateFromASN1(current)); - } - } catch (IllegalArgumentException iae) { - result.add(certificateFromASN1(content)); - } - } else if (content instanceof DERSet) { - // EXPLICIT Set shouldn't apper here but keep this for backward compatibility. - for (Enumeration enm = ((DERSet) content).getObjects(); enm.hasMoreElements();) { - DEREncodable current = (DEREncodable) enm.nextElement(); - result.add(certificateFromASN1(current)); - } - } else { - throw new PKCS7Exception(PKCS7.F_B64_READ_PKCS7, PKCS7.R_CERTIFICATE_VERIFY_ERROR, "unknown certificates format"); - } - return result; - } - - private static X509AuxCertificate certificateFromASN1(DEREncodable current) throws PKCS7Exception { - X509CertificateStructure struct = X509CertificateStructure.getInstance(current); - try { - return new X509AuxCertificate(new X509CertificateObject(struct)); - } catch (CertificateParsingException cpe) { - throw new PKCS7Exception(PKCS7.F_B64_READ_PKCS7, PKCS7.R_CERTIFICATE_VERIFY_ERROR, cpe); - } - } - - private static Set algorithmIdentifiersFromASN1Set(DEREncodable content) { - ASN1Set set = (ASN1Set)content; - Set result = new HashSet(); - for(Enumeration e = set.getObjects(); e.hasMoreElements();) { - result.add(AlgorithmIdentifier.getInstance(e.nextElement())); - } - return result; - } - - private static Collection signerInfosFromASN1Set(DEREncodable content) { - ASN1Set set = (ASN1Set)content; - Collection result = new ArrayList(); - for(Enumeration e = set.getObjects(); e.hasMoreElements();) { - result.add(SignerInfoWithPkey.getInstance(e.nextElement())); - } - return result; - } -}// Signed diff --git a/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java b/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java deleted file mode 100644 index 5ddc594..0000000 --- a/src/java/org/jruby/ext/openssl/impl/SignerInfoWithPkey.java +++ /dev/null @@ -1,365 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.PrivateKey; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.util.Enumeration; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber; -import org.bouncycastle.asn1.pkcs.SignerInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.X509Name; -import org.jruby.ext.openssl.x509store.X509AuxCertificate; - -/** - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class SignerInfoWithPkey extends ASN1Encodable { - private DERInteger version; - private IssuerAndSerialNumber issuerAndSerialNumber; - private AlgorithmIdentifier digAlgorithm; - private ASN1Set authenticatedAttributes; - private AlgorithmIdentifier digEncryptionAlgorithm; - private ASN1OctetString encryptedDigest; - private ASN1Set unauthenticatedAttributes; - - public static SignerInfoWithPkey getInstance(Object o) { - if(o instanceof SignerInfo) { - return (SignerInfoWithPkey)o; - } else if (o instanceof ASN1Sequence) { - return new SignerInfoWithPkey((ASN1Sequence)o); - } - - throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); - } - - public SignerInfoWithPkey dup() { - SignerInfoWithPkey copy = new SignerInfoWithPkey(version, - issuerAndSerialNumber, - digAlgorithm, - authenticatedAttributes, - digEncryptionAlgorithm, - encryptedDigest, - unauthenticatedAttributes); - copy.pkey = pkey; - return copy; - } - - SignerInfoWithPkey() { - } - - public SignerInfoWithPkey(DERInteger version, - IssuerAndSerialNumber issuerAndSerialNumber, - AlgorithmIdentifier digAlgorithm, - ASN1Set authenticatedAttributes, - AlgorithmIdentifier digEncryptionAlgorithm, - ASN1OctetString encryptedDigest, - ASN1Set unauthenticatedAttributes) { - this.version = version; - this.issuerAndSerialNumber = issuerAndSerialNumber; - this.digAlgorithm = digAlgorithm; - this.authenticatedAttributes = authenticatedAttributes; - this.digEncryptionAlgorithm = digEncryptionAlgorithm; - this.encryptedDigest = encryptedDigest; - this.unauthenticatedAttributes = unauthenticatedAttributes; - } - - public SignerInfoWithPkey(ASN1Sequence seq) { - Enumeration e = seq.getObjects(); - - version = (DERInteger)e.nextElement(); - issuerAndSerialNumber = IssuerAndSerialNumber.getInstance(e.nextElement()); - digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); - - Object obj = e.nextElement(); - - if(obj instanceof ASN1TaggedObject) { - authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false); - - digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); - } - else { - authenticatedAttributes = null; - digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj); - } - - encryptedDigest = ASN1OctetString.getInstance(e.nextElement()); - - if(e.hasMoreElements()) { - unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); - } - else { - unauthenticatedAttributes = null; - } - } - - public DERInteger getVersion() { - return version; - } - - public IssuerAndSerialNumber getIssuerAndSerialNumber() { - return issuerAndSerialNumber; - } - - public ASN1Set getAuthenticatedAttributes() { - return authenticatedAttributes; - } - - public AlgorithmIdentifier getDigestAlgorithm() { - return digAlgorithm; - } - - public ASN1OctetString getEncryptedDigest() { - return encryptedDigest; - } - - public AlgorithmIdentifier getDigestEncryptionAlgorithm() { - return digEncryptionAlgorithm; - } - - public ASN1Set getUnauthenticatedAttributes() { - return unauthenticatedAttributes; - } - - /* c: PKCS7_SIGNER_INFO_set - * - */ - public void set(X509AuxCertificate x509, PrivateKey pkey, MessageDigest dgst) throws PKCS7Exception { - boolean dsa = - (pkey instanceof DSAPrivateKey) || - (pkey instanceof ECPrivateKey); - - version = new DERInteger(1); - - try { - X509Name issuer = X509Name.getInstance(new ASN1InputStream(new ByteArrayInputStream(x509.getIssuerX500Principal().getEncoded())).readObject()); - BigInteger serial = x509.getSerialNumber(); - issuerAndSerialNumber = new IssuerAndSerialNumber(issuer, serial); - } catch(IOException e) { - throw new PKCS7Exception(-1, -1, e); - } - - this.pkey = pkey; - - if(dsa) { - digAlgorithm = new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_sha1)); - } else { - digAlgorithm = new AlgorithmIdentifier(ASN1Registry.nid2obj(EVP.type(dgst))); - } - - if(pkey instanceof RSAPrivateKey) { - digEncryptionAlgorithm = new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_rsaEncryption)); - } else if(pkey instanceof DSAPrivateKey) { - digEncryptionAlgorithm = new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_dsa)); - } else if(pkey instanceof ECPrivateKey) { - digEncryptionAlgorithm = new AlgorithmIdentifier(ASN1Registry.nid2obj(ASN1Registry.NID_ecdsa_with_SHA1)); - } - } - - /** - * Produce an object suitable for an ASN1OutputStream. - *

    -     *  SignerInfo ::= SEQUENCE {
    -     *      version Version,
    -     *      issuerAndSerialNumber IssuerAndSerialNumber,
    -     *      digestAlgorithm DigestAlgorithmIdentifier,
    -     *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
    -     *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
    -     *      encryptedDigest EncryptedDigest,
    -     *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
    -     *  }
    -     *
    -     *  EncryptedDigest ::= OCTET STRING
    -     *
    -     *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
    -     *
    -     *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
    -     * 
    - */ - public DERObject toASN1Object() { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(version); - v.add(issuerAndSerialNumber); - v.add(digAlgorithm); - - if (authenticatedAttributes != null) { - v.add(new DERTaggedObject(false, 0, authenticatedAttributes)); - } - - v.add(digEncryptionAlgorithm); - v.add(encryptedDigest); - - if (unauthenticatedAttributes != null) { - v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); - } - - return new DERSequence(v); - } - - /** - * Describe pkey here. - */ - private PrivateKey pkey; - - /** - * Get the Pkey value. - * - * @return a PrivateKey value - */ - public final PrivateKey getPkey() { - return pkey; - } - - /** - * Set the Pkey value. - * - * @param newPkey The new Pkey value. - */ - public final void setPkey(final PrivateKey newPkey) { - this.pkey = newPkey; - } - - public void setAuthenticatedAttributes(ASN1Set authAttr) { - this.authenticatedAttributes = authAttr; - } - - public void setUnauthenticatedAttributes(ASN1Set unauthAttr) { - this.unauthenticatedAttributes = unauthAttr; - } - - public void setEncryptedDigest(ASN1OctetString encryptedDigest) { - this.encryptedDigest = encryptedDigest; - } - - /** c: PKCS7_get_signed_attribute - * - */ - public DEREncodable getSignedAttribute(int nid) { - return getAttribute(this.authenticatedAttributes, nid); - } - - /** c: PKCS7_get_attribute - * - */ - public DEREncodable getAttribute(int nid) { - return getAttribute(this.unauthenticatedAttributes, nid); - } - - /** c: static get_attribute - * - */ - public static DEREncodable getAttribute(ASN1Set sk, int nid) { - Attribute xa = null; - DERObjectIdentifier o = ASN1Registry.nid2obj(nid); - - if(null == o || null == sk) { - return null; - } - - for(Enumeration e = sk.getObjects(); e.hasMoreElements();) { - Object val = e.nextElement(); - if(val instanceof Attribute) { - xa = (Attribute)val; - } else { - xa = Attribute.getInstance(val); - } - - if(o.equals(xa.getAttrType())) { - if(xa.getAttrValues().size() > 0) { - return xa.getAttrValues().getObjectAt(0); - } else { - return null; - } - } - } - return null; - } - - /** c: PKCS7_add_signed_attribute - * - */ - public void addSignedAttribute(int atrType, DEREncodable value) { - this.authenticatedAttributes = addAttribute(this.authenticatedAttributes, atrType, value); - } - - /** c: PKCS7_add_attribute - * - */ - public void addAttribute(int atrType, DEREncodable value) { - this.unauthenticatedAttributes = addAttribute(this.unauthenticatedAttributes, atrType, value); - } - - /** c: static add_attribute - * - */ - private ASN1Set addAttribute(ASN1Set base, int atrType, DEREncodable value) { - ASN1EncodableVector vector = new ASN1EncodableVector(); - if(base == null) { - base = new DERSet(); - } - Attribute attr = null; - for(Enumeration e = base.getObjects(); e.hasMoreElements();) { - Object val = e.nextElement(); - if(val instanceof Attribute) { - attr = (Attribute)val; - } else { - attr = Attribute.getInstance(val); - } - if(ASN1Registry.obj2nid(attr.getAttrType()) != atrType) { - vector.add(attr); - } - } - attr = new Attribute(ASN1Registry.nid2obj(atrType), new DERSet(value)); - vector.add(attr); - return new DERSet(vector); - } -}// SignerInfoWithPkey diff --git a/src/java/org/jruby/ext/openssl/impl/TypeDiscriminating.java b/src/java/org/jruby/ext/openssl/impl/TypeDiscriminating.java deleted file mode 100644 index bd75b71..0000000 --- a/src/java/org/jruby/ext/openssl/impl/TypeDiscriminating.java +++ /dev/null @@ -1,34 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2008 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.impl; - -/** - * @author Ola Bini - */ -public abstract class TypeDiscriminating { -}// TypeDiscriminating diff --git a/src/java/org/jruby/ext/openssl/x509store/CRL.java b/src/java/org/jruby/ext/openssl/x509store/CRL.java deleted file mode 100644 index ce2ce25..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/CRL.java +++ /dev/null @@ -1,59 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.security.cert.X509CRL; - -/** - * c: X509_OBJECT - * - * @author Ola Bini - */ -public class CRL extends X509Object { - public java.security.cert.CRL crl; - - public int type() { - return X509Utils.X509_LU_CRL; - } - - public boolean isName(Name nm) { - return nm.isEqual(((X509CRL)crl).getIssuerX500Principal()); - } - - public boolean matches(X509Object o) { - return o instanceof CRL && ((X509CRL)crl).getIssuerX500Principal().equals(((X509CRL)((CRL)o).crl).getIssuerX500Principal()); - } - - public int compareTo(X509Object oth) { - int ret1 = super.compareTo(oth); - if(ret1 == 0) { - ret1 = crl.equals(((CRL)oth).crl) ? 0 : -1; - } - return ret1; - } -}// X509_OBJECT_CRL diff --git a/src/java/org/jruby/ext/openssl/x509store/Certificate.java b/src/java/org/jruby/ext/openssl/x509store/Certificate.java deleted file mode 100644 index 8b20758..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Certificate.java +++ /dev/null @@ -1,57 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * c: X509_OBJECT - * - * @author Ola Bini - */ -public class Certificate extends X509Object { - public X509AuxCertificate x509; - - public int type() { - return X509Utils.X509_LU_X509; - } - - public boolean isName(Name nm) { - return nm.isEqual(x509.getSubjectX500Principal()); - } - - public boolean matches(X509Object o) { - return o instanceof Certificate && x509.getSubjectX500Principal().equals(((Certificate)o).x509.getSubjectX500Principal()); - } - - public int compareTo(X509Object oth) { - int ret1 = super.compareTo(oth); - if(ret1 == 0) { - ret1 = x509.equals(((Certificate)oth).x509) ? 0 : -1; - } - return ret1; - } -}// X509_OBJECT_CERT diff --git a/src/java/org/jruby/ext/openssl/x509store/CertificateFile.java b/src/java/org/jruby/ext/openssl/x509store/CertificateFile.java deleted file mode 100644 index 934edc7..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/CertificateFile.java +++ /dev/null @@ -1,46 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Contains information like x509_file_st and X509_CERT_FILER_CTX in - * x509_vfy.h - * - * @author Ola Bini - */ -public class CertificateFile { - public static class Path { - public Path(String name, int type) { - this.name = name; this.type = type; - } - public String name; - public int type; - } - public int numberOfPaths; // This details how many of the paths-var that is actually used - public Path[] paths; -}// X509_CERT_FILE_CTX diff --git a/src/java/org/jruby/ext/openssl/x509store/CertificateHashDir.java b/src/java/org/jruby/ext/openssl/x509store/CertificateHashDir.java deleted file mode 100644 index eee5cd2..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/CertificateHashDir.java +++ /dev/null @@ -1,46 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Contains information like x509_hash_dir_st and X509_HASH_DIR_CTX in - * x509_vfy.h - * - * @author Ola Bini - */ -public class CertificateHashDir { - public static class Dir { - public Dir(String name, int type) { - this.name = name; this.type = type; - } - public String name; - public int type; - } - public int numberOfDirs; // This details how many of the dirs-var that is actually used - public Dir[] dirs; -}// X509_HASH_DIR_CTX diff --git a/src/java/org/jruby/ext/openssl/x509store/Function0.java b/src/java/org/jruby/ext/openssl/x509store/Function0.java deleted file mode 100644 index 4815f60..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function0.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Zero arity function call. - * - * @author Ola Bini - */ -public interface Function0 { - public static class Empty implements Function0 { - public int call() { - return -1; - } - } - public static final Function0.Empty EMPTY = new Empty(); - int call() throws Exception; -}// Function0 diff --git a/src/java/org/jruby/ext/openssl/x509store/Function1.java b/src/java/org/jruby/ext/openssl/x509store/Function1.java deleted file mode 100644 index 5b61b7e..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function1.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * One arity function call. - * - * @author Ola Bini - */ -public interface Function1 { - public static class Empty implements Function1 { - public int call(Object arg0) { - return -1; - } - } - public static final Function1.Empty EMPTY = new Empty(); - int call(Object arg0) throws Exception; -}// Function1 diff --git a/src/java/org/jruby/ext/openssl/x509store/Function2.java b/src/java/org/jruby/ext/openssl/x509store/Function2.java deleted file mode 100644 index 3818dc1..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function2.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Two arity function call. - * - * @author Ola Bini - */ -public interface Function2 { - public static class Empty implements Function2 { - public int call(Object arg0,Object arg1) { - return -1; - } - } - public static final Function2.Empty EMPTY = new Empty(); - int call(Object arg0,Object arg1) throws Exception; -}// Function2 diff --git a/src/java/org/jruby/ext/openssl/x509store/Function3.java b/src/java/org/jruby/ext/openssl/x509store/Function3.java deleted file mode 100644 index 14d8151..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function3.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Three arity function call. - * - * @author Ola Bini - */ -public interface Function3 { - public static class Empty implements Function3 { - public int call(Object arg0,Object arg1,Object arg2) { - return -1; - } - } - public static final Function3.Empty EMPTY = new Empty(); - int call(Object arg0,Object arg1,Object arg2) throws Exception; -}// Function3 diff --git a/src/java/org/jruby/ext/openssl/x509store/Function4.java b/src/java/org/jruby/ext/openssl/x509store/Function4.java deleted file mode 100644 index 4955640..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function4.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Four arity function call. - * - * @author Ola Bini - */ -public interface Function4 { - public static class Empty implements Function4 { - public int call(Object arg0,Object arg1,Object arg2,Object arg3) { - return -1; - } - } - public static final Function4.Empty EMPTY = new Empty(); - int call(Object arg0,Object arg1,Object arg2,Object arg3) throws Exception; -}// Function4 diff --git a/src/java/org/jruby/ext/openssl/x509store/Function5.java b/src/java/org/jruby/ext/openssl/x509store/Function5.java deleted file mode 100644 index d2a0a76..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Function5.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * Five arity function call. - * - * @author Ola Bini - */ -public interface Function5 { - public static class Empty implements Function5 { - public int call(Object arg0,Object arg1,Object arg2,Object arg3,Object arg4) { - return -1; - } - } - public static final Function5.Empty EMPTY = new Empty(); - int call(Object arg0,Object arg1,Object arg2,Object arg3,Object arg4) throws Exception; -}// Function5 diff --git a/src/java/org/jruby/ext/openssl/x509store/Lookup.java b/src/java/org/jruby/ext/openssl/x509store/Lookup.java deleted file mode 100644 index d66a499..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Lookup.java +++ /dev/null @@ -1,624 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.io.InputStream; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.InputStreamReader; - -import java.math.BigInteger; - -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.cert.CRL; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import org.jruby.Ruby; -import org.jruby.RubyHash; -import org.jruby.util.io.ChannelDescriptor; -import org.jruby.util.io.ChannelStream; -import org.jruby.util.io.FileExistsException; -import org.jruby.util.io.InvalidValueException; -import org.jruby.util.io.ModeFlags; - -import java.security.KeyStore; -import java.security.cert.PKIXParameters; -import java.security.cert.TrustAnchor; - -/** - * X509_LOOKUP - * - * @author Ola Bini - */ -public class Lookup { - public boolean init; - public boolean skip; - public LookupMethod method; - public Object methodData; - public Store store; - - /** - * c: X509_LOOKUP_new - */ - public Lookup(LookupMethod method) throws Exception { - init=false; - skip=false; - this.method=method; - methodData=null; - store=null; - if(method.newItem != null && method.newItem != Function1.EMPTY && method.newItem.call(this) == 0) { - throw new Exception(); - } - } - - /** - * c: X509_LOOKUP_load_file - */ - public int loadFile(CertificateFile.Path file) throws Exception { - return control(X509Utils.X509_L_FILE_LOAD,file.name,file.type,null); - } - - /** - * c: X509_LOOKUP_add_dir - */ - public int addDir(CertificateHashDir.Dir dir) throws Exception { - return control(X509Utils.X509_L_ADD_DIR,dir.name,dir.type,null); - } - - /** - * c: X509_LOOKUP_hash_dir - */ - public static LookupMethod hashDirLookup() { - return x509DirectoryLookup; - } - - /** - * c: X509_LOOKUP_file - */ - public static LookupMethod fileLookup() { - return x509FileLookup; - } - - /** - * c: X509_LOOKUP_ctrl - */ - public int control(int cmd, String argc, long argl, String[] ret) throws Exception { - if(method == null) { - return -1; - } - if(method.control != null && method.control != Function5.EMPTY) { - return method.control.call(this,new Integer(cmd),argc,new Long(argl),ret); - } else { - return 1; - } - } - - /** - * c: X509_LOOKUP_load_cert_file - */ - public int loadCertificateFile(String file, int type) throws Exception { - if (file == null) { - return 1; - } - int count = 0; - int ret = 0; - Reader reader = null; - try { - InputStream in = wrapJRubyNormalizedInputStream(file); - X509AuxCertificate x = null; - if (type == X509Utils.X509_FILETYPE_PEM) { - reader = new BufferedReader(new InputStreamReader(in)); - for (;;) { - x = PEMInputOutput.readX509Aux(reader, null); - if (null == x) { - break; - } - int i = store.addCertificate(x); - if (i == 0) { - return ret; - } - count++; - x = null; - } - ret = count; - } else if (type == X509Utils.X509_FILETYPE_ASN1) { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - x = StoreContext.ensureAux((X509Certificate) cf.generateCertificate(in)); - if (x == null) { - X509Error.addError(13); - return ret; - } - int i = store.addCertificate(x); - if (i == 0) { - return ret; - } - ret = i; - } else { - X509Error.addError(X509Utils.X509_R_BAD_X509_FILETYPE); - } - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception ignored) { - } - } - } - return ret; - } - - /** - * c: X509_LOOKUP_load_crl_file - */ - public int loadCRLFile(String file, int type) throws Exception { - if (file == null) { - return 1; - } - int count = 0; - int ret = 0; - Reader reader = null; - try { - InputStream in = wrapJRubyNormalizedInputStream(file); - CRL x = null; - if (type == X509Utils.X509_FILETYPE_PEM) { - reader = new BufferedReader(new InputStreamReader(in)); - for (;;) { - x = PEMInputOutput.readX509CRL(reader, null); - if (null == x) { - break; - } - int i = store.addCRL(x); - if (i == 0) { - return ret; - } - count++; - x = null; - } - ret = count; - } else if (type == X509Utils.X509_FILETYPE_ASN1) { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - x = cf.generateCRL(in); - if (x == null) { - X509Error.addError(13); - return ret; - } - int i = store.addCRL(x); - if (i == 0) { - return ret; - } - ret = i; - } else { - X509Error.addError(X509Utils.X509_R_BAD_X509_FILETYPE); - } - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception ignored) { - } - } - } - return ret; - } - - /** - * c: X509_LOOKUP_load_cert_crl_file - */ - public int loadCertificateOrCRLFile(String file, int type) throws Exception { - if (type != X509Utils.X509_FILETYPE_PEM) { - return loadCertificateFile(file, type); - } - int count = 0; - Reader reader = null; - try { - InputStream in = wrapJRubyNormalizedInputStream(file); - reader = new BufferedReader(new InputStreamReader(in)); - for (;;) { - Object v = PEMInputOutput.readPEM(reader, null); - if (null == v) { - break; - } - if (v instanceof X509Certificate) { - store.addCertificate(StoreContext.ensureAux((X509Certificate) v)); - count++; - } else if (v instanceof CRL) { - store.addCRL((CRL) v); - count++; - } - } - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception ignored) { - } - } - } - return count; - } - - public int loadDefaultJavaCACertsFile() throws Exception { - int count = 0; - String certsFile = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar); - FileInputStream fin = new FileInputStream(certsFile); - try { - KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); - // we pass a null password, as the cacerts file isn't password protected - keystore.load(fin, null); - PKIXParameters params = new PKIXParameters(keystore); - for(TrustAnchor trustAnchor : params.getTrustAnchors()) { - X509Certificate certificate = trustAnchor.getTrustedCert(); - store.addCertificate(certificate); - count++; - } - } finally { - if (fin != null) { - try { - fin.close(); - } catch (Exception ignored) { - } - } - } - return count; - } - - private InputStream wrapJRubyNormalizedInputStream(String file) throws IOException { - Ruby runtime = Ruby.getGlobalRuntime(); - try { - ChannelDescriptor descriptor = ChannelDescriptor.open(runtime.getCurrentDirectory(), file, new ModeFlags(ModeFlags.RDONLY)); - return ChannelStream.open(runtime, descriptor).newInputStream(); - } catch (NoSuchMethodError nsme) { - return new BufferedInputStream(new FileInputStream(file)); - } catch (FileExistsException fee) { - // should not happen because ModeFlag does not contain CREAT. - fee.printStackTrace(System.err); - throw new IllegalStateException(fee.getMessage(), fee); - } catch (InvalidValueException ive) { - // should not happen because ModeFlasg does not contain APPEND. - ive.printStackTrace(System.err); - throw new IllegalStateException(ive.getMessage(), ive); - } - } - - /** - * c: X509_LOOKUP_free - */ - public void free() throws Exception { - if(method != null && method.free != null && method.free != Function1.EMPTY) { - method.free.call(this); - } - } - - /** - * c: X509_LOOKUP_init - */ - public int init() throws Exception { - if(method == null) { - return 0; - } - if(method.init != null && method.init != Function1.EMPTY) { - return method.init.call(this); - } - return 1; - } - - /** - * c: X509_LOOKUP_by_subject - */ - public int bySubject(int type, Name name,X509Object[] ret) throws Exception { - if(method == null || method.getBySubject == null || method.getBySubject == Function4.EMPTY) { - return X509Utils.X509_LU_FAIL; - } - if(skip) { - return 0; - } - return method.getBySubject.call(this,new Integer(type),name,ret); - } - - /** - * c: X509_LOOKUP_by_issuer_serial - */ - public int byIssuerSerialNumber(int type, Name name,BigInteger serial, X509Object[] ret) throws Exception { - if(method == null || method.getByIssuerSerialNumber == null || method.getByIssuerSerialNumber == Function5.EMPTY) { - return X509Utils.X509_LU_FAIL; - } - return method.getByIssuerSerialNumber.call(this,new Integer(type),name,serial,ret); - } - - /** - * c: X509_LOOKUP_by_fingerprint - */ - public int byFingerprint(int type,String bytes, X509Object[] ret) throws Exception { - if(method == null || method.getByFingerprint == null || method.getByFingerprint == Function4.EMPTY) { - return X509Utils.X509_LU_FAIL; - } - return method.getByFingerprint.call(this,new Integer(type),bytes,ret); - } - - /** - * c: X509_LOOKUP_by_alias - */ - public int byAlias(int type, String str, X509Object[] ret) throws Exception { - if(method == null || method.getByAlias == null || method.getByAlias == Function4.EMPTY) { - return X509Utils.X509_LU_FAIL; - } - return method.getByAlias.call(this,new Integer(type),str,ret); - } - - /** - * c: X509_LOOKUP_shutdown - */ - public int shutdown() throws Exception { - if(method == null) { - return 0; - } - if(method.shutdown != null && method.shutdown != Function1.EMPTY) { - return method.shutdown.call(this); - } - return 1; - } - - /** - * c: x509_file_lookup - */ - private final static LookupMethod x509FileLookup = new LookupMethod(); - - /** - * c: x509_dir_lookup - */ - private final static LookupMethod x509DirectoryLookup = new LookupMethod(); - - static { - x509FileLookup.name = "Load file into cache"; - x509FileLookup.control = new ByFile(); - - x509DirectoryLookup.name = "Load certs from files in a directory"; - x509DirectoryLookup.newItem = new NewLookupDir(); - x509DirectoryLookup.free = new FreeLookupDir(); - x509DirectoryLookup.control = new LookupDirControl(); - x509DirectoryLookup.getBySubject = new GetCertificateBySubject(); - } - - /** - * c: by_file_ctrl - */ - private static class ByFile implements LookupMethod.ControlFunction { - public int call(Object _ctx, Object _cmd, Object _argp, Object _argl, Object _ret) throws Exception { - Lookup ctx = (Lookup)_ctx; - int cmd = ((Integer)_cmd).intValue(); - String argp = (String)_argp; - long argl = ((Long)_argl).longValue(); - - int ok = 0; - String file = null; - - switch(cmd) { - case X509Utils.X509_L_FILE_LOAD: - if (argl == X509Utils.X509_FILETYPE_DEFAULT) { - try { - RubyHash env = (RubyHash)Ruby.getGlobalRuntime().getObject().getConstant("ENV"); - file = (String)env.get(Ruby.getGlobalRuntime().newString(X509Utils.getDefaultCertificateFileEnvironment())); - } catch (Error error) { - } - if (file != null) { - ok = ctx.loadCertificateOrCRLFile(file, X509Utils.X509_FILETYPE_PEM) != 0 ? 1 : 0; - } else { - ok = (ctx.loadDefaultJavaCACertsFile() != 0) ? 1: 0; - } - if (ok == 0) { - X509Error.addError(X509Utils.X509_R_LOADING_DEFAULTS); - } - } else { - if (argl == X509Utils.X509_FILETYPE_PEM) { - ok = (ctx.loadCertificateOrCRLFile(argp, X509Utils.X509_FILETYPE_PEM) != 0) ? 1 : 0; - } else { - ok = (ctx.loadCertificateFile(argp, (int) argl) != 0) ? 1 : 0; - } - } - break; - } - - return ok; - } - } - - /** - * c: BY_DIR, lookup_dir_st - */ - private static class LookupDir { - List dirs; - List dirsType; - } - - /** - * c: new_dir - */ - private static class NewLookupDir implements LookupMethod.NewItemFunction { - public int call(Object _lu) { - Lookup lu = (Lookup)_lu; - LookupDir a = new LookupDir(); - a.dirs = new ArrayList(); - a.dirsType = new ArrayList(); - lu.methodData = a; - return 1; - } - } - - /** - * c: free_dir - */ - private static class FreeLookupDir implements LookupMethod.FreeFunction { - public int call(Object _lu) { - Lookup lu = (Lookup)_lu; - LookupDir a = (LookupDir)lu.methodData; - a.dirs = null; - a.dirsType = null; - lu.methodData = null; - return -1; - } - } - - /** - * c: dir_ctrl - */ - private static class LookupDirControl implements LookupMethod.ControlFunction { - public int call(Object _ctx, Object _cmd, Object _argp, Object _argl, Object _retp) { - Lookup ctx = (Lookup)_ctx; - int cmd = ((Integer)_cmd).intValue(); - String argp = (String)_argp; - long argl = ((Long)_argl).longValue(); - int ret = 0; - LookupDir ld = (LookupDir)ctx.methodData; - String dir = null; - switch(cmd) { - case X509Utils.X509_L_ADD_DIR: - if(argl == X509Utils.X509_FILETYPE_DEFAULT) { - try { - RubyHash env = (RubyHash)Ruby.getGlobalRuntime().getObject().getConstant("ENV"); - dir = (String)env.get(Ruby.getGlobalRuntime().newString(X509Utils.getDefaultCertificateDirectoryEnvironment())); - } catch (Error error) { - } - if(null != dir) { - ret = addCertificateDirectory(ld,dir,X509Utils.X509_FILETYPE_PEM); - } else { - ret = addCertificateDirectory(ld,X509Utils.getDefaultCertificateDirectory(),X509Utils.X509_FILETYPE_PEM); - } - if(ret == 0) { - X509Error.addError(X509Utils.X509_R_LOADING_CERT_DIR); - } - } else { - ret = addCertificateDirectory(ld,argp,(int)argl); - } - break; - } - return ret; - } - - /** - * c: add_cert_dir - */ - private int addCertificateDirectory(LookupDir ctx,String dir,int type) { - if(dir == null || "".equals(dir)) { - X509Error.addError(X509Utils.X509_R_INVALID_DIRECTORY); - return 0; - } - - String[] dirs = dir.split(System.getProperty("path.separator")); - - for(int i=0;i iter = ctx.dirsType.iterator(); - for(String cdir : ctx.dirs) { - int tp = iter.next(); - int k = 0; - for(;;) { - b.append(String.format("%s%s%08x.%s%d", cdir, File.separator, h, postfix, k)); - k++; - if(!(new File(b.toString()).exists())) { - break; - } - if(type == X509Utils.X509_LU_X509) { - if((x1.loadCertificateFile(b.toString(),tp)) == 0) { - break; - } - } else if(type == X509Utils.X509_LU_CRL) { - if((x1.loadCRLFile(b.toString(),tp)) == 0) { - break; - } - } - } - X509Object tmp = null; - synchronized(X509Utils.CRYPTO_LOCK_X509_STORE) { - for(X509Object o : x1.store.objs) { - if(o.type() == type && o.isName(name)) { - tmp = o; - break; - } - } - } - if(tmp != null) { - ok = 1; - ret[0] = tmp; - break; - } - } - - return ok; - } - } -}// X509_LOOKUP diff --git a/src/java/org/jruby/ext/openssl/x509store/LookupMethod.java b/src/java/org/jruby/ext/openssl/x509store/LookupMethod.java deleted file mode 100644 index 8bf7f24..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/LookupMethod.java +++ /dev/null @@ -1,84 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * x509_lookup_method_st and X509_LOOKUP_METHOD in x509_vfy.h - * - * @author Ola Bini - */ -public class LookupMethod { - public String name; - - public static interface NewItemFunction extends Function1 {} - public static interface FreeFunction extends Function1 {} - public static interface InitFunction extends Function1 {} - public static interface ShutdownFunction extends Function1 {} - public static interface ControlFunction extends Function5 {} - public static interface BySubjectFunction extends Function4 {} - public static interface ByIssuerSerialNumberFunction extends Function5 {} - public static interface ByFingerprintFunction extends Function4 {} - public static interface ByAliasFunction extends Function4 {} - - /** - * c: new_item - */ - public NewItemFunction newItem; - /** - * c: free - */ - public FreeFunction free; - /** - * c: init - */ - public InitFunction init; - /** - * c: shutdown - */ - public ShutdownFunction shutdown; - /** - * c: ctrl - */ - public ControlFunction control; - /** - * c: get_by_subject - */ - public BySubjectFunction getBySubject; - /** - * c: get_by_issuer_serial - */ - public ByIssuerSerialNumberFunction getByIssuerSerialNumber; - /** - * c: get_by_fingerprint - */ - public ByFingerprintFunction getByFingerprint; - /** - * c: get_by_alias - */ - public ByAliasFunction getByAlias; -}// X509_LOOKUP_METHOD diff --git a/src/java/org/jruby/ext/openssl/x509store/Name.java b/src/java/org/jruby/ext/openssl/x509store/Name.java deleted file mode 100644 index dada079..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Name.java +++ /dev/null @@ -1,86 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.security.MessageDigest; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.x509.X509Name; - -/** - * c: X509_NAME - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class Name { - public X509Name name; - - public Name(X500Principal nm) { - try { - this.name = new X509Name((ASN1Sequence)new ASN1InputStream(nm.getEncoded()).readObject()); - } catch(Exception e) { - this.name = null; - } - } - - public Name(X509Name nm) { - this.name = nm; - } - - /** - * c: X509_NAME_hash - */ - public long hash() { - try { - byte[] bytes = name.getEncoded(); - byte[] md = null; - MessageDigest md5 = MessageDigest.getInstance("MD5"); - md = md5.digest(bytes); - long result = 0; - result |= md[3] & 0xff; result <<= 8; - result |= md[2] & 0xff; result <<= 8; - result |= md[1] & 0xff; result <<= 8; - result |= md[0] & 0xff; - return result & 0xffffffff; - } catch(Exception e) { - return 0; - } - } - - public boolean isEqual(X500Principal oname) { - try { - return new X500Principal(name.getEncoded()).equals(oname); - } catch(Exception e) { - return false; - } - } -}// X509_NAME diff --git a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java b/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java deleted file mode 100644 index c0d0c24..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java +++ /dev/null @@ -1,1275 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * Copyright (C) 2007 William N Dortch - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.io.IOException; -import java.io.Writer; -import java.io.BufferedWriter; -import java.io.BufferedReader; -import java.io.Reader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; - -import java.math.BigInteger; - -import java.security.KeyPair; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.security.cert.X509CRL; -import java.security.cert.CertificateEncodingException; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.crypto.spec.DHParameterSpec; - -import org.jruby.ext.openssl.OpenSSLReal; -import org.jruby.ext.openssl.PKCS10CertificationRequestExt; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1OutputStream; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.DERObject; -import org.bouncycastle.asn1.x509.DSAParameter; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.pkcs.EncryptionScheme; -import org.bouncycastle.asn1.pkcs.PBES2Parameters; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.RC2CBCParameter; -import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure; -import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.crypto.engines.DESedeEngine; -import org.bouncycastle.crypto.engines.RC2Engine; -import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.modes.CBCBlockCipher; -import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.cms.CMSSignedData; - -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.CertificateFactory; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.StringTokenizer; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.jruby.ext.openssl.Cipher.CipherModule; -import org.jruby.ext.openssl.impl.ASN1Registry; -import org.jruby.ext.openssl.impl.CipherSpec; - -/** - * Helper class to read and write PEM files correctly. - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public class PEMInputOutput { - public static final String BEF = "-----"; - public static final String AFT = "-----"; - public static final String BEF_G = BEF+"BEGIN "; - public static final String BEF_E = BEF+"END "; - public static final String PEM_STRING_X509_OLD="X509 CERTIFICATE"; - public static final String PEM_STRING_X509="CERTIFICATE"; - public static final String PEM_STRING_X509_PAIR="CERTIFICATE PAIR"; - public static final String PEM_STRING_X509_TRUSTED="TRUSTED CERTIFICATE"; - public static final String PEM_STRING_X509_REQ_OLD="NEW CERTIFICATE REQUEST"; - public static final String PEM_STRING_X509_REQ="CERTIFICATE REQUEST"; - public static final String PEM_STRING_X509_CRL="X509 CRL"; - public static final String PEM_STRING_EVP_PKEY="ANY PRIVATE KEY"; - public static final String PEM_STRING_PUBLIC="PUBLIC KEY"; - public static final String PEM_STRING_RSA="RSA PRIVATE KEY"; - public static final String PEM_STRING_RSA_PUBLIC="RSA PUBLIC KEY"; - public static final String PEM_STRING_DSA="DSA PRIVATE KEY"; - public static final String PEM_STRING_DSA_PUBLIC="DSA PUBLIC KEY"; - public static final String PEM_STRING_PKCS7="PKCS7"; - public static final String PEM_STRING_PKCS8="ENCRYPTED PRIVATE KEY"; - public static final String PEM_STRING_PKCS8INF="PRIVATE KEY"; - public static final String PEM_STRING_DHPARAMS="DH PARAMETERS"; - public static final String PEM_STRING_SSL_SESSION="SSL SESSION PARAMETERS"; - public static final String PEM_STRING_DSAPARAMS="DSA PARAMETERS"; - public static final String PEM_STRING_ECDSA_PUBLIC="ECDSA PUBLIC KEY"; - public static final String PEM_STRING_ECPARAMETERS="EC PARAMETERS"; - public static final String PEM_STRING_ECPRIVATEKEY="EC PRIVATE KEY"; - - private static final Pattern DH_PARAM_PATTERN = Pattern.compile( - "(-----BEGIN DH PARAMETERS-----)(.*)(-----END DH PARAMETERS-----)", - Pattern.MULTILINE); - private static final int DH_PARAM_GROUP = 2; // the group above containing encoded params - - private static BufferedReader makeBuffered(Reader in) { - if(in instanceof BufferedReader) { - return (BufferedReader)in; - } - return new BufferedReader(in); - } - - private static BufferedWriter makeBuffered(Writer out) { - if(out instanceof BufferedWriter) { - return (BufferedWriter)out; - } - return new BufferedWriter(out); - } - - /** - * c: PEM_X509_INFO_read_bio - */ - public static Object readPEM(Reader in,char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) { - try { - return readPublicKey(_in,BEF_E+PEM_STRING_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating public key: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_DSA) != -1) { - try { - return readKeyPair(_in,f, "DSA", BEF_E+PEM_STRING_DSA); - } catch (Exception e) { - throw new IOException("problem creating DSA private key: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) { - try { - return readPublicKey(_in,BEF_E+PEM_STRING_RSA_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating RSA public key: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_OLD); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_CRL) != -1) { - try { - return readCRL(_in,BEF_E+PEM_STRING_X509_CRL); - } catch (Exception e) { - throw new IOException("problem creating X509 CRL: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_REQ) != -1) { - try { - return readCertificateRequest(_in,BEF_E+PEM_STRING_X509_REQ); - } catch (Exception e) { - throw new IOException("problem creating X509 REQ: " + e.toString()); - } - } - } - return null; - } - - public static byte[] readX509PEM(Reader in) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if (line.indexOf(BEF_G + PEM_STRING_X509_OLD) != -1) { - try { - return readBytes(_in, BEF_E + PEM_STRING_X509_OLD); - } catch (Exception e) { - throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_X509) != -1) { - try { - return readBytes(_in, BEF_E + PEM_STRING_X509); - } catch (Exception e) { - throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_X509_TRUSTED) != -1) { - try { - return readBytes(_in, BEF_E + PEM_STRING_X509_TRUSTED); - } catch (Exception e) { - throw new IOException("problem reading PEM X509 Aux certificate: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_X509_CRL) != -1) { - try { - return readBytes(_in, BEF_E + PEM_STRING_X509_CRL); - } catch (Exception e) { - throw new IOException("problem reading PEM X509 CRL: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_X509_REQ) != -1) { - try { - return readBytes(_in, BEF_E + PEM_STRING_X509_REQ); - } catch (Exception e) { - throw new IOException("problem reading PEM X509 REQ: " + e.toString()); - } - } - } - return null; - } - - /** - * c: PEM_read_PrivateKey + PEM_read_bio_PrivateKey - * CAUTION: KeyPair#getPublic() may be null. - */ - public static KeyPair readPrivateKey(Reader in, char[] password) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if (line.indexOf(BEF_G + PEM_STRING_RSA) != -1) { - try { - return readKeyPair(_in, password, "RSA", BEF_E + PEM_STRING_RSA); - } catch (Exception e) { - throw new IOException("problem creating RSA private key: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_DSA) != -1) { - try { - return readKeyPair(_in, password, "DSA", BEF_E + PEM_STRING_DSA); - } catch (Exception e) { - throw new IOException("problem creating DSA private key: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_ECPRIVATEKEY) != -1) { - throw new IOException("EC private key not supported"); - } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8INF) != -1) { - try { - byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8INF); - PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(bytes).readObject()); - String type = getPrivateKeyTypeFromObjectId(info.getAlgorithmId().getObjectId()); - return org.jruby.ext.openssl.impl.PKey.readPrivateKey(info.getPrivateKey().getDEREncoded(), type); - } catch (Exception e) { - throw new IOException("problem creating private key: " + e.toString()); - } - } else if (line.indexOf(BEF_G + PEM_STRING_PKCS8) != -1) { - try { - byte[] bytes = readBytes(_in, BEF_E + PEM_STRING_PKCS8); - org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo( - (ASN1Sequence) new ASN1InputStream(bytes).readObject()); - AlgorithmIdentifier algId = eIn.getEncryptionAlgorithm(); - PrivateKey privKey; - if (algId.getAlgorithm().toString().equals("1.2.840.113549.1.5.13")) { // PBES2 - privKey = derivePrivateKeyPBES2(eIn, algId, password); - } else { - privKey = derivePrivateKeyPBES1(eIn, algId, password); - } - return new KeyPair(null, privKey); - } catch (Exception e) { - throw new IOException("problem creating private key: " + e.toString()); - } - } - } - return null; - } - - private static PrivateKey derivePrivateKeyPBES1(org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password) - throws GeneralSecurityException { - PKCS12PBEParams pkcs12Params = new PKCS12PBEParams((ASN1Sequence) algId.getParameters()); - PBEParameterSpec pbeParams = new PBEParameterSpec(pkcs12Params.getIV(), pkcs12Params.getIterations().intValue()); - - String algorithm = ASN1Registry.o2a(algId.getAlgorithm()); - algorithm = (algorithm.split("-"))[0]; - Cipher cipher = OpenSSLReal.getCipherBC(algorithm); // need to use BC for PBEParameterSpec. - - SecretKeyFactory fact = OpenSSLReal.getSecretKeyFactoryBC(algorithm); // need to use BC for PKCS12PBEParams. - SecretKey key = fact.generateSecret(new PBEKeySpec(password)); - - cipher.init(Cipher.UNWRAP_MODE, key, pbeParams); - // wrappedKeyAlgorithm is unknown ("") - return (PrivateKey) cipher.unwrap(eIn.getEncryptedData(), "", Cipher.PRIVATE_KEY); - } - - private static PrivateKey derivePrivateKeyPBES2(org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn, AlgorithmIdentifier algId, char[] password) - throws GeneralSecurityException, InvalidCipherTextException { - PBES2Parameters pbeParams = new PBES2Parameters((ASN1Sequence) algId.getParameters()); - CipherParameters cipherParams = extractPBES2CipherParams(password, pbeParams); - - EncryptionScheme scheme = pbeParams.getEncryptionScheme(); - BufferedBlockCipher cipher; - if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) { - RC2CBCParameter rc2Params = new RC2CBCParameter((ASN1Sequence) scheme.getObject()); - byte[] iv = rc2Params.getIV(); - CipherParameters param = new ParametersWithIV(cipherParams, iv); - cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine())); - cipher.init(false, param); - } else { - byte[] iv = ((ASN1OctetString) scheme.getObject()).getOctets(); - CipherParameters param = new ParametersWithIV(cipherParams, iv); - cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine())); - cipher.init(false, param); - } - - byte[] data = eIn.getEncryptedData(); - byte[] out = new byte[cipher.getOutputSize(data.length)]; - int len = cipher.processBytes(data, 0, data.length, out, 0); - len += cipher.doFinal(out, len); - byte[] pkcs8 = new byte[len]; - System.arraycopy(out, 0, pkcs8, 0, len); - KeyFactory fact = KeyFactory.getInstance("RSA"); // It seems to work for both RSA and DSA. - return fact.generatePrivate(new PKCS8EncodedKeySpec(pkcs8)); - } - - private static CipherParameters extractPBES2CipherParams(char[] password, PBES2Parameters pbeParams) { - PBKDF2Params pbkdfParams = PBKDF2Params.getInstance(pbeParams.getKeyDerivationFunc().getParameters()); - int keySize = 192; - if (pbkdfParams.getKeyLength() != null) { - keySize = pbkdfParams.getKeyLength().intValue() * 8; - } - int iterationCount = pbkdfParams.getIterationCount().intValue(); - byte[] salt = pbkdfParams.getSalt(); - PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); - generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, iterationCount); - return generator.generateDerivedParameters(keySize); - } - - // PEM_read_bio_PUBKEY - public static PublicKey readPubKey(Reader in) throws IOException { - PublicKey pubKey = readRSAPubKey(in); - if (pubKey == null) { - pubKey = readDSAPubKey(in); - } - return pubKey; - } - - /* - * c: PEM_read_bio_DSA_PUBKEY - */ - public static DSAPublicKey readDSAPubKey(Reader in) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_DSA_PUBLIC) != -1) { - try { - return (DSAPublicKey)readPublicKey(_in,"DSA",BEF_E+PEM_STRING_DSA_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating DSA public key: " + e.toString()); - } - } - } - return null; - } - - /* - * c: PEM_read_bio_DSAPublicKey - */ - public static DSAPublicKey readDSAPublicKey(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) { - try { - return (DSAPublicKey)readPublicKey(_in,"DSA",BEF_E+PEM_STRING_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating DSA public key: " + e.toString()); - } - } - } - return null; - } - - /* - * c: PEM_read_bio_DSAPrivateKey - */ - public static KeyPair readDSAPrivateKey(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_DSA) != -1) { - try { - return readKeyPair(_in,f, "DSA", BEF_E+PEM_STRING_DSA); - } catch (Exception e) { - throw new IOException("problem creating DSA private key: " + e.toString()); - } - } - } - return null; - } - - /** - * reads an RSA public key encoded in an SubjectPublicKeyInfo RSA structure. - * c: PEM_read_bio_RSA_PUBKEY - */ - public static RSAPublicKey readRSAPubKey(Reader in) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) { - try { - return readRSAPublicKey(_in,BEF_E+PEM_STRING_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating RSA public key: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) { - try { - return readRSAPublicKey(_in,BEF_E+PEM_STRING_RSA_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating RSA public key: " + e.toString()); - } - } - } - return null; - } - - /** - * reads an RSA public key encoded in an PKCS#1 RSA structure. - * c: PEM_read_bio_RSAPublicKey - */ - public static RSAPublicKey readRSAPublicKey(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_PUBLIC) != -1) { - try { - return (RSAPublicKey)readPublicKey(_in,"RSA",BEF_E+PEM_STRING_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating RSA public key: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_RSA_PUBLIC) != -1) { - try { - return (RSAPublicKey)readPublicKey(_in,"RSA",BEF_E+PEM_STRING_RSA_PUBLIC); - } catch (Exception e) { - throw new IOException("problem creating RSA public key: " + e.toString()); - } - } - } - return null; - } - - /** - * c: PEM_read_bio_RSAPrivateKey - */ - public static KeyPair readRSAPrivateKey(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_RSA) != -1) { - try { - return readKeyPair(_in,f, "RSA", BEF_E+PEM_STRING_RSA); - } catch (Exception e) { - throw new IOException("problem creating RSA private key: " + e.toString()); - } - } - } - return null; - } - public static CMSSignedData readPKCS7(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_PKCS7) != -1) { - try { - return readPKCS7(_in,f, BEF_E+PEM_STRING_PKCS7); - } catch (Exception e) { - throw new IOException("problem creating PKCS7: " + e.toString()); - } - } - } - return null; - } - public static X509AuxCertificate readX509Certificate(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) { - try { - return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509_OLD)); - } catch (Exception e) { - throw new IOException("problem creating X509 certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) { - try { - return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509)); - } catch (Exception e) { - throw new IOException("problem creating X509 certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) { - try { - return new X509AuxCertificate(readCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED)); - } catch (Exception e) { - throw new IOException("problem creating X509 certificate: " + e.toString()); - } - } - } - return null; - } - public static X509AuxCertificate readX509Aux(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_X509_OLD) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_OLD); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } else if(line.indexOf(BEF_G+PEM_STRING_X509_TRUSTED) != -1) { - try { - return readAuxCertificate(_in,BEF_E+PEM_STRING_X509_TRUSTED); - } catch (Exception e) { - throw new IOException("problem creating X509 Aux certificate: " + e.toString()); - } - } - } - return null; - } - public static X509CRL readX509CRL(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_X509_CRL) != -1) { - try { - return readCRL(_in,BEF_E+PEM_STRING_X509_CRL); - } catch (Exception e) { - throw new IOException("problem creating X509 CRL: " + e.toString()); - } - } - } - return null; - } - public static PKCS10CertificationRequestExt readX509Request(Reader in, char[] f) throws IOException { - BufferedReader _in = makeBuffered(in); - String line; - while ((line = _in.readLine()) != null) { - if(line.indexOf(BEF_G+PEM_STRING_X509_REQ) != -1) { - try { - return readCertificateRequest(_in,BEF_E+PEM_STRING_X509_REQ); - } catch (Exception e) { - throw new IOException("problem creating X509 REQ: " + e.toString()); - } - } - } - return null; - } - - public static DHParameterSpec readDHParameters(Reader _in) throws IOException { - BufferedReader in = makeBuffered(_in); - String line; - StringBuilder buf = new StringBuilder(); - while ((line = in.readLine()) != null) { - if (line.indexOf(BEF_G + PEM_STRING_DHPARAMS) >= 0) { - do { - buf.append(line.trim()); - } while (line.indexOf(BEF_E + PEM_STRING_DHPARAMS) < 0 && (line = in.readLine()) != null); - break; - } - } - Matcher m = DH_PARAM_PATTERN.matcher(buf.toString()); - if (m.find()) { - try { - byte[] decoded = Base64.decode(m.group(DH_PARAM_GROUP)); - return org.jruby.ext.openssl.impl.PKey.readDHParameter(decoded); - } catch (Exception e) { - } - } - return null; - } - - private static byte[] getEncoded(java.security.Key key) { - if (key != null) { - return key.getEncoded(); - } - return new byte[] { '0', 0 }; - } - - private static byte[] getEncoded(ASN1Encodable obj) throws IOException { - if (obj != null) { - return obj.getEncoded(); - } - return new byte[] { '0', 0 }; - } - - private static byte[] getEncoded(CMSSignedData obj) throws IOException { - if (obj != null) { - return obj.getEncoded(); - } - return new byte[] { '0', 0 }; - } - - private static byte[] getEncoded(X509Certificate cert) throws IOException { - if (cert != null) { - try { - return cert.getEncoded(); - } catch (GeneralSecurityException gse) { - throw new IOException("problem with encoding object in write_X509"); - } - } - return new byte[] { '0', 0 }; - } - - private static byte[] getEncoded(X509CRL crl) throws IOException { - if (crl != null) { - try { - return crl.getEncoded(); - } catch (GeneralSecurityException gse) { - throw new IOException("problem with encoding object in write_X509_CRL"); - } - } - return new byte[] { '0', 0 }; - } - - public static void writeDSAPublicKey(Writer _out, DSAPublicKey obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_DSA_PUBLIC + AFT); - out.newLine(); - writeEncoded(out, encoding); - out.write(BEF_E + PEM_STRING_DSA_PUBLIC + AFT); - out.newLine(); - out.flush(); - } - /** writes an RSA public key encoded in an PKCS#1 RSA structure. */ - public static void writeRSAPublicKey(Writer _out, RSAPublicKey obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_RSA_PUBLIC + AFT); - out.newLine(); - writeEncoded(out, encoding); - out.write(BEF_E + PEM_STRING_RSA_PUBLIC + AFT); - out.newLine(); - out.flush(); - } - public static void writePKCS7(Writer _out, ContentInfo obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_PKCS7 + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_PKCS7 + AFT); - out.newLine(); - out.flush(); - } - public static void writePKCS7(Writer _out, CMSSignedData obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_PKCS7 + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_PKCS7 + AFT); - out.newLine(); - out.flush(); - } - public static void writePKCS7(Writer _out, byte[] encoded) throws IOException { - BufferedWriter out = makeBuffered(_out); - out.write(BEF_G + PEM_STRING_PKCS7 + AFT); - out.newLine(); - writeEncoded(out,encoded); - out.write(BEF_E + PEM_STRING_PKCS7 + AFT); - out.newLine(); - out.flush(); - } - public static void writeX509Certificate(Writer _out, X509Certificate obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_X509 + AFT); - out.newLine(); - writeEncoded(out, encoding); - out.write(BEF_E + PEM_STRING_X509 + AFT); - out.newLine(); - out.flush(); - } - public static void writeX509Aux(Writer _out, X509AuxCertificate obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = null; - try { - if(obj.getAux() == null) { - encoding = obj.getEncoded(); - } else { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] ymp = obj.getEncoded(); - baos.write(ymp,0,ymp.length); - - X509Aux aux = obj.getAux(); - ASN1EncodableVector a1 = new ASN1EncodableVector(); - if(aux.trust.size()>0) { - ASN1EncodableVector a2 = new ASN1EncodableVector(); - for(String trust : aux.trust) { - a2.add(new DERObjectIdentifier(trust)); - } - a1.add(new DERSequence(a2)); - } - if(aux.reject.size()>0) { - ASN1EncodableVector a2 = new ASN1EncodableVector(); - for(String reject : aux.reject) { - a2.add(new DERObjectIdentifier(reject)); - } - a1.add(new DERTaggedObject(0,new DERSequence(a2))); - } - if(aux.alias != null) { - a1.add(new DERUTF8String(aux.alias)); - } - if(aux.keyid != null) { - a1.add(new DEROctetString(aux.keyid)); - } - if(aux.other.size()>0) { - ASN1EncodableVector a2 = new ASN1EncodableVector(); - for(DERObject other : aux.other) { - a2.add(other); - } - a1.add(new DERTaggedObject(1,new DERSequence(a2))); - } - ymp = new DERSequence(a1).getEncoded(); - baos.write(ymp,0,ymp.length); - encoding = baos.toByteArray(); - } - } catch(CertificateEncodingException e) { - throw new IOException("problem with encoding object in write_X509_AUX"); - } - out.write(BEF_G + PEM_STRING_X509_TRUSTED + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_X509_TRUSTED + AFT); - out.newLine(); - out.flush(); - } - public static void writeX509CRL(Writer _out, X509CRL obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_X509_CRL + AFT); - out.newLine(); - writeEncoded(out, encoding); - out.write(BEF_E + PEM_STRING_X509_CRL + AFT); - out.newLine(); - out.flush(); - } - public static void writeX509Request(Writer _out, PKCS10CertificationRequestExt obj) throws IOException { - BufferedWriter out = makeBuffered(_out); - byte[] encoding = getEncoded(obj); - out.write(BEF_G + PEM_STRING_X509_REQ + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_X509_REQ + AFT); - out.newLine(); - out.flush(); - } - - private static SecureRandom random; - static { - try { - random = SecureRandom.getInstance("SHA1PRNG"); - } catch(Exception e) { - random = null; - } - } - - public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, CipherSpec cipher, char[] passwd) throws IOException { - BufferedWriter out = makeBuffered(_out); - PrivateKeyInfo info = new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(getEncoded(obj)).readObject()); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters()); - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new DERInteger(0)); - v.add(new DERInteger(p.getP())); - v.add(new DERInteger(p.getQ())); - v.add(new DERInteger(p.getG())); - - BigInteger x = obj.getX(); - BigInteger y = p.getG().modPow(x, p.getP()); - - v.add(new DERInteger(y)); - v.add(new DERInteger(x)); - - aOut.writeObject(new DERSequence(v)); - byte[] encoding = bOut.toByteArray(); - - if (cipher != null && passwd != null) { - writePemEncrypted(out, PEM_STRING_DSA, encoding, cipher, passwd); - } else { - writePemPlain(out, PEM_STRING_DSA, encoding); - } - } - - public static void writeRSAPrivateKey(Writer _out, RSAPrivateCrtKey obj, CipherSpec cipher, char[] passwd) throws IOException { - assert (obj != null); - BufferedWriter out = makeBuffered(_out); - RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(obj.getModulus(), obj.getPublicExponent(), obj.getPrivateExponent(), obj.getPrimeP(), - obj.getPrimeQ(), obj.getPrimeExponentP(), obj.getPrimeExponentQ(), obj.getCrtCoefficient()); - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - aOut.writeObject(keyStruct); - aOut.close(); - byte[] encoding = bOut.toByteArray(); - - if (cipher != null && passwd != null) { - writePemEncrypted(out, PEM_STRING_RSA, encoding, cipher, passwd); - } else { - writePemPlain(out, PEM_STRING_RSA, encoding); - } - } - - private static void writePemPlain(BufferedWriter out, String pemHeader, byte[] encoding) throws IOException { - out.write(BEF_G + pemHeader + AFT); - out.newLine(); - writeEncoded(out, encoding); - out.write(BEF_E + pemHeader + AFT); - out.newLine(); - out.flush(); - } - - private static void writePemEncrypted(BufferedWriter out, String pemHeader, byte[] encoding, CipherSpec cipher, char[] passwd) throws IOException { - Cipher c = cipher.getCipher(); - byte[] iv = new byte[c.getBlockSize()]; - random.nextBytes(iv); - byte[] salt = new byte[8]; - System.arraycopy(iv, 0, salt, 0, 8); - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(cipher.getKeyLenInBits()); - SecretKey secretKey = new SecretKeySpec(param.getKey(), org.jruby.ext.openssl.Cipher.Algorithm.getAlgorithmBase(c)); - byte[] encData = null; - try { - c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); - encData = c.doFinal(encoding); - } catch (GeneralSecurityException gse) { - throw new IOException("exception using cipher: " + gse.toString()); - } - out.write(BEF_G + pemHeader + AFT); - out.newLine(); - out.write("Proc-Type: 4,ENCRYPTED"); - out.newLine(); - out.write("DEK-Info: " + cipher.getOsslName() + ","); - writeHexEncoded(out, iv); - out.newLine(); - out.newLine(); - writeEncoded(out, encData); - out.write(BEF_E + pemHeader + AFT); - out.flush(); - } - - public static void writeDHParameters(Writer _out, DHParameterSpec params) throws IOException { - BufferedWriter out = makeBuffered(_out); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - ASN1EncodableVector v = new ASN1EncodableVector(); - - BigInteger value; - if ((value = params.getP()) != null) { - v.add(new DERInteger(value)); - } - if ((value = params.getG()) != null) { - v.add(new DERInteger(value)); - } - - aOut.writeObject(new DERSequence(v)); - byte[] encoding = bOut.toByteArray(); - - out.write(BEF_G + PEM_STRING_DHPARAMS + AFT); - out.newLine(); - writeEncoded(out,encoding); - out.write(BEF_E + PEM_STRING_DHPARAMS + AFT); - out.newLine(); - out.flush(); - } - - private static String getPrivateKeyTypeFromObjectId(DERObjectIdentifier oid) { - if (ASN1Registry.obj2nid(oid) == ASN1Registry.NID_rsaEncryption) { - return "RSA"; - } else { - return "DSA"; - } - } - - private static byte[] readBytes(BufferedReader in, String endMarker) throws IOException { - String line; - StringBuffer buf = new StringBuffer(); - - while ((line = in.readLine()) != null) { - if (line.indexOf(endMarker) != -1) { - break; - } - buf.append(line.trim()); - } - - if (line == null) { - throw new IOException(endMarker + " not found"); - } - - return Base64.decode(buf.toString()); - } - - private static RSAPublicKey readRSAPublicKey(BufferedReader in, String endMarker) throws IOException { - Object asnObject = new ASN1InputStream(readBytes(in, endMarker)).readObject(); - ASN1Sequence sequence = (ASN1Sequence) asnObject; - RSAPublicKeyStructure rsaPubStructure = new RSAPublicKeyStructure(sequence); - RSAPublicKeySpec keySpec = new RSAPublicKeySpec( - rsaPubStructure.getModulus(), - rsaPubStructure.getPublicExponent()); - - try { - KeyFactory keyFact = KeyFactory.getInstance("RSA"); - return (RSAPublicKey) keyFact.generatePublic(keySpec); - } catch (NoSuchAlgorithmException e) { - // ignore - } catch (InvalidKeySpecException e) { - // ignore - } - - return null; - } - - private static PublicKey readPublicKey(byte[] input, String alg, String endMarker) throws IOException { - KeySpec keySpec = new X509EncodedKeySpec(input); - try { - KeyFactory keyFact = KeyFactory.getInstance(alg); - PublicKey pubKey = keyFact.generatePublic(keySpec); - return pubKey; - } catch (NoSuchAlgorithmException e) { - // ignore - } catch (InvalidKeySpecException e) { - // ignore - } - return null; - } - - private static PublicKey readPublicKey(BufferedReader in, String alg, String endMarker) throws IOException { - return readPublicKey(readBytes(in, endMarker), alg, endMarker); - } - - private static PublicKey readPublicKey(BufferedReader in, String endMarker) throws IOException { - byte[] input = readBytes(in, endMarker); - String[] algs = { "RSA", "DSA" }; - for (int i = 0; i < algs.length; i++) { - PublicKey key = readPublicKey(input, algs[i], endMarker); - if (key != null) { - return key; - } - } - return null; - } - - /** - * Read a Key Pair - */ - private static KeyPair readKeyPair(BufferedReader _in, char[] passwd, String type, String endMarker) throws Exception { - boolean isEncrypted = false; - String line = null; - String dekInfo = null; - StringBuffer buf = new StringBuffer(); - - while ((line = _in.readLine()) != null) { - if (line.startsWith("Proc-Type: 4,ENCRYPTED")) { - isEncrypted = true; - } else if (line.startsWith("DEK-Info:")) { - dekInfo = line.substring(10); - } else if (line.indexOf(endMarker) != -1) { - break; - } else { - buf.append(line.trim()); - } - } - byte[] keyBytes = null; - byte[] decoded = Base64.decode(buf.toString()); - if (isEncrypted) { - keyBytes = decrypt(decoded, dekInfo, passwd); - } else { - keyBytes = decoded; - } - return org.jruby.ext.openssl.impl.PKey.readPrivateKey(keyBytes, type); - } - - private static byte[] decrypt(byte[] decoded, String dekInfo, char[] passwd) throws IOException, GeneralSecurityException { - if (passwd == null) { - throw new IOException("Password is null, but a password is required"); - } - StringTokenizer tknz = new StringTokenizer(dekInfo, ","); - String algorithm = tknz.nextToken(); - byte[] iv = Hex.decode(tknz.nextToken()); - if (!CipherModule.isSupportedCipher(algorithm)) { - throw new IOException("Unknown algorithm: " + algorithm); - } - String[] cipher = org.jruby.ext.openssl.Cipher.Algorithm.osslToJsse(algorithm); - String realName = cipher[3]; - int[] lengths = org.jruby.ext.openssl.Cipher.Algorithm.osslKeyIvLength(algorithm); - int keyLen = lengths[0]; - int ivLen = lengths[1]; - if (iv.length != ivLen) { - throw new IOException("Illegal IV length"); - } - byte[] salt = new byte[8]; - System.arraycopy(iv, 0, salt, 0, 8); - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(passwd), salt); - KeyParameter param = (KeyParameter) pGen.generateDerivedParameters(keyLen * 8); - SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(param.getKey(), realName); - Cipher c = Cipher.getInstance(realName); - c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); - return c.doFinal(decoded); - } - - /** - * Reads in a X509Certificate. - * - * @return the X509Certificate - * @throws IOException if an I/O error occured - */ - private static X509Certificate readCertificate(BufferedReader in, String endMarker) throws IOException { - String line; - StringBuffer buf = new StringBuffer(); - - while ((line = in.readLine()) != null) { - if (line.indexOf(endMarker) != -1) { - break; - } - buf.append(line.trim()); - } - - if (line == null) { - throw new IOException(endMarker + " not found"); - } - - try { - CertificateFactory certFact = CertificateFactory.getInstance("X.509"); - ByteArrayInputStream bIn = new ByteArrayInputStream(Base64.decode(buf.toString())); - return (X509Certificate) certFact.generateCertificate(bIn); - } catch (Exception e) { - throw new IOException("problem parsing cert: " + e.toString()); - } - } - - private static X509AuxCertificate readAuxCertificate(BufferedReader in,String endMarker) throws IOException { - String line; - StringBuffer buf = new StringBuffer(); - - while ((line = in.readLine()) != null) { - if (line.indexOf(endMarker) != -1) { - break; - } - buf.append(line.trim()); - } - - if (line == null) { - throw new IOException(endMarker + " not found"); - } - - ASN1InputStream try1 = new ASN1InputStream(Base64.decode(buf.toString())); - ByteArrayInputStream bIn = new ByteArrayInputStream((try1.readObject()).getEncoded()); - - try { - CertificateFactory certFact = CertificateFactory.getInstance("X.509"); - X509Certificate bCert = (X509Certificate)certFact.generateCertificate(bIn); - DERSequence aux = (DERSequence)try1.readObject(); - X509Aux ax = null; - if(aux != null) { - ax = new X509Aux(); - int ix = 0; - if(aux.size() > ix && aux.getObjectAt(ix) instanceof DERSequence) { - DERSequence trust = (DERSequence)aux.getObjectAt(ix++); - for(int i=0;i ix && aux.getObjectAt(ix) instanceof DERTaggedObject && ((DERTaggedObject)aux.getObjectAt(ix)).getTagNo() == 0) { - DERSequence reject = (DERSequence)((DERTaggedObject)aux.getObjectAt(ix++)).getObject(); - for(int i=0;iix && aux.getObjectAt(ix) instanceof DERUTF8String) { - ax.alias = ((DERUTF8String)aux.getObjectAt(ix++)).getString(); - } - if(aux.size()>ix && aux.getObjectAt(ix) instanceof DEROctetString) { - ax.keyid = ((DEROctetString)aux.getObjectAt(ix++)).getOctets(); - } - if(aux.size() > ix && aux.getObjectAt(ix) instanceof DERTaggedObject && ((DERTaggedObject)aux.getObjectAt(ix)).getTagNo() == 1) { - DERSequence other = (DERSequence)((DERTaggedObject)aux.getObjectAt(ix++)).getObject(); - for(int i=0;i= bytes.length) { - break; - } - buf[index] = (char)bytes[i + index]; - index++; - } - out.write(buf, 0, index); - out.newLine(); - } - } - - /** - * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS - * API. - * - * @return the X509Certificate - * @throws IOException if an I/O error occured - */ - private static CMSSignedData readPKCS7(BufferedReader in, char[] p, String endMarker) throws IOException { - String line; - StringBuffer buf = new StringBuffer(); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - while ((line = in.readLine()) != null) { - if (line.indexOf(endMarker) != -1) { - break; - } - line = line.trim(); - buf.append(line.trim()); - Base64.decode(buf.substring(0, (buf.length() / 4) * 4), bOut); - buf.delete(0, (buf.length() / 4) * 4); - } - if (buf.length() != 0) { - throw new RuntimeException("base64 data appears to be truncated"); - } - if (line == null) { - throw new IOException(endMarker + " not found"); - } - try { - ASN1InputStream aIn = new ASN1InputStream(bOut.toByteArray()); - return new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); - } catch (Exception e) { - throw new IOException("problem parsing PKCS7 object: " + e.toString()); - } - } -}// PEM diff --git a/src/java/org/jruby/ext/openssl/x509store/PKey.java b/src/java/org/jruby/ext/openssl/x509store/PKey.java deleted file mode 100644 index f3be5b9..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/PKey.java +++ /dev/null @@ -1,41 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * c: X509_OBJECT - * - * @author Ola Bini - */ -public class PKey extends X509Object { - public java.security.PrivateKey pkey; - - public int type() { - return X509Utils.X509_LU_PKEY; - } -}// X509_OBJECT_PKEY diff --git a/src/java/org/jruby/ext/openssl/x509store/PolicyTree.java b/src/java/org/jruby/ext/openssl/x509store/PolicyTree.java deleted file mode 100644 index a8223a1..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/PolicyTree.java +++ /dev/null @@ -1,36 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -/** - * c: X509_POLICY_TREE - * - * @author Ola Bini - */ -public class PolicyTree { -}// X509_POLICY_TREE diff --git a/src/java/org/jruby/ext/openssl/x509store/Purpose.java b/src/java/org/jruby/ext/openssl/x509store/Purpose.java deleted file mode 100644 index 2370da4..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Purpose.java +++ /dev/null @@ -1,476 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - - -import java.util.ArrayList; -import java.util.List; - -/** - * c: X509_PURPOSE - * - * @author Ola Bini - */ -public class Purpose { - private static final String XKU_EMAIL_PROTECT = "1.3.6.1.5.5.7.3.4"; // Email protection - private static final String XKU_SSL_CLIENT = "1.3.6.1.5.5.7.3.2"; // SSL Client Authentication - private static final String[] XKU_SSL_SERVER = new String[]{ - "1.3.6.1.5.5.7.3.1", // SSL Server Authentication - "2.16.840.1.113730.4.1", // Netscape Server Gated Crypto - "1.3.6.1.4.1.311.10.3.3" // Microsoft Server Gated Crypto - }; - - public static interface CheckPurposeFunction extends Function3 { - public static final CheckPurposeFunction EMPTY = new CheckPurposeFunction(){ - public int call(Object arg0, Object arg1, Object arg2) { - return -1; - } - }; - } - - public int purpose; - public int trust; /* Default trust ID */ - public int flags; - public CheckPurposeFunction checkPurpose; - public String name; - public String sname; - public Object userData; - - public Purpose() {} - - public Purpose(int p, int t, int f, CheckPurposeFunction cp, String n, String s, Object u) { - this.purpose = p; this.trust = t; - this.flags = f; this.checkPurpose = cp; - this.name = n; this.sname = s; - this.userData = u; - } - - /** - * c: X509_check_purpose - */ - public static int checkPurpose(X509AuxCertificate x, int id, int ca) throws Exception { - if(id == -1) { - return 1; - } - int idx = getByID(id); - if(idx == -1) { - return -1; - } - Purpose pt = getFirst(idx); - return pt.checkPurpose.call(pt,x,new Integer(ca)); - } - - /** - * c: X509_PURPOSE_set - */ - public static int set(int[] p, int purpose) { - if(getByID(purpose) == -1) { - X509Error.addError(X509Utils.X509V3_R_INVALID_PURPOSE); - return 0; - } - p[0] = purpose; - return 1; - } - - private final static List xptable = new ArrayList(); - - /** - * c: X509_PURPOSE_get_count - */ - public static int getCount() { - return xptable.size() + xstandard.length; - } - - /** - * c: X509_PURPOSE_get0 - */ - public static Purpose getFirst(int idx) { - if(idx < 0) { - return null; - } - if(idx < xstandard.length) { - return xstandard[idx]; - } - return xptable.get(idx - xstandard.length); - } - - /** - * c: X509_PURPOSE_get_by_sname - */ - public static int getBySName(String sname) { - for(int i=0;i= X509Utils.X509_PURPOSE_MIN && (purpose <= X509Utils.X509_PURPOSE_MAX)) { - return purpose - X509Utils.X509_PURPOSE_MIN; - } - int i = 0; - for(Purpose p : xptable) { - if(p.purpose == purpose) { - return i + xstandard.length; - } - } - return -1; - } - - /** - * c: X509_PURPOSE_add - */ - public static int add(int id, int trust, int flags, CheckPurposeFunction ck, String name, String sname, Object arg) { - flags &= ~X509Utils.X509_PURPOSE_DYNAMIC; - flags |= X509Utils.X509_PURPOSE_DYNAMIC_NAME; - int idx = getByID(id); - Purpose ptmp; - if(idx == -1) { - ptmp = new Purpose(); - ptmp.flags = X509Utils.X509_PURPOSE_DYNAMIC; - } else { - ptmp = getFirst(idx); - } - ptmp.name = name; - ptmp.sname = sname; - ptmp.flags &= X509Utils.X509_PURPOSE_DYNAMIC; - ptmp.flags |= flags; - ptmp.purpose = id; - ptmp.trust = trust; - ptmp.checkPurpose = ck; - ptmp.userData = arg; - if(idx == -1) { - xptable.add(ptmp); - } - return 1; - } - - /** - * c: X509_PURPOSE_cleanup - */ - public static void cleanup() { - xptable.clear(); - } - - /** - * c: X509_PURPOSE_get_id - */ - public int getID() { - return purpose; - } - - /** - * c: X509_PURPOSE_get0_name - */ - public String getName() { - return name; - } - - /** - * c: X509_PURPOSE_get0_sname - */ - public String getSName() { - return sname; - } - - /** - * c: X509_PURPOSE_get_trust - */ - public int getTrust() { - return trust; - } - - /** - * c: X509_check_ca - */ - public static int checkCA(X509AuxCertificate x) throws Exception { - if(x.getKeyUsage() != null && !x.getKeyUsage()[5]) { // KEY_CERT_SIGN - return 0; - } - if(x.getExtensionValue("2.5.29.19") != null) { // BASIC_CONSTRAINTS - if(x.getBasicConstraints() != -1) { // is CA. - return 1; - } else { - return 0; - } - } else { - if(x.getVersion() == 1 && x.getIssuerX500Principal().equals(x.getSubjectX500Principal())) { // V1_ROOT - return 3; - } - if(x.getKeyUsage() != null) { - return 4; - } - Integer nsCertType = x.getNsCertType(); - if (nsCertType != null && (nsCertType & X509Utils.NS_ANY_CA) != 0) { - return 5; - } - return 0; - } - } - - /** - * c: check_ssl_ca - */ - public static int checkSSLCA(X509AuxCertificate x) throws Exception { - int ca_ret = checkCA(x); - if(ca_ret == 0) { - return 0; - } - Integer nsCertType = x.getNsCertType(); - boolean v2 = nsCertType != null && (nsCertType & X509Utils.NS_SSL_CA) != 0; - if(ca_ret != 5 || v2) { - return ca_ret; - } - return 0; - } - - /** - * c: xku_reject: check if the cert must be rejected(true) or not - */ - public static boolean xkuReject(X509AuxCertificate x, String mustHaveXku) throws Exception { - List xku = x.getExtendedKeyUsage(); - return (xku != null) && !xku.contains(mustHaveXku); - } - public static boolean xkuReject(X509AuxCertificate x, String[] mustHaveOneOfXku) throws Exception { - List xku = x.getExtendedKeyUsage(); - if(xku == null) { - return false; - } - for (String mustHaveXku : mustHaveOneOfXku) { - if(xku.contains(mustHaveXku)) { - return false; - } - } - return true; - } - - /** - * c: ns_reject - */ - public static boolean nsReject(X509AuxCertificate x, int mustHaveCertType) throws Exception { - Integer nsCertType = x.getNsCertType(); - return (nsCertType != null) && (nsCertType & mustHaveCertType) == 0; - } - - /** - * c: purpose_smime - */ - public static int purposeSMIME(X509AuxCertificate x, int ca) throws Exception { - if(xkuReject(x,XKU_EMAIL_PROTECT)) { - return 0; // must allow email protection - } - if(ca != 0) { - int ca_ret = checkCA(x); - if(ca_ret == 0) { - return 0; - } - Integer nsCertType = x.getNsCertType(); - boolean v2 = nsCertType != null && (nsCertType & X509Utils.NS_SMIME_CA) != 0; - if(ca_ret != 5 || v2) { - return ca_ret; - } else { - return 0; - } - } - Integer nsCertType = x.getNsCertType(); - if (nsCertType != null) { - if ((nsCertType & X509Utils.NS_SMIME) != 0) { - return 1; - } - if ((nsCertType & X509Utils.NS_SSL_CLIENT) != 0) { - return 2; - } - return 0; - } - return 1; - } - - /** - * c: check_purpose_ssl_client - */ - public final static CheckPurposeFunction checkPurposeSSLClient = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - X509AuxCertificate x = (X509AuxCertificate)_x; - if(xkuReject(x, XKU_SSL_CLIENT)) { - return 0; - } - int ca = ((Integer)_ca).intValue(); - if(ca != 0) { - return checkSSLCA(x); - } - if(x.getKeyUsage() != null && !x.getKeyUsage()[0]) { - return 0; - } - if(nsReject(x, X509Utils.NS_SSL_CLIENT)) { - // when the cert has nsCertType, it must include NS_SSL_CLIENT - return 0; - } - return 1; - } - }; - - /** - * c: check_purpose_ssl_server - */ - public final static CheckPurposeFunction checkPurposeSSLServer = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - X509AuxCertificate x = (X509AuxCertificate)_x; - int ca = ((Integer)_ca).intValue(); - if(xkuReject(x, XKU_SSL_SERVER)) { - return 0; - } - if(ca != 0) { - return checkSSLCA(x); - } - if(nsReject(x, X509Utils.NS_SSL_SERVER)) { - // when the cert has nsCertType, it must include NS_SSL_SERVER - return 0; - } - /* Now as for keyUsage: we'll at least need to sign OR encipher */ - if(x.getKeyUsage() != null && !(x.getKeyUsage()[0] || x.getKeyUsage()[2])) { - return 0; - } - return 1; - } - }; - - /** - * c: check_purpose_ns_ssl_server - */ - public final static CheckPurposeFunction checkPurposeNSSSLServer = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - Purpose xp = (Purpose)_xp; - X509AuxCertificate x = (X509AuxCertificate)_x; - int ca = ((Integer)_ca).intValue(); - int ret = checkPurposeSSLServer.call(xp,x,_ca); - if(ret == 0 || ca != 0) { - return ret; - } - if(x.getKeyUsage() != null && !x.getKeyUsage()[2]) { - return 0; - } - return 1; - } - }; - - /** - * c: check_purpose_smime_sign - */ - public final static CheckPurposeFunction checkPurposeSMIMESign = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - X509AuxCertificate x = (X509AuxCertificate)_x; - int ca = ((Integer)_ca).intValue(); - int ret = purposeSMIME(x,ca); - if(ret == 0 || ca != 0) { - return ret; - } - if(x.getKeyUsage() != null && (!x.getKeyUsage()[0] || !x.getKeyUsage()[1])) { - return 0; - } - return ret; - } - }; - - /** - * c: check_purpose_smime_encrypt - */ - public final static CheckPurposeFunction checkPurposeSMIMEEncrypt = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - X509AuxCertificate x = (X509AuxCertificate)_x; - int ca = ((Integer)_ca).intValue(); - int ret = purposeSMIME(x,ca); - if(ret == 0 || ca != 0) { - return ret; - } - if(x.getKeyUsage() != null && !x.getKeyUsage()[2]) { - return 0; - } - return ret; - } - }; - - /** - * c: check_purpose_crl_sign - */ - public final static CheckPurposeFunction checkPurposeCRLSign = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - X509AuxCertificate x = (X509AuxCertificate)_x; - int ca = ((Integer)_ca).intValue(); - - if(ca != 0) { - int ca_ret = checkCA(x); - if(ca_ret != 2) { - return ca_ret; - } - return 0; - } - if(x.getKeyUsage() != null && !x.getKeyUsage()[6]) { - return 0; - } - return 1; - } - }; - - /** - * c: no_check - */ - public final static CheckPurposeFunction noCheck = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) { - return 1; - } - }; - - /** - * c: ocsp_helper - */ - public final static CheckPurposeFunction oscpHelper = new CheckPurposeFunction() { - public int call(Object _xp, Object _x, Object _ca) throws Exception { - if(((Integer)_ca).intValue() != 0) { - return checkCA((X509AuxCertificate)_x); - } - return 1; - } - }; - - public final static Purpose[] xstandard = new Purpose[] { - new Purpose(X509Utils.X509_PURPOSE_SSL_CLIENT, X509Utils.X509_TRUST_SSL_CLIENT, 0, checkPurposeSSLClient, "SSL client", "sslclient", null), - new Purpose(X509Utils.X509_PURPOSE_SSL_SERVER, X509Utils.X509_TRUST_SSL_SERVER, 0, checkPurposeSSLServer, "SSL server", "sslserver", null), - new Purpose(X509Utils.X509_PURPOSE_NS_SSL_SERVER, X509Utils.X509_TRUST_SSL_SERVER, 0, checkPurposeNSSSLServer, "Netscape SSL server", "nssslserver", null), - new Purpose(X509Utils.X509_PURPOSE_SMIME_SIGN, X509Utils.X509_TRUST_EMAIL, 0, checkPurposeSMIMESign, "S/MIME signing", "smimesign", null), - new Purpose(X509Utils.X509_PURPOSE_SMIME_ENCRYPT, X509Utils.X509_TRUST_EMAIL, 0, checkPurposeSMIMEEncrypt, "S/MIME encryption", "smimeencrypt", null), - new Purpose(X509Utils.X509_PURPOSE_CRL_SIGN, X509Utils.X509_TRUST_COMPAT, 0, checkPurposeCRLSign, "CRL signing", "crlsign", null), - new Purpose(X509Utils.X509_PURPOSE_ANY, X509Utils.X509_TRUST_DEFAULT, 0, noCheck, "Any Purpose", "any", null), - new Purpose(X509Utils.X509_PURPOSE_OCSP_HELPER, X509Utils.X509_TRUST_COMPAT, 0, oscpHelper, "OCSP helper", "ocsphelper", null), - }; -}// X509_PURPOSE diff --git a/src/java/org/jruby/ext/openssl/x509store/Store.java b/src/java/org/jruby/ext/openssl/x509store/Store.java deleted file mode 100644 index b8a29f8..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Store.java +++ /dev/null @@ -1,375 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.io.FileNotFoundException; -import java.security.cert.X509Certificate; - -import java.util.ArrayList; -import java.util.List; - -import javax.net.ssl.X509TrustManager; - -/** - * c: X509_STORE - * - * @author Ola Bini - */ -public class Store implements X509TrustManager { - public int cache; - public List objs; - public List certificateMethods; - public VerifyParameter param; - - public static interface VerifyFunction extends Function1 { - public static final VerifyFunction EMPTY = new VerifyFunction(){ - public int call(Object arg0) { - return -1; - } - }; - } - public static interface VerifyCallbackFunction extends Function2 { - public static final VerifyCallbackFunction EMPTY = new VerifyCallbackFunction(){ - public int call(Object arg0, Object arg1) { - return -1; - } - }; - } - public static interface GetIssuerFunction extends Function3 { - public static final GetIssuerFunction EMPTY = new GetIssuerFunction(){ - public int call(Object arg0, Object arg1, Object arg2) { - return -1; - } - }; - } - public static interface CheckIssuedFunction extends Function3 { - public static final CheckIssuedFunction EMPTY = new CheckIssuedFunction(){ - public int call(Object arg0, Object arg1, Object arg2) { - return -1; - } - }; - } - public static interface CheckRevocationFunction extends Function1 { - public static final CheckRevocationFunction EMPTY = new CheckRevocationFunction(){ - public int call(Object arg0) { - return -1; - } - }; - } - public static interface GetCRLFunction extends Function3 { - public static final GetCRLFunction EMPTY = new GetCRLFunction(){ - public int call(Object arg0, Object arg1, Object arg2) { - return -1; - } - }; - } - public static interface CheckCRLFunction extends Function2 { - public static final CheckCRLFunction EMPTY = new CheckCRLFunction(){ - public int call(Object arg0, Object arg1) { - return -1; - } - }; - } - public static interface CertificateCRLFunction extends Function3 { - public static final CertificateCRLFunction EMPTY = new CertificateCRLFunction(){ - public int call(Object arg0, Object arg1, Object arg2) { - return -1; - } - }; - } - public static interface CleanupFunction extends Function1 { - public static final CleanupFunction EMPTY = new CleanupFunction(){ - public int call(Object arg0) { - return -1; - } - }; - } - - public VerifyFunction verify; - public VerifyCallbackFunction verifyCallback; - public GetIssuerFunction getIssuer; - public CheckIssuedFunction checkIssued; - public CheckRevocationFunction checkRevocation; - public GetCRLFunction getCRL; - public CheckCRLFunction checkCRL; - public CertificateCRLFunction certificateCRL; - public CleanupFunction cleanup; - - public List extraData; - public int references; - - /** - * c: X509_STORE_new - */ - public Store() { - objs = new ArrayList(); - cache = 1; - certificateMethods = new ArrayList(); - - verify = VerifyFunction.EMPTY; - verifyCallback = VerifyCallbackFunction.EMPTY; - - param = new VerifyParameter(); - - getIssuer = GetIssuerFunction.EMPTY; - checkIssued = CheckIssuedFunction.EMPTY; - checkRevocation = CheckRevocationFunction.EMPTY; - getCRL = GetCRLFunction.EMPTY; - checkCRL = CheckCRLFunction.EMPTY; - certificateCRL = CertificateCRLFunction.EMPTY; - cleanup = CleanupFunction.EMPTY; - - references = 1; - extraData = new ArrayList(); - this.extraData.add(null);this.extraData.add(null);this.extraData.add(null); - this.extraData.add(null);this.extraData.add(null);this.extraData.add(null); - this.extraData.add(null);this.extraData.add(null);this.extraData.add(null); - } - - /** - * c: X509_STORE_set_verify_func - */ - public void setVerifyFunction(VerifyFunction func) { - verify = func; - } - - /** - * c: X509_STORE_set_verify_cb_func - */ - public void setVerifyCallbackFunction(VerifyCallbackFunction func) { - verifyCallback = func; - } - - /** - * c: X509_STORE_free - */ - public void free() throws Exception { - for(Lookup lu : certificateMethods) { - lu.shutdown(); - lu.free(); - } - if(param != null) { - param.free(); - } - } - - /** - * c: X509_set_ex_data - */ - public int setExtraData(int idx,Object data) { - extraData.set(idx,data); - return 1; - } - - /** - * c: X509_get_ex_data - */ - public Object getExtraData(int idx) { - return extraData.get(idx); - } - - /** - * c: X509_STORE_set_depth - */ - public int setDepth(int depth) { - param.setDepth(depth); - return 1; - } - - /** - * c: X509_STORE_set_flags - */ - public int setFlags(long flags) { - return param.setFlags(flags); - } - - /** - * c: X509_STORE_set_purpose - */ - public int setPurpose(int purpose) { - return param.setPurpose(purpose); - } - - /** - * c: X509_STORE_set_trust - */ - public int setTrust(int trust) { - return param.setTrust(trust); - } - - /** - * c: X509_STORE_set1_param - */ - public int setParam(VerifyParameter pm) { - return param.set(param); - } - - /** - * c: X509_STORE_add_lookup - */ - public Lookup addLookup(LookupMethod m) throws Exception { - Lookup lu; - - for(Lookup l : certificateMethods) { - if(l.equals(m)) { - return l; - } - } - lu = new Lookup(m); - lu.store = this; - certificateMethods.add(lu); - return lu; - } - - /** - * c: X509_STORE_add_cert - */ - public int addCertificate(X509Certificate x) { - int ret = 1; - if(x == null) { - return 0; - } - - Certificate obj = new Certificate(); - obj.x509 = StoreContext.ensureAux(x); - - synchronized(X509Utils.CRYPTO_LOCK_X509_STORE) { - if(X509Object.retrieveMatch(objs,obj) != null) { - X509Error.addError(X509Utils.X509_R_CERT_ALREADY_IN_HASH_TABLE); - ret=0; - } else { - objs.add(obj); - } - } - return ret; - } - - /** - * c: X509_STORE_add_crl - */ - public int addCRL(java.security.cert.CRL x) { - int ret = 1; - if(null == x) { - return 0; - } - CRL obj = new CRL(); - obj.crl = x; - - synchronized(X509Utils.CRYPTO_LOCK_X509_STORE) { - if(X509Object.retrieveMatch(objs,obj) != null) { - X509Error.addError(X509Utils.X509_R_CERT_ALREADY_IN_HASH_TABLE); - ret=0; - } else { - objs.add(obj); - } - } - return ret; - } - - /** - * c: X509_STORE_load_locations - */ - public int loadLocations(String file, String path) throws Exception { - Lookup lookup; - - if(file != null) { - lookup = addLookup(Lookup.fileLookup()); - if(lookup == null) { - return 0; - } - if(lookup.loadFile(new CertificateFile.Path(file,X509Utils.X509_FILETYPE_PEM)) != 1) { - return 0; - } - } - - if(path != null) { - lookup = addLookup(Lookup.hashDirLookup()); - if(lookup == null) { - return 0; - } - if(lookup.addDir(new CertificateHashDir.Dir(path,X509Utils.X509_FILETYPE_PEM)) != 1) { - return 0; - } - } - if((path == null) && (file == null)) { - return 0; - } - - return 1; - } - - /** - * c: X509_STORE_set_default_paths - */ - public int setDefaultPaths() throws Exception { - Lookup lookup; - - lookup = addLookup(Lookup.fileLookup()); - if(lookup == null) { - return 0; - } - try { - lookup.loadFile(new CertificateFile.Path(null,X509Utils.X509_FILETYPE_DEFAULT)); - } - catch(FileNotFoundException e) { - // set_default_paths ignores FileNotFound - } - - lookup = addLookup(Lookup.hashDirLookup()); - if(lookup == null) { - return 0; - } - try { - lookup.addDir(new CertificateHashDir.Dir(null,X509Utils.X509_FILETYPE_DEFAULT)); - } - catch(FileNotFoundException e) { - // set_default_paths ignores FileNotFound - } - - X509Error.clearErrors(); - - return 1; - } - - - public void checkClientTrusted(X509Certificate[] chain, String authType) { - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) { - } - - public X509Certificate[] getAcceptedIssuers() { - List l = new ArrayList(); - for(X509Object o : objs) { - if(o instanceof Certificate) { - l.add(((Certificate)o).x509); - } - } - return l.toArray(new X509Certificate[l.size()]); - } -}// X509_STORE diff --git a/src/java/org/jruby/ext/openssl/x509store/StoreContext.java b/src/java/org/jruby/ext/openssl/x509store/StoreContext.java deleted file mode 100644 index caae9a2..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/StoreContext.java +++ /dev/null @@ -1,1400 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.security.PublicKey; -import java.security.cert.X509CRL; -import java.security.cert.X509Certificate; -import java.security.cert.X509Extension; - -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.HashSet; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERInteger; - -/** - * c: X509_STORE_CTX - * - * @author Ola Bini - */ -public class StoreContext { - public Store ctx; - public int currentMethod; - - public X509AuxCertificate certificate; - public List untrusted; - public List crls; - - public VerifyParameter param; - - public List otherContext; - - public static interface CheckPolicyFunction extends Function1 { - public static final CheckPolicyFunction EMPTY = new CheckPolicyFunction(){ - public int call(Object arg0) { - return -1; - } - }; - } - - public Store.VerifyFunction verify; - public Store.VerifyCallbackFunction verifyCallback; - public Store.GetIssuerFunction getIssuer; - public Store.CheckIssuedFunction checkIssued; - public Store.CheckRevocationFunction checkRevocation; - public Store.GetCRLFunction getCRL; - public Store.CheckCRLFunction checkCRL; - public Store.CertificateCRLFunction certificateCRL; - public CheckPolicyFunction checkPolicy; - public Store.CleanupFunction cleanup; - - public boolean isValid; - public int lastUntrusted; - - public List chain; //List - public PolicyTree tree; - - public int explicitPolicy; - - public int errorDepth; - public int error; - public X509AuxCertificate currentCertificate; - public X509AuxCertificate currentIssuer; - public java.security.cert.CRL currentCRL; - - public List extraData; - - /** - * c: X509_STORE_CTX_set_depth - */ - public void setDepth(int depth) { - param.setDepth(depth); - } - - /** - * c: X509_STORE_CTX_set_app_data - */ - public void setApplicationData(Object data) { - setExtraData(0,data); - } - - /** - * c: X509_STORE_CTX_get_app_data - */ - public Object getApplicationData() { - return getExtraData(0); - } - - /** - * c: X509_STORE_CTX_get1_issuer - */ - public int getFirstIssuer(X509AuxCertificate[] issuer, X509AuxCertificate x) throws Exception { - Name xn = new Name(x.getIssuerX500Principal()); - X509Object[] s_obj = new X509Object[1]; - int ok = ctx == null ? 0 : getBySubject(X509Utils.X509_LU_X509,xn,s_obj); - if(ok != X509Utils.X509_LU_X509) { - if(ok == X509Utils.X509_LU_RETRY) { - X509Error.addError(X509Utils.X509_R_SHOULD_RETRY); - return -1; - } else if (ok != X509Utils.X509_LU_FAIL) { - return -1; - } - return 0; - } - X509Object obj = s_obj[0]; - if(this.checkIssued.call(this,x,((Certificate)obj).x509) != 0) { - issuer[0] = ((Certificate)obj).x509; - return 1; - } - - int idx = X509Object.indexBySubject(ctx.objs,X509Utils.X509_LU_X509, xn); - if(idx == -1) { - return 0; - } - - /* Look through all matching certificates for a suitable issuer */ - for(int i = idx; i < ctx.objs.size(); i++) { - X509Object pobj = ctx.objs.get(i); - if(pobj.type() != X509Utils.X509_LU_X509) { - return 0; - } - if(!xn.isEqual((((Certificate)pobj).x509).getSubjectX500Principal())) { - return 0; - } - if(this.checkIssued.call(this,x,((Certificate)pobj).x509) != 0) { - issuer[0] = ((Certificate)pobj).x509; - return 1; - } - } - return 0; - } - - public static List ensureAux(Collection inp) { - if (inp == null) { - return null; - } - List out = new ArrayList(); - for(X509Certificate o : inp) { - out.add(ensureAux(o)); - } - return out; - } - - public static List ensureAux(X509Certificate[] inp) { - if (inp == null) { - return null; - } - List o = new ArrayList(); - for(X509Certificate c : inp) { - o.add(ensureAux(c)); - } - return o; - } - - public static X509AuxCertificate ensureAux(X509Certificate i) { - if (i == null) { - return null; - } - if(i instanceof X509AuxCertificate) { - return (X509AuxCertificate)i; - } else { - return new X509AuxCertificate(i); - } - } - - /** - * c: X509_STORE_CTX_init - */ - public int init(Store store, X509AuxCertificate x509, List chain) { - int ret = 1; - this.ctx=store; - this.currentMethod=0; - this.certificate=x509; - this.untrusted=chain; - this.crls = null; - this.lastUntrusted=0; - this.otherContext = null; - this.isValid=false; - this.chain = null; - this.error=0; - this.explicitPolicy=0; - this.errorDepth=0; - this.currentCertificate=null; - this.currentIssuer=null; - this.tree = null; - - this.param = new VerifyParameter(); - - if(store != null) { - ret = param.inherit(store.param); - } else { - param.flags |= X509Utils.X509_VP_FLAG_DEFAULT | X509Utils.X509_VP_FLAG_ONCE; - } - if(store != null) { - verifyCallback = store.verifyCallback; - cleanup = store.cleanup; - } else { - cleanup = Store.CleanupFunction.EMPTY; - } - - if(ret != 0) { - ret = param.inherit(VerifyParameter.lookup("default")); - } - - if(ret == 0) { - X509Error.addError(X509Utils.ERR_R_MALLOC_FAILURE); - return 0; - } - - if(store != null && store.checkIssued != null && store.checkIssued != Store.CheckIssuedFunction.EMPTY) { - this.checkIssued = store.checkIssued; - } else { - this.checkIssued = defaultCheckIssued; - } - - if(store != null && store.getIssuer != null && store.getIssuer != Store.GetIssuerFunction.EMPTY) { - this.getIssuer = store.getIssuer; - } else { - this.getIssuer = new Store.GetIssuerFunction() { - public int call(Object arg1, Object arg2, Object arg3) throws Exception { - return ((StoreContext)arg2).getFirstIssuer((X509AuxCertificate[])arg1,(X509AuxCertificate)arg3); - } - }; - } - - if(store != null && store.verifyCallback != null && store.verifyCallback != Store.VerifyCallbackFunction.EMPTY) { - this.verifyCallback = store.verifyCallback; - } else { - this.verifyCallback = NullCallback; - } - - if(store != null && store.verify != null && store.verify != Store.VerifyFunction.EMPTY) { - this.verify = store.verify; - } else { - this.verify = internalVerify; - } - - if(store != null && store.checkRevocation != null && store.checkRevocation != Store.CheckRevocationFunction.EMPTY) { - this.checkRevocation = store.checkRevocation; - } else { - this.checkRevocation = defaultCheckRevocation; - } - - if(store != null && store.getCRL != null && store.getCRL != Store.GetCRLFunction.EMPTY) { - this.getCRL = store.getCRL; - } else { - this.getCRL = defaultGetCRL; - } - - if(store != null && store.checkCRL != null && store.checkCRL != Store.CheckCRLFunction.EMPTY) { - this.checkCRL = store.checkCRL; - } else { - this.checkCRL = defaultCheckCRL; - } - - if(store != null && store.certificateCRL != null && store.certificateCRL != Store.CertificateCRLFunction.EMPTY) { - this.certificateCRL = store.certificateCRL; - } else { - this.certificateCRL = defaultCertificateCRL; - } - - this.checkPolicy = defaultCheckPolicy; - - this.extraData = new ArrayList(); - this.extraData.add(null);this.extraData.add(null);this.extraData.add(null); - this.extraData.add(null);this.extraData.add(null);this.extraData.add(null); - return 1; - } - - /** - * c: X509_STORE_CTX_trusted_stack - */ - public void trustedStack(List sk) { - otherContext = sk; - getIssuer = getIssuerStack; - } - - /** - * c: X509_STORE_CTX_cleanup - */ - public void cleanup() throws Exception { - if(cleanup != null && cleanup != Store.CleanupFunction.EMPTY) { - cleanup.call(this); - } - param = null; - tree = null; - chain = null; - extraData = null; - } - - /** - * c: find_issuer - */ - public X509AuxCertificate findIssuer(List sk, X509AuxCertificate x) throws Exception { - for(X509AuxCertificate issuer : sk) { - if(checkIssued.call(this,x,issuer) != 0) { - return issuer; - } - } - return null; - } - - /** - * c: X509_STORE_CTX_set_ex_data - */ - public int setExtraData(int idx,Object data) { - extraData.set(idx,data); - return 1; - } - - /** - * c: X509_STORE_CTX_get_ex_data - */ - public Object getExtraData(int idx) { - return extraData.get(idx); - } - - /** - * c: X509_STORE_CTX_get_error - */ - public int getError() { - return error; - } - - /** - * c: X509_STORE_CTX_set_error - */ - public void setError(int s) { - this.error = s; - } - - /** - * c: X509_STORE_CTX_get_error_depth - */ - public int getErrorDepth() { - return errorDepth; - } - - /** - * c: X509_STORE_CTX_get_current_cert - */ - public X509AuxCertificate getCurrentCertificate() { - return currentCertificate; - } - - /** - * c: X509_STORE_CTX_get_chain - */ - public List getChain() { - return chain; - } - - /** - * c: X509_STORE_CTX_get1_chain - */ - public List getFirstChain() { - if(null == chain) { - return null; - } - return new ArrayList(chain); - } - - /** - * c: X509_STORE_CTX_set_cert - */ - public void setCertificate(X509AuxCertificate x) { - this.certificate = x; - } - - public void setCertificate(X509Certificate x) { - this.certificate = ensureAux(x); - } - - /** - * c: X509_STORE_CTX_set_chain - */ - public void setChain(List sk) { - this.untrusted = ensureAux(sk); - } - - public void setChain(X509Certificate[] sk) { - this.untrusted = ensureAux(sk); - } - - /** - * c: X509_STORE_CTX_set0_crls - */ - public void setCRLs(List sk) { - this.crls = sk; - } - - /** - * c: X509_STORE_CTX_set_purpose - */ - public int setPurpose(int purpose) { - return purposeInherit(0,purpose,0); - } - - /** - * c: X509_STORE_CTX_set_trust - */ - public int setTrust(int trust) { - return purposeInherit(0,0,trust); - } - - private void resetSettingsToWithoutStore() { - ctx = null; - this.param = new VerifyParameter(); - this.param.flags |= X509Utils.X509_VP_FLAG_DEFAULT | X509Utils.X509_VP_FLAG_ONCE; - this.param.inherit(VerifyParameter.lookup("default")); - this.cleanup = Store.CleanupFunction.EMPTY; - this.checkIssued = defaultCheckIssued; - this.getIssuer = new Store.GetIssuerFunction() { - public int call(Object arg1, Object arg2, Object arg3) throws Exception { - return ((StoreContext)arg2).getFirstIssuer((X509AuxCertificate[])arg1,(X509AuxCertificate)arg3); - } - }; - this.verifyCallback = NullCallback; - this.verify = internalVerify; - this.checkRevocation = defaultCheckRevocation; - this.getCRL = defaultGetCRL; - this.checkCRL = defaultCheckCRL; - this.certificateCRL = defaultCertificateCRL; - } - - /** - * c: SSL_CTX_load_verify_locations - */ - public int loadVerifyLocations(String CAfile, String CApath) { - boolean reset = false; - try { - if(ctx == null) { - reset = true; - ctx = new Store(); - this.param.inherit(ctx.param); - param.inherit(VerifyParameter.lookup("default")); - this.cleanup = ctx.cleanup; - if(ctx.checkIssued != null && ctx.checkIssued != Store.CheckIssuedFunction.EMPTY) { - this.checkIssued = ctx.checkIssued; - } - if(ctx.getIssuer != null && ctx.getIssuer != Store.GetIssuerFunction.EMPTY) { - this.getIssuer = ctx.getIssuer; - } - - if(ctx.verifyCallback != null && ctx.verifyCallback != Store.VerifyCallbackFunction.EMPTY) { - this.verifyCallback = ctx.verifyCallback; - } - - if(ctx.verify != null && ctx.verify != Store.VerifyFunction.EMPTY) { - this.verify = ctx.verify; - } - - if(ctx.checkRevocation != null && ctx.checkRevocation != Store.CheckRevocationFunction.EMPTY) { - this.checkRevocation = ctx.checkRevocation; - } - - if(ctx.getCRL != null && ctx.getCRL != Store.GetCRLFunction.EMPTY) { - this.getCRL = ctx.getCRL; - } - - if(ctx.checkCRL != null && ctx.checkCRL != Store.CheckCRLFunction.EMPTY) { - this.checkCRL = ctx.checkCRL; - } - - if(ctx.certificateCRL != null && ctx.certificateCRL != Store.CertificateCRLFunction.EMPTY) { - this.certificateCRL = ctx.certificateCRL; - } - } - - int ret = ctx.loadLocations(CAfile, CApath); - if(ret == 0 && reset) resetSettingsToWithoutStore(); - - return ret; - } catch(Exception e) { - if(reset) { - resetSettingsToWithoutStore(); - } - return 0; - } - } - - /** - * c: X509_STORE_CTX_purpose_inherit - */ - public int purposeInherit(int defaultPurpose,int purpose, int trust) { - int idx; - if(purpose == 0) { - purpose = defaultPurpose; - } - if(purpose != 0) { - idx = Purpose.getByID(purpose); - if(idx == -1) { - X509Error.addError(X509Utils.X509_R_UNKNOWN_PURPOSE_ID); - return 0; - } - Purpose ptmp = Purpose.getFirst(idx); - if(ptmp.trust == X509Utils.X509_TRUST_DEFAULT) { - idx = Purpose.getByID(defaultPurpose); - if(idx == -1) { - X509Error.addError(X509Utils.X509_R_UNKNOWN_PURPOSE_ID); - return 0; - } - ptmp = Purpose.getFirst(idx); - } - if(trust == 0) { - trust = ptmp.trust; - } - } - if(trust != 0) { - idx = Trust.getByID(trust); - if(idx == -1) { - X509Error.addError(X509Utils.X509_R_UNKNOWN_TRUST_ID); - return 0; - } - } - - if(purpose != 0 && param.purpose == 0) { - param.purpose = purpose; - } - if(trust != 0 && param.trust == 0) { - param.trust = trust; - } - return 1; - } - - /** - * c: X509_STORE_CTX_set_flags - */ - public void setFlags(long flags) { - param.setFlags(flags); - } - - /** - * c: X509_STORE_CTX_set_time - */ - public void setTime(long flags,Date t) { - param.setTime(t); - } - - /** - * c: X509_STORE_CTX_set_verify_cb - */ - public void setVerifyCallback(Store.VerifyCallbackFunction verifyCallback) { - this.verifyCallback = verifyCallback; - } - - /** - * c: X509_STORE_CTX_get0_policy_tree - */ - PolicyTree getPolicyTree() { - return tree; - } - - /** - * c: X509_STORE_CTX_get_explicit_policy - */ - public int getExplicitPolicy() { - return explicitPolicy; - } - - /** - * c: X509_STORE_CTX_get0_param - */ - public VerifyParameter getParam() { - return param; - } - - /** - * c: X509_STORE_CTX_set0_param - */ - public void setParam(VerifyParameter param) { - this.param = param; - } - - /** - * c: X509_STORE_CTX_set_default - */ - public int setDefault(String name) { - VerifyParameter p = VerifyParameter.lookup(name); - if(p == null) { - return 0; - } - return param.inherit(p); - } - - /** - * c: X509_STORE_get_by_subject (it gets X509_STORE_CTX as the first parameter) - */ - public int getBySubject(int type,Name name,X509Object[] ret) throws Exception { - Store c = ctx; - - X509Object tmp = X509Object.retrieveBySubject(c.objs,type,name); - if(tmp == null) { - for(int i=currentMethod; i0) { - tmp = stmp[0]; - break; - } - } - currentMethod = 0; - if(tmp == null) { - return 0; - } - } - ret[0] = tmp; - return 1; - } - - /** - * c: X509_verify_cert - */ - public int verifyCertificate() throws Exception { - X509AuxCertificate x,xtmp=null,chain_ss = null; - //X509_NAME xn; - int bad_chain = 0; - int depth,i,ok=0; - int num; - Store.VerifyCallbackFunction cb; - List sktmp = null; - if(certificate == null) { - X509Error.addError(X509Utils.X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); - return -1; - } - cb=verifyCallback; - - /* first we make sure the chain we are going to build is - * present and that the first entry is in place */ - - if(null == chain) { - chain = new ArrayList(); - chain.add(certificate); - lastUntrusted = 1; - } - - /* We use a temporary STACK so we can chop and hack at it */ - - if(untrusted != null) { - sktmp = new ArrayList(untrusted); - } - num = chain.size(); - x = chain.get(num-1); - depth = param.depth; - for(;;) { - if(depth < num) { - break; - } - - if(checkIssued.call(this,x,x) != 0) { - break; - } - - if(untrusted != null) { - xtmp = findIssuer(sktmp,x); - if(xtmp != null) { - chain.add(xtmp); - sktmp.remove(xtmp); - lastUntrusted++; - x = xtmp; - num++; - continue; - } - } - break; - } - - /* at this point, chain should contain a list of untrusted - * certificates. We now need to add at least one trusted one, - * if possible, otherwise we complain. */ - - /* Examine last certificate in chain and see if it - * is self signed. - */ - - i = chain.size(); - x = chain.get(i-1); - - if(checkIssued.call(this,x,x) != 0) { - /* we have a self signed certificate */ - if(chain.size() == 1) { - /* We have a single self signed certificate: see if - * we can find it in the store. We must have an exact - * match to avoid possible impersonation. - */ - X509AuxCertificate[] p_xtmp = new X509AuxCertificate[]{xtmp}; - ok = getIssuer.call(p_xtmp,this,x); - xtmp = p_xtmp[0]; - if(ok <= 0 || !x.equals(xtmp)) { - error = X509Utils.V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; - currentCertificate = x; - errorDepth = i-1; - bad_chain = 1; - ok = cb.call(new Integer(0),this); - if(ok == 0) { - return ok; - } - } else { - /* We have a match: replace certificate with store version - * so we get any trust settings. - */ - x = xtmp; - chain.set(i-1,x); - lastUntrusted = 0; - } - } else { - /* extract and save self signed certificate for later use */ - chain_ss = chain.remove(chain.size()-1); - lastUntrusted--; - num--; - x = chain.get(num-1); - } - } - /* We now lookup certs from the certificate store */ - for(;;) { - /* If we have enough, we break */ - if(depth= num) { - error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; - } else { - error = X509Utils.V_ERR_UNABLE_TO_GET_ISSUER_CERT; - } - currentCertificate = x; - } else { - chain.add(chain_ss); - num++; - lastUntrusted = num; - currentCertificate = chain_ss; - error = X509Utils.V_ERR_SELF_SIGNED_CERT_IN_CHAIN; - chain_ss = null; - } - errorDepth = num-1; - bad_chain = 1; - ok = cb.call(new Integer(0),this); - if(ok == 0) { - return ok; - } - } - - /* We have the chain complete: now we need to check its purpose */ - ok = checkChainExtensions(); - if(ok == 0) { - return ok; - } - - /* TODO: Check name constraints (from 1.0.0) */ - - /* The chain extensions are OK: check trust */ - if(param.trust > 0) { - ok = checkTrust(); - } - if(ok == 0) { - return ok; - } - - /* Check revocation status: we do this after copying parameters - * because they may be needed for CRL signature verification. - */ - ok = checkRevocation.call(this); - if(ok == 0) { - return ok; - } - - /* At this point, we have a chain and need to verify it */ - if(verify != null && verify != Store.VerifyFunction.EMPTY) { - ok = verify.call(this); - } else { - ok = internalVerify.call(this); - } - if(ok == 0) { - return ok; - } - - /* TODO: RFC 3779 path validation, now that CRL check has been done (from 1.0.0) */ - - /* If we get this far evaluate policies */ - if(bad_chain == 0 && (param.flags & X509Utils.V_FLAG_POLICY_CHECK) != 0) { - ok = checkPolicy.call(this); - } - return ok; - } - - - private final static Set CRITICAL_EXTENSIONS = new HashSet(); - static { - CRITICAL_EXTENSIONS.add("2.16.840.1.113730.1.1"); // netscape cert type, NID 71 - CRITICAL_EXTENSIONS.add("2.5.29.15"); // key usage, NID 83 - CRITICAL_EXTENSIONS.add("2.5.29.17"); // subject alt name, NID 85 - CRITICAL_EXTENSIONS.add("2.5.29.19"); // basic constraints, NID 87 - CRITICAL_EXTENSIONS.add("2.5.29.37"); // ext key usage, NID 126 - CRITICAL_EXTENSIONS.add("1.3.6.1.5.5.7.1.14"); // proxy cert info, NID 661 - } - - private static boolean supportsCriticalExtension(String oid) { - return CRITICAL_EXTENSIONS.contains(oid); - } - - private static boolean unhandledCritical(X509Extension xx) { - if(xx.getCriticalExtensionOIDs() == null || xx.getCriticalExtensionOIDs().size() == 0) { - return false; - } - for(String ss : xx.getCriticalExtensionOIDs()) { - if(!supportsCriticalExtension(ss)) { - return true; - } - } - return false; - } - - /** - * c: check_chain_extensions - */ - public int checkChainExtensions() throws Exception { - int ok=0, must_be_ca; - X509AuxCertificate x; - Store.VerifyCallbackFunction cb; - int proxy_path_length = 0; - int allow_proxy_certs = (param.flags & X509Utils.V_FLAG_ALLOW_PROXY_CERTS) != 0 ? 1 : 0; - cb = verifyCallback; - must_be_ca = -1; - - try { - if (System.getenv("OPENSSL_ALLOW_PROXY_CERTS") != null && !"false".equalsIgnoreCase(System.getenv("OPENSSL_ALLOW_PROXY_CERTS"))) { - allow_proxy_certs = 1; - } - } catch (Error e) { - // just ignore if we can't use System.getenv - } - - for(int i = 0; i 0) { - ret = Purpose.checkPurpose(x,param.purpose, must_be_ca > 0 ? 1 : 0); - if(ret == 0 || ((param.flags & X509Utils.V_FLAG_X509_STRICT) != 0 && ret != 1)) { - error = X509Utils.V_ERR_INVALID_PURPOSE; - errorDepth = i; - currentCertificate = x; - ok = cb.call(new Integer(0),this); - if(ok == 0) { - return ok; - } - } - } - - if(i > 1 && x.getBasicConstraints() != -1 && x.getBasicConstraints() != Integer.MAX_VALUE && (i > (x.getBasicConstraints() + proxy_path_length + 1))) { - error = X509Utils.V_ERR_PATH_LENGTH_EXCEEDED; - errorDepth = i; - currentCertificate = x; - ok = cb.call(new Integer(0),this); - if(ok == 0) { - return ok; - } - } - - if(x.getExtensionValue("1.3.6.1.5.5.7.1.14") != null) { - DERSequence pci = (DERSequence)new ASN1InputStream(x.getExtensionValue("1.3.6.1.5.5.7.1.14")).readObject(); - if(pci.size() > 0 && pci.getObjectAt(0) instanceof DERInteger) { - int pcpathlen = ((DERInteger)pci.getObjectAt(0)).getValue().intValue(); - if(i > pcpathlen) { - error = X509Utils.V_ERR_PROXY_PATH_LENGTH_EXCEEDED; - errorDepth = i; - currentCertificate = x; - ok = cb.call(new Integer(0),this); - if(ok == 0) { - return ok; - } - } - } - proxy_path_length++; - must_be_ca = 0; - } else { - must_be_ca = 1; - } - } - return 1; - } - - /** - * c: X509_check_trust - */ - public int checkTrust() throws Exception { - int i,ok; - X509AuxCertificate x; - Store.VerifyCallbackFunction cb; - cb = verifyCallback; - i = chain.size()-1; - x = chain.get(i); - ok = Trust.checkTrust(x,param.trust,0); - if(ok == X509Utils.X509_TRUST_TRUSTED) { - return 1; - } - errorDepth = 1; - currentCertificate = x; - if(ok == X509Utils.X509_TRUST_REJECTED) { - error = X509Utils.V_ERR_CERT_REJECTED; - } else { - error = X509Utils.V_ERR_CERT_UNTRUSTED; - } - return cb.call(new Integer(0),this); - } - - /** - * c: check_cert_time - */ - public int checkCertificateTime(X509AuxCertificate x) throws Exception { - Date ptime = null; - - if((param.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0) { - ptime = this.param.checkTime; - } else { - ptime = Calendar.getInstance().getTime(); - } - if(!x.getNotBefore().before(ptime)) { - error = X509Utils.V_ERR_CERT_NOT_YET_VALID; - currentCertificate = x; - if(verifyCallback.call(new Integer(0),this) == 0) { - return 0; - } - } - if(!x.getNotAfter().after(ptime)) { - error = X509Utils.V_ERR_CERT_HAS_EXPIRED; - currentCertificate = x; - if(verifyCallback.call(new Integer(0),this) == 0) { - return 0; - } - } - return 1; - } - - /** - * c: check_cert - */ - public int checkCertificate() throws Exception { - X509CRL[] crl = new X509CRL[1]; - X509AuxCertificate x; - int ok,cnum; - cnum = errorDepth; - x = chain.get(cnum); - currentCertificate = x; - ok = getCRL.call(this,crl,x); - if(ok == 0) { - error = X509Utils.V_ERR_UNABLE_TO_GET_CRL; - ok = verifyCallback.call(new Integer(0), this); - currentCRL = null; - return ok; - } - currentCRL = crl[0]; - ok = checkCRL.call(this, crl[0]); - if(ok == 0) { - currentCRL = null; - return ok; - } - ok = certificateCRL.call(this,crl[0],x); - currentCRL = null; - return ok; - } - - /** - * c: check_crl_time - */ - public int checkCRLTime(X509CRL crl, int notify) throws Exception { - currentCRL = crl; - Date ptime = null; - - if((param.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0) { - ptime = this.param.checkTime; - } else { - ptime = Calendar.getInstance().getTime(); - } - - if(!crl.getThisUpdate().before(ptime)) { - error=X509Utils.V_ERR_CRL_NOT_YET_VALID; - if(notify == 0 || verifyCallback.call(new Integer(0),this) == 0) { - return 0; - } - } - if(crl.getNextUpdate() != null && !crl.getNextUpdate().after(ptime)) { - error=X509Utils.V_ERR_CRL_HAS_EXPIRED; - if(notify == 0 || verifyCallback.call(new Integer(0),this) == 0) { - return 0; - } - } - - currentCRL = null; - return 1; - } - - /** - * c: get_crl_sk - */ - public int getCRLStack(X509CRL[] pcrl, Name nm, List crls) throws Exception { - X509CRL best_crl = null; - if(null != crls) { - for(X509CRL crl : crls) { - if(!nm.isEqual(crl.getIssuerX500Principal())) { - continue; - } - if(checkCRLTime(crl,0) != 0) { - pcrl[0] = crl; - return 1; - } - best_crl = crl; - } - } - if(best_crl != null) { - pcrl[0] = best_crl; - } - return 0; - } - - /** - * c: get_issuer_sk - */ - public final static Store.GetIssuerFunction getIssuerStack = new Store.GetIssuerFunction() { - public int call(Object a1, Object a2, Object a3) throws Exception { - X509AuxCertificate[] issuer = (X509AuxCertificate[])a1; - StoreContext ctx = (StoreContext)a2; - X509AuxCertificate x = (X509AuxCertificate)a3; - issuer[0] = ctx.findIssuer(ctx.otherContext,x); - if(issuer[0] != null) { - return 1; - } else { - return 0; - } - } - }; - - /** - * c: check_issued - */ - public final static Store.CheckIssuedFunction defaultCheckIssued = new Store.CheckIssuedFunction() { - public int call(Object a1, Object a2, Object a3) throws Exception { - StoreContext ctx = (StoreContext)a1; - X509AuxCertificate x = (X509AuxCertificate)a2; - X509AuxCertificate issuer = (X509AuxCertificate)a3; - int ret = X509Utils.checkIfIssuedBy(issuer,x); - if(ret == X509Utils.V_OK) { - return 1; - } - if((ctx.param.flags & X509Utils.V_FLAG_CB_ISSUER_CHECK) == 0) { - return 0; - } - ctx.error = ret; - ctx.currentCertificate = x; - ctx.currentIssuer = issuer; - return ctx.verifyCallback.call(new Integer(0),ctx); - } - }; - - /** - * c: null_callback - */ - public final static Store.VerifyCallbackFunction NullCallback = new Store.VerifyCallbackFunction() { - public int call(Object a1, Object a2) { - return ((Integer)a1).intValue(); - } - }; - - /** - * c: internal_verify - */ - public final static Store.VerifyFunction internalVerify = new Store.VerifyFunction() { - public int call(Object a1) throws Exception { - StoreContext ctx = (StoreContext)a1; - Store.VerifyCallbackFunction cb = ctx.verifyCallback; - int n = ctx.chain.size(); - ctx.errorDepth = n-1; - n--; - X509AuxCertificate xi = ctx.chain.get(n); - X509AuxCertificate xs = null; - int ok = 0; - if(ctx.checkIssued.call(ctx,xi,xi) != 0) { - xs = xi; - } else { - if(n<=0) { - ctx.error = X509Utils.V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; - ctx.currentCertificate = xi; - ok = cb.call(new Integer(0),ctx); - return ok; - } else { - n--; - ctx.errorDepth = n; - xs = ctx.chain.get(n); - } - } - while(n>=0) { - ctx.errorDepth = n; - if(!xs.isValid()) { - try { - xs.verify(xi.getPublicKey()); - } catch(Exception e) { - /* - System.err.println("n: " + n); - System.err.println("verifying: " + xs); - System.err.println("verifying with issuer?: " + xi); - System.err.println("verifying with issuer.key?: " + xi.getPublicKey()); - System.err.println("exception: " + e); - */ - ctx.error = X509Utils.V_ERR_CERT_SIGNATURE_FAILURE; - ctx.currentCertificate = xs; - ok = cb.call(new Integer(0),ctx); - if(ok == 0) { - return ok; - } - } - } - xs.setValid(true); - ok = ctx.checkCertificateTime(xs); - if(ok == 0) { - return ok; - } - ctx.currentIssuer = xi; - ctx.currentCertificate = xs; - ok = cb.call(new Integer(1),ctx); - if(ok == 0) { - return ok; - } - n--; - if(n>=0) { - xi = xs; - xs = ctx.chain.get(n); - } - } - ok = 1; - return ok; - } - }; - - /** - * c: check_revocation - */ - public final static Store.CheckRevocationFunction defaultCheckRevocation = new Store.CheckRevocationFunction() { - public int call(Object a1) throws Exception { - StoreContext ctx = (StoreContext)a1; - int last,ok=0; - if((ctx.param.flags & X509Utils.V_FLAG_CRL_CHECK) == 0) { - return 1; - } - if((ctx.param.flags & X509Utils.V_FLAG_CRL_CHECK_ALL) != 0) { - last = ctx.chain.size() -1; - } else { - last = 0; - } - for(int i=0;i<=last;i++) { - ctx.errorDepth = i; - ok = ctx.checkCertificate(); - if(ok == 0) { - return 0; - } - } - return 1; - } - }; - - /** - * c: get_crl - */ - public final static Store.GetCRLFunction defaultGetCRL = new Store.GetCRLFunction() { - public int call(Object a1, Object a2, Object a3) throws Exception { - StoreContext ctx = (StoreContext)a1; - X509CRL[] pcrl = (X509CRL[])a2; - X509AuxCertificate x = (X509AuxCertificate)a3; - Name nm = new Name(x.getIssuerX500Principal()); - X509CRL[] crl = new X509CRL[1]; - int ok = ctx.getCRLStack(crl,nm,ctx.crls); - if(ok != 0) { - pcrl[0] = crl[0]; - return 1; - } - X509Object[] xobj = new X509Object[1]; - ok = ctx.getBySubject(X509Utils.X509_LU_CRL,nm,xobj); - if(ok == 0) { - if(crl[0] != null) { - pcrl[0] = crl[0]; - return 1; - } - return 0; - } - pcrl[0] = (X509CRL)(((CRL)xobj[0]).crl); - return 1; - } - }; - - /** - * c: check_crl - */ - public final static Store.CheckCRLFunction defaultCheckCRL = new Store.CheckCRLFunction() { - public int call(Object a1, Object a2) throws Exception { - StoreContext ctx = (StoreContext)a1; - final X509CRL crl = (X509CRL)a2; - X509AuxCertificate issuer = null; - int ok = 0,chnum,cnum; - cnum = ctx.errorDepth; - chnum = ctx.chain.size()-1; - if(cnum < chnum) { - issuer = ctx.chain.get(cnum+1); - } else { - issuer = ctx.chain.get(chnum); - if(ctx.checkIssued.call(ctx,issuer,issuer) == 0) { - ctx.error = X509Utils.V_ERR_UNABLE_TO_GET_CRL_ISSUER; - ok = ctx.verifyCallback.call(new Integer(0),ctx); - if(ok == 0) { - return ok; - } - } - } - - if (issuer != null) { - if (issuer.getKeyUsage() != null && !issuer.getKeyUsage()[6]) { - ctx.error = X509Utils.V_ERR_KEYUSAGE_NO_CRL_SIGN; - ok = ctx.verifyCallback.call(new Integer(0), ctx); - if (ok == 0) { - return ok; - } - } - final PublicKey ikey = issuer.getPublicKey(); - if (ikey == null) { - ctx.error = X509Utils.V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; - ok = ctx.verifyCallback.call(new Integer(0), ctx); - if (ok == 0) { - return ok; - } - } else { - try { - crl.verify(ikey); - } catch (Exception ignored) { - ctx.error = X509Utils.V_ERR_CRL_SIGNATURE_FAILURE; - ok = ctx.verifyCallback.call(new Integer(0), ctx); - if (ok == 0) { - return ok; - } - } - } - } - - ok = ctx.checkCRLTime(crl,1); - if(ok == 0) { - return ok; - } - return 1; - } - }; - - /** - * c: cert_crl - */ - public final static Store.CertificateCRLFunction defaultCertificateCRL = new Store.CertificateCRLFunction() { - public int call(Object a1, Object a2, Object a3) throws Exception { - StoreContext ctx = (StoreContext)a1; - X509CRL crl = (X509CRL)a2; - X509AuxCertificate x = (X509AuxCertificate)a3; - int ok; - if(crl.getRevokedCertificate(x.getSerialNumber()) != null) { - ctx.error = X509Utils.V_ERR_CERT_REVOKED; - ok = ctx.verifyCallback.call(new Integer(0), ctx); - if(ok == 0) { - return 0; - } - } - if((ctx.param.flags & X509Utils.V_FLAG_IGNORE_CRITICAL) != 0) { - return 1; - } - - if(crl.getCriticalExtensionOIDs() != null && crl.getCriticalExtensionOIDs().size()>0) { - ctx.error = X509Utils.V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION; - ok = ctx.verifyCallback.call(new Integer(0), ctx); - if(ok == 0) { - return 0; - } - } - return 1; - } - }; - - /** - * c: check_policy - */ - public final static CheckPolicyFunction defaultCheckPolicy = new CheckPolicyFunction() { - public int call(Object a1) throws Exception { - return 1; - } - }; -}// X509_STORE_CTX diff --git a/src/java/org/jruby/ext/openssl/x509store/Trust.java b/src/java/org/jruby/ext/openssl/x509store/Trust.java deleted file mode 100644 index a414379..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/Trust.java +++ /dev/null @@ -1,279 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.util.ArrayList; -import java.util.List; - -/** - * c: X509_TRUST - * - * @author Ola Bini - */ -public class Trust { - public static interface Checker extends Function3 {} - public int trust; - public int flags; - public Checker checkTrust; - public String name; - public String arg1; - public Object arg2; - - public Trust() {} - - public Trust(int t, int f, Checker ct, String n, String a1, Object a2) { - this.trust = t; - this.flags = f; this.checkTrust = ct; - this.name = n; this.arg1 = a1; - this.arg2 = a2; - } - - /** - * c: X509_TRUST_set_default - */ - public static Checker setDefault(Checker trust) { - Checker old_trust = defaultTrust; - defaultTrust = trust; - return old_trust; - } - - private final static List trtable = new ArrayList(); - - /** - * c: X509_check_trust - */ - public static int checkTrust(X509AuxCertificate x, int id, int flags) throws Exception { - if(id == -1) { - return 1; - } - int idx = getByID(id); - if(idx == -1) { - return defaultTrust.call(new Integer(id),x,new Integer(flags)); - } - Trust pt = getFirst(idx); - return pt.checkTrust.call(pt,x,new Integer(flags)); - } - - /** - * c: X509_TRUST_get_count - */ - public static int getCount() { - return trtable.size() + trstandard.length; - } - - /** - * c: X509_TRUST_get0 - */ - public static Trust getFirst(int idx) { - if(idx < 0) { - return null; - } - if(idx < trstandard.length) { - return trstandard[idx]; - } - return trtable.get(idx - trstandard.length); - } - - /** - * c: X509_TRUST_get_by_id - */ - public static int getByID(int id) { - if(id >= X509Utils.X509_TRUST_MIN && id <= X509Utils.X509_TRUST_MAX) { - return id - X509Utils.X509_TRUST_MIN; - } - int i = 0; - for(Trust t : trtable) { - if(t.trust == id) { - return i + trstandard.length; - } - } - return -1; - } - - /** - * c: X509_TRUST_set - */ - public static int set(int[] t, int trust) { - if(getByID(trust) == -1) { - X509Error.addError(X509Utils.X509_R_INVALID_TRUST); - return 0; - } - t[0] = trust; - return 1; - } - - /** - * c: X509_TRUST_add - */ - public static int add(int id, int flags, Checker ck, String name, String arg1, Object arg2) { - int idx; - Trust trtmp; - flags &= ~X509Utils.X509_TRUST_DYNAMIC; - flags |= X509Utils.X509_TRUST_DYNAMIC_NAME; - idx = getByID(id); - if(idx == -1) { - trtmp = new Trust(); - trtmp.flags = X509Utils.X509_TRUST_DYNAMIC; - } else { - trtmp = getFirst(idx); - } - trtmp.name = name; - trtmp.flags &= X509Utils.X509_TRUST_DYNAMIC; - trtmp.flags |= flags; - trtmp.trust = id; - trtmp.checkTrust = ck; - trtmp.arg1 = arg1; - trtmp.arg2 = arg2; - if(idx == -1) { - trtable.add(trtmp); - } - return 1; - } - - /** - * c: X509_TRUST_cleanup - */ - public static void cleanup() { - trtable.clear(); - } - - /** - * c: X509_TRUST_get_flags - */ - public int getFlags() { - return flags; - } - - /** - * c: X509_TRUST_get0_name - */ - public String getName() { - return name; - } - - /** - * c: X509_TRUST_get_trust - */ - public int getTrust() { - return trust; - } - - /** - * c: trust_compat - */ - public final static Checker trustCompatibe = new Checker() { - public int call(Object _trust, Object _x, Object _flags) throws Exception { - //X509_TRUST trust = (X509_TRUST)_trust; - X509AuxCertificate x = (X509AuxCertificate)_x; - //int flags = ((Integer)_flags).intValue(); - - Purpose.checkPurpose(x,-1,0); - if(x.getIssuerX500Principal().equals(x.getSubjectX500Principal())) { // self signed - return X509Utils.X509_TRUST_TRUSTED; - } else { - return X509Utils.X509_TRUST_UNTRUSTED; - } - } - }; - - /** - * c: trust_1oidany - */ - public final static Checker trust1OIDAny = new Checker() { - public int call(Object _trust, Object _x, Object _flags) throws Exception { - Trust trust = (Trust)_trust; - X509AuxCertificate x = (X509AuxCertificate)_x; - int flags = ((Integer)_flags).intValue(); - - X509Aux ax = x.getAux(); - if(ax != null && (ax.trust.size() > 0 || ax.reject.size() > 0)) { - return objTrust.call(trust.arg1,x,new Integer(flags)); - } - return trustCompatibe.call(trust,x,new Integer(flags)); - } - }; - - /** - * c: trust_1oid - */ - public final static Checker trust1OID = new Checker() { - public int call(Object _trust, Object _x, Object _flags) throws Exception { - Trust trust = (Trust)_trust; - X509AuxCertificate x = (X509AuxCertificate)_x; - int flags = ((Integer)_flags).intValue(); - - if(x.getAux() != null) { - return objTrust.call(trust.arg1,x,new Integer(flags)); - } - return X509Utils.X509_TRUST_UNTRUSTED; - } - }; - - /** - * c: obj_trust - */ - public final static Checker objTrust = new Checker() { - public int call(Object _id, Object _x, Object _flags) { - String id = (String)_id; - X509AuxCertificate x = (X509AuxCertificate)_x; - //int flags = ((Integer)_flags).intValue(); - - X509Aux ax = x.getAux(); - if(null == ax) { - return X509Utils.X509_TRUST_UNTRUSTED; - } - for(String rej : ax.reject) { - if(rej.equals(id)) { - return X509Utils.X509_TRUST_REJECTED; - } - } - for(String t : ax.trust) { - if(t.equals(id)) { - return X509Utils.X509_TRUST_TRUSTED; - } - } - return X509Utils.X509_TRUST_UNTRUSTED; - } - }; - - /** - * c: default_trust - */ - public static Checker defaultTrust = objTrust; - - public final static Trust[] trstandard = new Trust[] { - new Trust(X509Utils.X509_TRUST_COMPAT, 0, trustCompatibe, "compatible", null, null), - new Trust(X509Utils.X509_TRUST_SSL_CLIENT, 0, trust1OIDAny, "SSL Client", "1.3.6.1.5.5.7.3.2", null), - new Trust(X509Utils.X509_TRUST_SSL_SERVER, 0, trust1OIDAny, "SSL Server", "1.3.6.1.5.5.7.3.1", null), - new Trust(X509Utils.X509_TRUST_EMAIL, 0, trust1OIDAny, "S/MIME email", "1.3.6.1.5.5.7.3.4", null), - new Trust(X509Utils.X509_TRUST_OBJECT_SIGN, 0, trust1OIDAny, "Object Signer", "1.3.6.1.5.5.7.3.3", null), - new Trust(X509Utils.X509_TRUST_OCSP_SIGN, 0, trust1OID, "OCSP responder", "1.3.6.1.5.5.7.3.9", null), - new Trust(X509Utils.X509_TRUST_OCSP_REQUEST, 0, trust1OID, "OCSP request", "1.3.6.1.5.5.7.48.1", null) - - }; -}// X509_TRUST diff --git a/src/java/org/jruby/ext/openssl/x509store/VerifyParameter.java b/src/java/org/jruby/ext/openssl/x509store/VerifyParameter.java deleted file mode 100644 index 83a57a3..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/VerifyParameter.java +++ /dev/null @@ -1,324 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.util.Date; - -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; - -import org.bouncycastle.asn1.DERObject; - -/** - * c: X509_VERIFY_PARAM - * - * @author Ola Bini - */ -public class VerifyParameter { - public String name; - public Date checkTime; - public long inheritFlags; - public long flags; - public int purpose; - public int trust; - public int depth; - public List policies; - - /** - * c: X509_VERIFY_PARAM_new - */ - public VerifyParameter() { - zero(); - } - - public VerifyParameter(String n, long t, long i_f, long f, int p, int trs, int d, List pol) { - this.name = n; - this.checkTime = new Date(t); - this.inheritFlags = i_f; - this.flags = f; - this.purpose = p; - this.trust = trs; - this.depth = d; - this.policies = pol; - } - - private void zero() { - name = null; - purpose = 0; - trust = 0; - inheritFlags = X509Utils.X509_VP_FLAG_DEFAULT; - flags = 0; - depth = -1; - policies = null; - } - - /** - * c: X509_VERIFY_PARAM_free - */ - public void free() { - zero(); - } - - /** - * c: X509_VERIFY_PARAM_inherit - */ - public int inherit(VerifyParameter src) { - long inh_flags; - boolean to_d, to_o; - - if(src == null) { - return 1; - } - - - inh_flags = src.inheritFlags | this.inheritFlags; - if((inh_flags & X509Utils.X509_VP_FLAG_ONCE) != 0) { - this.inheritFlags = 0; - } - if((inh_flags & X509Utils.X509_VP_FLAG_LOCKED) != 0) { - return 1; - } - to_d = ((inh_flags & X509Utils.X509_VP_FLAG_DEFAULT) != 0); - to_o = ((inh_flags & X509Utils.X509_VP_FLAG_OVERWRITE) != 0); - - if(to_o || ((src.purpose != 0 && (to_d || this.purpose == 0)))) { - this.purpose = src.purpose; - } - if(to_o || ((src.trust != 0 && (to_d || this.trust == 0)))) { - this.trust = src.trust; - } - if(to_o || ((src.depth != -1 && (to_d || this.depth == -1)))) { - this.depth = src.depth; - } - - if(to_o || !((this.flags & X509Utils.V_FLAG_USE_CHECK_TIME) != 0)) { - this.checkTime = src.checkTime; - this.flags &= ~X509Utils.V_FLAG_USE_CHECK_TIME; - } - - if((inh_flags & X509Utils.X509_VP_FLAG_RESET_FLAGS) != 0) { - this.flags = 0; - } - - this.flags |= src.flags; - - if(to_o || ((src.policies != null && (to_d || this.policies == null)))) { - setPolicies(src.policies); - } - return 1; - } - - /** - * c: X509_VERIFY_PARAM_set1 - */ - public int set(VerifyParameter from) { - inheritFlags |= X509Utils.X509_VP_FLAG_DEFAULT; - return inherit(from); - } - - /** - * c: X509_VERIFY_PARAM_set1_name - */ - public int setName(String name) { - this.name = name; - return 1; - } - - /** - * c: X509_VERIFY_PARAM_set_flags - */ - public int setFlags(long flags) { - this.flags |= flags; - if((flags & X509Utils.V_FLAG_POLICY_MASK) == X509Utils.V_FLAG_POLICY_MASK) { - this.flags |= X509Utils.V_FLAG_POLICY_CHECK; - } - return 1; - } - - /** - * c: X509_VERIFY_PARAM_clear_flags - */ - public int clearFlags(long flags) { - this.flags &= ~flags; - return 1; - } - - /** - * c: X509_VERIFY_PARAM_get_flags - */ - public long getFlags() { - return flags; - } - - /** - * c: X509_VERIFY_PARAM_set_purpose - */ - public int setPurpose(int purpose) { - int[] arg = new int[]{this.purpose}; - int v = Purpose.set(arg,purpose); - this.purpose = arg[0]; - return v; - } - - /** - * c: X509_VERIFY_PARAM_set_trust - */ - public int setTrust(int trust) { - int[] arg = new int[]{this.trust}; - int v = Trust.set(arg,trust); - this.trust = arg[0]; - return v; - } - - /** - * c: X509_VERIFY_PARAM_set_depth - */ - public void setDepth(int depth) { - this.depth = depth; - } - - /** - * c: X509_VERIFY_PARAM_set_time - */ - public void setTime(Date t) { - this.checkTime = t; - this.flags |= X509Utils.V_FLAG_USE_CHECK_TIME; - } - - /** - * c: X509_VERIFY_PARAM_add0_policy - */ - public int addPolicy(DERObject policy) { - if(policies == null) { - policies = new ArrayList(); - } - policies.add(policy); - return 1; - } - - /** - * c: X509_VERIFY_PARAM_set1_policies - */ - public int setPolicies(List policies) { - if(policies == null) { - this.policies = null; - return 1; - } - this.policies = new ArrayList(); - this.policies.addAll(policies); - this.flags |= X509Utils.V_FLAG_POLICY_CHECK; - return 1; - } - - /** - * c: X509_VERIFY_PARAM_get_depth - */ - public int getDepth() { - return depth; - } - - /** - * c: X509_VERIFY_PARAM_add0_table - */ - public int addTable() { - for(Iterator iter = parameterTable.iterator();iter.hasNext();) { - VerifyParameter v = iter.next(); - if(this.name.equals(v.name)) { - iter.remove(); - } - } - parameterTable.add(this); - return 1; - } - - public static VerifyParameter lookup(String name) { - for(VerifyParameter v : parameterTable) { - if(name.equals(v.name)) { - return v; - } - } - for(VerifyParameter v : defaultTable) { - if(name.equals(v.name)) { - return v; - } - } - return null; - } - - /** - * c: X509_VERIFY_PARAM_table_cleanup - */ - public static void tableCleanup() { - parameterTable.clear(); - } - - private final static VerifyParameter[] defaultTable = new VerifyParameter[] { - new VerifyParameter( - "default", /* X509 default parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - 0, /* purpose */ - 0, /* trust */ - 100, /* depth */ - null /* policies */ - ), - new VerifyParameter( - "pkcs7", /* SSL/TLS client parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SMIME_SIGN, /* purpose */ - X509Utils.X509_TRUST_EMAIL, /* trust */ - -1, /* depth */ - null /* policies */ - ), - new VerifyParameter( - "ssl_client", /* SSL/TLS client parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SSL_CLIENT, /* purpose */ - X509Utils.X509_TRUST_SSL_CLIENT, /* trust */ - -1, /* depth */ - null /* policies */ - ), - new VerifyParameter( - "ssl_server", /* SSL/TLS server parameters */ - 0, /* Check time */ - 0, /* internal flags */ - 0, /* flags */ - X509Utils.X509_PURPOSE_SSL_SERVER, /* purpose */ - X509Utils.X509_TRUST_SSL_SERVER, /* trust */ - -1, /* depth */ - null /* policies */ - )}; - - private final static List parameterTable = new ArrayList(); -}// X509_VERIFY_PARAM diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Aux.java b/src/java/org/jruby/ext/openssl/x509store/X509Aux.java deleted file mode 100644 index f7d56ed..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/X509Aux.java +++ /dev/null @@ -1,43 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.util.List; -import java.util.ArrayList; -import org.bouncycastle.asn1.DERObject; - -/** - * @author Ola Bini - */ -public class X509Aux { - public List trust = new ArrayList(); // String of OID's /* trusted uses */ - public List reject = new ArrayList(); // String of OID's /* rejected uses */ - public String alias; /* "friendly name" */ - public byte[] keyid; /* key id of private key */ - public List other = new ArrayList(); /* String of OID's of sigAlgs, other unspecified info */ -}// X509_AUX diff --git a/src/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java b/src/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java deleted file mode 100644 index 555d247..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/X509AuxCertificate.java +++ /dev/null @@ -1,170 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.io.IOException; -import java.math.BigInteger; - -import java.security.Principal; -import java.security.PublicKey; -import java.security.NoSuchAlgorithmException; -import java.security.InvalidKeyException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.CertificateParsingException; -import java.security.cert.X509Certificate; - -import java.util.Date; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.security.auth.x500.X500Principal; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DEROctetString; - -/** - * Since regular X509Certificate doesn't represent the Aux part of a - * certification, this class uses composition and extension to contain - * both pieces of information. - * - * @author Ola Bini - */ -public class X509AuxCertificate extends X509Certificate { - private static final long serialVersionUID = -909543379295427515L; - private final X509Certificate wrap; - private final X509Aux aux; - - private boolean valid = false; - private int ex_flags = 0; - - public X509AuxCertificate(X509Certificate wrap) { - this(wrap,null); - } - - public X509AuxCertificate(X509Certificate wrap, X509Aux aux) { - super(); - this.wrap = wrap; - this.aux = aux; - } - - public X509Aux getAux() { - return this.aux; - } - - public boolean isValid() { - return valid; - } - - public void setValid(boolean v) { - this.valid = v; - } - - public int getExFlags() { - return ex_flags; - } - - public void setExFlags(int ex_flags) { - this.ex_flags = ex_flags; - } - - public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { wrap.checkValidity(); } - public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException { wrap.checkValidity(date); } - public int getBasicConstraints() { return wrap.getBasicConstraints(); } - public List getExtendedKeyUsage() throws CertificateParsingException { return wrap.getExtendedKeyUsage(); } - public Collection> getIssuerAlternativeNames() throws CertificateParsingException { return wrap.getIssuerAlternativeNames(); } - public Principal getIssuerDN() { return wrap.getIssuerDN(); } - public boolean[] getIssuerUniqueID() { return wrap.getIssuerUniqueID(); } - public X500Principal getIssuerX500Principal() { return wrap.getIssuerX500Principal(); } - public boolean[] getKeyUsage() { return wrap.getKeyUsage(); } - public Date getNotAfter() { return wrap.getNotAfter(); } - public Date getNotBefore() { return wrap.getNotBefore(); } - public BigInteger getSerialNumber() { return wrap.getSerialNumber(); } - public String getSigAlgName() { return wrap.getSigAlgName(); } - public String getSigAlgOID() { return wrap.getSigAlgOID(); } - public byte[] getSigAlgParams() { return wrap.getSigAlgParams(); } - public byte[] getSignature() { return wrap.getSignature(); } - public Collection> getSubjectAlternativeNames() throws CertificateParsingException { return wrap.getSubjectAlternativeNames(); } - public Principal getSubjectDN() { return wrap.getSubjectDN(); } - public boolean[] getSubjectUniqueID() { return wrap.getSubjectUniqueID(); } - public X500Principal getSubjectX500Principal() { return wrap.getSubjectX500Principal(); } - public byte[] getTBSCertificate() throws CertificateEncodingException { return wrap.getTBSCertificate(); } - public int getVersion() { return wrap.getVersion(); } - - public boolean equals(Object other) { - boolean ret = this == other; - if(!ret && (other instanceof X509AuxCertificate)) { - X509AuxCertificate o = (X509AuxCertificate)other; - ret = this.wrap.equals(o.wrap) && ((this.aux == null) ? o.aux == null : this.aux.equals(o.aux)); - } - return ret; - } - public byte[] getEncoded() throws CertificateEncodingException { return wrap.getEncoded(); } - public PublicKey getPublicKey(){ return wrap.getPublicKey(); } - public int hashCode() { - int ret = wrap.hashCode(); - ret += 3 * (aux == null ? 1 : aux.hashCode()); - return ret; - } - public String toString(){ return wrap.toString(); } - public void verify(PublicKey key) throws CertificateException,NoSuchAlgorithmException,InvalidKeyException,NoSuchProviderException,SignatureException { wrap.verify(key); } - public void verify(PublicKey key, String sigProvider) throws CertificateException,NoSuchAlgorithmException,InvalidKeyException,NoSuchProviderException,SignatureException { wrap.verify(key,sigProvider); } - public Set getCriticalExtensionOIDs(){ return wrap.getCriticalExtensionOIDs(); } - public byte[] getExtensionValue(String oid){ return wrap.getExtensionValue(oid); } - public Set getNonCriticalExtensionOIDs(){ return wrap.getNonCriticalExtensionOIDs(); } - public boolean hasUnsupportedCriticalExtension(){ return wrap.hasUnsupportedCriticalExtension(); } - - private static final String NS_CERT_TYPE_OID = "2.16.840.1.113730.1.1"; - public Integer getNsCertType() throws CertificateException { - byte[] bytes = getExtensionValue(NS_CERT_TYPE_OID); - if (bytes == null) { - return null; - } - try { - Object o = new ASN1InputStream(bytes).readObject(); - if (o instanceof DERBitString) { - return ((DERBitString) o).intValue(); - } else if (o instanceof DEROctetString) { - // just reads initial object for nsCertType definition and ignores trailing objects. - ASN1InputStream in = new ASN1InputStream(((DEROctetString) o).getOctets()); - o = in.readObject(); - return ((DERBitString) o).intValue(); - } else { - throw new CertificateException("unknown type from ASN1InputStream.readObject: " + o); - } - } catch (IOException ioe) { - throw new CertificateEncodingException(ioe.getMessage(), ioe); - } - } - -}// X509AuxCertificate diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Error.java b/src/java/org/jruby/ext/openssl/x509store/X509Error.java deleted file mode 100644 index 63cb26d..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/X509Error.java +++ /dev/null @@ -1,148 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.util.ArrayList; -import java.util.List; - -/** - * Used to handle OpenSSL errors in a sane way. These are not safe for - * multi runtimes at the moments. - * - * @author Ola Bini - */ -public class X509Error { - private static ThreadLocal> errors = new ThreadLocal>(); - - public static class ErrorException extends Exception { - private static final long serialVersionUID = -3214495184277468063L; - - private int reason; - - public ErrorException(int reason) { - super(); - this.reason = reason; - } - - public int getReason() { - return reason; - } - - @Override - public String getMessage() { - switch (reason) { - case X509Utils.X509_R_BAD_X509_FILETYPE: - return "bad x509 filetype"; - case X509Utils.X509_R_BASE64_DECODE_ERROR: - return "base64 decode error"; - case X509Utils.X509_R_CANT_CHECK_DH_KEY: - return "cant check dh key"; - case X509Utils.X509_R_CERT_ALREADY_IN_HASH_TABLE: - return "cert already in hash table"; - case X509Utils.X509_R_ERR_ASN1_LIB: - return "err asn1 lib"; - case X509Utils.X509_R_INVALID_DIRECTORY: - return "invalid directory"; - case X509Utils.X509_R_INVALID_FIELD_NAME: - return "invalid field name"; - case X509Utils.X509_R_INVALID_TRUST: - return "invalid trust"; - case X509Utils.X509_R_KEY_TYPE_MISMATCH: - return "key type mismatch"; - case X509Utils.X509_R_KEY_VALUES_MISMATCH: - return "key values mismatch"; - case X509Utils.X509_R_LOADING_CERT_DIR: - return "loading cert dir"; - case X509Utils.X509_R_LOADING_DEFAULTS: - return "loading defaults"; - case X509Utils.X509_R_METHOD_NOT_SUPPORTED: - return "method not supported"; - case X509Utils.X509_R_NO_CERT_SET_FOR_US_TO_VERIFY: - return "no cert set for us to verify"; - case X509Utils.X509_R_PUBLIC_KEY_DECODE_ERROR: - return "public key decode error"; - case X509Utils.X509_R_PUBLIC_KEY_ENCODE_ERROR: - return "public key encode error"; - case X509Utils.X509_R_SHOULD_RETRY: - return "should retry"; - case X509Utils.X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN: - return "unable to find parameters in chain"; - case X509Utils.X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY: - return "unable to get certs public key"; - case X509Utils.X509_R_UNKNOWN_KEY_TYPE: - return "unknown key type"; - case X509Utils.X509_R_UNKNOWN_NID: - return "unknown nid"; - case X509Utils.X509_R_UNKNOWN_PURPOSE_ID: - return "unknown purpose id"; - case X509Utils.X509_R_UNKNOWN_TRUST_ID: - return "unknown trust id"; - case X509Utils.X509_R_UNSUPPORTED_ALGORITHM: - return "unsupported algorithm"; - case X509Utils.X509_R_WRONG_LOOKUP_TYPE: - return "wrong lookup type"; - case X509Utils.X509_R_WRONG_TYPE: - return "wrong type"; - - default: - return "(unknown X509 error)"; - } - } - } - - public static void addError(int reason) { - synchronized (errors) { - List errs = errors.get(); - if (errs == null) { - errs = new ArrayList(); - errors.set(errs); - } - errs.add(new ErrorException(reason)); - } - } - - public static void clearErrors() { - synchronized (errors) { - List errs = errors.get(); - if (errs != null) { - errs.clear(); - } - } - } - - public static List getErrors() { - synchronized (errors) { - List errs = errors.get(); - if (errs == null) { - errs = new ArrayList(); - errors.set(errs); - } - return errs; - } - } -}// Err diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Object.java b/src/java/org/jruby/ext/openssl/x509store/X509Object.java deleted file mode 100644 index 61a6a1b..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/X509Object.java +++ /dev/null @@ -1,89 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - -import java.util.List; - -/** - * c: X509_OBJECT - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public abstract class X509Object implements Comparable { - /** - * c: X509_OBJECT_idx_by_subject - */ - public static int indexBySubject(List h, int type, Name name) { - int ix = 0; - for(X509Object oo : h) { - if(type == oo.type() && oo.isName(name)) { - return ix; - } - } - return -1; - } - - /** - * c: X509_OBJECT_retrieve_by_subject - */ - public static X509Object retrieveBySubject(List h,int type,Name name) { - for(X509Object o : h) { - if(type == o.type() && o.isName(name)) { - return o; - } - } - return null; - } - - /** - * c: X509_OBJECT_retrieve_match - */ - public static X509Object retrieveMatch(List h, X509Object x) { - for(X509Object o : h) { - if(o.matches(x)) { - return o; - } - } - return null; - } - - public boolean isName(Name nm) { - return false; - } - - public boolean matches(X509Object o) { - return false; - } - - public abstract int type(); - - public int compareTo(X509Object other) { - return type() - other.type(); - } -}// X509_OBJECT diff --git a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java b/src/java/org/jruby/ext/openssl/x509store/X509Utils.java deleted file mode 100644 index 63b8f3c..0000000 --- a/src/java/org/jruby/ext/openssl/x509store/X509Utils.java +++ /dev/null @@ -1,536 +0,0 @@ -/***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Common Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Copyright (C) 2006 Ola Bini - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. - ***** END LICENSE BLOCK *****/ -package org.jruby.ext.openssl.x509store; - - -import java.util.Arrays; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEREncodable; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; - -/** - * Contains most of the functionality that beings with X509 in - * crypty/x509/x509_def.c, crypty/x509/x509_txt.c and others. - * - * @author Ola Bini - */ -@SuppressWarnings("deprecation") -public abstract class X509Utils { - private X509Utils() {} - - /** - * c: X509_get_default_private_dir - */ - public static String getDefaultPrivateDir() { - return X509_PRIVATE_DIR; - } - - /** - * c: X509_get_default_cert_area - */ - public static String getDefaultCertificateArea() { - return X509_CERT_AREA; - } - - /** - * c: X509_get_default_cert_dir - */ - public static String getDefaultCertificateDirectory() { - return X509_CERT_DIR; - } - - /** - * c: X509_get_default_cert_file - */ - public static String getDefaultCertificateFile() { - return X509_CERT_FILE; - } - - /** - * c: X509_get_default_cert_dir_env - */ - public static String getDefaultCertificateDirectoryEnvironment() { - return X509_CERT_DIR_EVP; - } - - /** - * c: X509_get_default_cert_file_env - */ - public static String getDefaultCertificateFileEnvironment() { - return X509_CERT_FILE_EVP; - } - - /** - * c: X509_verify_cert_error_string - */ - public static String verifyCertificateErrorString(int n) { - switch(n){ - case V_OK: - return("ok"); - case V_ERR_UNABLE_TO_GET_ISSUER_CERT: - return("unable to get issuer certificate"); - case V_ERR_UNABLE_TO_GET_CRL: - return("unable to get certificate CRL"); - case V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: - return("unable to decrypt certificate's signature"); - case V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: - return("unable to decrypt CRL's signature"); - case V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: - return("unable to decode issuer public key"); - case V_ERR_CERT_SIGNATURE_FAILURE: - return("certificate signature failure"); - case V_ERR_CRL_SIGNATURE_FAILURE: - return("CRL signature failure"); - case V_ERR_CERT_NOT_YET_VALID: - return("certificate is not yet valid"); - case V_ERR_CRL_NOT_YET_VALID: - return("CRL is not yet valid"); - case V_ERR_CERT_HAS_EXPIRED: - return("certificate has expired"); - case V_ERR_CRL_HAS_EXPIRED: - return("CRL has expired"); - case V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - return("format error in certificate's notBefore field"); - case V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - return("format error in certificate's notAfter field"); - case V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - return("format error in CRL's lastUpdate field"); - case V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - return("format error in CRL's nextUpdate field"); - case V_ERR_OUT_OF_MEM: - return("out of memory"); - case V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - return("self signed certificate"); - case V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - return("self signed certificate in certificate chain"); - case V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - return("unable to get local issuer certificate"); - case V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: - return("unable to verify the first certificate"); - case V_ERR_CERT_CHAIN_TOO_LONG: - return("certificate chain too long"); - case V_ERR_CERT_REVOKED: - return("certificate revoked"); - case V_ERR_INVALID_CA: - return ("invalid CA certificate"); - case V_ERR_INVALID_NON_CA: - return ("invalid non-CA certificate (has CA markings)"); - case V_ERR_PATH_LENGTH_EXCEEDED: - return ("path length constraint exceeded"); - case V_ERR_PROXY_PATH_LENGTH_EXCEEDED: - return("proxy path length constraint exceeded"); - case V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: - return("proxy cerificates not allowed, please set the appropriate flag"); - case V_ERR_INVALID_PURPOSE: - return ("unsupported certificate purpose"); - case V_ERR_CERT_UNTRUSTED: - return ("certificate not trusted"); - case V_ERR_CERT_REJECTED: - return ("certificate rejected"); - case V_ERR_APPLICATION_VERIFICATION: - return("application verification failure"); - case V_ERR_SUBJECT_ISSUER_MISMATCH: - return("subject issuer mismatch"); - case V_ERR_AKID_SKID_MISMATCH: - return("authority and subject key identifier mismatch"); - case V_ERR_AKID_ISSUER_SERIAL_MISMATCH: - return("authority and issuer serial number mismatch"); - case V_ERR_KEYUSAGE_NO_CERTSIGN: - return("key usage does not include certificate signing"); - case V_ERR_UNABLE_TO_GET_CRL_ISSUER: - return("unable to get CRL issuer certificate"); - case V_ERR_UNHANDLED_CRITICAL_EXTENSION: - return("unhandled critical extension"); - case V_ERR_KEYUSAGE_NO_CRL_SIGN: - return("key usage does not include CRL signing"); - case V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: - return("key usage does not include digital signature"); - case V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: - return("unhandled critical CRL extension"); - case V_ERR_INVALID_EXTENSION: - return("invalid or inconsistent certificate extension"); - case V_ERR_INVALID_POLICY_EXTENSION: - return("invalid or inconsistent certificate policy extension"); - case V_ERR_NO_EXPLICIT_POLICY: - return("no explicit policy"); - default: - return "error number " + n; - } - } - - private static Object get(Object str) throws Exception { - return get(((DEROctetString)str).getOctets()); - } - - private static Object get(byte[] str) throws Exception { - return new ASN1InputStream(str).readObject(); - } - - /** - * c: X509_check_issued - */ - public static int checkIfIssuedBy(X509AuxCertificate issuer, X509AuxCertificate subject) throws Exception { - if(!issuer.getSubjectX500Principal().equals(subject.getIssuerX500Principal())) { - return V_ERR_SUBJECT_ISSUER_MISMATCH; - } - - if(subject.getExtensionValue("2.5.29.35") != null) { //authorityKeyID - // I hate ASN1 and DER - Object key = get(subject.getExtensionValue("2.5.29.35")); - if(!(key instanceof ASN1Sequence)) { - key = get(key); - } - - ASN1Sequence seq = (ASN1Sequence)key; - AuthorityKeyIdentifier sakid = null; - if(seq.size() == 1 && (seq.getObjectAt(0) instanceof ASN1OctetString)) { - sakid = new AuthorityKeyIdentifier(new DERSequence(new DERTaggedObject(0, seq.getObjectAt(0)))); - } else { - sakid = new AuthorityKeyIdentifier(seq); - } - - if(sakid.getKeyIdentifier() != null) { - if(issuer.getExtensionValue("2.5.29.14") != null) { - DEROctetString der = (DEROctetString)get(issuer.getExtensionValue("2.5.29.14")); - if(der.getOctets().length > 20) { - der = (DEROctetString)get(der.getOctets()); - } - SubjectKeyIdentifier iskid = new SubjectKeyIdentifier(der); - if(iskid.getKeyIdentifier() != null) { - if(!Arrays.equals(sakid.getKeyIdentifier(),iskid.getKeyIdentifier())) { - return V_ERR_AKID_SKID_MISMATCH; - } - } - } - } - if(sakid.getAuthorityCertSerialNumber() != null && !sakid.getAuthorityCertSerialNumber().equals(issuer.getSerialNumber())) { - return V_ERR_AKID_ISSUER_SERIAL_MISMATCH; - } - if(sakid.getAuthorityCertIssuer() != null) { - GeneralName[] gens = sakid.getAuthorityCertIssuer().getNames(); - org.bouncycastle.asn1.x509.X509Name nm = null; - for(int i=0;i 0x00907000 - def test_ciphers - OpenSSL::Cipher.ciphers.each{|name| - assert(OpenSSL::Cipher::Cipher.new(name).is_a?(OpenSSL::Cipher::Cipher)) - } - end - - def test_AES - pt = File.read(__FILE__) - %w(ECB CBC CFB OFB).each{|mode| - c1 = OpenSSL::Cipher::AES256.new(mode) - c1.encrypt - assert_nothing_raised('This test fails w/o Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files') do - c1.pkcs5_keyivgen("passwd") - end - ct = c1.update(pt) + c1.final - - c2 = OpenSSL::Cipher::AES256.new(mode) - c2.decrypt - c2.pkcs5_keyivgen("passwd") - assert_equal(pt, c2.update(ct) + c2.final) - } - end - end - - # JRUBY-4028 - def test_jruby_4028 - key = "0599E113A7EE32A9" - data = "1234567890~5J96LC303C1D22DD~20090930005944~http%3A%2F%2Flocalhost%3A8080%2Flogin%3B0%3B1~http%3A%2F%2Fmix-stage.oracle.com%2F~00" - c1 = OpenSSL::Cipher::Cipher.new("DES-CBC") - c1.padding = 0 - c1.iv = "0" * 8 - c1.encrypt - c1.key = key - e = c1.update data - e << c1.final - - c2 = OpenSSL::Cipher::Cipher.new("DES-CBC") - c2.padding = 0 - c2.iv = "0" * 8 - c2.decrypt - c2.key = key - d = c2.update e - d << c2.final - - assert_equal "\342\320B.\300&X\310\344\253\025\215\017*\22015\344\024D\342\213\361\336\311\271\326\016\243\214\026\2545\002\237,\017s\202\316&Ew\323\221H\376\200\304\201\365\332Im\240\361\037\246\3536\001A2\341\324o0\350\364%=\325\330\240\324u\225\304h\277\272\361f\024\324\352\336\353N\002/]C\370!\003)\212oa\225\207\333\340\245\207\024\351\037\327[\212\001{\216\f\315\345\372\v\226\r\233?\002\vJK", e - assert_equal data, d - end -end - -end diff --git a/test/1.8/test_config.rb b/test/1.8/test_config.rb deleted file mode 100644 index 84f5ee3..0000000 --- a/test/1.8/test_config.rb +++ /dev/null @@ -1,290 +0,0 @@ -require 'openssl' -require "test/unit" -require 'tempfile' -require File.join(File.dirname(__FILE__), "utils.rb") - -class OpenSSL::TestConfig < Test::Unit::TestCase - def setup - file = Tempfile.open("openssl.cnf") - file << <<__EOD__ -HOME = . -[ ca ] -default_ca = CA_default -[ CA_default ] -dir = ./demoCA -certs = ./certs -__EOD__ - file.close - @it = OpenSSL::Config.new(file.path) - end - - def TODO_test_constants - assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) - assert_nothing_raised do - OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE) - end - end - - def test_s_parse - c = OpenSSL::Config.parse('') - assert_equal("[ default ]\n\n", c.to_s) - c = OpenSSL::Config.parse(@it.to_s) - assert_equal(['CA_default', 'ca', 'default'], c.sections.sort) - end - - def test_s_parse_format - c = OpenSSL::Config.parse(<<__EOC__) - baz =qx\t # "baz = qx" - -foo::bar = baz # shortcut section::key format - default::bar = baz # ditto -a=\t \t # "a = ": trailing spaces are ignored - =b # " = b": empty key - =c # " = c": empty key (override the above line) - d= # "c = ": trailing comment is ignored - -sq = 'foo''b\\'ar' - dq ="foo""''\\"" - dq2 = foo""bar -esc=a\\r\\n\\b\\tb -foo\\bar = foo\\b\\\\ar -foo\\bar::foo\\bar = baz -[default1 default2]\t\t # space is allowed in section name - fo =b ar # space allowed in value -[emptysection] - [doller ] -foo=bar -bar = $(foo) -baz = 123$(default::bar)456${foo}798 -qux = ${baz} -quxx = $qux.$qux -__EOC__ - assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) - assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort) - assert_equal('c', c['default']['']) - assert_equal('', c['default']['a']) - assert_equal('qx', c['default']['baz']) - assert_equal('', c['default']['d']) - assert_equal('baz', c['default']['bar']) - assert_equal("foob'ar", c['default']['sq']) - assert_equal("foo''\"", c['default']['dq']) - assert_equal("foobar", c['default']['dq2']) - assert_equal("a\r\n\b\tb", c['default']['esc']) - assert_equal("foo\b\\ar", c['default']['foo\\bar']) - assert_equal('baz', c['foo']['bar']) - assert_equal('baz', c['foo\\bar']['foo\\bar']) - assert_equal('b ar', c['default1 default2']['fo']) - - # dolloer - assert_equal('bar', c['doller']['foo']) - assert_equal('bar', c['doller']['bar']) - assert_equal('123baz456bar798', c['doller']['baz']) - assert_equal('123baz456bar798', c['doller']['qux']) - assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx']) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $bar") - end - assert_equal("error in line 1: variable has no value", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $(bar") - end - assert_equal("error in line 1: no close brace", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("f o =b ar # no space in key") - end - assert_equal("error in line 1: missing equal sign", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse(<<__EOC__) -# comment 1 # comments - -# - # comment 2 -\t#comment 3 - [second ]\t -[third # section not terminated -__EOC__ - end - assert_equal("error in line 7: missing close square bracket", excn.message) - end - - def test_s_load - # alias of new - c = OpenSSL::Config.load - assert_equal("", c.to_s) - assert_equal([], c.sections) - # - file = Tempfile.open("openssl.cnf") - file.close - c = OpenSSL::Config.load(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - end - - def test_initialize - c = OpenSSL::Config.new - assert_equal("", c.to_s) - assert_equal([], c.sections) - end - - def test_initialize_with_empty_file - file = Tempfile.open("openssl.cnf") - file.close - c = OpenSSL::Config.new(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - end - - def test_initialize_with_example_file - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - end - - def test_get_value - assert_equal('CA_default', @it.get_value('ca', 'default_ca')) - assert_equal(nil, @it.get_value('ca', 'no such key')) - assert_equal(nil, @it.get_value('no such section', 'no such key')) - assert_equal('.', @it.get_value('', 'HOME')) - assert_raise(TypeError) do - @it.get_value(nil, 'HOME') # not allowed unlike Config#value - end - # fallback to 'default' ugly... - assert_equal('.', @it.get_value('unknown', 'HOME')) - end - - def test_get_value_ENV - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.get_value('ENV', key)) - end - - def test_value - # supress deprecation warnings - OpenSSL::TestUtils.silent do - assert_equal('CA_default', @it.value('ca', 'default_ca')) - assert_equal(nil, @it.value('ca', 'no such key')) - assert_equal(nil, @it.value('no such section', 'no such key')) - assert_equal('.', @it.value('', 'HOME')) - assert_equal('.', @it.value(nil, 'HOME')) - assert_equal('.', @it.value('HOME')) - # fallback to 'default' ugly... - assert_equal('.', @it.value('unknown', 'HOME')) - end - end - - def test_value_ENV - OpenSSL::TestUtils.silent do - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.value('ENV', key)) - end - end - - def test_aref - assert_equal({'HOME' => '.'}, @it['default']) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default']) - assert_equal({}, @it['no_such_section']) - assert_equal({}, @it['']) - end - - def test_section - OpenSSL::TestUtils.silent do - assert_equal({'HOME' => '.'}, @it.section('default')) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) - assert_equal({}, @it.section('no_such_section')) - assert_equal({}, @it.section('')) - end - end - - def test_sections - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - @it['new_section'] = {'foo' => 'bar'} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - @it['new_section'] = {} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - end - - def test_add_value - c = OpenSSL::Config.new - assert_equal("", c.to_s) - # add key - c.add_value('default', 'foo', 'bar') - assert_equal("[ default ]\nfoo=bar\n\n", c.to_s) - # add another key - c.add_value('default', 'baz', 'qux') - assert_equal('bar', c['default']['foo']) - assert_equal('qux', c['default']['baz']) - # update the value - c.add_value('default', 'baz', 'quxxx') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - # add section and key - c.add_value('section', 'foo', 'bar') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - assert_equal('bar', c['section']['foo']) - end - - def test_aset - @it['foo'] = {'bar' => 'baz'} - assert_equal({'bar' => 'baz'}, @it['foo']) - @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'} - assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - - # OpenSSL::Config is add only for now. - @it['foo'] = {'foo' => 'foo'} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - # you cannot override or remove any section and key. - @it['foo'] = {} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - end - - def test_each - # each returns [section, key, value] array. - ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] } - assert_equal(4, ary.size) - assert_equal('CA_default', ary[0][0]) - assert_equal('CA_default', ary[1][0]) - assert_equal(["ca", "default_ca", "CA_default"], ary[2]) - assert_equal(["default", "HOME", "."], ary[3]) - end - - def test_to_s - c = OpenSSL::Config.parse("[empty]\n") - assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s) - end - - def test_inspect - assert_match(/#/, @it.inspect) - end - - def test_freeze - c = OpenSSL::Config.new - c['foo'] = [['key', 'value']] - c.freeze - - # [ruby-core:18377] - # RuntimeError for 1.9, TypeError for 1.8 - assert_raise(TypeError, /frozen/) do - c['foo'] = [['key', 'wrong']] - end - end - - def test_dup - assert(!@it.sections.empty?) - c = @it.dup - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end - - def test_clone - assert(!@it.sections.empty?) - c = @it.clone - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end -end diff --git a/test/1.8/test_digest.rb b/test/1.8/test_digest.rb deleted file mode 100644 index 8941588..0000000 --- a/test/1.8/test_digest.rb +++ /dev/null @@ -1,88 +0,0 @@ -begin - require "openssl" -rescue LoadError -end -require "digest/md5" -require "test/unit" - -if defined?(OpenSSL) - -class OpenSSL::TestDigest < Test::Unit::TestCase - def setup - @d1 = OpenSSL::Digest::Digest::new("MD5") - @d2 = OpenSSL::Digest::MD5.new - @md = Digest::MD5.new - @data = "DATA" - end - - def teardown - @d1 = @d2 = @md = nil - end - - def test_digest - assert_equal(@md.digest, @d1.digest) - assert_equal(@md.hexdigest, @d1.hexdigest) - @d1 << @data - @d2 << @data - @md << @data - assert_equal(@md.digest, @d1.digest) - assert_equal(@md.hexdigest, @d1.hexdigest) - assert_equal(@d1.digest, @d2.digest) - assert_equal(@d1.hexdigest, @d2.hexdigest) - assert_equal(@md.digest, OpenSSL::Digest::MD5.digest(@data)) - assert_equal(@md.hexdigest, OpenSSL::Digest::MD5.hexdigest(@data)) - end - - def test_eql - assert(@d1 == @d2, "==") - d = @d1.clone - assert(d == @d1, "clone") - end - - def test_info - assert_equal("MD5", @d1.name, "name") - assert_equal("MD5", @d2.name, "name") - assert_equal(16, @d1.size, "size") - end - - def test_dup - @d1.update(@data) - assert_equal(@d1.name, @d1.dup.name, "dup") - assert_equal(@d1.name, @d1.clone.name, "clone") - assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") - end - - def test_reset - @d1.update(@data) - dig1 = @d1.digest - @d1.reset - @d1.update(@data) - dig2 = @d1.digest - assert_equal(dig1, dig2, "reset") - end - - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 - def encode16(str) - str.unpack("H*").first - end - - def test_098_features - sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" - sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" - sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" - sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" - - assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) - assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) - assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) - assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) - - assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) - assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) - assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) - assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) - end - end -end - -end diff --git a/test/1.8/test_ec.rb b/test/1.8/test_ec.rb deleted file mode 100644 index 39f5577..0000000 --- a/test/1.8/test_ec.rb +++ /dev/null @@ -1,128 +0,0 @@ -begin - require "openssl" - require File.join(File.dirname(__FILE__), "utils.rb") -rescue LoadError -end -require "test/unit" - -if defined?(OpenSSL::PKey::EC) - -class OpenSSL::TestEC < Test::Unit::TestCase - def setup - @data1 = 'foo' - @data2 = 'bar' * 1000 # data too long for DSA sig - - @group1 = OpenSSL::PKey::EC::Group.new('secp112r1') - @group2 = OpenSSL::PKey::EC::Group.new('sect163k1') - - @key1 = OpenSSL::PKey::EC.new - @key1.group = @group1 - @key1.generate_key - - @key2 = OpenSSL::PKey::EC.new(@group2.curve_name) - @key2.generate_key - - @groups = [@group1, @group2] - @keys = [@key1, @key2] - end - - def compare_keys(k1, k2) - assert_equal(k1.to_pem, k2.to_pem) - end - - def test_curve_names - @groups.each_with_index do |group, idx| - key = @keys[idx] - assert_equal(group.curve_name, key.group.curve_name) - end - end - - def test_check_key - for key in @keys - assert_equal(key.check_key, true) - assert_equal(key.private_key?, true) - assert_equal(key.public_key?, true) - end - end - - def test_encoding - for group in @groups - for meth in [:to_der, :to_pem] - txt = group.send(meth) - gr = OpenSSL::PKey::EC::Group.new(txt) - assert_equal(txt, gr.send(meth)) - - assert_equal(group.generator.to_bn, gr.generator.to_bn) - assert_equal(group.cofactor, gr.cofactor) - assert_equal(group.order, gr.order) - assert_equal(group.seed, gr.seed) - assert_equal(group.degree, gr.degree) - end - end - - for key in @keys - group = key.group - - for meth in [:to_der, :to_pem] - txt = key.send(meth) - assert_equal(txt, OpenSSL::PKey::EC.new(txt).send(meth)) - end - - bn = key.public_key.to_bn - assert_equal(bn, OpenSSL::PKey::EC::Point.new(group, bn).to_bn) - end - end - - def test_set_keys - for key in @keys - k = OpenSSL::PKey::EC.new - k.group = key.group - k.private_key = key.private_key - k.public_key = key.public_key - - compare_keys(key, k) - end - end - - def test_dsa_sign_verify - for key in @keys - sig = key.dsa_sign_asn1(@data1) - assert(key.dsa_verify_asn1(@data1, sig)) - end - end - - def test_dsa_sign_asn1_FIPS186_3 - for key in @keys - size = key.group.order.num_bits / 8 + 1 - dgst = (1..size).to_a.pack('C*') - begin - sig = key.dsa_sign_asn1(dgst) - # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m - assert(key.dsa_verify_asn1(dgst + "garbage", sig)) - rescue OpenSSL::PKey::ECError => e - # just an exception for longer dgst before openssl-0.9.8m - assert_equal('ECDSA_sign: data too large for key size', e.message) - # no need to do following tests - return - end - end - end - - def test_dh_compute_key - for key in @keys - k = OpenSSL::PKey::EC.new(key.group) - k.generate_key - - puba = key.public_key - pubb = k.public_key - a = key.dh_compute_key(pubb) - b = k.dh_compute_key(puba) - assert_equal(a, b) - end - end - -# test Group: asn1_flag, point_conversion - -end - -end diff --git a/test/1.8/test_hmac.rb b/test/1.8/test_hmac.rb deleted file mode 100644 index 50ad675..0000000 --- a/test/1.8/test_hmac.rb +++ /dev/null @@ -1,46 +0,0 @@ -begin - require "openssl" -rescue LoadError -end -require "test/unit" - -class OpenSSL::TestHMAC < Test::Unit::TestCase - def setup - @digest = OpenSSL::Digest::MD5 - @key = "KEY" - @data = "DATA" - @h1 = OpenSSL::HMAC.new(@key, @digest.new) - @h2 = OpenSSL::HMAC.new(@key, "MD5") - end - - def teardown - end - - def test_hmac - @h1.update(@data) - @h2.update(@data) - assert_equal(@h1.digest, @h2.digest) - - assert_equal(OpenSSL::HMAC.digest(@digest.new, @key, @data), @h1.digest, "digest") - assert_equal(OpenSSL::HMAC.hexdigest(@digest.new, @key, @data), @h1.hexdigest, "hexdigest") - - assert_equal(OpenSSL::HMAC.digest("MD5", @key, @data), @h2.digest, "digest") - assert_equal(OpenSSL::HMAC.hexdigest("MD5", @key, @data), @h2.hexdigest, "hexdigest") - end - - def test_dup - @h1.update(@data) - h = @h1.dup - assert_equal(@h1.digest, h.digest, "dup digest") - end - - def test_sha256 - digest256 = OpenSSL::Digest::Digest.new("sha256") - assert_equal( - "\210\236-\3270\331Yq\265\177sE\266\231hXa\332\250\026\235O&c*\307\001\227~\260n\362", - OpenSSL::HMAC.digest(digest256, 'blah', "blah")) - assert_equal( - "889e2dd730d95971b57f7345b699685861daa8169d4f26632ac701977eb06ef2", - OpenSSL::HMAC.hexdigest(digest256, 'blah', "blah")) - end -end diff --git a/test/1.8/test_ns_spki.rb b/test/1.8/test_ns_spki.rb deleted file mode 100644 index 3937132..0000000 --- a/test/1.8/test_ns_spki.rb +++ /dev/null @@ -1,59 +0,0 @@ -begin - require "openssl" - require File.join(File.dirname(__FILE__), "utils.rb") -rescue LoadError -end -require "test/unit" - -if defined?(OpenSSL) - - -class OpenSSL::TestNSSPI < Test::Unit::TestCase - def setup - # This request data is adopt from the specification of - # "Netscape Extensions for User Key Generation". - # -- http://wp.netscape.com/eng/security/comm4-keygen.html - @b64 = "MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" - @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" - @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" - @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" - @b64 << "i0//rgBvmco=" - end - - def teardown - end - - def test_build_data - key1 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - spki = OpenSSL::Netscape::SPKI.new - spki.challenge = "RandomString" - spki.public_key = key1.public_key - spki.sign(key1, OpenSSL::Digest::SHA1.new) - assert(spki.verify(spki.public_key)) - assert(spki.verify(key1.public_key)) - assert(!spki.verify(key2.public_key)) - - der = spki.to_der - spki = OpenSSL::Netscape::SPKI.new(der) - assert_equal("RandomString", spki.challenge) - assert_equal(key1.public_key.to_der, spki.public_key.to_der) - assert(spki.verify(spki.public_key)) - end - - def test_decode_data - spki = OpenSSL::Netscape::SPKI.new(@b64) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - - spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - end -end - -end diff --git a/test/1.8/test_pair.rb b/test/1.8/test_pair.rb deleted file mode 100644 index e13d63e..0000000 --- a/test/1.8/test_pair.rb +++ /dev/null @@ -1,149 +0,0 @@ -begin - require "openssl" -rescue LoadError -end -require 'test/unit' - -if defined?(OpenSSL) - -require 'socket' -require File.join(File.dirname(__FILE__), "../ut_eof") - -module SSLPair - def server - host = "127.0.0.1" - port = 0 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - tcps = TCPServer.new(host, port) - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - return ssls - end - - def client(port) - host = "127.0.0.1" - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - s = TCPSocket.new(host, port) - ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) - ssl.connect - ssl.sync_close = true - ssl - end - - def ssl_pair - ssls = server - th = Thread.new { - ns = ssls.accept - ssls.close - ns - } - port = ssls.to_io.addr[1] - c = client(port) - s = th.value - if block_given? - begin - yield c, s - ensure - c.close unless c.closed? - s.close unless s.closed? - end - else - return c, s - end - end -end - -class OpenSSL::TestEOF1 < Test::Unit::TestCase - include TestEOF - include SSLPair - - def open_file(content) - s1, s2 = ssl_pair - Thread.new { s2 << content; s2.close } - yield s1 - end -end - -class OpenSSL::TestEOF2 < Test::Unit::TestCase - include TestEOF - include SSLPair - - def open_file(content) - s1, s2 = ssl_pair - Thread.new { s1 << content; s1.close } - yield s2 - end -end - -class OpenSSL::TestPair < Test::Unit::TestCase - include SSLPair - - def test_getc - ssl_pair {|s1, s2| - s1 << "a" - assert_equal(?a, s2.getc) - } - end - - def test_readpartial - ssl_pair {|s1, s2| - s2.write "a\nbcd" - assert_equal("a\n", s1.gets) - read = s1.readpartial(10) - assert_equal("bcd"[0, read.bytesize], read) - s1.read(read.bytesize - 3) # drop unread bytes - - s2.write "efg" - read = s1.readpartial(10) - assert_equal("efg"[0, read.bytesize], read) - rest = 3 - read.bytesize - while rest > 0 - rest -= s1.readpartial(rest).size - end - s2.close - assert_raise(EOFError) { s1.readpartial(10) } - assert_raise(EOFError) { s1.readpartial(10) } - assert_equal("", s1.readpartial(0)) - } - end - - def test_readall - ssl_pair {|s1, s2| - s2.close - assert_equal("", s1.read) - } - end - - def test_readline - ssl_pair {|s1, s2| - s2.close - assert_raise(EOFError) { s1.readline } - } - end - - def test_puts_meta - ssl_pair {|s1, s2| - begin - old = $/ - $/ = '*' - s1.puts 'a' - ensure - $/ = old - end - s1.close - assert_equal("a\n", s2.read) - } - end - - def test_puts_empty - ssl_pair {|s1, s2| - s1.puts - s1.close - assert_equal("\n", s2.read) - } - end - -end - -end diff --git a/test/1.8/test_pkcs7.rb b/test/1.8/test_pkcs7.rb deleted file mode 100644 index 5a54820..0000000 --- a/test/1.8/test_pkcs7.rb +++ /dev/null @@ -1,489 +0,0 @@ -begin - require "openssl" - require File.join(File.dirname(__FILE__), "utils.rb") -rescue LoadError -end -require "test/unit" - -if defined?(OpenSSL) - -class OpenSSL::TestPKCS7 < Test::Unit::TestCase - def setup - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - 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") - - now = Time.now - 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) - ee_exts = [ - ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], - ["authorityKeyIdentifier","keyid:always",false], - ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], - ["nsCertType","client,email",false], - ] - @ee1_cert = issue_cert(ee1, @rsa1024, 2, Time.now, Time.now+1800, ee_exts, - @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - @ee2_cert = issue_cert(ee2, @rsa1024, 3, Time.now, Time.now+1800, ee_exts, - @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - end - - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - - def test_signed - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\r\nbbbbb\r\nccccc\r\n" - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # Normaly OpenSSL tries to translate the supplied content into canonical - # MIME format (e.g. a newline character is converted into CR+LF). - # If the content is a binary, PKCS7::BINARY flag should be used. - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # A signed-data which have multiple signatures can be created - # through the following steps. - # 1. create two signed-data - # 2. copy signerInfo and certificate from one to another - - tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) - tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) - tmp1.add_signer(tmp2.signers[0]) - tmp1.add_certificate(@ee2_cert) - - p7 = OpenSSL::PKCS7.new(tmp1.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(2, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - assert_equal(@ee2_cert.serial, signers[1].serial) - assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) - end - - def test_detached_sign - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - a1 = OpenSSL::ASN1.decode(p7) - - certs = p7.certificates - signers = p7.signers - assert(!p7.verify([], store)) - assert(p7.verify([], store, data)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - end - - def test_enveloped - if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x0090704f - # PKCS7_encrypt() of OpenSSL-0.9.7d goes to SEGV. - # http://www.mail-archive.com/openssl-dev@openssl.org/msg17376.html - return - end - - certs = [@ee1_cert, @ee2_cert] - cipher = OpenSSL::Cipher::AES.new("128-CBC") - data = "aaaaa\nbbbbb\nccccc\n" - - tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - recip = p7.recipients - assert_equal(:enveloped, p7.type) - assert_equal(2, recip.size) - - assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) - assert_equal(2, recip[0].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) - - assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) - assert_equal(3, recip[1].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) - end - - def test_envelope_des3 - certs = [@ee1_cert] - cipher = OpenSSL::Cipher.new("des-ede3-cbc") - data = "aaaaa\nbbbbb\nccccc\n" - tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) - end - - def test_envelope_nil # RC2-40-CBC by default - certs = [@ee1_cert] - data = "aaaaa\nbbbbb\nccccc\n" - tmp = OpenSSL::PKCS7.encrypt(certs, data, nil, OpenSSL::PKCS7::BINARY) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) - end - - def test_envelope_des3_compat - data = "aaaaa\nbbbbb\nccccc\n" - cruby_envelope = < Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_OK - true - end - ) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.connect - assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) - - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params( - :verify_callback => Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION - false - end - ) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) - } - end - - def test_extra_chain_cert - start_server(PORT, OpenSSL::SSL::VERIFY_PEER, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) - } - # server returns a chain w/o root cert so the client verification fails - # with UNABLE_TO_GET_ISSUER_CERT_LOCALLY not SELF_SIGNED_CERT_IN_CHAIN. - args = {} - args[:ctx_proc] = proc { |server_ctx| - server_ctx.cert = @svr_cert - server_ctx.key = @svr_key - server_ctx.extra_chain_cert = [@svr_cert] - } - start_server(PORT, OpenSSL::SSL::VERIFY_PEER, true, args){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, ssl.verify_result) - } - end - - def test_client_ca - args = {} - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - - # client_ca as a cert - args[:ctx_proc] = proc { |server_ctx| - server_ctx.cert = @svr_cert - server_ctx.key = @svr_key - server_ctx.client_ca = @ca_cert - } - start_server(PORT, vflag, true, args){|server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - } - - # client_ca as an array - args[:ctx_proc] = proc { |server_ctx| - server_ctx.cert = @svr_cert - server_ctx.key = @svr_key - server_ctx.client_ca = [@ca_cert, @svr_cert] - } - start_server(PORT, vflag, true, args){|server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - } - end - - def test_sslctx_ssl_version_client - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE - ctx.ssl_version = "TLSv1" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.puts("hello TLSv1") - ssl.close - sock.close - # - sock = TCPSocket.new("127.0.0.1", port) - ctx.ssl_version = "SSLv3" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.puts("hello SSLv3") - ssl.close - sock.close - # - sock = TCPSocket.new("127.0.0.1", port) - ctx.ssl_version = "SSLv3_server" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError) do - ssl.connect - end - sock.close - # - sock = TCPSocket.new("127.0.0.1", port) - ctx.ssl_version = "TLSv1_client" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.puts("hello TLSv1_client") - ssl.close - sock.close - } - end - - def test_sslctx_ssl_version - args = {} - args[:ctx_proc] = proc { |server_ctx| - server_ctx.ssl_version = "TLSv1" - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, args){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE - ctx.ssl_version = "TLSv1" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.puts("hello TLSv1") - ssl.close - sock.close - # - sock = TCPSocket.new("127.0.0.1", port) - ctx.ssl_version = "SSLv3" - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError) do - ssl.connect - end - } - end - - def test_verify_depth - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - args = {} - # depth == 1 => OK - args[:ctx_proc] = proc { |server_ctx| - server_ctx.cert = @svr_cert - server_ctx.key = @svr_key - server_ctx.verify_mode = vflag - server_ctx.verify_depth = 1 - } - start_server(PORT, vflag, true, args){|server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.close - } - # depth == 0 => error - error = nil - args[:ctx_proc] = proc { |server_ctx| - server_ctx.cert = @svr_cert - server_ctx.key = @svr_key - server_ctx.verify_mode = vflag - server_ctx.verify_depth = 0 - server_ctx.verify_callback = proc { |preverify_ok, store_ctx| - error = store_ctx.error - preverify_ok - } - } - start_server(PORT, vflag, true, args){|server, port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raises(OpenSSL::SSL::SSLError) do - ssl.connect - end - ssl.close - } - assert_equal OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, error - end - - def test_sslctx_set_params - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - assert_equal(OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode) - assert_equal(OpenSSL::SSL::OP_ALL, ctx.options) - ciphers = ctx.ciphers - ciphers_versions = ciphers.collect{|_, v, _, _| v } - ciphers_names = ciphers.collect{|v, _, _, _| v } - assert(ciphers_names.all?{|v| /ADH/ !~ v }) - assert(ciphers_versions.all?{|v| /SSLv2/ !~ v }) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) - } - end - - def test_sslctx_ciphers - c = OpenSSL::SSL::SSLContext.new - - c.ciphers = 'DEFAULT' - default = c.ciphers - assert(default.size > 0) - - c.ciphers = 'ALL' - all = c.ciphers - assert(all.size > 0) - - c.ciphers = 'LOW' - low = c.ciphers - assert(low.size > 0) - - c.ciphers = 'MEDIUM' - medium = c.ciphers - assert(medium.size > 0) - - c.ciphers = 'HIGH' - high = c.ciphers - assert(high.size > 0) - - c.ciphers = 'EXP' - exp = c.ciphers - assert(exp.size > 0) - - # - - c.ciphers = 'ALL:-LOW' - assert_equal(all - low, c.ciphers) - c.ciphers = 'ALL:-MEDIUM' - assert_equal(all - medium, c.ciphers) - c.ciphers = 'ALL:-HIGH' - assert_equal(all - high, c.ciphers) - c.ciphers = 'ALL:-EXP' - assert_equal(all - exp, c.ciphers) - c.ciphers = 'ALL:-LOW:-MEDIUM' - assert_equal(all - low - medium, c.ciphers) - c.ciphers = 'ALL:-LOW:-MEDIUM:-HIGH' - assert_equal(all - low - medium - high, c.ciphers) - assert_raise(OpenSSL::SSL::SSLError) do - # should be empty for OpenSSL/0.9.8l. check OpenSSL changes if this test fail. - c.ciphers = 'ALL:-LOW:-MEDIUM:-HIGH:-EXP' - end - - # ! - c.ciphers = 'ALL:-LOW:LOW' - assert_equal(all.sort, c.ciphers.sort) - c.ciphers = 'ALL:!LOW:LOW' - assert_equal(all - low, c.ciphers) - c.ciphers = 'ALL:!LOW:+LOW' - assert_equal(all - low, c.ciphers) - - # + - c.ciphers = 'HIGH:LOW:+LOW' - assert_equal(high + low, c.ciphers) - c.ciphers = 'HIGH:LOW:+HIGH' - assert_equal(low + high, c.ciphers) - - # name+name - c.ciphers = 'RC4' - rc4 = c.ciphers - c.ciphers = 'RSA' - rsa = c.ciphers - c.ciphers = 'RC4+RSA' - assert_equal(rc4&rsa, c.ciphers) - c.ciphers = 'RSA+RC4' - assert_equal(rc4&rsa, c.ciphers) - c.ciphers = 'ALL:RSA+RC4' - assert_equal(all + ((rc4&rsa) - all), c.ciphers) - end - - def test_sslctx_options - args = {} - args[:ctx_proc] = proc { |server_ctx| - # TLSv1 only - server_ctx.options = OpenSSL::SSL::OP_NO_SSLv2|OpenSSL::SSL::OP_NO_SSLv3 - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, args){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE - ctx.options = OpenSSL::SSL::OP_NO_TLSv1 - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET) do - ssl.connect - end - ssl.close - sock.close - # - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE - ctx.options = OpenSSL::SSL::OP_NO_SSLv3 - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_nothing_raised do - ssl.connect - end - ssl.close - sock.close - } - end - - def test_post_connection_check - sslerr = OpenSSL::SSL::SSLError - - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert(ssl.post_connection_check("localhost")) - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - - now = Time.now - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:localhost.localdomain",false], - ["subjectAltName","IP:127.0.0.1",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, - @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert(ssl.post_connection_check("localhost.localdomain")) - assert(ssl.post_connection_check("127.0.0.1")) - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - - now = Time.now - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:*.localdomain",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, - @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert(ssl.post_connection_check("localhost.localdomain")) - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - end - - def TODO_implement_SSLSession_test_client_session - last_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| - 2.times do - sock = TCPSocket.new("127.0.0.1", port) - # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), - # when use default SSLContext. [ruby-dev:36167] - ctx = OpenSSL::SSL::SSLContext.new("TLSv1") - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = last_session if last_session - ssl.connect - - session = ssl.session - if last_session - assert(ssl.session_reused?) - - if session.respond_to?(:id) - assert_equal(session.id, last_session.id) - end - assert_equal(session.to_pem, last_session.to_pem) - assert_equal(session.to_der, last_session.to_der) - # Older version of OpenSSL may not be consistent. Look up which versions later. - assert_equal(session.to_text, last_session.to_text) - else - assert(!ssl.session_reused?) - end - last_session = session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end - - def TODO_implement_SSLSession_test_server_session - connections = 0 - saved_session = nil - - ctx_proc = Proc.new do |ctx, ssl| -# add test for session callbacks here - end - - server_proc = Proc.new do |ctx, ssl| - session = ssl.session - stats = ctx.session_cache_stats - - case connections - when 0 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 0) - assert_equal(stats[:cache_misses], 0) - assert(!ssl.session_reused?) - when 1 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 0) - assert(ssl.session_reused?) - ctx.session_remove(session) - saved_session = session - when 2 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 1) - assert(!ssl.session_reused?) - ctx.session_add(saved_session) - when 3 - assert_equal(stats[:cache_num], 2) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 1) - assert(ssl.session_reused?) - ctx.flush_sessions(Time.now + 5000) - when 4 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 2) - assert(!ssl.session_reused?) - ctx.session_add(saved_session) - end - connections += 1 - - readwrite_loop(ctx, ssl) - end - - first_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| - 10.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - if defined?(OpenSSL::SSL::OP_NO_TICKET) - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = first_session if first_session - ssl.connect - - session = ssl.session - if first_session - case i - when 1; assert(ssl.session_reused?) - when 2; assert(!ssl.session_reused?) - when 3; assert(ssl.session_reused?) - when 4; assert(!ssl.session_reused?) - when 5..10; assert(ssl.session_reused?) - end - end - first_session ||= session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end - - def test_tlsext_hostname - return unless OpenSSL::SSL::SSLSocket.instance_methods.include?("hostname") - - ctx_proc = Proc.new do |ctx, ssl| - foo_ctx = ctx.dup - - ctx.servername_cb = Proc.new do |ssl2, hostname| - case hostname - when 'foo.example.com' - foo_ctx - when 'bar.example.com' - nil - else - raise "unknown hostname #{hostname.inspect}" - end - end - end - - server_proc = Proc.new do |ctx, ssl| - readwrite_loop(ctx, ssl) - end - - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| - 2.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - if defined?(OpenSSL::SSL::OP_NO_TICKET) - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.hostname = (i & 1 == 0) ? 'foo.example.com' : 'bar.example.com' - ssl.connect - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end -end - -end diff --git a/test/1.8/test_x509cert.rb b/test/1.8/test_x509cert.rb deleted file mode 100644 index cfea149..0000000 --- a/test/1.8/test_x509cert.rb +++ /dev/null @@ -1,277 +0,0 @@ -begin - require "openssl" - require File.join(File.dirname(__FILE__), "utils.rb") -rescue LoadError -end -require "test/unit" - -if defined?(OpenSSL) - -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_wrong_key_type - cert_rsa = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - cert_dsa = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - begin - assert_equal(false, cert_rsa.verify(@dsa256)) - rescue OpenSSL::X509::CertificateError => e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - - begin - assert_equal(false, cert_dsa.verify(@rsa1024)) - rescue OpenSSL::X509::CertificateError => e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - 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("sha1WithRSAEncryption", cert.signature_algorithm) - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - 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("md5WithRSAEncryption", cert.signature_algorithm) - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - 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("dsaWithSHA1", cert.signature_algorithm) - assert_equal(false, cert.verify(@dsa256)) - assert_equal(true, cert.verify(@dsa512)) - cert.not_after = Time.now - assert_equal(false, cert.verify(@dsa512)) - - assert_raise(OpenSSL::X509::CertificateError){ - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - } - assert_raise(OpenSSL::X509::CertificateError){ - cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::MD5.new) - } - end - - def test_dsig_algorithm_mismatch - assert_raise(OpenSSL::X509::CertificateError) do - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - end - assert_raise(OpenSSL::X509::CertificateError) do - cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::MD5.new) - end - end - - def test_dsa_with_sha2 - begin - cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA256.new) - assert_equal("dsa_with_SHA256", cert.signature_algorithm) - rescue OpenSSL::X509::CertificateError - # dsa_with_sha2 not supported. skip following test. - return - end - # TODO: need more tests for dsa + sha2 - - # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requireds DSS1) - cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - assert_equal("dsaWithSHA1", cert.signature_algorithm) - end - - def test_check_private_key - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - assert_equal(true, cert.check_private_key(@rsa2048)) - end - - def test_to_text - cert_pem = < e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - - begin - assert_equal(false, crl_dsa.verify(@rsa1024)) - rescue OpenSSL::X509::CRLError => e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - 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)) - 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(@dsa256)) - assert_equal(true, crl.verify(@dsa512)) - crl.version = 0 - assert_equal(false, crl.verify(@dsa512)) - end - - def test_create_from_pem - crl = <#;"], - ["O", ",=+<>#;"], - ["OU", ""], - ["OU", ""], - ["L", "aaa=\"bbb, ccc\""], - ["L", "aaa=\"bbb, ccc\""], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ], - scanner.call( - "emailAddress=gotoyuzo@ruby-lang.org," + - "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + - 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + - 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + - '2.5.4.3=GOTOU\,\20Yuuzou,' + - '2.5.4.3=GOTOU\, Yuuzou,' + - '2.5.4.3="GOTOU, Yuuzou",' + - '2.5.4.3="GOTOU\, Yuuzou",' + - "CN=#0C0CE5BE8CE897A4E8A395E894B5," + - 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + - "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + - "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + - 'L=aaa\=\"bbb\, ccc\",' + - 'L="aaa=\"bbb, ccc\"",' + - 'OU=,' + - 'OU="",' + - 'O=\,\=\+\<\>\#\;,' + - 'O=",=+<>#;",' + - "DC=ruby-lang," + - "DC=org") - ) - - [ - "DC=org+DC=jp", - "DC=org,DC=ruby-lang+DC=rubyist,DC=www" - ].each{|dn| - ex = scanner.call(dn) rescue $! - dn_r = Regexp.escape(dn) - assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) - } - - [ - ["DC=org,DC=exapmle,CN", "CN"], - ["DC=org,DC=example,", ""], - ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], - ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], - ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], - ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], - ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], - ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], - ].each{|dn, msg| - ex = scanner.call(dn) rescue $! - assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) - } - - dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" - name = OpenSSL::X509::Name.parse_rfc2253(dn) - assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) - 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]) - 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 - - def name_hash(name) - # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of - # X509Name for X509_NAME_hash. - name.respond_to?(:hash_old) ? name.hash_old : name.hash - end - - def calc_hash(d) - (d[0] & 0xff) | (d[1] & 0xff) << 8 | (d[2] & 0xff) << 16 | (d[3] & 0xff) << 24 - end - - def test_hash - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = Digest::MD5.digest(name.to_der) - assert_equal(calc_hash(d), name_hash(name)) - # - dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = Digest::MD5.digest(name.to_der) - assert_equal(calc_hash(d), name_hash(name)) - end -end - -end diff --git a/test/1.8/test_x509req.rb b/test/1.8/test_x509req.rb deleted file mode 100644 index d96628d..0000000 --- a/test/1.8/test_x509req.rb +++ /dev/null @@ -1,195 +0,0 @@ -begin - require "openssl" - require File.join(File.dirname(__FILE__), "utils.rb") -rescue LoadError -end -require "test/unit" - -if defined?(OpenSSL) - -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_wrong_key_type - req_rsa = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) - req_dsa = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::DSS1.new) - begin - assert_equal(false, req_rsa.verify(@dsa256)) - rescue OpenSSL::X509::RequestError => e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - - begin - assert_equal(false, req_dsa.verify(@rsa1024)) - rescue OpenSSL::X509::RequestError => e - # OpenSSL 1.0.0 added checks for pkey OID - assert_equal('wrong public key type', e.message) - end - 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)) - 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)) - 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(@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::MD5.new) } - end - - def test_dsig_algorithm_mismatch - assert_raise(OpenSSL::X509::RequestError) do - issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) - end - assert_raise(OpenSSL::X509::RequestError) do - issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) - end - end - - def test_create_from_pem - req = < e - #ok - end - end - - def test_decode_all - expected = %w{ 02 01 01 02 01 02 02 01 03 } - raw = [expected.join('')].pack('H*') - ary = OpenSSL::ASN1.decode_all(raw) - assert_equal(3, ary.size) - ary.each_with_index do |asn1, i| - assert_universal(OpenSSL::ASN1::INTEGER, asn1) - assert_equal(i + 1, asn1.value) - end - end - - def test_create_inf_length_primitive - expected = %w{ 24 80 04 01 61 00 00 } - raw = [expected.join('')].pack('H*') - val = OpenSSL::ASN1::OctetString.new('a') - cons = OpenSSL::ASN1::Constructive.new([val, - OpenSSL::ASN1::EndOfContent.new], - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - cons.infinite_length = true - assert_equal(nil, cons.tagging) - assert_equal(raw, cons.to_der) - asn1 = OpenSSL::ASN1.decode(raw) - assert(asn1.infinite_length) - assert_equal(raw, asn1.to_der) - end - - def test_cons_without_inf_length_forbidden - assert_raise(OpenSSL::ASN1::ASN1Error) do - val = OpenSSL::ASN1::OctetString.new('a') - cons = OpenSSL::ASN1::Constructive.new([val], - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - cons.to_der - end - end - - def test_cons_without_array_forbidden - assert_raise(OpenSSL::ASN1::ASN1Error) do - val = OpenSSL::ASN1::OctetString.new('a') - cons = OpenSSL::ASN1::Constructive.new(val, - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - cons.infinite_length = true - cons.to_der - end - end - - def test_parse_empty_sequence - expected = %w{ A0 07 30 02 30 00 02 01 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(raw, asn1.to_der) - assert_equal(2, asn1.value.size) - seq = asn1.value[0] - assert_equal(1, seq.value.size) - inner_seq = seq.value[0] - assert_equal(0, inner_seq.value.size) - end - - def test_parse_tagged_0_infinite - expected = %w{ 30 80 02 01 01 80 01 02 00 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(3, asn1.value.size) - int = asn1.value[0] - assert_universal(OpenSSL::ASN1::INTEGER, int) - tagged = asn1.value[1] - assert_equal(0, tagged.tag) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[2]) - assert_equal(raw, asn1.to_der) - end - - def test_seq_infinite_length - begin - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new ] - cons = OpenSSL::ASN1::Sequence.new(content) - cons.infinite_length = true - expected = %w{ 30 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_set_infinite_length - begin - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Set.new(content) - cons.infinite_length = true - expected = %w{ 31 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_octet_string_infinite_length - begin - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new( - octets, - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 24 80 04 03 61 61 61 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_prim_explicit_tagging - begin - oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - expected = %w{ A0 03 04 01 61 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, oct_str.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_prim_explicit_tagging_tag_class - begin - oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - oct_str2 = OpenSSL::ASN1::OctetString.new( - "a", - 0, - :EXPLICIT, - :CONTEXT_SPECIFIC) - assert_equal(oct_str.to_der, oct_str2.to_der) - end - end - - def test_prim_implicit_tagging - begin - int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - expected = %w{ 80 01 01 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, int.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_prim_implicit_tagging_tag_class - begin - int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC); - assert_equal(int.to_der, int2.to_der) - end - end - - def test_cons_explicit_tagging - begin - content = [ OpenSSL::ASN1::PrintableString.new('abc') ] - seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) - expected = %w{ A2 07 30 05 13 03 61 62 63 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_cons_explicit_tagging_inf_length - begin - content = [ OpenSSL::ASN1::PrintableString.new('abc') , - OpenSSL::ASN1::EndOfContent.new() ] - seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT) - seq.infinite_length = true - expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_cons_implicit_tagging - begin - content = [ OpenSSL::ASN1::Null.new(nil) ] - seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) - expected = %w{ A1 02 05 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_cons_implicit_tagging_inf_length - begin - content = [ OpenSSL::ASN1::Null.new(nil), - OpenSSL::ASN1::EndOfContent.new() ] - seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT) - seq.infinite_length = true - expected = %w{ A1 80 05 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, seq.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_octet_string_infinite_length_explicit_tagging - begin - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new( - octets, - 1, - :EXPLICIT) - cons.infinite_length = true - expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_octet_string_infinite_length_implicit_tagging - begin - octets = [ OpenSSL::ASN1::OctetString.new('aaa'), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new( - octets, - 0, - :IMPLICIT) - cons.infinite_length = true - expected = %w{ A0 80 04 03 61 61 61 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_recursive_octet_string_infinite_length - begin - octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"), - OpenSSL::ASN1::EndOfContent.new() ] - octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"), - OpenSSL::ASN1::EndOfContent.new() ] - container1 = OpenSSL::ASN1::Constructive.new( - octets_sub1, - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - container1.infinite_length = true - container2 = OpenSSL::ASN1::Constructive.new( - octets_sub2, - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - container2.infinite_length = true - octets3 = OpenSSL::ASN1::OctetString.new("\x03") - - octets = [ container1, container2, octets3, - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new( - octets, - OpenSSL::ASN1::OCTET_STRING, - nil, - :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_bit_string_infinite_length - begin - content = [ OpenSSL::ASN1::BitString.new("\x01"), - OpenSSL::ASN1::EndOfContent.new() ] - cons = OpenSSL::ASN1::Constructive.new( - content, - OpenSSL::ASN1::BIT_STRING, - nil, - :UNIVERSAL) - cons.infinite_length = true - expected = %w{ 23 80 03 02 00 01 00 00 } - raw = [expected.join('')].pack('H*') - assert_equal(raw, cons.to_der) - assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) - end - end - - def test_primitive_inf_length - assert_raises(OpenSSL::ASN1::ASN1Error) do - spec = %w{ 02 80 02 01 01 00 00 } - raw = [spec.join('')].pack('H*') - OpenSSL::ASN1.decode(raw) - OpenSSL::ASN1.decode_all(raw) - end - end - - def test_recursive_octet_string_parse - test = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } - raw = [test.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(OpenSSL::ASN1::Constructive, asn1.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) - assert_equal(true, asn1.infinite_length) - assert_equal(4, asn1.value.size) - nested1 = asn1.value[0] - assert_equal(OpenSSL::ASN1::Constructive, nested1.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) - assert_equal(true, nested1.infinite_length) - assert_equal(2, nested1.value.size) - oct1 = nested1.value[0] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) - assert_equal(false, oct1.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested1.value[1]) - assert_equal(false, nested1.value[1].infinite_length) - nested2 = asn1.value[1] - assert_equal(OpenSSL::ASN1::Constructive, nested2.class) - assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) - assert_equal(true, nested2.infinite_length) - assert_equal(2, nested2.value.size) - oct2 = nested2.value[0] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) - assert_equal(false, oct2.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested2.value[1]) - assert_equal(false, nested2.value[1].infinite_length) - oct3 = asn1.value[2] - assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) - assert_equal(false, oct3.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[3]) - assert_equal(false, asn1.value[3].infinite_length) - end - - private - - def assert_universal(tag, asn1) - assert_equal(tag, asn1.tag) - if asn1.respond_to?(:tagging) - assert_nil(asn1.tagging) - end - assert_equal(:UNIVERSAL, asn1.tag_class) - end - -end if defined?(OpenSSL) - diff --git a/test/1.9/test_bn.rb b/test/1.9/test_bn.rb deleted file mode 100644 index 7136de9..0000000 --- a/test/1.9/test_bn.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestBN < Test::Unit::TestCase - def test_integer_to_bn - assert_equal(999.to_bn, OpenSSL::BN.new(999.to_s(16), 16)) - assert_equal((2 ** 107 - 1).to_bn, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16)) - end - - def test_prime_p - assert_equal(true, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16).prime?) - assert_equal(true, OpenSSL::BN.new((2 ** 127 - 1).to_s(16), 16).prime?(1)) - end - - def test_cmp_nil - bn = OpenSSL::BN.new('1') - assert_equal(false, bn == nil) - assert_equal(true, bn != nil) - end -end - -end diff --git a/test/1.9/test_buffering.rb b/test/1.9/test_buffering.rb deleted file mode 100644 index 1e21975..0000000 --- a/test/1.9/test_buffering.rb +++ /dev/null @@ -1,88 +0,0 @@ -require_relative 'utils' -require 'stringio' - -class OpenSSL::TestBuffering < Test::Unit::TestCase - - class IO - include OpenSSL::Buffering - - attr_accessor :sync - - def initialize - @io = "" - def @io.sync - true - end - - super - - @sync = false - end - - def string - @io - end - - def sysread(size) - str = @io.slice!(0, size) - raise EOFError if str.empty? - str - end - - def syswrite(str) - @io << str - str.size - end - end - - def setup - @io = IO.new - end - - def test_flush - @io.write 'a' - - refute @io.sync - assert_empty @io.string - - assert_equal @io, @io.flush - - refute @io.sync - assert_equal 'a', @io.string - end - - def test_flush_error - @io.write 'a' - - refute @io.sync - assert_empty @io.string - - def @io.syswrite *a - raise SystemCallError, 'fail' - end - - assert_raises SystemCallError do - @io.flush - end - - refute @io.sync, 'sync must not change' - end - - def test_getc - @io.syswrite('abc') - res = [] - assert_equal(?a, @io.getc) - assert_equal(?b, @io.getc) - assert_equal(?c, @io.getc) - end - - def test_each_byte - @io.syswrite('abc') - res = [] - @io.each_byte do |c| - res << c - end - assert_equal([97, 98, 99], res) - end - -end if defined?(OpenSSL) diff --git a/test/1.9/test_cipher.rb b/test/1.9/test_cipher.rb deleted file mode 100644 index 4a23f1b..0000000 --- a/test/1.9/test_cipher.rb +++ /dev/null @@ -1,107 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestCipher < Test::Unit::TestCase - def setup - @c1 = OpenSSL::Cipher::Cipher.new("DES-EDE3-CBC") - @c2 = OpenSSL::Cipher::DES.new(:EDE3, "CBC") - @key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - @iv = "\0\0\0\0\0\0\0\0" - @hexkey = "0000000000000000000000000000000000000000000000" - @hexiv = "0000000000000000" - @data = "DATA" - end - - def teardown - @c1 = @c2 = nil - end - - def test_crypt - @c1.encrypt.pkcs5_keyivgen(@key, @iv) - @c2.encrypt.pkcs5_keyivgen(@key, @iv) - s1 = @c1.update(@data) + @c1.final - s2 = @c2.update(@data) + @c2.final - assert_equal(s1, s2, "encrypt") - - @c1.decrypt.pkcs5_keyivgen(@key, @iv) - @c2.decrypt.pkcs5_keyivgen(@key, @iv) - assert_equal(@data, @c1.update(s1)+@c1.final, "decrypt") - assert_equal(@data, @c2.update(s2)+@c2.final, "decrypt") - end - - def test_info - assert_equal("DES-EDE3-CBC", @c1.name, "name") - assert_equal("DES-EDE3-CBC", @c2.name, "name") - assert_kind_of(Fixnum, @c1.key_len, "key_len") - assert_kind_of(Fixnum, @c1.iv_len, "iv_len") - end - - def test_dup - assert_equal(@c1.name, @c1.dup.name, "dup") - assert_equal(@c1.name, @c1.clone.name, "clone") - @c1.encrypt - @c1.key = @key - @c1.iv = @iv - tmpc = @c1.dup - s1 = @c1.update(@data) + @c1.final - s2 = tmpc.update(@data) + tmpc.final - assert_equal(s1, s2, "encrypt dup") - end - - def test_reset - @c1.encrypt - @c1.key = @key - @c1.iv = @iv - s1 = @c1.update(@data) + @c1.final - @c1.reset - s2 = @c1.update(@data) + @c1.final - assert_equal(s1, s2, "encrypt reset") - end - - def test_empty_data - @c1.encrypt - assert_raise(ArgumentError){ @c1.update("") } - end - - def test_initialize - assert_raise(RuntimeError) {@c1.__send__(:initialize, "DES-EDE3-CBC")} - assert_raise(RuntimeError) {OpenSSL::Cipher.allocate.final} - end - - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00907000 - def test_ciphers - OpenSSL::Cipher.ciphers.each{|name| - assert(OpenSSL::Cipher::Cipher.new(name).is_a?(OpenSSL::Cipher::Cipher)) - } - end - - # This test fails without unlimited US_export.policy - def test_AES - pt = File.read(__FILE__) - %w(ECB CBC CFB OFB).each{|mode| - c1 = OpenSSL::Cipher::AES256.new(mode) - c1.encrypt - c1.pkcs5_keyivgen("passwd") - ct = c1.update(pt) + c1.final - - c2 = OpenSSL::Cipher::AES256.new(mode) - c2.decrypt - c2.pkcs5_keyivgen("passwd") - assert_equal(pt, c2.update(ct) + c2.final) - } - end - - # In JRuby key must be provided first. (CipherError) - def NOT_test_AES_crush - 500.times do - assert_nothing_raised("[Bug #2768]") do - # it caused OpenSSL SEGV by uninitialized key - OpenSSL::Cipher::AES128.new("ECB").update "." * 17 - end - end - end - end -end - -end diff --git a/test/1.9/test_config.rb b/test/1.9/test_config.rb deleted file mode 100644 index 77f89b2..0000000 --- a/test/1.9/test_config.rb +++ /dev/null @@ -1,288 +0,0 @@ -require_relative 'utils' - -class OpenSSL::TestConfig < Test::Unit::TestCase - def setup - file = Tempfile.open("openssl.cnf") - file << <<__EOD__ -HOME = . -[ ca ] -default_ca = CA_default -[ CA_default ] -dir = ./demoCA -certs = ./certs -__EOD__ - file.close - @it = OpenSSL::Config.new(file.path) - end - - def test_constants - assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE)) - assert_nothing_raised do - OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE) - end - end - - def test_s_parse - c = OpenSSL::Config.parse('') - assert_equal("[ default ]\n\n", c.to_s) - c = OpenSSL::Config.parse(@it.to_s) - assert_equal(['CA_default', 'ca', 'default'], c.sections.sort) - end - - def test_s_parse_format - c = OpenSSL::Config.parse(<<__EOC__) - baz =qx\t # "baz = qx" - -foo::bar = baz # shortcut section::key format - default::bar = baz # ditto -a=\t \t # "a = ": trailing spaces are ignored - =b # " = b": empty key - =c # " = c": empty key (override the above line) - d= # "c = ": trailing comment is ignored - -sq = 'foo''b\\'ar' - dq ="foo""''\\"" - dq2 = foo""bar -esc=a\\r\\n\\b\\tb -foo\\bar = foo\\b\\\\ar -foo\\bar::foo\\bar = baz -[default1 default2]\t\t # space is allowed in section name - fo =b ar # space allowed in value -[emptysection] - [doller ] -foo=bar -bar = $(foo) -baz = 123$(default::bar)456${foo}798 -qux = ${baz} -quxx = $qux.$qux -__EOC__ - assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) - assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort) - assert_equal('c', c['default']['']) - assert_equal('', c['default']['a']) - assert_equal('qx', c['default']['baz']) - assert_equal('', c['default']['d']) - assert_equal('baz', c['default']['bar']) - assert_equal("foob'ar", c['default']['sq']) - assert_equal("foo''\"", c['default']['dq']) - assert_equal("foobar", c['default']['dq2']) - assert_equal("a\r\n\b\tb", c['default']['esc']) - assert_equal("foo\b\\ar", c['default']['foo\\bar']) - assert_equal('baz', c['foo']['bar']) - assert_equal('baz', c['foo\\bar']['foo\\bar']) - assert_equal('b ar', c['default1 default2']['fo']) - - # dolloer - assert_equal('bar', c['doller']['foo']) - assert_equal('bar', c['doller']['bar']) - assert_equal('123baz456bar798', c['doller']['baz']) - assert_equal('123baz456bar798', c['doller']['qux']) - assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx']) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $bar") - end - assert_equal("error in line 1: variable has no value", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("foo = $(bar") - end - assert_equal("error in line 1: no close brace", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse("f o =b ar # no space in key") - end - assert_equal("error in line 1: missing equal sign", excn.message) - - excn = assert_raise(OpenSSL::ConfigError) do - OpenSSL::Config.parse(<<__EOC__) -# comment 1 # comments - -# - # comment 2 -\t#comment 3 - [second ]\t -[third # section not terminated -__EOC__ - end - assert_equal("error in line 7: missing close square bracket", excn.message) - end - - def test_s_load - # alias of new - c = OpenSSL::Config.load - assert_equal("", c.to_s) - assert_equal([], c.sections) - # - file = Tempfile.open("openssl.cnf") - file.close - c = OpenSSL::Config.load(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - end - - def test_initialize - c = OpenSSL::Config.new - assert_equal("", c.to_s) - assert_equal([], c.sections) - end - - def test_initialize_with_empty_file - file = Tempfile.open("openssl.cnf") - file.close - c = OpenSSL::Config.new(file.path) - assert_equal("[ default ]\n\n", c.to_s) - assert_equal(['default'], c.sections) - end - - def test_initialize_with_example_file - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - end - - def test_get_value - assert_equal('CA_default', @it.get_value('ca', 'default_ca')) - assert_equal(nil, @it.get_value('ca', 'no such key')) - assert_equal(nil, @it.get_value('no such section', 'no such key')) - assert_equal('.', @it.get_value('', 'HOME')) - assert_raise(TypeError) do - @it.get_value(nil, 'HOME') # not allowed unlike Config#value - end - # fallback to 'default' ugly... - assert_equal('.', @it.get_value('unknown', 'HOME')) - end - - def test_get_value_ENV - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.get_value('ENV', key)) - end - - def test_value - # supress deprecation warnings - OpenSSL::TestUtils.silent do - assert_equal('CA_default', @it.value('ca', 'default_ca')) - assert_equal(nil, @it.value('ca', 'no such key')) - assert_equal(nil, @it.value('no such section', 'no such key')) - assert_equal('.', @it.value('', 'HOME')) - assert_equal('.', @it.value(nil, 'HOME')) - assert_equal('.', @it.value('HOME')) - # fallback to 'default' ugly... - assert_equal('.', @it.value('unknown', 'HOME')) - end - end - - def test_value_ENV - OpenSSL::TestUtils.silent do - key = ENV.keys.first - assert_not_nil(key) # make sure we have at least one ENV var. - assert_equal(ENV[key], @it.value('ENV', key)) - end - end - - def test_aref - assert_equal({'HOME' => '.'}, @it['default']) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default']) - assert_equal({}, @it['no_such_section']) - assert_equal({}, @it['']) - end - - def test_section - OpenSSL::TestUtils.silent do - assert_equal({'HOME' => '.'}, @it.section('default')) - assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default')) - assert_equal({}, @it.section('no_such_section')) - assert_equal({}, @it.section('')) - end - end - - def test_sections - assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort) - @it['new_section'] = {'foo' => 'bar'} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - @it['new_section'] = {} - assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort) - end - - def test_add_value - c = OpenSSL::Config.new - assert_equal("", c.to_s) - # add key - c.add_value('default', 'foo', 'bar') - assert_equal("[ default ]\nfoo=bar\n\n", c.to_s) - # add another key - c.add_value('default', 'baz', 'qux') - assert_equal('bar', c['default']['foo']) - assert_equal('qux', c['default']['baz']) - # update the value - c.add_value('default', 'baz', 'quxxx') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - # add section and key - c.add_value('section', 'foo', 'bar') - assert_equal('bar', c['default']['foo']) - assert_equal('quxxx', c['default']['baz']) - assert_equal('bar', c['section']['foo']) - end - - def test_aset - @it['foo'] = {'bar' => 'baz'} - assert_equal({'bar' => 'baz'}, @it['foo']) - @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'} - assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - - # OpenSSL::Config is add only for now. - @it['foo'] = {'foo' => 'foo'} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - # you cannot override or remove any section and key. - @it['foo'] = {} - assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo']) - end - - def test_each - # each returns [section, key, value] array. - ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] } - assert_equal(4, ary.size) - assert_equal('CA_default', ary[0][0]) - assert_equal('CA_default', ary[1][0]) - assert_equal(["ca", "default_ca", "CA_default"], ary[2]) - assert_equal(["default", "HOME", "."], ary[3]) - end - - def test_to_s - c = OpenSSL::Config.parse("[empty]\n") - assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s) - end - - def test_inspect - assert_match(/#/, @it.inspect) - end - - def test_freeze - c = OpenSSL::Config.new - c['foo'] = [['key', 'value']] - c.freeze - - bug = '[ruby-core:18377]' - # RuntimeError for 1.9, TypeError for 1.8 - e = assert_raise(TypeError, bug) do - c['foo'] = [['key', 'wrong']] - end - assert_match(/can't modify/, e.message, bug) - end - - def test_dup - assert(!@it.sections.empty?) - c = @it.dup - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end - - def test_clone - assert(!@it.sections.empty?) - c = @it.clone - assert_equal(@it.sections.sort, c.sections.sort) - @it['newsection'] = {'a' => 'b'} - assert_not_equal(@it.sections.sort, c.sections.sort) - end -end if defined?(OpenSSL) diff --git a/test/1.9/test_digest.rb b/test/1.9/test_digest.rb deleted file mode 100644 index 81085d2..0000000 --- a/test/1.9/test_digest.rb +++ /dev/null @@ -1,118 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestDigest < Test::Unit::TestCase - def setup - @d1 = OpenSSL::Digest::Digest::new("MD5") - @d2 = OpenSSL::Digest::MD5.new - @md = Digest::MD5.new - @data = "DATA" - end - - def teardown - @d1 = @d2 = @md = nil - end - - def test_digest - assert_equal(@md.digest, @d1.digest) - assert_equal(@md.hexdigest, @d1.hexdigest) - @d1 << @data - @d2 << @data - @md << @data - assert_equal(@md.digest, @d1.digest) - assert_equal(@md.hexdigest, @d1.hexdigest) - assert_equal(@d1.digest, @d2.digest) - assert_equal(@d1.hexdigest, @d2.hexdigest) - assert_equal(@md.digest, OpenSSL::Digest::MD5.digest(@data)) - assert_equal(@md.hexdigest, OpenSSL::Digest::MD5.hexdigest(@data)) - end - - def test_eql - assert(@d1 == @d2, "==") - d = @d1.clone - assert(d == @d1, "clone") - end - - def test_info - assert_equal("MD5", @d1.name, "name") - assert_equal("MD5", @d2.name, "name") - assert_equal(16, @d1.size, "size") - end - - def test_dup - @d1.update(@data) - assert_equal(@d1.name, @d1.dup.name, "dup") - assert_equal(@d1.name, @d1.clone.name, "clone") - assert_equal(@d1.digest, @d1.clone.digest, "clone .digest") - end - - def test_reset - @d1.update(@data) - dig1 = @d1.digest - @d1.reset - @d1.update(@data) - dig2 = @d1.digest - assert_equal(dig1, dig2, "reset") - end - - def test_digest_constants - algs = %w(DSS1 MD4 MD5 RIPEMD160 SHA SHA1) - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 - algs += %w(SHA224 SHA256 SHA384 SHA512) - end - algs.each do |alg| - assert_not_nil(OpenSSL::Digest.new(alg)) - klass = OpenSSL::Digest.const_get(alg) - assert_not_nil(klass.new) - end - end - - def test_digest_by_oid_and_name - check_digest(OpenSSL::ASN1::ObjectId.new("MD5")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA1")) - end - - if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000 - def encode16(str) - str.unpack("H*").first - end - - def test_098_features - sha224_a = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" - sha256_a = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" - sha384_a = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" - sha512_a = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" - - assert_equal(sha224_a, OpenSSL::Digest::SHA224.hexdigest("a")) - assert_equal(sha256_a, OpenSSL::Digest::SHA256.hexdigest("a")) - assert_equal(sha384_a, OpenSSL::Digest::SHA384.hexdigest("a")) - assert_equal(sha512_a, OpenSSL::Digest::SHA512.hexdigest("a")) - - assert_equal(sha224_a, encode16(OpenSSL::Digest::SHA224.digest("a"))) - assert_equal(sha256_a, encode16(OpenSSL::Digest::SHA256.digest("a"))) - assert_equal(sha384_a, encode16(OpenSSL::Digest::SHA384.digest("a"))) - assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) - end - - def test_digest_by_oid_and_name_sha2 - check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA384")) - check_digest(OpenSSL::ASN1::ObjectId.new("SHA512")) - end - end - - private - - def check_digest(oid) - d = OpenSSL::Digest.new(oid.sn) - assert_not_nil(d) - d = OpenSSL::Digest.new(oid.ln) - assert_not_nil(d) - d = OpenSSL::Digest.new(oid.oid) - assert_not_nil(d) - end -end - -end diff --git a/test/1.9/test_engine.rb b/test/1.9/test_engine.rb deleted file mode 100644 index 97c5381..0000000 --- a/test/1.9/test_engine.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) && defined?(OpenSSL::Engine) - -class OpenSSL::TestEngine < Test::Unit::TestCase - - def test_engines_free # [ruby-dev:44173] - OpenSSL::Engine.load - OpenSSL::Engine.engines - OpenSSL::Engine.engines - end - -end - -end diff --git a/test/1.9/test_hmac.rb b/test/1.9/test_hmac.rb deleted file mode 100644 index ba158d2..0000000 --- a/test/1.9/test_hmac.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative 'utils' - -class OpenSSL::TestHMAC < Test::Unit::TestCase - def setup - @digest = OpenSSL::Digest::MD5 - @key = "KEY" - @data = "DATA" - @h1 = OpenSSL::HMAC.new(@key, @digest.new) - @h2 = OpenSSL::HMAC.new(@key, "MD5") - end - - def teardown - end - - def test_hmac - @h1.update(@data) - @h2.update(@data) - assert_equal(@h1.digest, @h2.digest) - - assert_equal(OpenSSL::HMAC.digest(@digest.new, @key, @data), @h1.digest, "digest") - assert_equal(OpenSSL::HMAC.hexdigest(@digest.new, @key, @data), @h1.hexdigest, "hexdigest") - - assert_equal(OpenSSL::HMAC.digest("MD5", @key, @data), @h2.digest, "digest") - assert_equal(OpenSSL::HMAC.hexdigest("MD5", @key, @data), @h2.hexdigest, "hexdigest") - end - - def test_dup - @h1.update(@data) - h = @h1.dup - assert_equal(@h1.digest, h.digest, "dup digest") - end -end if defined?(OpenSSL) diff --git a/test/1.9/test_ns_spki.rb b/test/1.9/test_ns_spki.rb deleted file mode 100644 index 3bcf3e6..0000000 --- a/test/1.9/test_ns_spki.rb +++ /dev/null @@ -1,50 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestNSSPI < Test::Unit::TestCase - def setup - # This request data is adopt from the specification of - # "Netscape Extensions for User Key Generation". - # -- http://wp.netscape.com/eng/security/comm4-keygen.html - @b64 = "MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" - @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" - @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" - @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" - @b64 << "i0//rgBvmco=" - end - - def test_build_data - key1 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - spki = OpenSSL::Netscape::SPKI.new - spki.challenge = "RandomString" - spki.public_key = key1.public_key - spki.sign(key1, OpenSSL::Digest::SHA1.new) - assert(spki.verify(spki.public_key)) - assert(spki.verify(key1.public_key)) - assert(!spki.verify(key2.public_key)) - - der = spki.to_der - spki = OpenSSL::Netscape::SPKI.new(der) - assert_equal("RandomString", spki.challenge) - assert_equal(key1.public_key.to_der, spki.public_key.to_der) - assert(spki.verify(spki.public_key)) - end - - def test_decode_data - spki = OpenSSL::Netscape::SPKI.new(@b64) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - - spki = OpenSSL::Netscape::SPKI.new(@b64.unpack("m").first) - assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) - assert_equal("MozillaIsMyFriend", spki.challenge) - assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) - end -end - -end diff --git a/test/1.9/test_ocsp.rb b/test/1.9/test_ocsp.rb deleted file mode 100644 index b42b57d..0000000 --- a/test/1.9/test_ocsp.rb +++ /dev/null @@ -1,47 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestOCSP < Test::Unit::TestCase - def setup - ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") - ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - ca_serial = 0xabcabcabcabc - - 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, [], nil, nil, dgst) - @cert = OpenSSL::TestUtils.issue_cert( - subj, @key, serial, now, now+3600, [], @ca_cert, nil, dgst) - end - - def test_new_certificate_id - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) - assert_kind_of OpenSSL::OCSP::CertificateId, cid - assert_equal @cert.serial, cid.serial - end - - def test_new_certificate_id_with_digest - cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA256.new) - assert_kind_of OpenSSL::OCSP::CertificateId, cid - assert_equal @cert.serial, cid.serial - end if defined?(OpenSSL::Digest::SHA256) - - def test_new_ocsp_request - 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, [@cert]) - assert_kind_of OpenSSL::OCSP::Request, request - # in current implementation not same instance of certificate id, but should contain same data - assert_equal cid.serial, request.certid.first.serial - end -end - -end diff --git a/test/1.9/test_pair.rb b/test/1.9/test_pair.rb deleted file mode 100644 index 1214f14..0000000 --- a/test/1.9/test_pair.rb +++ /dev/null @@ -1,257 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -require 'socket' -require_relative '../ruby/ut_eof' - -module SSLPair - DHParam = OpenSSL::PKey::DH.new(128) - def server - host = "127.0.0.1" - port = 0 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.tmp_dh_callback = proc { DHParam } - tcps = TCPServer.new(host, port) - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - return ssls - end - - def client(port) - host = "127.0.0.1" - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - s = TCPSocket.new(host, port) - ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) - ssl.connect - ssl.sync_close = true - ssl - end - - def ssl_pair - ssls = server - th = Thread.new { - ns = ssls.accept - ssls.close - ns - } - port = ssls.to_io.addr[1] - c = client(port) - s = th.value - if block_given? - begin - yield c, s - ensure - c.close unless c.closed? - s.close unless s.closed? - end - else - return c, s - end - ensure - if th && th.alive? - th.kill - th.join - end - end -end - -class OpenSSL::TestEOF1 < Test::Unit::TestCase - include TestEOF - include SSLPair - - def open_file(content) - s1, s2 = ssl_pair - Thread.new { s2 << content; s2.close } - yield s1 - end -end - -class OpenSSL::TestEOF2 < Test::Unit::TestCase - include TestEOF - include SSLPair - - def open_file(content) - s1, s2 = ssl_pair - Thread.new { s1 << content; s1.close } - yield s2 - end -end - -class OpenSSL::TestPair < Test::Unit::TestCase - include SSLPair - - def test_getc - ssl_pair {|s1, s2| - s1 << "a" - assert_equal(?a, s2.getc) - } - end - - def test_readpartial - ssl_pair {|s1, s2| - s2.write "a\nbcd" - assert_equal("a\n", s1.gets) - read = s1.readpartial(10) - assert_equal("bcd"[0, read.bytesize], read) - s1.read(read.bytesize - 3) # drop unread bytes - s2.write "efg" - read = s1.readpartial(10) - assert_equal("efg"[0, read.bytesize], read) - rest = 3 - read.bytesize - while rest > 0 - rest -= s1.readpartial(rest).size - end - s2.close - assert_raise(EOFError) { s1.readpartial(10) } - assert_raise(EOFError) { s1.readpartial(10) } - assert_equal("", s1.readpartial(0)) - } - end - - def test_readall - ssl_pair {|s1, s2| - s2.close - assert_equal("", s1.read) - } - end - - def test_readline - ssl_pair {|s1, s2| - s2.close - assert_raise(EOFError) { s1.readline } - } - end - - def test_puts_meta - ssl_pair {|s1, s2| - begin - old = $/ - $/ = '*' - s1.puts 'a' - ensure - $/ = old - end - s1.close - assert_equal("a\n", s2.read) - } - end - - def test_puts_empty - ssl_pair {|s1, s2| - s1.puts - s1.close - assert_equal("\n", s2.read) - } - end - - def test_read_nonblock - ssl_pair {|s1, s2| - err = nil - assert_raise(OpenSSL::SSL::SSLError) { - begin - s2.read_nonblock(10) - ensure - err = $! - end - } - assert_kind_of(IO::WaitReadable, err) - s1.write "abc\ndef\n" - IO.select([s2]) - assert_equal("ab", s2.read_nonblock(2)) - assert_equal("c\n", s2.gets) - ret = nil - assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) } - assert_equal("def\n", ret) - } - end - - def test_write_nonblock - ssl_pair {|s1, s2| - n = 0 - begin - n += s1.write_nonblock("a" * 100000) - n += s1.write_nonblock("b" * 100000) - n += s1.write_nonblock("c" * 100000) - n += s1.write_nonblock("d" * 100000) - n += s1.write_nonblock("e" * 100000) - n += s1.write_nonblock("f" * 100000) - rescue IO::WaitWritable - end - s1.close - assert_equal(n, s2.read.length) - } - end - - def test_write_nonblock_with_buffered_data - ssl_pair {|s1, s2| - s1.write "foo" - s1.write_nonblock("bar") - s1.write "baz" - s1.close - assert_equal("foobarbaz", s2.read) - } - end - - def test_connect_accept_nonblock - host = "127.0.0.1" - port = 0 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - ctx.tmp_dh_callback = proc { DHParam } - serv = TCPServer.new(host, port) - - port = serv.connect_address.ip_port - - sock1 = TCPSocket.new(host, port) - sock2 = serv.accept - serv.close - - th = Thread.new { - s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx) - s2.sync_close = true - begin - sleep 0.2 - s2.accept_nonblock - rescue IO::WaitReadable - IO.select([s2]) - retry - rescue IO::WaitWritable - IO.select(nil, [s2]) - retry - end - s2 - } - - sleep 0.1 - ctx = OpenSSL::SSL::SSLContext.new() - ctx.ciphers = "ADH" - s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx) - begin - sleep 0.2 - s1.connect_nonblock - rescue IO::WaitReadable - IO.select([s1]) - retry - rescue IO::WaitWritable - IO.select(nil, [s1]) - retry - end - s1.sync_close = true - - s2 = th.value - - s1.print "a\ndef" - assert_equal("a\n", s2.gets) - ensure - s1.close if s1 && !s1.closed? - s2.close if s2 && !s2.closed? - serv.close if serv && !serv.closed? - sock1.close if sock1 && !sock1.closed? - sock2.close if sock2 && !sock2.closed? - end - -end - -end diff --git a/test/1.9/test_pkcs12.rb b/test/1.9/test_pkcs12.rb deleted file mode 100644 index 64e7530..0000000 --- a/test/1.9/test_pkcs12.rb +++ /dev/null @@ -1,209 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -module OpenSSL - class TestPKCS12 < Test::Unit::TestCase - include OpenSSL::TestUtils - - def setup - ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - - now = Time.now - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - - @cacert = issue_cert(ca, TEST_KEY_RSA2048, 1, now, now+3600, ca_exts, - nil, nil, OpenSSL::Digest::SHA1.new) - - inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA") - inter_ca_key = OpenSSL::PKey.read <<-_EOS_ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K -oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT -ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB -AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV -5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9 -iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC -G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5 -Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA -HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf -ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG -jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK -FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3 -Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= ------END RSA PRIVATE KEY----- - _EOS_ - - @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, now, now+3600, ca_exts, - @ca_cert, TEST_KEY_RSA2048, OpenSSL::Digest::SHA1.new) - - exts = [ - ["keyUsage","digitalSignature",true], - ["subjectKeyIdentifier","hash",false], - ] - ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") - @mycert = issue_cert(ee, TEST_KEY_RSA1024, 3, now, now+3600, exts, - @inter_cacert, inter_ca_key, OpenSSL::Digest::SHA1.new) - end - - def test_create - pkcs12 = OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert - ) - assert_equal @mycert, pkcs12.certificate - assert_equal TEST_KEY_RSA1024, pkcs12.key - assert_nil pkcs12.ca_certs - end - - def test_create_no_pass - pkcs12 = OpenSSL::PKCS12.create( - nil, - "hello", - TEST_KEY_RSA1024, - @mycert - ) - assert_equal @mycert, pkcs12.certificate - assert_equal TEST_KEY_RSA1024, pkcs12.key - assert_nil pkcs12.ca_certs - - decoded = OpenSSL::PKCS12.new(pkcs12.to_der) - assert_cert @mycert, decoded.certificate - end - - def test_create_with_chain - chain = [@inter_cacert, @cacert] - - pkcs12 = OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - chain - ) - assert_equal chain, pkcs12.ca_certs - end - - def test_create_with_chain_decode - chain = [@cacert, @inter_cacert] - - passwd = "omg" - - pkcs12 = OpenSSL::PKCS12.create( - passwd, - "hello", - TEST_KEY_RSA1024, - @mycert, - chain - ) - - decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd) - assert_equal chain.size, decoded.ca_certs.size - assert_include_cert @cacert, decoded.ca_certs - assert_include_cert @inter_cacert, decoded.ca_certs - assert_cert @mycert, decoded.certificate - assert_equal TEST_KEY_RSA1024.to_der, decoded.key.to_der - end - - def test_create_with_bad_nid - assert_raises(ArgumentError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - [], - "foo" - ) - end - end - - def test_create_with_itr - OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - [], - nil, - nil, - 2048 - ) - - assert_raises(TypeError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - [], - nil, - nil, - "omg" - ) - end - end - - def test_create_with_mac_itr - OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - [], - nil, - nil, - nil, - 2048 - ) - - assert_raises(TypeError) do - OpenSSL::PKCS12.create( - "omg", - "hello", - TEST_KEY_RSA1024, - @mycert, - [], - nil, - nil, - nil, - "omg" - ) - end - end - - private - def assert_cert expected, actual - [ - :subject, - :issuer, - :serial, - :not_before, - :not_after, - ].each do |attribute| - assert_equal expected.send(attribute), actual.send(attribute) - end - assert_equal expected.to_der, actual.to_der - end - - def assert_include_cert cert, ary - der = cert.to_der - ary.each do |candidate| - if candidate.to_der == der - return true - end - end - false - end - - end -end - -end diff --git a/test/1.9/test_pkcs7.rb b/test/1.9/test_pkcs7.rb deleted file mode 100644 index b17cbda..0000000 --- a/test/1.9/test_pkcs7.rb +++ /dev/null @@ -1,156 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestPKCS7 < Test::Unit::TestCase - def setup - @rsa1024 = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @rsa2048 = OpenSSL::TestUtils::TEST_KEY_RSA2048 - 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") - - now = Time.now - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","keyCertSign, cRLSign",true], - ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], - ] - @ca_cert = issue_cert(ca, @rsa2048, 1, now, now+3600, ca_exts, - nil, nil, OpenSSL::Digest::SHA1.new) - ee_exts = [ - ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], - ["authorityKeyIdentifier","keyid:always",false], - ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], - ] - @ee1_cert = issue_cert(ee1, @rsa1024, 2, now, now+1800, ee_exts, - @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - @ee2_cert = issue_cert(ee2, @rsa1024, 3, now, now+1800, ee_exts, - @ca_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - end - - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - - def test_signed - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\r\nbbbbb\r\nccccc\r\n" - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # Normaly OpenSSL tries to translate the supplied content into canonical - # MIME format (e.g. a newline character is converted into CR+LF). - # If the content is a binary, PKCS7::BINARY flag should be used. - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - - # A signed-data which have multiple signatures can be created - # through the following steps. - # 1. create two signed-data - # 2. copy signerInfo and certificate from one to another - - tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, [], flag) - tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @rsa1024, data, [], flag) - tmp1.add_signer(tmp2.signers[0]) - tmp1.add_certificate(@ee2_cert) - - p7 = OpenSSL::PKCS7.new(tmp1.to_der) - certs = p7.certificates - signers = p7.signers - assert(p7.verify([], store)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(2, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - assert_equal(@ee2_cert.serial, signers[1].serial) - assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s) - end - - def test_detached_sign - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - ca_certs = [@ca_cert] - - data = "aaaaa\nbbbbb\nccccc\n" - flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED - tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - assert_nothing_raised do - OpenSSL::ASN1.decode(p7) - end - - certs = p7.certificates - signers = p7.signers - assert(!p7.verify([], store)) - assert(p7.verify([], store, data)) - assert_equal(data, p7.data) - assert_equal(2, certs.size) - assert_equal(@ee1_cert.subject.to_s, certs[0].subject.to_s) - assert_equal(@ca_cert.subject.to_s, certs[1].subject.to_s) - assert_equal(1, signers.size) - assert_equal(@ee1_cert.serial, signers[0].serial) - assert_equal(@ee1_cert.issuer.to_s, signers[0].issuer.to_s) - end - - def test_enveloped - if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x0090704f - # PKCS7_encrypt() of OpenSSL-0.9.7d goes to SEGV. - # http://www.mail-archive.com/openssl-dev@openssl.org/msg17376.html - return - end - - certs = [@ee1_cert, @ee2_cert] - cipher = OpenSSL::Cipher::AES.new("128-CBC") - data = "aaaaa\nbbbbb\nccccc\n" - - tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY) - p7 = OpenSSL::PKCS7.new(tmp.to_der) - recip = p7.recipients - assert_equal(:enveloped, p7.type) - assert_equal(2, recip.size) - - assert_equal(@ca_cert.subject.to_s, recip[0].issuer.to_s) - assert_equal(2, recip[0].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee1_cert)) - - assert_equal(@ca_cert.subject.to_s, recip[1].issuer.to_s) - assert_equal(3, recip[1].serial) - assert_equal(data, p7.decrypt(@rsa1024, @ee2_cert)) - end - - def test_graceful_parsing_failure #[ruby-core:43250] - contents = File.read(__FILE__) - assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } - end -end - -end diff --git a/test/1.9/test_pkey_dh.rb b/test/1.9/test_pkey_dh.rb deleted file mode 100644 index bcba400..0000000 --- a/test/1.9/test_pkey_dh.rb +++ /dev/null @@ -1,72 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestPKeyDH < Test::Unit::TestCase - def test_new - dh = OpenSSL::PKey::DH.new(256) - assert_key(dh) - end - - def test_to_der - dh = OpenSSL::PKey::DH.new(256) - der = dh.to_der - dh2 = OpenSSL::PKey::DH.new(der) - assert_equal_params(dh, dh2) - assert_no_key(dh2) - end - - def test_to_pem - dh = OpenSSL::PKey::DH.new(256) - pem = dh.to_pem - dh2 = OpenSSL::PKey::DH.new(pem) - assert_equal_params(dh, dh2) - assert_no_key(dh2) - end - - def test_public_key - dh = OpenSSL::PKey::DH.new(256) - public_key = dh.public_key - assert_no_key(public_key) #implies public_key.public? is false! - assert_equal(dh.to_der, public_key.to_der) - assert_equal(dh.to_pem, public_key.to_pem) - end - - def test_generate_key - dh = OpenSSL::TestUtils::TEST_KEY_DH512.public_key # creates a copy - assert_no_key(dh) - dh.generate_key! - assert_key(dh) - end - - def test_key_exchange - dh = OpenSSL::TestUtils::TEST_KEY_DH512 - dh2 = dh.public_key - dh.generate_key! - dh2.generate_key! - assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) - end - - private - - def assert_equal_params(dh1, dh2) - assert_equal(dh1.g, dh2.g) - assert_equal(dh1.p, dh2.p) - end - - def assert_no_key(dh) - assert_equal(false, dh.public?) - assert_equal(false, dh.private?) - assert_equal(nil, dh.pub_key) - assert_equal(nil, dh.priv_key) - end - - def assert_key(dh) - assert(dh.public?) - assert(dh.private?) - assert(dh.pub_key) - assert(dh.priv_key) - end -end - -end diff --git a/test/1.9/test_pkey_dsa.rb b/test/1.9/test_pkey_dsa.rb deleted file mode 100644 index e498e3c..0000000 --- a/test/1.9/test_pkey_dsa.rb +++ /dev/null @@ -1,224 +0,0 @@ -require_relative 'utils' -require 'base64' - -if defined?(OpenSSL) - -class OpenSSL::TestPKeyDSA < Test::Unit::TestCase - def test_private - key = OpenSSL::PKey::DSA.new(256) - assert(key.private?) - key2 = OpenSSL::PKey::DSA.new(key.to_der) - assert(key2.private?) - key3 = key.public_key - assert(!key3.private?) - key4 = OpenSSL::PKey::DSA.new(key3.to_der) - assert(!key4.private?) - end - - def test_new - key = OpenSSL::PKey::DSA.new 256 - pem = key.public_key.to_pem - OpenSSL::PKey::DSA.new pem - assert_equal([], OpenSSL.errors) - end - - def test_sys_sign_verify - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - data = 'Sign me!' - digest = OpenSSL::Digest::SHA1.digest(data) - sig = key.syssign(digest) - assert(key.sysverify(digest, sig)) - end - - def test_sign_verify - check_sign_verify(OpenSSL::Digest::DSS1.new) - end - -if (OpenSSL::OPENSSL_VERSION_NUMBER > 0x10000000) - def test_sign_verify_sha1 - check_sign_verify(OpenSSL::Digest::SHA1.new) - end - - def test_sign_verify_sha256 - check_sign_verify(OpenSSL::Digest::SHA256.new) - end -end - - def test_digest_state_irrelevant_verify - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - digest1 = OpenSSL::Digest::DSS1.new - digest2 = OpenSSL::Digest::DSS1.new - data = 'Sign me!' - sig = key.sign(digest1, data) - digest1.reset - digest1 << 'Change state of digest1' - assert(key.verify(digest1, sig, data)) - assert(key.verify(digest2, sig, data)) - end - - def test_read_DSA_PUBKEY - p = 7188211954100152441468596248707152960171255279130004340103875772401008316444412091945435731597638374542374929457672178957081124632837356913990200866056699 - q = 957032439192465935099784319494405376402293318491 - g = 122928973717064636255205666162891733518376475981809749897454444301389338825906076467196186192907631719698166056821519884939865041993585844526937010746285 - y = 1235756183583465414789073313502727057075641172514181938731172021825149551960029708596057102104063395063907739571546165975727369183495540798749742124846271 - algo = OpenSSL::ASN1::ObjectId.new('DSA') - params = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(p), - OpenSSL::ASN1::Integer.new(q), - OpenSSL::ASN1::Integer.new(g)]) - algo_id = OpenSSL::ASN1::Sequence.new ([algo, params]) - pub_key = OpenSSL::ASN1::Integer.new(y) - seq = OpenSSL::ASN1::Sequence.new([algo_id, OpenSSL::ASN1::BitString.new(pub_key.to_der)]) - key = OpenSSL::PKey::DSA.new(seq.to_der) - assert(key.public?) - assert(!key.private?) - assert_equal(p, key.p) - assert_equal(q, key.q) - assert_equal(g, key.g) - assert_equal(y, key.pub_key) - assert_equal(nil, key.priv_key) - assert_equal([], OpenSSL.errors) - end - - def test_read_DSAPublicKey_pem - p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699 - q = 979494906553787301107832405790107343409973851677 - g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845 - y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695 - pem = <<-EOF ------BEGIN DSA PUBLIC KEY----- -MIHfAkEAyJSJ+g+P/knVcgDwwTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4 -VUC/phySExY0PdcqItkR/xYAYNMbNwJBAOoV57X0FxKO/PrNa/MkoWzkCKV/hzhE -p0zbFdsicw+hIjJ7S6Sd/FlDlo89HQZ2FuvWJ6wGLM1j00r39+F2qbMCFQCrkhIX -SG+is37hz1IaBeEudjB2HQJAR0AloavBvtsng8obsjLb7EKnB+pSeHr/BdIQ3VH7 -fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== ------END DSA PUBLIC KEY----- - EOF - key = OpenSSL::PKey::DSA.new(pem) - assert(key.public?) - assert(!key.private?) - assert_equal(p, key.p) - assert_equal(q, key.q) - assert_equal(g, key.g) - assert_equal(y, key.pub_key) - assert_equal(nil, key.priv_key) - assert_equal([], OpenSSL.errors) - end - - def test_read_DSA_PUBKEY_pem - p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699 - q = 979494906553787301107832405790107343409973851677 - g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845 - y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695 - pem = <<-EOF ------BEGIN PUBLIC KEY----- -MIHxMIGoBgcqhkjOOAQBMIGcAkEA6hXntfQXEo78+s1r8yShbOQIpX+HOESnTNsV -2yJzD6EiMntLpJ38WUOWjz0dBnYW69YnrAYszWPTSvf34XapswIVAKuSEhdIb6Kz -fuHPUhoF4S52MHYdAkBHQCWhq8G+2yeDyhuyMtvsQqcH6lJ4ev8F0hDdUft9Ys6q -qTMV5GtgwPNSmXfpeS1jpirwQliVb2kIyYFU3L91A0QAAkEAyJSJ+g+P/knVcgDw -wTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4VUC/phySExY0PdcqItkR/xYA -YNMbNw== ------END PUBLIC KEY----- - EOF - key = OpenSSL::PKey::DSA.new(pem) - assert(key.public?) - assert(!key.private?) - assert_equal(p, key.p) - assert_equal(q, key.q) - assert_equal(g, key.g) - assert_equal(y, key.pub_key) - assert_equal(nil, key.priv_key) - assert_equal([], OpenSSL.errors) - end - - def test_export_format_is_DSA_PUBKEY_pem - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - pem = key.public_key.to_pem - pem.gsub!(/^-+(\w|\s)+-+$/, "") # eliminate --------BEGIN...------- - asn1 = OpenSSL::ASN1.decode(Base64.decode64(pem)) - assert_equal(OpenSSL::ASN1::SEQUENCE, asn1.tag) - assert_equal(2, asn1.value.size) - seq = asn1.value - assert_equal(OpenSSL::ASN1::SEQUENCE, seq[0].tag) - assert_equal(2, seq[0].value.size) - algo_id = seq[0].value - assert_equal(OpenSSL::ASN1::OBJECT, algo_id[0].tag) - assert_equal('DSA', algo_id[0].value) - assert_equal(OpenSSL::ASN1::SEQUENCE, algo_id[1].tag) - assert_equal(3, algo_id[1].value.size) - params = algo_id[1].value - assert_equal(OpenSSL::ASN1::INTEGER, params[0].tag) - assert_equal(key.p, params[0].value) - assert_equal(OpenSSL::ASN1::INTEGER, params[1].tag) - assert_equal(key.q, params[1].value) - assert_equal(OpenSSL::ASN1::INTEGER, params[2].tag) - assert_equal(key.g, params[2].value) - assert_equal(OpenSSL::ASN1::BIT_STRING, seq[1].tag) - assert_equal(0, seq[1].unused_bits) - pub_key = OpenSSL::ASN1.decode(seq[1].value) - assert_equal(OpenSSL::ASN1::INTEGER, pub_key.tag) - assert_equal(key.pub_key, pub_key.value) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_der - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - der = key.to_der - key2 = OpenSSL::PKey.read(der) - assert(key2.private?) - assert_equal(der, key2.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - pem = key.to_pem - key2 = OpenSSL::PKey.read(pem) - assert(key2.private?) - assert_equal(pem, key2.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_der - key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key - der = key.to_der - key2 = OpenSSL::PKey.read(der) - assert(!key2.private?) - assert_equal(der, key2.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_pem - key = OpenSSL::TestUtils::TEST_KEY_DSA256.public_key - pem = key.to_pem - key2 = OpenSSL::PKey.read(pem) - assert(!key2.private?) - assert_equal(pem, key2.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem_pw - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - pem = key.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') - #callback form for password - key2 = OpenSSL::PKey.read(pem) do - 'secret' - end - assert(key2.private?) - # pass password directly - key2 = OpenSSL::PKey.read(pem, 'secret') - assert(key2.private?) - #omit pem equality check, will be different due to cipher iv - assert_equal([], OpenSSL.errors) - end - - private - - def check_sign_verify(digest) - key = OpenSSL::TestUtils::TEST_KEY_DSA256 - data = 'Sign me!' - sig = key.sign(digest, data) - assert(key.verify(digest, sig, data)) - end -end - -end diff --git a/test/1.9/test_pkey_ec.rb b/test/1.9/test_pkey_ec.rb deleted file mode 100644 index e63f617..0000000 --- a/test/1.9/test_pkey_ec.rb +++ /dev/null @@ -1,182 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL::PKey::EC) - -class OpenSSL::TestEC < Test::Unit::TestCase - def setup - @data1 = 'foo' - @data2 = 'bar' * 1000 # data too long for DSA sig - - @group1 = OpenSSL::PKey::EC::Group.new('secp112r1') - @group2 = OpenSSL::PKey::EC::Group.new('sect163k1') - @group3 = OpenSSL::PKey::EC::Group.new('prime256v1') - - @key1 = OpenSSL::PKey::EC.new - @key1.group = @group1 - @key1.generate_key - - @key2 = OpenSSL::PKey::EC.new(@group2.curve_name) - @key2.generate_key - - @key3 = OpenSSL::PKey::EC.new(@group3) - @key3.generate_key - - @groups = [@group1, @group2, @group3] - @keys = [@key1, @key2, @key3] - end - - def compare_keys(k1, k2) - assert_equal(k1.to_pem, k2.to_pem) - end - - def test_curve_names - @groups.each_with_index do |group, idx| - key = @keys[idx] - assert_equal(group.curve_name, key.group.curve_name) - end - end - - def test_check_key - for key in @keys - assert_equal(key.check_key, true) - assert_equal(key.private_key?, true) - assert_equal(key.public_key?, true) - end - end - - def test_encoding - for group in @groups - for meth in [:to_der, :to_pem] - txt = group.send(meth) - gr = OpenSSL::PKey::EC::Group.new(txt) - assert_equal(txt, gr.send(meth)) - - assert_equal(group.generator.to_bn, gr.generator.to_bn) - assert_equal(group.cofactor, gr.cofactor) - assert_equal(group.order, gr.order) - assert_equal(group.seed, gr.seed) - assert_equal(group.degree, gr.degree) - end - end - - for key in @keys - group = key.group - - for meth in [:to_der, :to_pem] - txt = key.send(meth) - assert_equal(txt, OpenSSL::PKey::EC.new(txt).send(meth)) - end - - bn = key.public_key.to_bn - assert_equal(bn, OpenSSL::PKey::EC::Point.new(group, bn).to_bn) - end - end - - def test_set_keys - for key in @keys - k = OpenSSL::PKey::EC.new - k.group = key.group - k.private_key = key.private_key - k.public_key = key.public_key - - compare_keys(key, k) - end - end - - def test_dsa_sign_verify - for key in @keys - sig = key.dsa_sign_asn1(@data1) - assert(key.dsa_verify_asn1(@data1, sig)) - end - end - - def test_dsa_sign_asn1_FIPS186_3 - for key in @keys - size = key.group.order.num_bits / 8 + 1 - dgst = (1..size).to_a.pack('C*') - begin - sig = key.dsa_sign_asn1(dgst) - # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m - assert(key.dsa_verify_asn1(dgst + "garbage", sig)) - rescue OpenSSL::PKey::ECError => e - # just an exception for longer dgst before openssl-0.9.8m - assert_equal('ECDSA_sign: data too large for key size', e.message) - # no need to do following tests - return - end - end - end - - def test_dh_compute_key - for key in @keys - k = OpenSSL::PKey::EC.new(key.group) - k.generate_key - - puba = key.public_key - pubb = k.public_key - a = key.dh_compute_key(pubb) - b = k.dh_compute_key(puba) - assert_equal(a, b) - end - end - - def test_read_private_key_der - ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - der = ec.to_der - ec2 = OpenSSL::PKey.read(der) - assert(ec2.private_key?) - assert_equal(der, ec2.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem - ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - pem = ec.to_pem - ec2 = OpenSSL::PKey.read(pem) - assert(ec2.private_key?) - assert_equal(pem, ec2.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_der - ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - ec2 = OpenSSL::PKey::EC.new(ec.group) - ec2.public_key = ec.public_key - der = ec2.to_der - ec3 = OpenSSL::PKey.read(der) - assert(!ec3.private_key?) - assert_equal(der, ec3.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_pem - ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - ec2 = OpenSSL::PKey::EC.new(ec.group) - ec2.public_key = ec.public_key - pem = ec2.to_pem - ec3 = OpenSSL::PKey.read(pem) - assert(!ec3.private_key?) - assert_equal(pem, ec3.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem_pw - ec = OpenSSL::TestUtils::TEST_KEY_EC_P256V1 - pem = ec.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') - #callback form for password - ec2 = OpenSSL::PKey.read(pem) do - 'secret' - end - assert(ec2.private_key?) - # pass password directly - ec2 = OpenSSL::PKey.read(pem, 'secret') - assert(ec2.private_key?) - #omit pem equality check, will be different due to cipher iv - assert_equal([], OpenSSL.errors) - end - -# test Group: asn1_flag, point_conversion - -end - -end diff --git a/test/1.9/test_pkey_rsa.rb b/test/1.9/test_pkey_rsa.rb deleted file mode 100644 index 5ba1422..0000000 --- a/test/1.9/test_pkey_rsa.rb +++ /dev/null @@ -1,244 +0,0 @@ -require_relative 'utils' -require 'base64' - -if defined?(OpenSSL) - -class OpenSSL::TestPKeyRSA < Test::Unit::TestCase - def test_padding - key = OpenSSL::PKey::RSA.new(512, 3) - - # Need right size for raw mode - plain0 = "x" * (512/8) - cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING) - plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING) - assert_equal(plain0, plain1) - - # Need smaller size for pkcs1 mode - plain0 = "x" * (512/8 - 11) - cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING) - plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING) - assert_equal(plain0, plain1) - - cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default - plain1 = key.public_decrypt(cipherdef) - assert_equal(plain0, plain1) - assert_equal(cipher1, cipherdef) - - # Failure cases - assert_raise(ArgumentError){ key.private_encrypt() } - assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) } - assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) } - end - - def test_private - key = OpenSSL::PKey::RSA.new(512, 3) - assert(key.private?) - key2 = OpenSSL::PKey::RSA.new(key.to_der) - assert(key2.private?) - key3 = key.public_key - assert(!key3.private?) - key4 = OpenSSL::PKey::RSA.new(key3.to_der) - assert(!key4.private?) - end - - def test_new - key = OpenSSL::PKey::RSA.new 512 - pem = key.public_key.to_pem - OpenSSL::PKey::RSA.new pem - assert_equal([], OpenSSL.errors) - end - - def test_sign_verify - key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - digest = OpenSSL::Digest::SHA1.new - data = 'Sign me!' - sig = key.sign(digest, data) - assert(key.verify(digest, sig, data)) - end - - def test_digest_state_irrelevant_sign - key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - digest1 = OpenSSL::Digest::SHA1.new - digest2 = OpenSSL::Digest::SHA1.new - data = 'Sign me!' - digest1 << 'Change state of digest1' - sig1 = key.sign(digest1, data) - sig2 = key.sign(digest2, data) - assert_equal(sig1, sig2) - end - - def test_digest_state_irrelevant_verify - key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - digest1 = OpenSSL::Digest::SHA1.new - digest2 = OpenSSL::Digest::SHA1.new - data = 'Sign me!' - sig = key.sign(digest1, data) - digest1.reset - digest1 << 'Change state of digest1' - assert(key.verify(digest1, sig, data)) - assert(key.verify(digest2, sig, data)) - end - - def test_read_RSAPublicKey - modulus = 10664264882656732240315063514678024569492171560814833397008094754351396057398262071307709191731289492697968568138092052265293364132872019762410446076526351 - exponent = 65537 - seq = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(modulus), OpenSSL::ASN1::Integer.new(exponent)]) - key = OpenSSL::PKey::RSA.new(seq.to_der) - assert(key.public?) - assert(!key.private?) - assert_equal(modulus, key.n) - assert_equal(exponent, key.e) - assert_equal(nil, key.d) - assert_equal(nil, key.p) - assert_equal(nil, key.q) - assert_equal([], OpenSSL.errors) - end - - def test_read_RSA_PUBKEY - modulus = 10664264882656732240315063514678024569492171560814833397008094754351396057398262071307709191731289492697968568138092052265293364132872019762410446076526351 - exponent = 65537 - algo = OpenSSL::ASN1::ObjectId.new('rsaEncryption') - null_params = OpenSSL::ASN1::Null.new(nil) - algo_id = OpenSSL::ASN1::Sequence.new ([algo, null_params]) - pub_key = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::Integer.new(modulus), OpenSSL::ASN1::Integer.new(exponent)]) - seq = OpenSSL::ASN1::Sequence.new([algo_id, OpenSSL::ASN1::BitString.new(pub_key.to_der)]) - key = OpenSSL::PKey::RSA.new(seq.to_der) - assert(key.public?) - assert(!key.private?) - assert_equal(modulus, key.n) - assert_equal(exponent, key.e) - assert_equal(nil, key.d) - assert_equal(nil, key.p) - assert_equal(nil, key.q) - assert_equal([], OpenSSL.errors) - end - - def test_read_RSAPublicKey_pem - modulus = 9416340886363418692990906464787534854462163316648195510702927337693641649864839352187127240942127674615733815606532506566068276485089353644309497938966061 - exponent = 65537 - pem = <<-EOF ------BEGIN RSA PUBLIC KEY----- -MEgCQQCzyh2RIZK62E2PbTWqUljD+K23XR9AGBKNtXjal6WD2yRGcLqzPJLNCa60 -AudJR1JobbIbDJrQu6AXnWh5k/YtAgMBAAE= ------END RSA PUBLIC KEY----- - EOF - key = OpenSSL::PKey::RSA.new(pem) - assert(key.public?) - assert(!key.private?) - assert_equal(modulus, key.n) - assert_equal(exponent, key.e) - assert_equal(nil, key.d) - assert_equal(nil, key.p) - assert_equal(nil, key.q) - assert_equal([], OpenSSL.errors) - end - - def test_read_RSA_PUBKEY_pem - modulus = 9416340886363418692990906464787534854462163316648195510702927337693641649864839352187127240942127674615733815606532506566068276485089353644309497938966061 - exponent = 65537 - pem = <<-EOF ------BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALPKHZEhkrrYTY9tNapSWMP4rbdd -H0AYEo21eNqXpYPbJEZwurM8ks0JrrQC50lHUmhtshsMmtC7oBedaHmT9i0C -AwEAAQ== ------END PUBLIC KEY----- - EOF - key = OpenSSL::PKey::RSA.new(pem) - assert(key.public?) - assert(!key.private?) - assert_equal(modulus, key.n) - assert_equal(exponent, key.e) - assert_equal(nil, key.d) - assert_equal(nil, key.p) - assert_equal(nil, key.q) - assert_equal([], OpenSSL.errors) - end - - def test_export_format_is_RSA_PUBKEY - key = OpenSSL::PKey::RSA.new(512) - asn1 = OpenSSL::ASN1.decode(key.public_key.to_der) - check_PUBKEY(asn1, key) - end - - def test_export_format_is_RSA_PUBKEY_pem - key = OpenSSL::PKey::RSA.new(512) - pem = key.public_key.to_pem - pem.gsub!(/^-+(\w|\s)+-+$/, "") # eliminate --------BEGIN...------- - asn1 = OpenSSL::ASN1.decode(Base64.decode64(pem)) - check_PUBKEY(asn1, key) - end - - def test_read_private_key_der - der = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_der - key = OpenSSL::PKey.read(der) - assert(key.private?) - assert_equal(der, key.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem - pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem - key = OpenSSL::PKey.read(pem) - assert(key.private?) - assert_equal(pem, key.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_der - der = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_der - key = OpenSSL::PKey.read(der) - assert(!key.private?) - assert_equal(der, key.to_der) - assert_equal([], OpenSSL.errors) - end - - def test_read_public_key_pem - pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.public_key.to_pem - key = OpenSSL::PKey.read(pem) - assert(!key.private?) - assert_equal(pem, key.to_pem) - assert_equal([], OpenSSL.errors) - end - - def test_read_private_key_pem_pw - pem = OpenSSL::TestUtils::TEST_KEY_RSA1024.to_pem(OpenSSL::Cipher.new('AES-128-CBC'), 'secret') - #callback form for password - key = OpenSSL::PKey.read(pem) do - 'secret' - end - assert(key.private?) - # pass password directly - key = OpenSSL::PKey.read(pem, 'secret') - assert(key.private?) - #omit pem equality check, will be different due to cipher iv - assert_equal([], OpenSSL.errors) - end - - private - - def check_PUBKEY(asn1, key) - assert_equal(OpenSSL::ASN1::SEQUENCE, asn1.tag) - assert_equal(2, asn1.value.size) - seq = asn1.value - assert_equal(OpenSSL::ASN1::SEQUENCE, seq[0].tag) - assert_equal(2, seq[0].value.size) - algo_id = seq[0].value - assert_equal(OpenSSL::ASN1::OBJECT, algo_id[0].tag) - assert_equal('rsaEncryption', algo_id[0].value) - assert_equal(OpenSSL::ASN1::NULL, algo_id[1].tag) - assert_equal(nil, algo_id[1].value) - assert_equal(OpenSSL::ASN1::BIT_STRING, seq[1].tag) - assert_equal(0, seq[1].unused_bits) - pub_key = OpenSSL::ASN1.decode(seq[1].value) - assert_equal(OpenSSL::ASN1::SEQUENCE, pub_key.tag) - assert_equal(2, pub_key.value.size) - assert_equal(OpenSSL::ASN1::INTEGER, pub_key.value[0].tag) - assert_equal(key.n, pub_key.value[0].value) - assert_equal(OpenSSL::ASN1::INTEGER, pub_key.value[1].tag) - assert_equal(key.e, pub_key.value[1].value) - assert_equal([], OpenSSL.errors) - end - -end - -end diff --git a/test/1.9/test_ssl.rb b/test/1.9/test_ssl.rb deleted file mode 100644 index 0e47234..0000000 --- a/test/1.9/test_ssl.rb +++ /dev/null @@ -1,499 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestSSL < OpenSSL::SSLTestCase - def test_ctx_setup - ctx = OpenSSL::SSL::SSLContext.new - assert_equal(ctx.setup, true) - assert_equal(ctx.setup, nil) - end - - def test_ctx_setup_no_compression - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_COMPRESSION - assert_equal(ctx.setup, true) - assert_equal(ctx.setup, nil) - assert_equal(OpenSSL::SSL::OP_NO_COMPRESSION, - ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION) - end if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) - - def test_not_started_session - skip "non socket argument of SSLSocket.new is not supported on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM - open(__FILE__) do |f| - assert_nil OpenSSL::SSL::SSLSocket.new(f).cert - end - end - - def test_ssl_read_nonblock - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - assert_raise(IO::WaitReadable) { ssl.read_nonblock(100) } - ssl.write("abc\n") - IO.select [ssl] - assert_equal('a', ssl.read_nonblock(1)) - assert_equal("bc\n", ssl.read_nonblock(100)) - assert_raise(IO::WaitReadable) { ssl.read_nonblock(100) } - } - end - - def test_connect_and_close - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - assert(ssl.connect) - ssl.close - assert(!sock.closed?) - sock.close - - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true # !! - assert(ssl.connect) - ssl.close - assert(sock.closed?) - } - end - - def test_read_and_write - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - - # puts and gets - ITERATIONS.times{ - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - str = "x" * 100 - ssl.puts(str) - assert_equal(str, ssl.gets("\n", 100)) - assert_equal("\n", ssl.gets) - } - - # read and write - ITERATIONS.times{|i| - str = "x" * 100 + "\n" - ssl.write(str) - assert_equal(str, ssl.read(str.size)) - - str = "x" * i * 100 + "\n" - buf = "" - ssl.write(str) - assert_equal(buf.object_id, ssl.read(str.size, buf).object_id) - assert_equal(str, buf) - } - - ssl.close - } - end - - def sysread_size(ssl, size) - buf = '' - while buf.bytesize < size - buf += ssl.sysread(size - buf.bytesize) - end - buf - end - - def test_sysread_chunks - args = {} - args[:server_proc] = proc { |ctx, ssl| - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.accept - next - end - ssl.write("0" * 800) - ssl.write("1" * 200) - ssl.close - break - end - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, args){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - ssl.syswrite("hello\n") - assert_equal("0" * 200, sysread_size(ssl, 200)) - assert_equal("0" * 200, sysread_size(ssl, 200)) - assert_equal("0" * 200, sysread_size(ssl, 200)) - assert_equal("0" * 200, sysread_size(ssl, 200)) - assert_equal("1" * 200, sysread_size(ssl, 200)) - ssl.close - } - end - - def test_sysread_buffer - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - ITERATIONS.times{|i| - # the given buffer is cleared before concatenating. - # NB: SSLSocket#readpartial depends sysread. - str = "x" * i * 100 + "\n" - ssl.syswrite(str) - buf = "asdf" - assert_equal(buf.object_id, ssl.sysread(0, buf).object_id) - assert_equal("", buf) - - buf = "asdf" - read = ssl.sysread(str.size, buf) - assert(!read.empty?) - assert_equal(buf.object_id, read.object_id) - assert_equal(str[0, buf.bytesize], buf) - sysread_size(ssl, str.bytesize - buf.bytesize) # drop unread bytes - - ssl.syswrite(str) - read = ssl.sysread(str.size, nil) - assert(!read.empty?) - assert_equal(str[0, read.bytesize], read) - sysread_size(ssl, str.bytesize - read.bytesize) # drop unread bytes - } - ssl.close - } - end - - def test_client_auth - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(PORT, vflag, true){|server, port| - assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET){ - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - } - - ctx = OpenSSL::SSL::SSLContext.new - ctx.key = @cli_key - ctx.cert = @cli_cert - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - ssl.close - - called = nil - ctx = OpenSSL::SSL::SSLContext.new - ctx.client_cert_cb = Proc.new{ |sslconn| - called = true - [@cli_cert, @cli_key] - } - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - assert(called) - ssl.puts("foo") - assert_equal("foo\n", ssl.gets) - ssl.close - } - end - - def test_client_ca - ctx_proc = Proc.new do |ctx| - ctx.client_ca = [@ca_cert] - end - - vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - start_server(PORT, vflag, true, :ctx_proc => ctx_proc){|server, port| - ctx = OpenSSL::SSL::SSLContext.new - client_ca_from_server = nil - ctx.client_cert_cb = Proc.new do |sslconn| - client_ca_from_server = sslconn.client_ca - [@cli_cert, @cli_key] - end - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - assert_equal([@ca], client_ca_from_server) - ssl.close - } - end - - def test_starttls - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - str = "x" * 1000 + "\n" - - OpenSSL::TestUtils.silent do - ITERATIONS.times{ - ssl.puts(str) - assert_equal(str, ssl.gets) - } - starttls(ssl) - end - - ITERATIONS.times{ - ssl.puts(str) - assert_equal(str, ssl.gets) - } - - ssl.close - } - end - - def test_parallel - GC.start - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - ssls = [] - 10.times{ - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - ssl.sync_close = true - ssls << ssl - } - str = "x" * 1000 + "\n" - ITERATIONS.times{ - ssls.each{|ssl| - ssl.puts(str) - assert_equal(str, ssl.gets) - } - } - ssls.each{|ssl| ssl.close } - } - end - - def test_verify_result - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) - - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params( - :verify_callback => Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_OK - true - end - ) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.connect - assert_equal(OpenSSL::X509::V_OK, ssl.verify_result) - - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params( - :verify_callback => Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION - false - end - ) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result) - } - end - - def test_exception_in_verify_callback_is_ignored - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params( - :verify_callback => Proc.new do |preverify_ok, store_ctx| - store_ctx.error = OpenSSL::X509::V_OK - raise RuntimeError - end - ) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - OpenSSL::TestUtils.silent do - # SSLError, not RuntimeError - assert_raise(OpenSSL::SSL::SSLError) { ssl.connect } - end - assert_equal(OpenSSL::X509::V_ERR_CERT_REJECTED, ssl.verify_result) - ssl.close - } - end - - def test_sslctx_set_params - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - ctx.set_params - assert_equal(OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode) - assert_equal(OpenSSL::SSL::OP_ALL, ctx.options) - ciphers = ctx.ciphers - ciphers_versions = ciphers.collect{|_, v, _, _| v } - ciphers_names = ciphers.collect{|v, _, _, _| v } - assert(ciphers_names.all?{|v| /ADH/ !~ v }) - assert(ciphers_versions.all?{|v| /SSLv2/ !~ v }) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - assert_raise(OpenSSL::SSL::SSLError){ ssl.connect } - assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) - } - end - - def test_post_connection_check - sslerr = OpenSSL::SSL::SSLError - - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert_raise(sslerr){ssl.post_connection_check("localhost.localdomain")} - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert(ssl.post_connection_check("localhost")) - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - - now = Time.now - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:localhost.localdomain",false], - ["subjectAltName","IP:127.0.0.1",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 4, now, now+1800, exts, - @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert(ssl.post_connection_check("localhost.localdomain")) - assert(ssl.post_connection_check("127.0.0.1")) - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - - now = Time.now - exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:*.localdomain",false], - ] - @svr_cert = issue_cert(@svr, @svr_key, 5, now, now+1800, exts, - @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.connect - assert(ssl.post_connection_check("localhost.localdomain")) - assert_raise(sslerr){ssl.post_connection_check("127.0.0.1")} - assert_raise(sslerr){ssl.post_connection_check("localhost")} - assert_raise(sslerr){ssl.post_connection_check("foo.example.com")} - cert = ssl.peer_cert - assert(OpenSSL::SSL.verify_certificate_identity(cert, "localhost.localdomain")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "127.0.0.1")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "localhost")) - assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com")) - } - end - - def test_tlsext_hostname - return unless OpenSSL::SSL::SSLSocket.instance_methods.include?(:hostname) - - ctx_proc = Proc.new do |ctx, ssl| - foo_ctx = ctx.dup - - ctx.servername_cb = Proc.new do |ssl2, hostname| - case hostname - when 'foo.example.com' - foo_ctx - when 'bar.example.com' - nil - else - raise "unknown hostname #{hostname.inspect}" - end - end - end - - server_proc = Proc.new do |ctx, ssl| - readwrite_loop(ctx, ssl) - end - - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| - 2.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - if defined?(OpenSSL::SSL::OP_NO_TICKET) - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.hostname = (i & 1 == 0) ? 'foo.example.com' : 'bar.example.com' - ssl.connect - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end - - def test_multibyte_read_write - #German a umlaut - auml = [%w{ C3 A4 }.join('')].pack('H*') - auml.force_encoding(Encoding::UTF_8) - - [10, 1000, 100000].each {|i| - str = nil - num_written = nil - server_proc = Proc.new {|ctx, ssl| - cmp = ssl.read - raw_size = cmp.size - cmp.force_encoding(Encoding::UTF_8) - assert_equal(str, cmp) - assert_equal(num_written, raw_size) - ssl.close - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :server_proc => server_proc){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - str = auml * i - num_written = ssl.write(str) - ssl.close - } - } - end - - def test_unset_OP_ALL - ctx_proc = Proc.new { |ctx| - ctx.options = OpenSSL::SSL::OP_ALL & ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc){|server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - ssl.connect - ssl.puts('hello') - assert_equal("hello\n", ssl.gets) - ssl.close - } - end - -end - -end diff --git a/test/1.9/test_ssl_session.rb b/test/1.9/test_ssl_session.rb deleted file mode 100644 index e6855d5..0000000 --- a/test/1.9/test_ssl_session.rb +++ /dev/null @@ -1,327 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) && defined?(OpenSSL::SSL::Session) - -class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase - def test_session - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new("TLSv1") - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - session = ssl.session - assert(session == OpenSSL::SSL::Session.new(session.to_pem)) - assert(session == OpenSSL::SSL::Session.new(ssl)) - assert_equal(300, session.timeout) - session.timeout = 5 - assert_equal(5, session.timeout) - assert_not_nil(session.time) - # SSL_SESSION_time keeps long value so we can't keep nsec fragment. - session.time = t1 = Time.now.to_i - assert_equal(Time.at(t1), session.time) - if session.respond_to?(:id) - assert_not_nil(session.id) - end - pem = session.to_pem - assert_match(/\A-----BEGIN SSL SESSION PARAMETERS-----/, pem) - assert_match(/-----END SSL SESSION PARAMETERS-----\Z/, pem) - pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\r\n]+/m, '') - assert_equal(session.to_der, pem.unpack('m*')[0]) - assert_not_nil(session.to_text) - ssl.close - end - end - - DUMMY_SESSION = <<__EOS__ ------BEGIN SSL SESSION PARAMETERS----- -MIIDzQIBAQICAwEEAgA5BCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad -MQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy -NNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB -BQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1 -MVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt -bGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs -k4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z -D9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO -BgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d -8fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1 -ek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU -zIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2 -sOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO -gF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr -KkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP -/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V -jismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh -8uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y -j+RBGfCFrrQbBdnkFI/ztgM= ------END SSL SESSION PARAMETERS----- -__EOS__ - - DUMMY_SESSION_NO_EXT = <<-__EOS__ ------BEGIN SSL SESSION PARAMETERS----- -MIIDCAIBAQICAwAEAgA5BCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+ -lAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53 -hPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B -AQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi -eS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3 -MTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5 -LWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB -7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/ -GQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw -DgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr -tDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3 -q9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz -FCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR -KYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4 -L6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr -a3EqpAIEAKUDAgET ------END SSL SESSION PARAMETERS----- -__EOS__ - - - def test_session_time - sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) - sess.time = (now = Time.now) - assert_equal(now.to_i, sess.time.to_i) - sess.time = 1 - assert_equal(1, sess.time.to_i) - sess.time = 1.2345 - assert_equal(1, sess.time.to_i) - # Can OpenSSL handle t>2038y correctly? Version? - sess.time = 2**31 - 1 - assert_equal(2**31 - 1, sess.time.to_i) - end - - def test_session_timeout - sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT) - assert_raise(TypeError) do - sess.timeout = (now = Time.now) - end - sess.timeout = 1 - assert_equal(1, sess.timeout.to_i) - sess.timeout = 1.2345 - assert_equal(1, sess.timeout.to_i) - sess.timeout = 2**31 - 1 - assert_equal(2**31 - 1, sess.timeout.to_i) - end - - def test_session_exts_read - assert(OpenSSL::SSL::Session.new(DUMMY_SESSION)) - end if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x009080bf - - def test_client_session - last_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| - 2.times do - sock = TCPSocket.new("127.0.0.1", port) - # Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?), - # when use default SSLContext. [ruby-dev:36167] - ctx = OpenSSL::SSL::SSLContext.new("TLSv1") - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = last_session if last_session - ssl.connect - - session = ssl.session - if last_session - assert(ssl.session_reused?) - - if session.respond_to?(:id) - assert_equal(session.id, last_session.id) - end - assert_equal(session.to_pem, last_session.to_pem) - assert_equal(session.to_der, last_session.to_der) - # Older version of OpenSSL may not be consistent. Look up which versions later. - assert_equal(session.to_text, last_session.to_text) - else - assert(!ssl.session_reused?) - end - last_session = session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end - - def test_server_session - connections = 0 - saved_session = nil - - ctx_proc = Proc.new do |ctx, ssl| -# add test for session callbacks here - end - - server_proc = Proc.new do |ctx, ssl| - session = ssl.session - stats = ctx.session_cache_stats - - case connections - when 0 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 0) - assert_equal(stats[:cache_misses], 0) - assert(!ssl.session_reused?) - when 1 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 0) - assert(ssl.session_reused?) - ctx.session_remove(session) - saved_session = session - when 2 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 1) - assert_equal(stats[:cache_misses], 1) - assert(!ssl.session_reused?) - ctx.session_add(saved_session) - when 3 - assert_equal(stats[:cache_num], 2) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 1) - assert(ssl.session_reused?) - ctx.flush_sessions(Time.now + 5000) - when 4 - assert_equal(stats[:cache_num], 1) - assert_equal(stats[:cache_hits], 2) - assert_equal(stats[:cache_misses], 2) - assert(!ssl.session_reused?) - ctx.session_add(saved_session) - end - connections += 1 - - readwrite_loop(ctx, ssl) - end - - first_session = nil - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| - 10.times do |i| - sock = TCPSocket.new("127.0.0.1", port) - ctx = OpenSSL::SSL::SSLContext.new - if defined?(OpenSSL::SSL::OP_NO_TICKET) - # disable RFC4507 support - ctx.options = OpenSSL::SSL::OP_NO_TICKET - end - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.session = first_session if first_session - ssl.connect - - session = ssl.session - if first_session - case i - when 1; assert(ssl.session_reused?) - when 2; assert(!ssl.session_reused?) - when 3; assert(ssl.session_reused?) - when 4; assert(!ssl.session_reused?) - when 5..10; assert(ssl.session_reused?) - end - end - first_session ||= session - - str = "x" * 100 + "\n" - ssl.puts(str) - assert_equal(str, ssl.gets) - - ssl.close - end - end - end - - def test_ctx_client_session_cb - called = {} - ctx = OpenSSL::SSL::SSLContext.new("SSLv3") - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT - - ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - } - - ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] - # any resulting value is OK (ignored) - } - - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx) - ssl.sync_close = true - ssl.connect - assert_equal(1, ctx.session_cache_stats[:cache_num]) - assert_equal(1, ctx.session_cache_stats[:connect_good]) - assert_equal([ssl, ssl.session], called[:new]) - assert(ctx.session_remove(ssl.session)) - assert(!ctx.session_remove(ssl.session)) - assert_equal([ctx, ssl.session], called[:remove]) - ssl.close - end - end - - def test_ctx_server_session_cb - called = {} - - ctx_proc = Proc.new { |ctx, ssl| - ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER - last_server_session = nil - - # get_cb is called whenever a client proposed to resume a session but - # the session could not be found in the internal session cache. - ctx.session_get_cb = lambda { |ary| - sess, data = ary - if last_server_session - called[:get2] = [sess, data] - last_server_session - else - called[:get1] = [sess, data] - last_server_session = sess - nil - end - } - - ctx.session_new_cb = lambda { |ary| - sock, sess = ary - called[:new] = [sock, sess] - # SSL server doesn't cache sessions so get_cb is called next time. - ctx.session_remove(sess) - } - - ctx.session_remove_cb = lambda { |ary| - ctx, sess = ary - called[:remove] = [ctx, sess] - } - } - - server_proc = Proc.new { |c, ssl| - session = ssl.session - stats = c.session_cache_stats - readwrite_loop(c, ssl) - } - start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port| - last_client_session = nil - 3.times do - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock, OpenSSL::SSL::SSLContext.new("SSLv3")) - ssl.sync_close = true - ssl.session = last_client_session if last_client_session - ssl.connect - last_client_session = ssl.session - ssl.close - Thread.pass # try to ensure server calls callbacks - assert(called.delete(:new)) - assert(called.delete(:remove)) - end - end - assert(called[:get1]) - assert(called[:get2]) - end -end - -end diff --git a/test/1.9/test_x509cert.rb b/test/1.9/test_x509cert.rb deleted file mode 100644 index 8b8c51c..0000000 --- a/test/1.9/test_x509cert.rb +++ /dev/null @@ -1,217 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -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, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_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, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_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, certificate_error_returns_false { cert.verify(@rsa1024) }) - assert_equal(false, certificate_error_returns_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)) - - begin - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) - cert.subject = @ee1 - assert_equal(false, cert.verify(@rsa2048)) - rescue OpenSSL::X509::CertificateError - end - - assert_raise(OpenSSL::X509::CertificateError){ - cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::MD5.new) - } - end - - def test_dsig_algorithm_mismatch - assert_raise(OpenSSL::X509::CertificateError) do - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - end - assert_raise(OpenSSL::X509::CertificateError) do - cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::MD5.new) - end - end - - def test_dsa_with_sha2 - begin - cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA256.new) - assert_equal("dsa_with_SHA256", cert.signature_algorithm) - rescue OpenSSL::X509::CertificateError - # dsa_with_sha2 not supported. skip following test. - return - end - # TODO: need more tests for dsa + sha2 - - # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) - cert = issue_cert(@ca, @dsa256, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - assert_equal("dsaWithSHA1", cert.signature_algorithm) - end if defined?(OpenSSL::Digest::SHA256) - - def test_check_private_key - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - assert_equal(true, cert.check_private_key(@rsa2048)) - end - - private - - def certificate_error_returns_false - yield - rescue OpenSSL::X509::CertificateError - false - end -end - -end diff --git a/test/1.9/test_x509crl.rb b/test/1.9/test_x509crl.rb deleted file mode 100644 index 56508e0..0000000 --- a/test/1.9/test_x509crl.rb +++ /dev/null @@ -1,221 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -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(cert.issuer.to_der, crl.issuer.to_der) - 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(cert.issuer.to_der, crl.issuer.to_der) - 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_error_returns_false { crl.verify(@dsa256) }) - assert_equal(false, crl_error_returns_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_error_returns_false { crl.verify(@rsa1024) }) - assert_equal(false, crl_error_returns_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 - - private - - def crl_error_returns_false - yield - rescue OpenSSL::X509::CRLError - false - end -end - -end diff --git a/test/1.9/test_x509ext.rb b/test/1.9/test_x509ext.rb deleted file mode 100644 index 89b45c7..0000000 --- a/test/1.9/test_x509ext.rb +++ /dev/null @@ -1,69 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestX509Extension < Test::Unit::TestCase - def setup - @basic_constraints_value = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Boolean(true), # CA - OpenSSL::ASN1::Integer(2) # pathlen - ]) - @basic_constraints = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::ObjectId("basicConstraints"), - OpenSSL::ASN1::Boolean(true), - OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der), - ]) - end - - def teardown - end - - def test_new - ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) - assert_equal("basicConstraints", ext.oid) - assert_equal(true, ext.critical?) - assert_equal("CA:TRUE, pathlen:2", ext.value) - - ext = OpenSSL::X509::Extension.new("2.5.29.19", - @basic_constraints_value.to_der, true) - assert_equal(@basic_constraints.to_der, ext.to_der) - end - - def test_create_by_factory - ef = OpenSSL::X509::ExtensionFactory.new - - bc = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") - assert_equal(@basic_constraints.to_der, bc.to_der) - - bc = ef.create_extension("basicConstraints", "CA:TRUE, pathlen:2", true) - assert_equal(@basic_constraints.to_der, bc.to_der) - - begin - ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_) - [crlDistPts] - URI.1 = http://www.example.com/crl - URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary - _end_of_cnf_ - rescue NotImplementedError - return - end - - cdp = ef.create_extension("crlDistributionPoints", "@crlDistPts") - assert_equal(false, cdp.critical?) - assert_equal("crlDistributionPoints", cdp.oid) - assert_match(%{URI:http://www\.example\.com/crl}, cdp.value) - assert_match( - %r{URI:ldap://ldap\.example\.com/cn=ca\?certificateRevocationList;binary}, - cdp.value) - - cdp = ef.create_extension("crlDistributionPoints", "critical, @crlDistPts") - assert_equal(true, cdp.critical?) - assert_equal("crlDistributionPoints", cdp.oid) - assert_match(%{URI:http://www.example.com/crl}, cdp.value) - assert_match( - %r{URI:ldap://ldap.example.com/cn=ca\?certificateRevocationList;binary}, - cdp.value) - end -end - -end diff --git a/test/1.9/test_x509name.rb b/test/1.9/test_x509name.rb deleted file mode 100644 index 90c0992..0000000 --- a/test/1.9/test_x509name.rb +++ /dev/null @@ -1,366 +0,0 @@ -require_relative 'utils' - -if defined?(OpenSSL) - -class OpenSSL::TestX509Name < Test::Unit::TestCase - OpenSSL::ASN1::ObjectId.register( - "1.2.840.113549.1.9.1", "emailAddress", "emailAddress") - OpenSSL::ASN1::ObjectId.register( - "2.5.4.5", "serialNumber", "serialNumber") - - 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_unrecognized_oid - dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.1", "Unknown OID 1"], - ["1.1.2.3.5.8.13.21.34", "Unknown OID 2"], - ["C", "US"], - ["postalCode", "60602"], - ["ST", "Illinois"], - ["L", "Chicago"], - #["street", "123 Fake St"], - ["O", "Some Company LLC"], - ["CN", "mydomain.com"] ] - - name = OpenSSL::X509::Name.new(dn) - ary = name.to_a - #assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/street=123 Fake St/O=Some Company LLC/CN=mydomain.com", name.to_s) - assert_equal("/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/O=Some Company LLC/CN=mydomain.com", name.to_s) - assert_equal("1.2.3.4.5.6.7.8.9.7.5.3.1", ary[0][0]) - assert_equal("1.1.2.3.5.8.13.21.34", ary[1][0]) - assert_equal("C", ary[2][0]) - assert_equal("postalCode", ary[3][0]) - assert_equal("ST", ary[4][0]) - assert_equal("L", ary[5][0]) - #assert_equal("street", ary[6][0]) - assert_equal("O", ary[6][0]) - assert_equal("CN", ary[7][0]) - assert_equal("Unknown OID 1", ary[0][1]) - assert_equal("Unknown OID 2", ary[1][1]) - assert_equal("US", ary[2][1]) - assert_equal("60602", ary[3][1]) - assert_equal("Illinois", ary[4][1]) - assert_equal("Chicago", ary[5][1]) - #assert_equal("123 Fake St", ary[6][1]) - assert_equal("Some Company LLC", ary[6][1]) - assert_equal("mydomain.com", ary[7][1]) - end - - def test_unrecognized_oid_parse_encode_equality - dn = [ ["1.2.3.4.5.6.7.8.9.7.5.3.2", "Unknown OID1"], - ["1.1.2.3.5.8.13.21.35", "Unknown OID2"], - ["C", "US"], - ["postalCode", "60602"], - ["ST", "Illinois"], - ["L", "Chicago"], - #["street", "123 Fake St"], - ["O", "Some Company LLC"], - ["CN", "mydomain.com"] ] - - name1 = OpenSSL::X509::Name.new(dn) - name2 = OpenSSL::X509::Name.parse(name1.to_s) - assert_equal(name1.to_s, name2.to_s) - assert_equal(name1.to_a, name2.to_a) - 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(dn2) - 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(dn2, @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_s_parse_rfc2253 - scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan) - - assert_equal([["C", "JP"]], scanner.call("C=JP")) - assert_equal([ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ], - scanner.call( - "emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,"+ - "DC=ruby-lang,DC=org") - ) - - u8 = OpenSSL::ASN1::UTF8STRING - assert_equal([ - ["DC", "org"], - ["DC", "ruby-lang"], - ["O", ",=+<>#;"], - ["O", ",=+<>#;"], - ["OU", ""], - ["OU", ""], - ["L", "aaa=\"bbb, ccc\""], - ["L", "aaa=\"bbb, ccc\""], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265"], - ["CN", "\345\276\214\350\227\244\350\243\225\350\224\265", u8], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["2.5.4.3", "GOTOU, Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["CN", "GOTOU \"gotoyuzo\" Yuuzou"], - ["1.2.840.113549.1.9.1", "gotoyuzo@ruby-lang.org"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ], - scanner.call( - "emailAddress=gotoyuzo@ruby-lang.org," + - "1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org," + - 'CN=GOTOU \"gotoyuzo\" Yuuzou,' + - 'CN="GOTOU \"gotoyuzo\" Yuuzou",' + - '2.5.4.3=GOTOU\,\20Yuuzou,' + - '2.5.4.3=GOTOU\, Yuuzou,' + - '2.5.4.3="GOTOU, Yuuzou",' + - '2.5.4.3="GOTOU\, Yuuzou",' + - "CN=#0C0CE5BE8CE897A4E8A395E894B5," + - 'CN=\E5\BE\8C\E8\97\A4\E8\A3\95\E8\94\B5,' + - "CN=\"\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5\"," + - "CN=\xE5\xBE\x8C\xE8\x97\xA4\xE8\xA3\x95\xE8\x94\xB5," + - 'L=aaa\=\"bbb\, ccc\",' + - 'L="aaa=\"bbb, ccc\"",' + - 'OU=,' + - 'OU="",' + - 'O=\,\=\+\<\>\#\;,' + - 'O=",=+<>#;",' + - "DC=ruby-lang," + - "DC=org") - ) - - [ - "DC=org+DC=jp", - "DC=org,DC=ruby-lang+DC=rubyist,DC=www" - ].each{|dn| - ex = scanner.call(dn) rescue $! - dn_r = Regexp.escape(dn) - assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) - } - - [ - ["DC=org,DC=exapmle,CN", "CN"], - ["DC=org,DC=example,", ""], - ["DC=org,DC=exapmle,CN=www.example.org;", "CN=www.example.org;"], - ["DC=org,DC=exapmle,CN=#www.example.org", "CN=#www.example.org"], - ["DC=org,DC=exapmle,CN=#777777.example.org", "CN=#777777.example.org"], - ["DC=org,DC=exapmle,CN=\"www.example\".org", "CN=\"www.example\".org"], - ["DC=org,DC=exapmle,CN=www.\"example.org\"", "CN=www.\"example.org\""], - ["DC=org,DC=exapmle,CN=www.\"example\".org", "CN=www.\"example\".org"], - ].each{|dn, msg| - ex = scanner.call(dn) rescue $! - assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message) - } - - dn = "CN=www.ruby-lang.org,DC=ruby-lang,DC=org" - name = OpenSSL::X509::Name.parse_rfc2253(dn) - assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253)) - 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]) - 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 - - def test_add_entry_street - return if OpenSSL::OPENSSL_VERSION_NUMBER < 0x009080df # 0.9.8m - # openssl/crypto/objects/obj_mac.h 1.83 - dn = [ - ["DC", "org"], - ["DC", "ruby-lang"], - ["CN", "GOTOU Yuuzou"], - ["emailAddress", "gotoyuzo@ruby-lang.org"], - ["serialNumber", "123"], - ["street", "Namiki"], - ] - 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/street=Namiki", name.to_s) - assert_equal("Namiki", ary[5][1]) - end - - def test_equals2 - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=a' - - assert_equal n1, n2 - end - - def test_spaceship - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=b' - - assert_equal -1, n1 <=> n2 - end - - def name_hash(name) - # OpenSSL 1.0.0 uses SHA1 for canonical encoding (not just a der) of - # X509Name for X509_NAME_hash. - name.respond_to?(:hash_old) ? name.hash_old : name.hash - end - - def test_hash - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = Digest::MD5.digest(name.to_der) - expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 - assert_equal(expected, name_hash(name)) - # - dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org" - name = OpenSSL::X509::Name.parse(dn) - d = Digest::MD5.digest(name.to_der) - expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24 - assert_equal(expected, name_hash(name)) - end -end - -end diff --git a/test/1.9/test_x509req.rb b/test/1.9/test_x509req.rb deleted file mode 100644 index 882a1d7..0000000 --- a/test/1.9/test_x509req.rb +++ /dev/null @@ -1,150 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -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, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_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, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_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, request_error_returns_false { req.verify(@rsa1024) }) - assert_equal(false, request_error_returns_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)) - - begin - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) - assert_equal(true, req.verify(@rsa1024)) - assert_equal(false, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.version = 1 - assert_equal(false, req.verify(@rsa1024)) - rescue OpenSSL::X509::RequestError - end - - assert_raise(OpenSSL::X509::RequestError){ - issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } - end - - private - - def request_error_returns_false - yield - rescue OpenSSL::X509::RequestError - false - end -end - -end diff --git a/test/1.9/test_x509store.rb b/test/1.9/test_x509store.rb deleted file mode 100644 index ff820c1..0000000 --- a/test/1.9/test_x509store.rb +++ /dev/null @@ -1,229 +0,0 @@ -require_relative "utils" - -if defined?(OpenSSL) - -class OpenSSL::TestX509Store < 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 - @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1") - @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2") - @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 test_nosegv_on_cleanup - cert = OpenSSL::X509::Certificate.new - store = OpenSSL::X509::Store.new - ctx = OpenSSL::X509::StoreContext.new(store, cert, []) - ctx.cleanup - ctx.verify - end - - def issue_cert(*args) - OpenSSL::TestUtils.issue_cert(*args) - end - - def issue_crl(*args) - OpenSSL::TestUtils.issue_crl(*args) - end - - def test_verify - now = Time.at(Time.now.to_i) - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","cRLSign,keyCertSign",true], - ] - ee_exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ] - ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, ca_exts, - nil, nil, OpenSSL::Digest::SHA1.new) - ca2_cert = issue_cert(@ca2, @rsa1024, 2, now, now+1800, ca_exts, - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - ee1_cert = issue_cert(@ee1, @dsa256, 10, now, now+1800, ee_exts, - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - ee2_cert = issue_cert(@ee2, @dsa512, 20, now, now+1800, ee_exts, - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - ee3_cert = issue_cert(@ee2, @dsa512, 30, now-100, now-1, ee_exts, - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - ee4_cert = issue_cert(@ee2, @dsa512, 40, now+1000, now+2000, ee_exts, - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - - revoke_info = [] - crl1 = issue_crl(revoke_info, 1, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [2, now, 1], ] - crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [20, now, 1], ] - crl2 = issue_crl(revoke_info, 1, now, now+1800, [], - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - revoke_info = [] - crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [], - ca2_cert, @rsa1024, OpenSSL::Digest::SHA1.new) - - assert_equal(true, ca1_cert.verify(ca1_cert.public_key)) # self signed - assert_equal(true, ca2_cert.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, ee1_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, ee2_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, ee3_cert.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, crl1.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, crl1_2.verify(ca1_cert.public_key)) # issued by ca1 - assert_equal(true, crl2.verify(ca2_cert.public_key)) # issued by ca2 - assert_equal(true, crl2_2.verify(ca2_cert.public_key)) # issued by ca2 - - store = OpenSSL::X509::Store.new - assert_equal(false, store.verify(ca1_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - assert_equal(false, store.verify(ca2_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - store.add_cert(ca1_cert) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - assert_equal("ok", store.error_string) - chain = store.chain - assert_equal(2, chain.size) - assert_equal(@ca2.to_der, chain[0].subject.to_der) - assert_equal(@ca1.to_der, chain[1].subject.to_der) - - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(false, store.verify(ca2_cert)) - assert_not_equal(OpenSSL::X509::V_OK, store.error) - - store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN - assert_equal(true, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - - store.add_cert(ca2_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(true, store.verify(ee1_cert)) - assert_equal(true, store.verify(ee2_cert)) - assert_equal(OpenSSL::X509::V_OK, store.error) - assert_equal("ok", store.error_string) - chain = store.chain - assert_equal(3, chain.size) - assert_equal(@ee2.to_der, chain[0].subject.to_der) - assert_equal(@ca2.to_der, chain[1].subject.to_der) - assert_equal(@ca1.to_der, chain[2].subject.to_der) - assert_equal(false, store.verify(ee3_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_match(/expire/i, store.error_string) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - assert_match(/not yet valid/i, store.error_string) - - store = OpenSSL::X509::Store.new - store.add_cert(ca1_cert) - store.add_cert(ca2_cert) - store.time = now + 1500 - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee4_cert)) - store.time = now + 1900 - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - store.time = now + 4000 - assert_equal(false, store.verify(ee1_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee4_cert)) - assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error) - - # the underlying X509 struct caches the result of the last - # verification for signature and not-before. so the following code - # rebuilds new objects to avoid site effect. - store.time = Time.now - 4000 - assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert))) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert))) - assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error) - - return unless defined?(OpenSSL::X509::V_FLAG_CRL_CHECK) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK - store.add_cert(ca1_cert) - store.add_crl(crl1) # revoke no cert - store.add_crl(crl2) # revoke ee2_cert - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee1_cert, [ca2_cert])) - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK - store.add_cert(ca1_cert) - store.add_crl(crl1_2) # revoke ca2_cert - store.add_crl(crl2) # revoke ee2_cert - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(true, store.verify(ee1_cert, [ca2_cert]), - "This test is expected to be success with OpenSSL 0.9.7c or later.") - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store.flags = - OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - assert_equal(true, store.verify(ca1_cert)) - assert_equal(false, store.verify(ca2_cert)) - assert_equal(false, store.verify(ee1_cert, [ca2_cert])) - assert_equal(false, store.verify(ee2_cert, [ca2_cert])) - - store = OpenSSL::X509::Store.new - store.purpose = OpenSSL::X509::PURPOSE_ANY - store.flags = - OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL - store.add_cert(ca1_cert) - store.add_cert(ca2_cert) - store.add_crl(crl1) - store.add_crl(crl2_2) # issued by ca2 but expired. - assert_equal(true, store.verify(ca1_cert)) - assert_equal(true, store.verify(ca2_cert)) - assert_equal(false, store.verify(ee1_cert)) - assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error) - assert_equal(false, store.verify(ee2_cert)) - end - - def test_set_errors - now = Time.now - ca1_cert = issue_cert(@ca1, @rsa2048, 1, now, now+3600, [], - nil, nil, OpenSSL::Digest::SHA1.new) - store = OpenSSL::X509::Store.new - store.add_cert(ca1_cert) - assert_raise(OpenSSL::X509::StoreError){ - store.add_cert(ca1_cert) # add same certificate twice - } - - revoke_info = [] - crl1 = issue_crl(revoke_info, 1, now, now+1800, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - revoke_info = [ [2, now, 1], ] - crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [], - ca1_cert, @rsa2048, OpenSSL::Digest::SHA1.new) - store.add_crl(crl1) - if /0\.9\.8.*-rhel/ =~ OpenSSL::OPENSSL_VERSION - # RedHat is distributing a patched version of OpenSSL that allows - # multiple CRL for a key (multi-crl.patch) - assert_nothing_raised do - store.add_crl(crl2) # add CRL issued by same CA twice. - end - else - assert_raise(OpenSSL::X509::StoreError){ - store.add_crl(crl2) # add CRL issued by same CA twice. - } - end - end -end - -end diff --git a/test/1.9/utils.rb b/test/1.9/utils.rb deleted file mode 100644 index 64fc6ed..0000000 --- a/test/1.9/utils.rb +++ /dev/null @@ -1,304 +0,0 @@ -begin - require "openssl" -rescue LoadError -end -require "test/unit" -require "digest/md5" -require 'tempfile' -require "rbconfig" -require "socket" -require_relative '../ruby/envutil' - -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_ - -if defined?(OpenSSL::PKey::EC) - - TEST_KEY_EC_P256V1 = OpenSSL::PKey::EC.new <<-_end_of_pem_ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 -AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt -CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== ------END EC PRIVATE KEY----- - _end_of_pem_ - -end - - TEST_KEY_DH512 = OpenSSL::PKey::DH.new <<-_end_of_pem_ ------BEGIN DH PARAMETERS----- -MEYCQQDmWXGPqk76sKw/edIOdhAQD4XzjJ+AR/PTk2qzaGs+u4oND2yU5D2NN4wr -aPgwHyJBiK1/ebK3tYcrSKrOoRyrAgEC ------END DH PARAMETERS----- - _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.issuer = issuer.subject - crl.version = 1 - crl.last_update = lastup - crl.next_update = nextup - revoke_info.each{|rserial, time, reason_code| - revoked = OpenSSL::X509::Revoked.new - revoked.serial = rserial - 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 - - def silent - begin - back, $VERBOSE = $VERBOSE, nil - yield - ensure - $VERBOSE = back - end - end - - class OpenSSL::SSLTestCase < Test::Unit::TestCase - RUBY = EnvUtil.rubybin - SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb") - PORT = 20443 - ITERATIONS = ($0 == __FILE__) ? 100 : 10 - - def setup - @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 - @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256 - @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") - @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") - now = Time.at(Time.now.to_i) - ca_exts = [ - ["basicConstraints","CA:TRUE",true], - ["keyUsage","cRLSign,keyCertSign",true], - ] - ee_exts = [ - ["keyUsage","keyEncipherment,digitalSignature",true], - ] - @ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new) - @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) - @server = nil - end - - def teardown - end - - def issue_cert(*arg) - OpenSSL::TestUtils.issue_cert(*arg) - end - - def issue_crl(*arg) - OpenSSL::TestUtils.issue_crl(*arg) - end - - def readwrite_loop(ctx, ssl) - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.accept - next - end - ssl.write(line) - end - rescue OpenSSL::SSL::SSLError - rescue IOError - ensure - ssl.close rescue nil - end - - def server_loop(ctx, ssls, server_proc) - loop do - ssl = nil - begin - ssl = ssls.accept - rescue OpenSSL::SSL::SSLError - retry - end - - Thread.start do - Thread.current.abort_on_exception = true - server_proc.call(ctx, ssl) - end - end - rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK - end - - DHParam = OpenSSL::PKey::DH.new(128) - def start_server(port0, verify_mode, start_immediately, args = {}, &block) - ctx_proc = args[:ctx_proc] - server_proc = args[:server_proc] - server_proc ||= method(:readwrite_loop) - - store = OpenSSL::X509::Store.new - store.add_cert(@ca_cert) - store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert_store = store - #ctx.extra_chain_cert = [ ca_cert ] - ctx.cert = @svr_cert - ctx.key = @svr_key - ctx.tmp_dh_callback = proc { DHParam } - ctx.verify_mode = verify_mode - ctx_proc.call(ctx) if ctx_proc - - Socket.do_not_reverse_lookup = true - tcps = nil - port = port0 - begin - tcps = TCPServer.new("127.0.0.1", port) - rescue Errno::EADDRINUSE - port += 1 - retry - end - - ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) - ssls.start_immediately = start_immediately - - begin - server = Thread.new do - Thread.current.abort_on_exception = true - server_loop(ctx, ssls, server_proc) - end - - $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, $$, port) if $DEBUG - - block.call(server, port.to_i) - ensure - # TODO: as a workaround, stop TCPServer#accept by close, not by shutdown. - # JRuby's IO cannot handle shutdown correctly for now. - tcps.close if (tcps) - if (server) - server.join(5) - if server.alive? - server.kill - server.join - flunk("TCPServer was closed and SSLServer is still alive") unless $! - end - end - end - end - - def starttls(ssl) - ssl.puts("STARTTLS") - sleep 1 # When this line is eliminated, process on Cygwin blocks - # forever at ssl.connect. But I don't know why it does. - ssl.connect - end - end - -end if defined?(OpenSSL) diff --git a/test/cert_with_ec_pk.cer b/test/cert_with_ec_pk.cer deleted file mode 100644 index 1160a32..0000000 --- a/test/cert_with_ec_pk.cer +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEgTCCA2mgAwIBAgIDBbhmMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYDVQQGEwJB -VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp -bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMR4wHAYDVQQLDBVhLXNpZ24tUHJl -bWl1bS1TaWctMDIxHjAcBgNVBAMMFWEtc2lnbi1QcmVtaXVtLVNpZy0wMjAeFw0w -OTA2MjYwOTExMzdaFw0xNDA2MjYwOTExMzdaMGAxCzAJBgNVBAYTAkFUMRcwFQYD -VQQDDA5NYXggTXVzdGVybWFubjETMBEGA1UEBAwKTXVzdGVybWFubjEMMAoGA1UE -KgwDTWF4MRUwEwYDVQQFEww3NTkzNjIxNTE2MTYwSTATBgcqhkjOPQIBBggqhkjO -PQMBAQMyAARbbFo9QvtuaQ5asz4LNXYpSq7Ey/AbNswno8CDMKD+tP39MfSUEjuY -7yZ8T3XVYjejggHlMIIB4TATBgNVHSMEDDAKgAhN3+H/S9nJ3zAnBggrBgEFBQcB -AwEB/wQYMBYwCAYGBACORgEBMAoGCCsGAQUFBwsBMHsGCCsGAQUFBwEBBG8wbTBC -BggrBgEFBQcwAoY2aHR0cDovL3d3dy5hLXRydXN0LmF0L2NlcnRzL2Etc2lnbi1Q -cmVtaXVtLVNpZy0wMmEuY3J0MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hLXRy -dXN0LmF0L29jc3AwWQYDVR0gBFIwUDBEBgYqKAARAQswOjA4BggrBgEFBQcCARYs -aHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3AvYS1zaWduLVByZW1pdW0wCAYG -BACLMAEBMIGaBgNVHR8EgZIwgY8wgYyggYmggYaGgYNsZGFwOi8vbGRhcC5hLXRy -dXN0LmF0L291PWEtc2lnbi1QcmVtaXVtLVNpZy0wMixvPUEtVHJ1c3QsYz1BVD9j -ZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2JqZWN0Y2xhc3M9ZWlkQ2Vy -dGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQIR1fr2jRYTEUwDgYDVR0PAQH/ -BAQDAgbAMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAHsrgU7+M1jpofom -DCx1sZHOX8yPodS2hJuSf0pE7TkazV7i0sZG92P5UPWhh+FdyK7Nrn07tGrLLbGG -occclVUf8wVsRipKfBjLTYXFZPddzQ/Urtf0zvUFH7wYnMaVX1k32V6R/C/mLC0l -qmn+1htPnNks/+I4uHcPKLhcXatDPfOdLjLZGLI63B6Azxsf2/gMKEOr2hvdqDIX -+bGTdwU5r/8+oPlaTbq6xLVhyr6dKSqaXOBZDk8I7lSxDC/YwOfC6yyC2gxyiZP+ -LPcGEzWnwX+9oz9gwfFKTH83i1ifHEI24NGTeJeeEPqP47XSLJf7bX264Vxtq2yf -xcxpndk= ------END CERTIFICATE----- diff --git a/test/fixture/ca-bundle.crt b/test/fixture/ca-bundle.crt deleted file mode 100644 index 628638c..0000000 --- a/test/fixture/ca-bundle.crt +++ /dev/null @@ -1,2794 +0,0 @@ -## -## ca-bundle.crt -- Bundle of CA Certificates -## Last Modified: Wed Jun 22 11:33:22 EDT 2005 -## -## This is a bundle of X.509 certificates of public -## Certificate Authorities (CA). -## - ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw -gYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2FzaGluZ3Rv -bjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFCQS5FQ09NIFJv -b3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3RydXN0LmNvbTAeFw05 -OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQswCQYDVQQGEwJVUzELMAkG -A1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24xFzAVBgNVBAoTDkFCQS5FQ09N -LCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBSb290IENBMSQwIgYJKoZIhvcNAQkB -FhVhZG1pbkBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCx0xHgeVVDBwhMywVCAOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM -0KLMsFWWU4RmBQDaREmA2FQKpSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFG -PR7wuSw0X4x8TAgpnUBV6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGU -LOR4SCQaJRk665WcOQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZs -iSrK2jMTecJVjO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU -+/94Qby9cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYB -Af8CAQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k -qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvTZOir -vRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHegTYjHInYZ -w8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm/lowdiT/QHI8 -eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgxfexgeqMiKL0ZJGA/ -O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJTzFxiNmIf1Q= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw -MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD -VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul -CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n -tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl -dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch -PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC -+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O -BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl -MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk -ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X -7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz -43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY -eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl -pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA -WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx -MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB -ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV -BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV -6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX -GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP -dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH -1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF -62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW -BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL -MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU -cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv -b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 -IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ -iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao -GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh -4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm -XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 -MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK -EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh -BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq -xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G -87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i -2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U -WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 -0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G -A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr -pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL -ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm -aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv -hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm -hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X -dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 -P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y -iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no -xqE= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICkDCCAfkCAgCNMA0GCSqGSIb3DQEBBAUAMIGPMQswCQYDVQQGEwJVUzEnMCUG -A1UEChMeQW1lcmljYW4gRXhwcmVzcyBDb21wYW55LCBJbmMuMSYwJAYDVQQLEx1B -bWVyaWNhbiBFeHByZXNzIFRlY2hub2xvZ2llczEvMC0GA1UEAxMmQW1lcmljYW4g -RXhwcmVzcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgwODE0MjIwMTAwWhcN -MDYwODE0MjM1OTAwWjCBjzELMAkGA1UEBhMCVVMxJzAlBgNVBAoTHkFtZXJpY2Fu -IEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1lcmljYW4gRXhwcmVz -cyBUZWNobm9sb2dpZXMxLzAtBgNVBAMTJkFtZXJpY2FuIEV4cHJlc3MgQ2VydGlm -aWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ8kmS -hcr9FSm1BrZE7PyIo/KGzv8UTyQckvnCI8HOQ99dNMi4FOzVKnCRSZXXVs2U8amT -0Ggi3E19oApyKkfqJfCFAF82VGHPC/k3Wmed6R/pZD9wlWGn0DAC3iYopGYDBOkw -+48zB/lvYYeictvzaHhjZlmpybdm4RWySDYs+QIDAQABMA0GCSqGSIb3DQEBBAUA -A4GBAGgXYrhzi0xs60qlPqvlnS7SzYoHV/PGWZd2Fxf4Uo4nk9hY2Chs9KIEeorC -diSxArTfKPL386infiNIYYj0EWiuJl32oUtTJWrYKhQCDuCHIG6eGVxzkAsj4jGX -Iz/VIqLTBnvaN/XXtUFEF3pFAtmFRWbWjsfwegyZYiJpW+3S ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEBDCCAuygAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVT -MScwJQYDVQQKEx5BbWVyaWNhbiBFeHByZXNzIENvbXBhbnksIEluYy4xJjAkBgNV -BAsTHUFtZXJpY2FuIEV4cHJlc3MgVGVjaG5vbG9naWVzMTYwNAYDVQQDEy1BbWVy -aWNhbiBFeHByZXNzIEdsb2JhbCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNOTgw -ODE0MTkwNjAwWhcNMTMwODE0MjM1OTAwWjCBljELMAkGA1UEBhMCVVMxJzAlBgNV -BAoTHkFtZXJpY2FuIEV4cHJlc3MgQ29tcGFueSwgSW5jLjEmMCQGA1UECxMdQW1l -cmljYW4gRXhwcmVzcyBUZWNobm9sb2dpZXMxNjA0BgNVBAMTLUFtZXJpY2FuIEV4 -cHJlc3MgR2xvYmFsIENlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAPAkJmYu++tKc3FTiUfLJjxTkpRMysKFtQ34w1e9 -Lyofahi3V68MABb6oLaQpvcaoS5mJsdoo4qTaWa1RlYtHYLqkAwKIsKJUI0F89Sr -c0HwzxKsKLRvFJSWWUuekHWG3+JH6+HpT0N+h8onGGaetcFAZX38YW+tm3LPqV7Y -8/nabpEQ+ky16n4g3qk5L/WI5IpvNcYgnCuGRjMK/DFVpWusFkDpzTVZbzIEw3u1 -D3t3cPNIuypSgs6vKW3xEW9t5gcAAe+a8yYNpnkTZ6/4qxx1rJG1a75AsN6cDLFp -hRlxkRNFyt/R/eayypaDedvFuKpbepALeFY+xteflEgR9a0CAwEAAaNaMFgwEgYD -VR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0gBBAwDjAMBgoq -hkiG+Q8KAQUBMBkGA1UdDgQSBBBXRzV7NicRqAj8L0Yl6yRpMA0GCSqGSIb3DQEB -BQUAA4IBAQDHYUWoinG5vjTpIXshzVYTmNUwY+kYqkuSFb8LHbvskmnFLsNhi+gw -RcsQRsFzOFyLGdIr80DrfHKzLh4n43WVihybLsSVBYZy0FX0oZJSeVzb9Pjc5dcS -sUDHPIbkMWVKyjfG3nZXGWlMRmn8Kq0WN3qTrPchSy3766lQy8HRQAjaA2mHpzde -VcHF7cTjjgwml5tcV0ty4/IDBdACOyYDQJCevgtbSQx48dVMVSng9v1MA6lUAjLR -V1qFrEPtWzsWX6C/NdtLnnvo/+cNPDuom0lBRvVzTv+SZSGDE1Vx60k8f4gawhIo -JaFGS0E3l3/sjvHUoZbCILZerakcHhGg ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSkwJwYD -VQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAeFw0wMDA1MTIx -ODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlC -YWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAnBgNVBAMTIEJhbHRpbW9y -ZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+ghY8vu9ThHB3yJB8osC+5pKVvoiIg -ZP6ERzx+K2xparjUwJaOjFINzW9B1L8ErqeBLy2YSNLBlKO1GV1dUWT0jkGwm8At -IqBexthaEmO8EUpeJhId4iYF5g9fIh96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAd -BgNVHQ4EFgQUyeKPwAImWrbAB+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3j -CzNx764zFE37+v0at1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddk -j5TfR/6ghWk2qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avi -eK318FL9m+pCDOjYVL5TZvU= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex -CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9CYW5rRW5n -aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz -aW9uMRMwEQYDVQQDEwpiYW5rZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBiYW5r -ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw -CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV -BAoTD0JhbmtFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmJhbmtlbmdpbmUxIDAeBgkqhkiG9w0B -CQEWEWNhQGJhbmtlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA14LoTUAl1/hEy+Kh1kLHiBdW2zD3V4IhM7xxTVKsYsIH56nr69ATTIxU -P36eRzeZ137qt1AxHFjDCidk3m1Ul6l59ProPexdslLLM2npM3f2cteg+toyiYiS -EJKjyzIu1xF1j9qzGkymSY/4DsXLZNk9FaczxMk/Ooc6Os1M3AverL4VG4rYIb6f -eR32cIKJ9Q1fGuyKk7ipq1XQfPW8a8TgZdbHbe7U9Gk3iasGMHHvpR9Ep3mGbgdT -uQ98SBEuIwe1BUCGg/MXpVy48MNXfAMotBgGw4pl9yqSjMni2FB+E9Q9DHFs2RgX -MqzKuo8zcPxKx2kZ6Arj8+27dw2clQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQBauupHX9EhpC/r57d6b5kkeWvognxIP9//TO4iw3qb -zIXEkPXmJmwVzlzoKJWqiya+aw19SP0+G6CzsFOBo/9ehmz+hZ8bhYX4MjlWzX5u -Tnkhz172j9fOBUmrTVPkcRIs6zjCD5PQAGoBPP1/Zdy2N36lZ0U7lg07Opirj/yJ -PSJeM2j0fwIFAroiVckvdT0BVwB6S/cPaAQGPghbbr1YGSmYrMriSv825ILJUfxz -rJYunGR9FiY9Ob7+jwJwiZMS4CxSPktutxr/3hOvr1+ALS7IcVakhhA3PuZAJbdH -FRclR9qMM8aBnBZmf+Uv3K3uhT+UBzzY654U9Yi1JYnA ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIC8zCCAlygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBszELMAkGA1UEBhMCQkUx -ETAPBgNVBAcTCEJydXNzZWxzMRMwEQYDVQQKEwpCZWxTaWduIE5WMTQwMgYDVQQL -EytCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSEw -HwYDVQQDExhCZWxTaWduIFNlY3VyZSBTZXJ2ZXIgQ0ExIzAhBgkqhkiG9w0BCQEW -FHdlYm1hc3RlckBiZWxzaWduLmJlMB4XDTk3MDcxNjIyMDA1NFoXDTA3MDcxNjIy -MDA1NFowgbMxCzAJBgNVBAYTAkJFMREwDwYDVQQHEwhCcnVzc2VsczETMBEGA1UE -ChMKQmVsU2lnbiBOVjE0MDIGA1UECxMrQmVsU2lnbiBTZWN1cmUgU2VydmVyIENl -cnRpZmljYXRlIEF1dGhvcml0eTEhMB8GA1UEAxMYQmVsU2lnbiBTZWN1cmUgU2Vy -dmVyIENBMSMwIQYJKoZIhvcNAQkBFhR3ZWJtYXN0ZXJAYmVsc2lnbi5iZTCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1gESeJL4BEJ/yccig/x8R3AwK0kLPjZA -kCjaIXODU/LE0RZAwFP/rqbGJLMnbaWzPTl3XagG9ubpvGMRTgZlcAqdk/miQIt/ -SoQOjRax1swIZBIM4ChLyKWEkBf7EUYu1qeFGMsYrmOasFgG9ADP+MQJGjUMofnu -Sv1t3v4mpTsCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgCgMA0GCSqGSIb3DQEB -BAUAA4GBAGw9mcMF4h3K5S2qaIWLQDEgZhNo5lg6idCNdbLFYth9go/32TKBd/Y1 -W4UpzmeyubwrGXjP84f9RvGVdbIJVwMwwXrNckdxgMp9ncllPEcRIn36BwsoeKGT -6AVFSOIyMko96FMcELfHc4wHUOH5yStTQfWDjeUJOUqOA2KqQGOL ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex -CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9DZXJ0RW5n -aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz -aW9uMRMwEQYDVQQDEwpjZXJ0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBjZXJ0 -ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw -CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV -BAoTD0NlcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmNlcnRlbmdpbmUxIDAeBgkqhkiG9w0B -CQEWEWNhQGNlcnRlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA7aTXURShaeVt9u/dP3Q2dVib3jTCZvEyc6yfpGgaYWewXWuP4HOSfI4h -GZblbpl+dzJc6RjhR+pguIRtbT5FJB8SJGjRqoujBEOQOxtVtc2fjM9Dqh0iOvMW -WS6buxHG55GVrHAQaO5HXEScKQBa9ZyNmpSXPTEBrDMej1OAGOkc524/TZrgFPF4 -AiJLLkxCcP8NuzUKlW3WzNMSSoCtjkUKy4wjSLlAWCFM0T9Df6/+Z8ZUQTzHoKCD -ncH5Qnynd7DlOwKQ2JwwxRhYGiGVTUN0GUq7qA11kW3+vnbFesKQXoF6o2PVx9s2 -YXviI2NXXUjZ0pVnsnFCc45Pm8XojwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQBP/aHOKJ00Akzc9HWM1X30hlWZFBaQi4pqD4Uhk8+p -KzzwFP5DRLBOz8TYBbtdXrS6hxVMr2sqWmhVkuyepWhHZazKGyHY/y0FbOXsewAV -1QxxSyx7ve89pCKv4/w0rQcP916iHc8Y/TCpmz7eITa3GId+8H/XTaBi8GBp9X9O -w8m25FmEB1NT+eJwefvfdKowjy4tSorKdW/eJspxNuTSRGmUy8G71W5dYvgpAlx6 -mdnHyzxEGvRYNNI2bS0ifXgbEFNWqSas9q34ea5KOpkJu8T/KyXfSb6rPOsBSb0t -wMowwGtCVH2C4Lw/8zo0EjhMpTOsPaub408PrZ+NQ2bl ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICjjCCAfegAwIBAgIBBjANBgkqhkiG9w0BAQQFADBtMQswCQYDVQQGEwJERTEc -MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEdMBsGA1UECxMUVGVsZVNlYyBU -cnVzdCBDZW50ZXIxITAfBgNVBAMTGERldXRzY2hlIFRlbGVrb20gUm9vdCBDQTAe -Fw05ODEyMDkwOTExMDBaFw0wNDEyMDkyMzU5MDBaMG0xCzAJBgNVBAYTAkRFMRww -GgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR0wGwYDVQQLExRUZWxlU2VjIFRy -dXN0IENlbnRlcjEhMB8GA1UEAxMYRGV1dHNjaGUgVGVsZWtvbSBSb290IENBMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBSz5BbO5EtdpcffqVjAIVxRDe7sa -nG0vV2HX4vVEa+42QZb2ZM7hwbK5pBQEmFDocPiONZp9ScFhHVmu2gYYlX2tzuyp -vtEYD0CRdiqj5f3+iRX0V/fgVdp1rQD0LME1zLRDJlViRC4BJZyKW/DB0AA1eP41 -3pRAZHiDocw5iQIDAQABoz4wPDAPBgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQE -AwIBBjAZBgNVHQ4EEgQQLIdZH4sTgLL5hp0+En5YljANBgkqhkiG9w0BAQQFAAOB -gQAP/nO1B4hvoAuJ6spQH5TelCsLJ15P9RyVJtqMllStGZE3Q12ryYuzzW+YOT3t -3TXjcbftE5OD6IblKTMTE7w1e/0oL3BZ1dO0jSgTWTvI1XT5RcIHYKq4GFT5pWj/ -1wXVj7YFMS5BSvQQH2BHGguLGU2SVyDS71AZ6M3QcLy8Ng== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg -bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ -j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV -Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw -MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 -fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i -+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN -QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ -gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw -CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp -dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE -CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B -CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx -ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO -U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 -IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx -ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf -WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK -xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE -zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F -5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv -OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG -9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz -ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME -lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG -Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q -gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k -Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ -k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso -LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o -TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 -MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C -TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 -WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR -xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL -B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw -CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp -dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE -CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B -CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy -MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO -U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0 -IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx -ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV -p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw -BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl -5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi -3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+ -QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG -9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ -2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN -I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL -553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q -10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN -uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u -ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh -Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV -BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU -MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D -bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq -RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G -CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo -6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux -5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm -AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC -ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 -cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m -by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp -IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg -Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg -KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV -HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E -BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE -FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA -BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7 -pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz -wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a -EkP/TOYGJqibGapEPHayXOw= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u -ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u -ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 -MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j -b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg -U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ -I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 -wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC -AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb -oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 -BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p -dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk -MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 -MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi -E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa -MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI -hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN -95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd -2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDIzCCAoygAwIBAgIENeHvHjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJV -UzEQMA4GA1UEChMHRXF1aWZheDEuMCwGA1UECxMlRXF1aWZheCBQcmVtaXVtIENl -cnRpZmljYXRlIEF1dGhvcml0eTAeFw05ODA4MjQyMjU0MjNaFw0xODA4MjQyMjU0 -MjNaME8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVF -cXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDOoQaOBswIC8GGqN4g1Q0O0Q3En+pq2bPCMkdAb4qI -pAm9OCwd5svmpPM269rrvPxkswf2Lbyqzp8ZSGhK/PWiRX4JEPWPs0lcIwY56hOL -uAvNkR12X9k3oUT7X5DyZ7PNGJlDH3YSawLylYM4Q8L2YjTKyXhdX9LYupr/vhBg -WwIDAQABo4IBCjCCAQYwcQYDVR0fBGowaDBmoGSgYqRgMF4xCzAJBgNVBAYTAlVT -MRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2Vy -dGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIw -MTgwODI0MjI1NDIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUFe6yKFmrbuX4 -z4uB9CThrj91G5gwHQYDVR0OBBYEFBXusihZq27l+M+LgfQk4a4/dRuYMAwGA1Ud -EwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEB -BQUAA4GBAL0LnCepA9so3JipS9DRjqeoGlqR4Jzx9xh8LiKeNh/JqLXNRkpu+jUH -G4YI65/iqPmdQS06rlxctl80BOv8KmCw+3TkhellOJbuFcfGd2MSvYpoH6tsfdrK -XBPO6snrCVzFc+cSAdXZUwee4A+W8Iu0u0VIn4bFGVWgy5bFA/xI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy -dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 -MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx -dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f -BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A -cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ -MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm -aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw -ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj -IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y -7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh -1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT -ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw -MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj -dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l -c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC -UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc -58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ -o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr -aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA -A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA -Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv -8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT -ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw -MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j -LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo -RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu -WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw -Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK -eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM -zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ -WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN -/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj -dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 -NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD -VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G -vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ -BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl -IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw -NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq -y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy -0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 -E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex -CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9Gb3J0RW5n -aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz -aW9uMRMwEQYDVQQDEwpmb3J0ZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBmb3J0 -ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw -CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV -BAoTD0ZvcnRFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCmZvcnRlbmdpbmUxIDAeBgkqhkiG9w0B -CQEWEWNhQGZvcnRlbmdpbmUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAyr7GbpwDxx1v3EYbo0gcO+ligEhlDqG2e7u/AbWGoVAqc8+q6auUJUtz -4i7oh0yNadu1o9kpXW+znkgO0zlrgjGskqqMO1ooppzTJdFy/P8gR6x1Iuv3kWtX -OuzwPPEjv09LWlhyJsN+oU4ztTVf07I0Q9zYupcoDQ58XKRheI9KdDB2DYSmxywA -WSLQwIeG0Qa7gvokeQlpkgkEC7viEecJ3752KXBJHnh7As51mxnlpmG6sDy67Eli -HDw5tHETRqbtnscGBjskGQBqR5xt7+QnnthZrN8HJHDoa9zgGephwizhkL44lXLF -YK9W5XhFbblw2c+mAcHkokRiwD7CPeIoyD2a/Jcw3n5hegKTlNhd4BFGVF6JR7gF -OFk2QfHXit5uthsij9Xhl7WAgQUqLgggD9MphqPf4nY66OZUJV9ZsmB+Qfp8UizB -0WAOegactKVyRqHtRa+KIEXQXNtZgjcmMk9CYkP0nIbKtgKXaH6+9VMHNOryCnFE -7pSsuPUkypncFWCHGSeiFO3w4w4J4csltxBADQzxfRu5KZnlToQN7bVpI/Q31tVX -E5bjrJcq6Oj/OTqZ3ID+OqbkUdAg0ggjRKcTgxnLHd/AbMzJ6PsclDDf7cLs0WSl -xMxQR/z5bNST1rNtT9rsiv2TOhfvCBxO9AOjBioO8PLO032HTNECAwEAAaMQMA4w -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAVyBpPWfT2VOyvVpslGKx -8h0+CWP8cilygGRtZJ5dAJzc//1REAHdvK+TgZ4Foz3dqHhXI+RNN0FpzuWaYMjW -ZTS0kAmcOQuGY1Oo4PGlPHI21pNz29oFDTJr0ZmLBJ4JKVsE2soJg55jdk9MZHA7 -K//7HH9RsmrWZOE5DZDlrxp6+naixhMwnlPKKisIy9GNZUPqGdUWABMdB/BUVVNl -NU5TtWpIXUClMd8a+eoKcItBeYXowkHOBpinPkDX3clFDIUfWiw0Ro08s8SrrFqR -8Szwbrj52Xv1RM56oGqCjnkvJctxihODV7NcpxoAFjIZokDom0q6zPrrTUsLFQov -Plovc3w5hmALiDMshaTvE1nm3Psn4yQ+FlRE8epTZrQiIGypZkZC6lcz0mYawueW -cThYWGFhVG4ktQzOjjNRsNxopW+W7cF1zQTxiWUDnxIKSj7gtdQ2jiubxEEhfVag -r8DMtAccNVTZVURpGi56TptOOuotrTqqC+2GviW4hlxvdvmuQN0OlXlUwzz2Trxc -FamNnuA54lZw/8arLtxsFmHrcnPw53+1spumLD0S5UkxHNu40h6LIVpZz3H+0rLz -uFofTfiyMjcfK2AyHQTgUCbsrvgNuLDQUbyFGVchdFUkhztX3DhEVnxnnrpY4BVj -QdTqWIvw7lGlSuDCjxEQAOc= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD -VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv -bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv -b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU -cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds -b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH -iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS -r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 -04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r -GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 -3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P -lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICETCCAXoCAU4wDQYJKoZIhvcNAQEEBQAwUTELMAkGA1UEBhMCSlAxHzAdBgNV -BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xITAfBgNVBAMTGEN5YmVyVHJ1c3Qg -SkFQQU4gUm9vdCBDQTAeFw05ODA4MDQwNzU3MDBaFw0wMzA4MDQyMzU5MDBaMFEx -CzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFuLCBJbmMuMSEw -HwYDVQQDExhDeWJlclRydXN0IEpBUEFOIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEB -BQADgY0AMIGJAoGBALet/MpHEHaJ/Wes5HMGfIFLHda1fA5Hr+ymVHWoxP1lr+fI -sbFsNDWN97lkVygLIVredP7ceC6GRhJMfxEf3JO9X75mmIa4t+xtSdOQ2eF5AFZo -uq1sHyw7H8ksjEOwBELqgXOmzjN1RQ2KRXIvqldV5AfDQ+J1Og+8PNCEzrrvAgMB -AAEwDQYJKoZIhvcNAQEEBQADgYEAt6ZkowyAPBzE2O5BO+WGpJ5gXdYBMqhqZC0g -cEC6ck5m+gdlTgOOC/1W4K07IKcy+rISHoDfHuN6GMxX2+bJNGDvdesQFtCkLnDY -JCO4pXdzQvkHOt0BbAiTBzUmECVgKf8J5WSfabkWSfNc3SRjRpMNsFM2dbxIILsZ -to/QIv0= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICIzCCAYwCAU8wDQYJKoZIhvcNAQEEBQAwWjELMAkGA1UEBhMCSlAxHzAdBgNV -BAoTFkN5YmVyVHJ1c3QgSmFwYW4sIEluYy4xKjAoBgNVBAMTIUN5YmVyVHJ1c3Qg -SkFQQU4gU2VjdXJlIFNlcnZlciBDQTAeFw05ODA4MDQwODA2MzJaFw0wMzA4MDQy -MzU5MDBaMFoxCzAJBgNVBAYTAkpQMR8wHQYDVQQKExZDeWJlclRydXN0IEphcGFu -LCBJbmMuMSowKAYDVQQDEyFDeWJlclRydXN0IEpBUEFOIFNlY3VyZSBTZXJ2ZXIg -Q0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKwmo6G4b2rALBL52zEFkuf9 -+tSBtLjVKtWQ+vBDZfwSFcrs27lh3jNjN0+vADx/kjcbGHPlnzyI8RoTRP558sMm -lQ8L8J4UByFsV8Jdw+JRsM2LX81fhjj4eZc57Oi/Ui6xXqqprozt7tfIty4xi7Q5 -kjt8gScHGgFEL0lzILbJAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAaB17Eu5aeSkx -ygGsi1CpJ5ksAPw4Ghz/wtXwE/4bpzn1gBTrUfrAjXuEG1musTVRbqE+1xvsoJ7f -4KWCluOxP9io8ct5gI738ESZfhT1I6MR42hLBTZuiOOrhqo4UwNCO9O5+eC/BenT -X8NKp7b9t12QSfiasq1mpoIAk65g/yA= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgICAbYwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVVMx -GDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1 -c3QgU29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290 -IDUwHhcNOTgwODE0MTQ1MDAwWhcNMTMwODE0MjM1OTAwWjBwMQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU -cnVzdCBTb2x1dGlvbnMsIEluYy4xHjAcBgNVBAMTFUdURSBDeWJlclRydXN0IFJv -b3QgNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwSbj+KfHqXAewe -uzlaAvR4RKJIG457SVJ6uHtHs6+Um2+7lvoramVcuByUc76/iQoigO5X/IwFu3Cf -lzkE2qOHXKjlyq/AM5rVN1xLrOSA0KYjYPv9ci6UncfOwgQy73hgXe2thw9FZR48 -mgqavl0dmezn8tHGehfZrZtUln/EfGC/haoVNR1A2hG87FQhKC0joajwzy3N3fx+ -D17hZQdWywe00lboXjHMGGPEhtIthc+Tkqtt/mg5+95zvYb45EZ66p8My/QZ/mO8 -0Sx7iDM29uThnAxTgWAc2i6rlqkWiBNQmbK9Vd8VMH7o5Zj7cH5stQf8/Ea30O03 -ln4y/iECAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMC -AQYwFwYDVR0gBBAwDjAMBgoqhkiG+GMBAgEDMBkGA1UdDgQSBBB2CkkhOEyf3vjE -ScdxcZGdMA0GCSqGSIb3DQEBBQUAA4IBAQBBOtQYW9q43iEc4Y4J5fFoNP/elvQH -9ac886xKsZv6kvqb7eYyIapKdsXcTzjl39WG5NXIdn2Y17HNj021kSNsi4rr6nzv -FJTExvAfSi0ycWMrY5EmAgm2gB3t4sy4f9uHY8jh0GwmsTUdQGYQG82VVBgzYewT -T9oT95mvPtDPjqZyorPDBZrJJ32SzH5SjbOrcG2eiZ9N6xp1wpiq1QIW1wyKvyXk -6y28mOlYOBl8uTf+2+KZCHMGx5eDan0QAS8yuRcFSmXmL86+XlOmgumaUwqEdC2D -ysiUFnZflGEo8IWnObvXi9moshMdVAk0JH0ggX1mfqKQdFwQxr3sqxvC ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD -VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv -b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU -cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv -RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M -ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5 -1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz -dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl -IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy -bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDnjCCAoagAwIBAgILAgAAAAAA1ni50a8wDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw -MDBaFw0wOTAxMjgxMjAwMDBaMF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xv -YmFsU2lnbiBQYXJ0bmVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBANIs+DKsShJ6N8gpkaWujG4eDsA0M4jlM3EWHHiEaMMYNFAuFj6xlIJPsZqf -APjGETXGaXuYAq0ABohs50wzKACIJ0Yfh7NxdWO8MruI3mYYDlAGk7T2vBQ3MD0i -3z3/dX7ZChrFn7P80KyzCHqJ0wHoAFznSgs9TXsmordiBovaRt2TFz8/WwJLC7aI -IBGSAK27xy7U40Wu9YlafI2krYVkMsAnjMbyioCShiRWWY10aKKDQrOePVBBhm8g -bvb9ztMZ4zLMj+2aXm0fKPVSrG4YXvg90ZLlumwBiEsK8i3eZTMFQqBMqjF2vv2/ -gXj5cRxGXi0VlS0wWY5MQdFiqz0CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgAGMB0G -A1UdDgQWBBRDJI1wFQhiVZxPDEAXXYZeD6JM+zAfBgNVHSMEGDAWgBRge2YaRQ2X -yolQL30EzTSo//z9SzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IB -AQBm7bSIaRGZgiGDrKFti5uErQ8tyB6Mynt+rarUjt4H1p5Fx6W4nAc5YCVVGsBP -GeXPFylJiRg1ZuXrKEBOV8mvs+S4IAWjO5VQkUmUKX0s5YhBpUWIXp2CJ/fS71u1 -T5++/jVlLFVkn+FR2iJhd7pYTo/GeVlZbjCAok+QbiELrdBoOZAQm+0iZW8eETjm -f4zS8zltR9Uh6Op1OkHRrfYWnV0LIb3zH2MGJR3BHzVxLOsgGdXBsOw95W/tAgc/ -E3tmktZEwZj3X1CLelvCb22w0fjldKBAN6MlD+Q9ymQxk5BcMHu5OTGaXkzNuUFP -UOQ9OK7IZtnHO11RR6ybq/Kt ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4N88wDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MTUxMjAw -MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDEgQ0ExJjAkBgNV -BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAxIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAvSA1R9Eo1gijEjkjRw29cCFSDlcxlaY0V2vsfkN5 -wwZSSM28taGZvdgfMrzP125ybS53IpCCTkuPmgwBQprZcFm2nR/mY9EMrR1O+IWB -+a7vn6ZSYUR5GnVF4GFWRW1CjD1yy6akErea9dZg0GBQs46mpuy09BLNf6jO77Ph -hTD+csTm53eznlhB1lGDiAfGtmlPNt7RC0g/vdafIXRkbycGPkv9Dqabv6RIV4yQ -7okYCwKBGL5n/lNgiCe6o3M0S1pWtN5zBe2Yll3sSudA/EsJYuvQ4zFPhdF6q1ln -K/uID+uqg701/WEn7GYOQlf3acIM7/xqwm5J2o9BOK5IqQIDAQABo2MwYTAOBgNV -HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFPzgZvZaNZnrQB7SuB5DvJiOH4rDMB8GA1Ud -IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEEBQADggEBAJujCETO8pCdcfMyswVqterPKZjeVT6gFn0GekTWr9L6 -E1iM+BzHqx20G+9paJhcCDmP4Pf7SMwh57gz2wWqNCRsSuXpe2Deg7MfCr5BdfzM -MEi3wSYdBDOqtnjtKsu6VpcybvcxlS5G8hTuJ8f3Yom5XFrTOIpk9Te08bM0ctXV -IT1L13iT1zFmNR6j2EdJbxyt4YB/+JgkbHOsDsIadwKjJge3x2tdvILVKkgdY89Q -Mqb7HBhHFQpbDFw4JJoEmKgISF98NIdjqy2NTAB3lBt2uvUWGKMVry+U9ikAdsEV -F9PpN0121MtLKVkkrNpKoOpj3l9Usfrz0UXLxWS0cyE= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4jY0wDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw -MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDIgQ0ExJjAkBgNV -BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAyIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAkoz+7/RFjhdBbvzYvyFvqwadUsEsAJ0/joW4f0qP -vaBjKspJJ65agvR04lWS/8LRqnmitvrVnYIET8ayxl5jpzq62O7rim+ftrsoQcAi -+05IGgaS17/Xz7nZvThPOw1EblVB/vwJ29i/844h8egStfYTpdPGTJMisAL/7h0M -xKhrT3VoVujcKBJQ96gknS4kOfsJBd7lo2RJIdBofnEwkbFg4Dn0UPh6TZgAa3x5 -uk7OSuK6Nh23xTYVlZxkQupfxLr1QAW+4TpZvYSnGbjeTVNQzgfR0lHT7w2BbObn -bctdfD98zOxPgycl/3BQ9oNZdYQGZlgs3omNAKZJ+aVDdwIDAQABo2MwYTAOBgNV -HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFHznsrEs3rGna+l2DOGj/U5sx7n2MB8GA1Ud -IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEEBQADggEBAGPdWc6KeaqYnU7FiWQ3foqTZy8Q6m8nw413bfJcVpQZ -GmlgMEZdj/JtRTyONZd8L7hR4uiJvYjPJxwINFyIwWgk25GF5M/7+0ON6CUBG8QO -9wBCSIYfJAhYWoyN8mtHLGiRsWlC/Q2NySbmkoamZG6Sxc4+PH1x4yOkq8fVqKnf -gqc76IbVw08Y40TQ4NzzxWgu/qUvBYTIfkdCU2uHSv4y/14+cIy3qBXMF8L/RuzQ -7C20bhIoqflA6evUZpdTqWlVwKmqsi7N0Wn0vvi7fGnuVKbbnvtapj7+mu+UUUt1 -7tjU4ZrxAlYTiQ6nQouWi4UMG4W+Jq6rppm8IvFz30I= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDrDCCApSgAwIBAgILAgAAAAAA1ni41sMwDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw -MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDMgQ0ExJjAkBgNV -BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAzIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAkV5WZdbAwAScv0fEXHt6MQH5WJaZ4xyEL9xWj631 -WYHVQ2ZdWpOMdcqp5xHBURAUYMks1HuvxneGq3onrm+VuQvKtkb7fhr0DRRt0slO -sq7wVPZcQEw2SHToVIxlZhCnvSu3II0FSa14fdIkI1Dj8LR5mwE5/6870y3u4UmN -jS88akFFL5vjPeES5JF1ns+gPjySgW+KLhjc4PKMjP2H2Qf0QJTJTk9D32dWb70D -UHyZZ6S5PJFsAm6E1vxG98xvGD4X8O8LZBZX5qyG8UiqQ8HJJ3hzREXihX26/7Ph -+xsFpEs7mRIlAVAUaq9d6sgM7uTa7EuLXGgTldzDtTA61wIDAQABo2MwYTAOBgNV -HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFMw2zBe0RZEv7c87MEh3+7UUmb7jMB8GA1Ud -IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEEBQADggEBAFeyVMy9lRdkYIm2U5EMRZLDPahsw8yyGPV4QXTYfaMn -r3cNWT6UHWn6idMMvRoB9D/o4Hcagiha5mLXt+M2yQ6feuPC08xZiQzvFovwNnci -yqS2t8FCZwFAY8znOGSHWxSWZnstFO69SW3/d9DiTlvTgMJND8q4nYGXpzRux+Oc -SOW0qkX19mVMSPISwtKTjMIVJPMrUv/jCK64btYsEs85yxIq56l7X5g9o+HMpmOJ -XH0xdfnV1l3y0NQ9355xqA7c5CCXeOZ/U6QNUU+OOwOuow1aTcN55zVYcELJXqFe -tNkio0RTNaTQz3OAxc+fVph2+RRMd4eCydx+XTTVNnU= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU -YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 -5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q -gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR -rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 -ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o -Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBqDELMAkGA1UEBhMCQ0Ex -CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRgwFgYDVQQKEw9NYWlsRW5n -aW5lIEluYy4xKTAnBgNVBAsTIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IERpdmlz -aW9uMRMwEQYDVQQDEwptYWlsZW5naW5lMSAwHgYJKoZIhvcNAQkBFhFjYUBtYWls -ZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBaMIGoMQsw -CQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8xGDAWBgNV -BAoTD01haWxFbmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgRGl2aXNpb24xEzARBgNVBAMTCm1haWxlbmdpbmUxIDAeBgkqhkiG9w0B -CQEWEWNhQG1haWxlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAqXmfsU+lx+NFmn6tN17RTOyaddHqLnr/3rzEDIyT9TN+tF9TG7jmK7lJ -Jrj5arQ3nTFaLF8JuND2U1z/cLPw6/TX+1tE3v3CNUDSjaisyUDiUyp3TE8hMMMz -zfZQn0JsGgNhhWxqyzjhRQGtKL4+xtn8VsF/8zGgZYke7nlmVKz/FslDFTnNoodL -BAEGiu9JQS9qqpbSs20NdZ6LXPL2A4iTjnsNFBW3jIMVIn/JVVyaycU7ue2oFviD -vLNpkVZcR7A+jjIdIumOc5VSF0y7y74cQC5YwkR2mLK7UBYDK6NCY3ta/C4M8NsM -0FpmvRl0+A1ivZtVwqI98dxDtp7HeQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQAjfNn5BCzxylBDakFQGWKE/P43PRibMOEzfd7+DzbY -WIekoz3i00DwoH3b6j4gwlDJRAOq4dF6/Pt/uBOHDo/op+ef+9ErmKPd+ehXN9h3 -7QbccTgz7DtVwA4iRlDRLru+JuXzT+OsCHuFZMOLJ+KD2JAGh3W68JjdcLkrlcpt -AU0wc5aOHPPfEBdIah8y8QtNzXRVzoBt8zzvgCARkXxTS2u/9QaXR1hML0JtDgQS -SdZ6Kd8SN6yzqxD+buYD5sOfJmjBF/n3lqFHNMHnnGXy2TAXZtIAWzffU3A0cGPB -N6FZ026a86HbF1X4k+xszhbJu/ikczyuWnCJIg3fTYSD ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj -IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X -DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw -EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE -ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy -dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD -QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 -dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK -wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 -G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF -AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 -c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P -9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt -YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu -Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT -AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa -MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG -cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh -d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY -DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E -rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq -uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN -BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP -MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa -/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei -gQ== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p -dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv -bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa -QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY -BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u -IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl -bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu -Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs -Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI -Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD -ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH -b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh -KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy -dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t -MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB -MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG -A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl -cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE -VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ -ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR -uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG -9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM -pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm -MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx -MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 -dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl -cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 -DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD -gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 -yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX -L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj -EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG -7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e -QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ -qdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIRIjCCCQoCAQAwDQYJKoZIhvcNAQEFBQAwVzEPMA0GA1UEChMGVGhhd3RlMSEw -HwYDVQQLExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QxITAfBgNVBAMTGFRoYXd0 -ZSBVbml2ZXJzYWwgQ0EgUm9vdDAeFw05OTEyMDUxMzU2MDVaFw0zNzA0MDMxMzU2 -MDVaMFcxDzANBgNVBAoTBlRoYXd0ZTEhMB8GA1UECxMYVGhhd3RlIFVuaXZlcnNh -bCBDQSBSb290MSEwHwYDVQQDExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3Qwgggi -MA0GCSqGSIb3DQEBAQUAA4IIDwAwgggKAoIIAQDiiQVtw3+tpok6/7vHzZ03seHS -IR6bYSoV53tXT1U80Lv52T0+przstK1TmhYC6wty/Yryj0QFxevT5b22RDnm+0e/ -ap4KlRjiaOLWltYhrYj99Rf109pCpZDtKZWWdTrah6HU9dOH3gVipuNmdJLPpby7 -32j/cXVWQVk16zNaZlHy0qMKwYzOc1wRby2MlYyRsf3P5a1WlcyFkoOQVUHJwnft -+aN0QgpoCPPQ0WX9Zyw0/yR/53nIBzslV92kDJg9vuDMGWXb8lSir0LUneKuhCMl -CTMStWoedsSL2UkAbF66H/Ib2mfKJ6qjRCMbg4LO8qsz7VSk3MmrWWXROA7BPhtn -j9Z1AeBVIt12d+yO3fTPeSJtuVcD9ZkIpzw+NPvEF64jWM0k8yPKagIolAGBNLRs -a66LGsOj0gk8FlT1Nl8k459KoeJkxhbDpoF6JDZHjsFeDvv5FXgE1g5Z2Z1YZmLS -lCkyMsh4uWb2tVbhbMYUS5ZSWZECJGpVR9c/tiMaYHeXLuJAr54EV56tEcXJQ3Dv -SLRerBxpLi6C1VuLvoK+GRRe5w0ix1Eb/x6b8TCPcTEGszQnj196ZoJPii0Tq0LP -IVael45mNg+Wm+Ur9AKpKmqMLMTDuHAsLSkeP1B3Hm0qVORVCpE4ocW1ZqJ2Wu4P -v7Rn4ShuD+E2oYLRv9R34cRnMpN4yOdUU/4jeeZozCaQ9hBjXSpvkS2kczJRIfK7 -Fd+qJAhIBt6hnia/uoO/fKTIoIy90v+8hGknEyQYxEUYIyZeGBTKLoiHYqNT5iG3 -uIV7moW7FSZy+Ln3anQPST+SvqkFt5knv78JF0uZTK0REHzfdDH2jyZfqoiuOFfI -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 -yJTuQFv5QgLC/7DYLOsof17JJgGZpw== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID6TCCAtGgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UEBhMCQ0Ex -CzAJBgNVBAgTAk9OMRAwDgYDVQQHEwdUb3JvbnRvMRowGAYDVQQKExFUcmFkZXJF -bmdpbmUgSW5jLjEpMCcGA1UECxMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRGl2 -aXNpb24xFTATBgNVBAMTDHRyYWRlcmVuZ2luZTEiMCAGCSqGSIb3DQEJARYTY2FA -dHJhZGVyZW5naW5lLmNvbTAeFw05ODAxMDEwMDAwMDBaFw0zODAxMTcwMDAwMDBa -MIGuMQswCQYDVQQGEwJDQTELMAkGA1UECBMCT04xEDAOBgNVBAcTB1Rvcm9udG8x -GjAYBgNVBAoTEVRyYWRlckVuZ2luZSBJbmMuMSkwJwYDVQQLEyBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBEaXZpc2lvbjEVMBMGA1UEAxMMdHJhZGVyZW5naW5lMSIw -IAYJKoZIhvcNAQkBFhNjYUB0cmFkZXJlbmdpbmUuY29tMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAzyX5QE+5SN+zgNn1v3zp9HmP4hQOWW8WuEVItZVP -9bt/xj5NeJd1kyPL/SqnF2qHcL3o/74r0Ga55aKHniwKYgQTlp5ELGfQ568QQeN9 -xNIHtUXeStI9zCNZyZC+4YqObdMR/ivKA/WsLfUVMl2lV5JzJJz1BOE0gKEYiEyz -gIq5oLzkP/mOXoHRvWSZD2D0eHYIO7ovV2epVFK7g7p+dC4QoeIUEli+GF/Myg88 -dV/qmi+Sybck2RLPXa8Nh27/ETVQ7kE1Eafmx7EyCqIhG+5lwJAy3HwHUBwAYuzj -iuZz5lD8aQmr8SKuvy3eOH9SVN5wh3YBlrNGwTStkESVLwIDAQABoxAwDjAMBgNV -HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAWOPAUhZd3x9EQiFJcuxFTMd9q -axgcriCzJsM6D96sYGko9xTeLhX/lr1bliVYI5AlupoLXAdMzGHJkOgaTirKjQXr -F9nymDdUWKe3TmwGob5016nQlH7qRKvGO3hka0rOGRK2U/2JT/4Qp8iH/DFi6cyM -uP0q8n64SAkxZXLzUuFQXqf7U/SNjzb9XJQEIAdjp7eYd3Qb4jDsDcX0FrKMF1aV -r0dCDnS7am7WTXPYCDGdSkPgEHEtLYIYH3lZp5sKdVZ9wl4F0WNFkRWRUr7AXPjw -50uLmUNmKCd8JZLMGA1TRNSTi7U9EcrWt0OkMWm74T2WVnAgNsDv2WrWsGfj ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEeDCCA+GgAwIBAgICJ0swDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMx -JTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsT -EHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4 -MTYyMTA2MzlaFw0yMDA4MTUxMzA2MjVaMG4xCzAJBgNVBAYTAlVTMSUwIwYDVQQK -ExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNw -cy5jb20vQ1BTMR0wGwYDVQQDExRVU1BTIFByb2R1Y3Rpb24gQ0EgMTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEAxta577JTOMrSdwxsNigwwtAoAnhxTg2JQsdZ -J7OQCCfUl1oetnhEQGt0xo2rUYvopu1RptZ1F+x6VF5Wg+fwbcRJ9Be9BgsSxlXv -6ajhKC+gQ4919P/Z3H3+qtR485yTxZnaYkab9XYkVAkKKesURUIL/w12Ax+nZYii -pH9v0E8CAwEAAaOCAiswggInMIHPBgNVHSAEgccwgcQwgcEGB2CGSIb5bWUwgbUw -IwYIKwYBBQUHAgETF2h0dHA6Ly93d3cudXNwcy5jb20vQ1BTMIGNBggrBgEFBQcC -AjCBgBp+U2VlIFVTUFMgQ1BTIGF0IGh0dHA6Ly93d3cudXNwcy5jb20vQ1BTLiBU -aGlzIGNlcnRpZmljYXRlIGlzIHRvIGJlIHVzZWQgb25seSBpbiBhY2NvcmRhbmNl -IHdpdGggVVNQUyByZWd1bGF0aW9ucyBhbmQgcG9saWNpZXMuMCQGCWCGSIb5bWQC -BgQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwJAYJYIZIhvltZAIIBBcwFaADAgEB -oQMCAQKiAwIBAaMEAgInFTAkBglghkiG+W1kAgcEFzAVoAMCAQGhAwIBAqIDAgEB -owQCAidLMBAGCWCGSIb5bWQCAQQDCgECMBAGCWCGSIb5bWQCAwQDCgEHMBkGCWCG -SIb5bWQCBAQMMAqgCBoGTm9Sb2xlMB0GA1UdDgQWBBQl5aDvLXJPbZUfNx8g1sMB -RAPH0DAfBgNVHSMEGDAWgBTTzoJ08y9LiWBypF4Rv191A6ICqzAdBgNVHRIEFjAU -gRJyb290MTAwMDFAdXNwcy5jb20wIQYDVR0RBBowGIEWY2FhZG1pbkBlbWFpbC51 -c3BzLmNvbTAPBgNVHQ8BAf8EBQMDB8YAMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQEFBQADgYEAcAmQhgkD1rSyWiOrPGVEr/WndJfcCC4EyFOXrWGpwjCKu2jT -wWbAzS70nbA+qWPj718XgmaQb3C+LUJkQWJ/IiXBtc9WOTF3bqCT+Rqpw9wKcHbF -tS2bl4N2zgJeyG3dgrDqW1kNCYdAh3G+xaiXBbxD++6tJgq8e0VfjlmoK4o= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDbjCCAtegAwIBAgICJxEwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMx -JTAjBgNVBAoTHFVuaXRlZCBTdGF0ZXMgUG9zdGFsIFNlcnZpY2UxGTAXBgNVBAsT -EHd3dy51c3BzLmNvbS9DUFMxFTATBgNVBAMTDFVTUFMgUm9vdCBDQTAeFw0wMDA4 -MTUxOTM1NThaFw0yMDA4MTUxOTM1NThaMGYxCzAJBgNVBAYTAlVTMSUwIwYDVQQK -ExxVbml0ZWQgU3RhdGVzIFBvc3RhbCBTZXJ2aWNlMRkwFwYDVQQLExB3d3cudXNw -cy5jb20vQ1BTMRUwEwYDVQQDEwxVU1BTIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEB -BQADgY0AMIGJAoGBALepJaxj2rCSz5Q2sAT/Fm52BFv1xjyfxrlCJlX7k3GFEWXJ -YSeIxF6b/ip4SlJqRZ+o+5G04yZd9UMUJrnePG0sZvVTfd7kVleyonn14bTaavck -5bMo/p53luIOxwUDzOlR9pb8EcCWLXM1/1hzX/JINeVES9B+1QAehG3YJdjRAgMB -AAGjggEpMIIBJTAkBglghkiG+W1kAgYEFzAVoAMCAQGhAwIBAqIDAgEBowQCAicR -MCQGCWCGSIb5bWQCBwQXMBWgAwIBAaEDAgECogMCAQGjBAICJxEwEAYJYIZIhvlt -ZAIBBAMKAQEwEAYJYIZIhvltZAIDBAMKAQYwUwYJYIZIhvltZAIEBEYwRKA0GjJD -QSBNQVNURVIgUlNBIDEwMjQgQmVyIChTRUxGIFNJR04pIChDaHJ5c0FsaXMgQ1NQ -KaEMMAqhAwoBAKIDAwEAMB0GA1UdDgQWBBTTzoJ08y9LiWBypF4Rv191A6ICqzAd -BgNVHREEFjAUgRJyb290MTAwMDFAdXNwcy5jb20wDwYDVR0PAQH/BAUDAwfGADAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAI7SbReJ5I5NalEKF2AR -ay289lC8DMpJqaw7qotxs9HL9hx+IkIh6av2EiAybbIYKhFpcdjKWUqYrTKYo5hj -UW0jIfJRrqB3giO7nciBgas7CFr6y02kLHfLYKik//iMkFQtsLSDSguwPOvsY5vl -lP4Fo94aBCf2/0+o6iQIKyWa ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy -NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y -LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ -TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y -TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 -LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW -I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw -nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy -NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY -dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 -WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS -v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v -UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu -IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy -NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD -cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs -2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY -JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE -Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ -n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A -PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICMTCCAZoCBQKmAAABMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBa -Fw05OTEyMzEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2ln -biwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LJ1 -9njQrlpQ9OlQqZ+M1++RlHDo0iSQdomF1t+s5gEXMoDwnZNHvJplnR+Xrr/phnVj -IIm9gFidBAydqMEk6QvlMXi9/C0MN2qeeIDpRnX57aP7E3vIwUzSo+/1PLBij0pd -O92VZ48TucE81qcmm+zDO3rZTbxtm+gVAePwR6kCAwEAATANBgkqhkiG9w0BAQIF -AAOBgQBT3dPwnCR+QKri/AAa19oM/DJhuBUNlvP6Vxt/M3yv6ZiaYch6s7f/sdyZ -g9ysEvxwyR84Qu1E9oAuW2szaayc01znX1oYx7EteQSWQZGZQbE8DbqEOcY7l/Am -yY7uvcxClf8exwI/VAx49byqYHwCaejcrOICdmHEPgPq0ook0Q== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 -NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD -VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp -bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N -H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR -4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN -BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo -EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 -FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx -lA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK -VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm -Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J -h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul -uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 -DzFc6PLZ ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 -nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO -8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV -ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb -PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 -6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr -n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a -qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 -wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 -ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs -pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 -E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh -YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 -FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg -J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc -r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns -YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y -aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe -Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj -IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx -KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM -HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw -DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC -AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji -nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX -rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn -jBJ7xUS0rg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy -aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp -Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV -BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp -Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g -Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt -IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU -J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO -JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY -wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o -koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN -qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E -Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe -xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u -7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU -sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI -sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP -cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do -lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc -AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 -pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 -13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk -U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i -F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY -oJ2daZH9 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b -N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t -KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu -kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm -CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ -Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu -imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te -2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe -DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p -F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt -TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM -HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK -qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj -cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y -cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP -T8qAkbYp ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 -GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ -+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd -U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm -NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY -ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ -ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 -CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq -g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm -fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c -2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ -bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICIzCCAZACBQJBAAAWMA0GCSqGSIb3DQEBAgUAMFwxCzAJBgNVBAYTAlVTMSAw -HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVy -Y2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NDExMDQxODU4MzRaFw05 -OTExMDMxODU4MzRaMFwxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdSU0EgRGF0YSBT -ZWN1cml0eSwgSW5jLjErMCkGA1UECxMiQ29tbWVyY2lhbCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTCBmzANBgkqhkiG9w0BAQEFAAOBiQAwgYUCfgCk+4Fie84QJ93o -975sbsZwmdu41QUDaSiCnHJ/lj+O7Kwpkj+KFPhCdr69XQO5kNTQvAayUTNfxMK/ -touPmbZiImDd298ggrTKoi8tUO2UMt7gVY3UaOLgTNLNBRYulWZcYVI4HlGogqHE -7yXpCuaLK44xZtn42f29O2nZ6wIDAQABMA0GCSqGSIb3DQEBAgUAA34AdrW2EP4j -9/dZYkuwX5zBaLxJu7NJbyFHXSudVMQAKD+YufKKg5tgf+tQx6sFEC097TgCwaVI -0v5loMC86qYjFmZsGySp8+x5NRhPJsjjr1BKx6cxa9B8GJ1Qv6km+iYrRpwUqbtb -MJhCKLVLU7tDCZJAuqiqWqTGtotXTcU= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD -VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0 -MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV -BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy -dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ -ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII -0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI -uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI -hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3 -YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc -1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDWDCCAkCgAwIBAgICAx0wDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMB4XDTAwMDgxNjIxNTIwMFoXDTIwMDgxNTIzNTkwMFow -TTELMAkGA1UEBhMCVVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50 -ZXJuYXRpb25hbCBTZXJ2aWNlIEFzc29jaWF0aW9uMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAxR1Nc0GV4SC0bGzOZ+p1BqzEBMJgLwiSzyDtbqnJcSZW -ov3auwz4lQnJ+fIdz0SV7TFK2m3gvfx1FpbC7wp6DMe4tJBGLqkXCuBHRIR8HD0g -RgZDQ4Vy613hA7wymsvuCcZXFbMu2jJgpxKYkpvTyiNCsCP3UGlOjJtooTcwkskh -L2iKoNaEqVhNDOtVPboKRkj6wr65B8DsvZM0eTk9t5o0oAw9o/+ahOb64D+qVIQB -M0qFxqgUXhXB12DV8Gl4aWR41xTuE9ij8v91YThs1Cay12iIGWcO6+G/vI6a6siU -6bbM+BWFk21mdyuxFwuIJmxGot/OQ6Vu9/0bR25Y9wIDAQABo0IwQDAOBgNVHQ8B -Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUy8PGY8recX/bp9f/ -QnT2y8y2UDIwDQYJKoZIhvcNAQEFBQADggEBALYYhKS+5n/N+0aRFH0AQHd3hrmN -cR2c/vHY5QE/2aJgG826czQs7l4EksQiRFbs6vv3yQEW/ego7fje/Tw+LpiMjeN4 -4s+Oi+CvwY1gFIKCVrGHLvDpEhUdPmkKrY6mWPSZ/BFG7vfJ7cavLLmGJdKX/k+d -2DLhwmZRc4YN3XXjivr0ijVm3YhnrXmo/Gn12/qvlbSckB9fwRbJyAiAGtcD8l5x -o1ZjHkU2fXG+MWd0hi/Z7IjCIL2ZTT1VBdCiWkxVIpjQ8XX0F/rY4/7iFOAPZfqy -1mksM1DJJ6CskDFLFOXrY2TgPeP8EkrFloIt2iU5/tR/LkHHYkjXcUU7eJI= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1 -MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT -QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp -b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX -ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i -/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU -58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g -halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E -1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ -ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb -mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ -kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN -dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ -ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn -B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDgDCCAmigAwIBAgICAx8wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDMwHhcNMDAwODE2MjMz -NDAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT -QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp -b24xEjAQBgNVBAMTCUdQIFJvb3QgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALrsQ7g06qNn33cJHxoQoh6pTpVMdOcM3GzGmNCr+hckmmejSRRkiY+T -Ei/vj9jOEASLhcDcL7wpmK+cQsXL0pbP9KXFLW5NjDiOsmoImdWRG6jtM5NJXcvn -FUNtUvHI6NfaMOCYKqlbo8PRAQOBXX62CZXo2zJu/TrDtZ6b/VkZILMjwOJq7kSW -gO9oCUCUwrczSYPlya4tIDeQGD0gNtp5Oa+4V59672AqIYT4/6A5IdPYbVTHw2o8 -yFwfLkdyFGxVSwkGzY7FawvnB0c6fZJffQ+wXDNXg4M/HoSoeZCfl04i3HUiyG4v -1tDLduEMV5fhJo8phFPy5Y6TykuKTDUCAwEAAaNCMEAwHQYDVR0OBBYEFKJcbg1l -CMH3TlvJbfDQVhs5gkO7MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQADjVYIs6Gt/XNC2WcsbprPvx7ITfJN0tk3yThE -ja6JDO+MmStKk/VtrGZKP1dqEKWiGhOmLOpi54D5vf3k/9oRnzlYbfVD8vT9pr+d -sauaRgff4fBbP/5dWUAGrBgIR0w8TEhGzojhqLaedaag934btsSN7fAqUxVK2ylP -OVPnUlijvtzkkC21yc6Y/yyGoQigyM73gjkJDMHC1KmkKg4zgcc8cMswbaRWt5tc -fAIivuUHfW0k0Sex1h0eXEc8vy5u+ByESOz14aCVEc3nMOtc8Cl7dYICBrLzkznS -DqzfXyQTFTBD9VDUx4OgQzlPZTS9punO4XS+IN/SchZLiUZ2 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICezCCAeSgAwIBAgICAyAwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDQwHhcNMDAwODE3MDAx -OTAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT -QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp -b24xEjAQBgNVBAMTCUdQIFJvb3QgNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC -gYEAuOvwj6Dm8eMAP15ynq4ED/RPzsraYjPq7lrCwfYuOIm0Dc+hrrkxs/2mx7bE -bIMMgGE4Ogq+HAGgGRvn+3JtkmObpq8z9LRbGugo3kznN/EU8eAX4BRI7EQdeaVO -quGkhHe9y0226nB+X6oXLEtbsOqF1GmoEekrNx27pgTum0ECAwEAAaNCMEAwHQYD -VR0OBBYEFEPGSEDAD8YYWklJ5YGABk1f3dSFMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAKQZPXPOh9GfVhJcyDjl7vkS -yNkB6p2DNMaia4t3epJ+h8dVIxSNwmhNGfJptOpHFJE7UYcY+nab4nscE9PmZh4K -ErldkMY7ExQizTWMLUVgAATI71gCxV2ZtJBt3lTXI+I5hCXDaKNio3nYmKFa0lyJ -/eUWDPSrF0h+reuAwFWB ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICezCCAeSgAwIBAgICAyEwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDUwHhcNMDAwODE3MDAy -ODAwWhcNMjAwODE2MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT -QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp -b24xEjAQBgNVBAMTCUdQIFJvb3QgNTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC -gYEArQBu8qB8MREcQbA3j4OiQ8uXXwIgiQ1uvCqx8aVk79iOStZynZ5uH5qo+YUD -rMEnaoTlZkhxml5CD4rin/aADyOsU8PBnwLE+FhG6vSpgq9tB0aG8S38BrgeVdU5 -YZKEi/HYijNOPBO11nH8az60HHoLh9U1ZjTDczJjWN8SayMCAwEAAaNCMEAwHQYD -VR0OBBYEFCNO8wIEBNfSpwBWwc5JLIwVljMvMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBADyUAYfyyM/hj665C+IcffEZ -rdHt9gFbNlMKgD6uNFZncG5DVE55zYvVUBky2Ek4NP22c0nrDkl6vxr36gcoJbsV -SRxRSlWaOC8tD1j5edECZROMWZ8Qf10XPHTytep3gTaGbzJbBbQNoyZn8OQ1Dke9 -a8GRnQv0P5oRfJQWZ7aY ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIID+DCCAuCgAwIBAgIRANAeQJAAACdLAAAAAQAAAAQwDQYJKoZIhvcNAQEFBQAw -gYwxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMRcwFQYDVQQHEw5TYWx0IExh -a2UgQ2l0eTEYMBYGA1UEChMPWGNlcnQgRVogYnkgRFNUMRgwFgYDVQQDEw9YY2Vy -dCBFWiBieSBEU1QxITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAe -Fw05OTA3MTQxNjE0MThaFw0wOTA3MTExNjE0MThaMIGMMQswCQYDVQQGEwJVUzEN -MAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxGDAWBgNVBAoT -D1hjZXJ0IEVaIGJ5IERTVDEYMBYGA1UEAxMPWGNlcnQgRVogYnkgRFNUMSEwHwYJ -KoZIhvcNAQkBFhJjYUBkaWdzaWd0cnVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCtVBjetL/3reh0qu2LfI/C1HUa1YS5tmL8ie/kl2GS+x24 -4VpHNJ6eBiL70+o4y7iLB/caoBd3B1owHNQpOCDXJ0DYUJNDv9IYoil2BXKqa7Zp -mKt5Hhxl9WqL/MUWqqJy2mDtTm4ZJXoKHTDjUJtCPETrobAgHtsCfv49H7/QAIrb -QHamGKUVp1e2UsIBF5h3j4qBxhq0airmr6nWAKzP2BVJfNsbof6B+of505DBAsD5 -0ELpkWglX8a/hznplQBgKL+DLMDnXrbXNhbnYId26OcnsiUNi3rlqh3lWc3OCw5v -xsic4xDZhTnTt5v6xrp8dNJddVardKSiUb9SfO5xAgMBAAGjUzBRMA8GA1UdEwEB -/wQFMAMBAf8wHwYDVR0jBBgwFoAUCCBsZuuBCmxc1bWmPEHdHJaRJ3cwHQYDVR0O -BBYEFAggbGbrgQpsXNW1pjxB3RyWkSd3MA0GCSqGSIb3DQEBBQUAA4IBAQBah1iP -Lat2IWtUDNnxQfZOzSue4x+boy1/2St9WMhnpCn16ezVvZY/o3P4xFs2fNBjLDQ5 -m0i4PW/2FMWeY+anNG7T6DOzxzwYbiOuQ5KZP5jFaTDxNjutuTCC1rZZFpYCCykS -YbQRifcML5SQhZgonFNsfmPdc/QZ/0qB0bJSI/08SjTOWhvgUIrtT4GV2GDn5MQN -u1g+WPdOaG8+Z8nLepcWJ+xCYRR2uwDF6wg9FX9LtiJdhzuQ9PPA/jez6dliDMDD -Wa9gvR8N26E0HzDEPYutsB0Ek+1f1eS/IDAE9EjpMwHRLpAnUrOb3jocq6mXf5vr -wo3CbezcE9NGxXl8 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDYzCCAkugAwIBAgIQCgEBAQAAAnwAAAACAAAAAjANBgkqhkiG9w0BAQUFADA7 -MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhj -ZXJ0IFJvb3QgQ0EwHhcNMDAwODE4MTgxODE3WhcNMjUwODE1MTkwMzE3WjA7MSEw -HwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xFjAUBgNVBAsTDVhjZXJ0 -IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCotGGLHRw+ -kHtwMkBtjRbKNWFhteL7Fcn0IV6BG88inKyru2DQoDPeEVMaCQ87GhOp1IfMWPct -Uqmiwqk67c80naEC77jyuCtXiBCTtak1Y7sFQkMif79wXtMopVUoIEuTSY+nvz1A -KA0Rr3ImCQU0CcWrAZNXoaxmVJginCPrugxknLY9++LGlsLPC0/qyDD6iivKHBGW -GikAjOty1FFFqZ13INUSu7XyfwY4gk19kh7o1frIKUdpGhURjK+mLMEo9GlbaZ7k -PBPuwKFg6kG/wmJLbaI3hDo+87AyroprbBPzOiEKe5ZYMylebqjKaaK+jgZFXfFm -OVVKHFoksUvRAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB8GA1UdIwQYMBaAFESoSTh1MWyrKOdx8tjUyK9BD0eRMB0GA1UdDgQWBBRE -qEk4dTFsqyjncfLY1MivQQ9HkTANBgkqhkiG9w0BAQUFAAOCAQEAPXNepQq7tRHD -8WfREhqiRykRTE5ZNyCGCUDyRfFJeTkaPSXXLynQCAUVFPvkRGw/fl61UtiRWDyW -+9RK7/EuwVYeTGkM2WAdSkcntQMz2xi721OeoXtRapDTpRXIggvAtzcydYVUXlUQ -fJE7qStgxjF2rMQwSQPEtlZApfBjr2lKiK/XqwvuOtu9E4OoO6LpuUX1UU2U8Fmp -26E3Z9IUnqd71xmqFSNraXXREz5Y9PMB6IjElFbJwP7fT0dVH2uBTlTtE19y/CaG -BDaPTxJNnFDiTlpWrLn9LB9YewUSB2M47xnj9DyRWqIlYle8xpSgd5zPNGLgv/t1 -POkbJhucZA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICaDCCAdGgAwIBAgIQCgEBAQAAAnwAAAADAAAAAjANBgkqhkiG9w0BAQUFADBA -MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xGzAZBgNVBAsTElhj -ZXJ0IFJvb3QgQ0EgMTAyNDAeFw0wMDA4MTgxODMxMzJaFw0yNTA4MTUxOTAwNTZa -MEAxITAfBgNVBAoTGFhjZXJ0IEludGVybmF0aW9uYWwgSW5jLjEbMBkGA1UECxMS -WGNlcnQgUm9vdCBDQSAxMDI0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW -vjeJEami90csKs9qACZlKESkiuTeoENVmURrvG64x87GY7bT6G/FmCskkbieorpx -SN40ICF61tLFiTKlicbchYRU8p5I7cxEtgb/jsTOWa2fbOkiWME/FApDgIcZUlDj -KAfIrBjisRqqo+Jgt3ZRByk5XkjpZnCBLjiavRl96wIDAQABo2MwYTAPBgNVHRMB -Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBSEecdPB1mxa8E6 -Nbq49NWZJ8i6DjAdBgNVHQ4EFgQUhHnHTwdZsWvBOjW6uPTVmSfIug4wDQYJKoZI -hvcNAQEFBQADgYEAc7DhAO2uaNJgA0br+RzxpaZ8XDJ87AJh0xwdczEsuo69SU3I -3dl3dUHnkiGabCnbp2xwhqBcw+TzMswBhFnXiDk486ji4hqwl80rF9xkBA+qanOU -1usIxoBpTd561cU38ZIXPG3TiiHMZBCq3mKHH4+4+Kp1SvQILPXcZs/DOH4= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIC/zCCAecCEAoBAQEAAAJ8AAAABAAAAAIwDQYJKoZIhvcNAQEFBQAwPjEhMB8G -A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBS -b290IENBIHYxMB4XDTAwMDgxODE4NDA1MFoXDTI1MDgxNTE5MDAzOFowPjEhMB8G -A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMRkwFwYDVQQLExBYY2VydCBS -b290IENBIHYxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwZKr8rY1 -NgJID4X0Ti+CZc1IvrG3PbN7rroyNIY8mL/4sL37wsz2CZc4XI2lI07hyITmkGd0 -O6P2bpkrj8MH0pdRB08Ey56y+Dz3OOaWSjrrFW/nYuZDMweyDVrPlSk5Z4gTI9SM -bV+OIeAx87XcmcXE7YUQfpLUoh08HwuzI+bAyySbbBCmzRTWo51Tj/ceQZq2Gx0I -XPc5QcMe3kwmo2B8LhOHkWzXwiMv530ZH81b6pjFuUZ9NUbke4tK2ZPgBqvAzEr9 -29oLMD+4XOAHE6jFMPy8hvaqvw5jL49JchDRnoX5Qe1IPHgM/aAqBhuv091nL+xI -L1FJNiK3SM1J7wIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCo3LMgLv1XSBAP5o1g -Uht2HZxmoG/6aAbYp5zLoQyOJeiux986cK2p+CokvLzHqscJt7sQ6R9a1aIBRosF -xKN1SQtAx7Frn9tYFmMyhFoQjWKWq5hmm7r6VggbumLz7zlr/GSxya7vXpThooD5 -CIMWEjaW2QmQ2Zg6rz2F2JEqkhxcuczVXHM4jntzUgy6n/KOv8h8ChO6cpGgOyDv -iSrDDIBpVnMQ9GAZ4B4WSmSr/EY60AvTl7Fc2ZysGDogB3oi+bcQZbrs5lPUquTD -Qbyb38LdmgFG1I5F7cnKFjSEjTJUPFRikI0aZlLN+hzMDPyx45PIp9nraGOP0H4u -Ld0p ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICBDCCAW0CEAoBAQEAAAJ8AAAABQAAAAIwDQYJKoZIhvcNAQEFBQAwQzEhMB8G -A1UEChMYWGNlcnQgSW50ZXJuYXRpb25hbCBJbmMuMR4wHAYDVQQLExVYY2VydCBS -b290IENBIHYxIDEwMjQwHhcNMDAwODE4MTg1MDU2WhcNMjUwODE1MTkwMTA4WjBD -MSEwHwYDVQQKExhYY2VydCBJbnRlcm5hdGlvbmFsIEluYy4xHjAcBgNVBAsTFVhj -ZXJ0IFJvb3QgQ0EgdjEgMTAyNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -pwnD0qmmGXDsKelFezbg6j7JmXBA0bZg9N0jx1l5nR6lvjVjAObALmxAU+bRdkbx -oMuDRVSYGc97mjj4dDMzP6klICgmXShxRoYgPTArq+ZN+j/qREBM+3PU3JZ09E7k -ah0bl6B8MOHAc7YNond68Rj4SnFxnviodf5i+Ko9z30CAwEAATANBgkqhkiG9w0B -AQUFAAOBgQB709VMf0yifnzXVmHZlZiFitdJ3IxHqgfsuNt5JJ7npZJXZgmPFLD+ -BPK9URC4OMOhEtuQg361Y1irM62XHkZQQhCsyKstHTVsxuZDUCgDoaz7EZX/6dVK -D5HlA+SIMDwcdtGX8ArUh6AMmo9hztp+crM7UMCAhA8hIJRoKtqMvg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJX -VzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQgUm9vdCBD -QXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYyMDE0MjEwNFoX -DTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNVBAoTCWJlVFJVU1Rl -ZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRowGAYDVQQDExFiZVRSVVNU -ZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANS0c3oT -CjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4SP+00PpeQY1hRIfo7clY+vyTmt9P -6j41ffgzeubx181vSUs9Ty1uDoM6GHh3o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwM -jmVZxXH/YgmPqsWPzGCgc0rXOD8Vcr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX -2P8ZDoMbjNx4RWc0PfSvHI3kbWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2N -R47rtMNE5qdMf1ZD6Li8tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5j -rEq2I8QBoa2k5MUCAwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNV -HSAEggFQMIIBTDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQa -gfFSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1 -bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0 -ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9uIHBy -YWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJlVFJVU1Rl -ZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0L3Rl -cm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNUZWQuY29tL3ZhdWx0 -L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYDVQQKEwliZVRSVVNUZWQx -CzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub2M3eKjEENGvKBxirZzAfBgNV -HSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxirZzAOBgNVHQ8BAf8EBAMCAf4wDQYJ -KoZIhvcNAQEFBQADggEBAHlh26Nebhax6nZR+csVm8tpvuaBa58oH2U+3RGFktTo -Qb9+M70j5/Egv6S0phkBxoyNNXxlpE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2 -jCBHOElQBp1yZzrwmAOtlmdE/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe -1lMBzW1MaFVA4e5rxyoAAEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5 -mlWXKWWuGVUlBXJH0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYc -tmBjRYoQtLpGEK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E -jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo -ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI -ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu -Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg -AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 -HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA -uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa -TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg -xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q -CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x -O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs -6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICjTCCAXWgAwIBAgIDAQAhMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA3MTIxNjMxNTNaFw0xMjA3MTIxNjMxNTNaMEMxCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xFzAVBgNVBAMTDkNlcnR1bSBM -ZXZlbCBJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl73pZ9DFcn7Qy0qBZ -K+So18cav7drUrJ8SiYOlDDVskt81+eIcL/4FelTSGjuAOvYdmm+HGYG998RPB0i -Z+Ak67vXFJ537vRWOcu6aMjNuAwu8BOdc5eSgB0Y8X4+3LOYfugtaZa8mrEQ8Hit -0yLE9UBcU9J+4PmkVGecmZ8jZQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQAlDS4aTmgK0YgmUvt/3zN7G2/ZrtBBCtONlUvC69c7 -TmLJWJ842y2AH7ryNXXkcsn6p0ZBTrTJ2tA2y/j2PXJeXrCkK/qAJIpM0l4u0MT7 -enY5akasduHp2NXMP9vDlgMy7elU2s3nkOT79gfh5XttC+5D/x4JDNi1DMAA9hk1 -6DK4zWmDVfjkiP/G3fEndtJgNDQsyqnaQ3E3bljv3f1KJTjZUvtA2Ml6MP2hFRhg -ZPsxuhW8QXidQYNiua1h7XUUiPiERLDLWZmfY6dxGrHXjSTx3shHNaQM0qkDs9gS -6UK8uWJN2bf2YBnvGmzy0IQvx5wDCH7h8AdaBD6DgIG1 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICjjCCAXagAwIBAgIDAQAiMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA3MTIxNjMyMDNaFw0xMjA3MTIxNjMyMDNaMEQxCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM -ZXZlbCBJSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyMQSaN5fA94hNE46 -bMKpGUb5yIPEowReGZzGttYBQnC6oUOy+iM3md8WerzXeBKf7iIZEDW2HAp7BKhS -4rMB6taxT07vDtkNfEKwOk6X7dODw6KY4mxnzjmjh5pf2feKKJ3MoZxi2HAz2a6J -vHKFMq8dAlGL2GBtLvzlFp2jwkMCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN -BgkqhkiG9w0BAQUFAAOCAQEAWo3wgy+/0B7UiTCu4Wn1rvGRXIUtbPNp4Bc4PP/i -1q6pPheIe0ooCopuqnDX9maTHhZeNpnApgCUSbyw71EaOremD7HjWXASRUTylhwL -5FdSx+D6MgF2uW9uwZ+NErkeRJYT2aRXe5FBOVIseC4g93Ay0D8Hg50MkAC5pQqW -+8GSszT94NzT7ppIaMtq53PZpUtLGiL3UBZ5vUJ5pE4lLKD7Ce+pXzZevy/MnkMG -D1L7LgjRWL17OcMlASFETyUTajNjvxMy+oM4C22rwHRh2WQrvgw5MO+Q3UyYA1r5 -VrSaqgQ1g06ZcQt+mhzoc2swlOSwm8iis8H6orR8xmCWrA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICjzCCAXegAwIBAgIDAQAjMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA3MTIxNjMyMTdaFw0xMjA3MTIxNjMyMTdaMEUxCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGTAXBgNVBAMTEENlcnR1bSBM -ZXZlbCBJSUkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZjBbfGFmlsLjPe -pWaDwG0LqhF11lWKabaHi1sQhK3qomHY7Em7qpL11dUQ1vsMcnnpzz/J0AEH6KDh -+yAyXV1SE/tVToLYYByZK+JGacLYIYF9aCwV8AhqyzOGurO5QX6vLboXB2WNnwmX -hyNVKUgnUVy4ktAR2qZJIw5Bjsn/AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAIsLt3vKCZqd/gui45ovm3FSO6FLjzzq4pagPvbN -nZ39HrhRaCpqkHDAj71L5L27U3eW2D4ILL0iUmZadbC4i3at/PUL9mjhGlajcCN8 -EF6IXGT87Tbcii735jRaaXSbEY4YhNOg9DPBoD4uJMkA8Z0Y/6lYmk4S6KUMCzzt -t5zZBiWjdd08yFi5VGMvpE74KVOMdMa3JNVaR0XvT0Q8yXo1XKCrY9OFIxnhVgDb -hzr9fwjKWDwu8kxhT9khAETm0BU2Buu+CTasaJdT/bBR2YEx9qcN7XyXTeDtkOO5 -QeGSqFgzquwjWEbKhf7l/e+efdRCg+ikH3O5snHB6iS+dgg= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICjjCCAXagAwIBAgIDAQAkMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA3MTIxNjMyMzVaFw0xMjA3MTIxNjMyMzVaMEQxCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM -ZXZlbCBJVjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmyb1lKqCAKE4juAy -6lpVNUl6aJ2DuWPSiJ3BBk3/6ty6I4Lr2Dpy1b1vjVelhaFsVKEDgK2JyQlk9XMq -LPZI2Ql166mJiPKFg77aY/W78EcQfGyjnRvVcs0tG40mAs/p84OEpFcVe/RSqDrD -/D7R01u+Wj5xLl0PUsFplIGDbikCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN -BgkqhkiG9w0BAQUFAAOCAQEAPS99JujKGVRfa50TKfieq+uK1SxjidErYaZTb3cJ -NNfQDYn6nk4lnrnab5EUVhO/NegP2yIu3YOnZGfxFDhvVozMTKKAB5r5XKOvzsP9 -9C9578PVMLozucfUMCSwau7Z4l5uuQOHuzjzlVLCibbbf4RwfvZ7hh5sB5c0pNbw -RQq64RXQUUEvul/W9gUeT9ISHOsASGTq+HJ5i7vNARjukEAXW/maqs9vyTWWbGVI -1FSOnVyteymq4Xk+9YlIyNPNyacgnsMnU72XKBLDS0KJdhIWALFAZI4dSh5WZNuW -ZguUnEmeH81lLbR+p/N3iuN8+oSo8UXik92jxeUY2tQJUA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx -EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h -bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy -YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp -Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy -MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG -A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt -YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD -VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA -isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj -Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 -QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt -bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR -yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID -AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 -cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f -BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj -cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 -U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl -YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos -SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ -t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u -mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb -K+9A46sd33oqK8n8 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF -MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU -QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI -MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN -AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla -Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy -ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y -IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 -c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA -dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y -AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw -TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8 -/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 -LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/ -jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms -Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF -MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU -QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI -MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN -AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla -Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy -ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y -IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1 -c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA -dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF -Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw -Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW -w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3 -LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE -Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD -2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIG2jCCBcKgAwIBAgIDFc/9MA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJE -RTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1E -Rk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9w -bGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNl -cnRpZnlAcGNhLmRmbi5kZTAeFw0wMTEyMDExMjExMTZaFw0xMDAxMzExMjExMTZa -MIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3Nu -ZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0w -KwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAf -BgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMF5rhMt6zmhxK5oWPwT2FG7Up7T5DovHSD/YKPIRxsv -DWmC4dTzByIBLnOmEflk+5KAqAYao6eY1qF0hR4WiS4DjCsn7l3zNo/4i2eF4EmG -EksBygb4tRlTThcO7heFX+Du5qFoks+ONqa70RlwOr2l53KVwjMXBCtCLFSKRLVu -xeh5+Smkm+FuOmwEugndM2n74Djjyf9DCOaHGZrHwVDh+Vpy5Ny4bKCSboujRxd5 -NxsStUshDVbTeS3B8TuzAJbywYWEE7erox+7WTfQr8ivSCBhrNJ36VRjAb8hiV9I -uy2TmJYo2oPyC8a3eM3xj9Ku2IW3tS2zpfiIzt9xvFMCAwEAAaOCAwEwggL9MA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAYL+rX4SHijILELPs+g0MTRf33QMIHb -BgNVHSMEgdMwgdCAFAYL+rX4SHijILELPs+g0MTRf33QoYGypIGvMIGsMQswCQYD -VQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYD -VQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRE -Rk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0B -CQEWEmNlcnRpZnlAcGNhLmRmbi5kZYIDFc/9MAsGA1UdDwQEAwIBBjARBglghkgB -hvhCAQEEBAMCAAcwgaUGA1UdHwSBnTCBmjBLoEmgR4ZFaHR0cDovL3d3dy5kZm4t -cGNhLmRlL2NlcnRpZmljYXRpb24veDUwOS9nMS9kYXRhL2NybHMvcm9vdC1jYS1j -cmwuY3J4MEugSaBHhkVodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv -bi94NTA5L2cxL2RhdGEvY3Jscy9yb290LWNhLWNybC5jcmwwOAYJYIZIAYb4QgED -BCsWKWh0dHBzOi8vd3d3LmRmbi1wY2EuZGUvY2dpL2NoZWNrLXJldi5jZ2k/MEsG -CWCGSAGG+EIBCAQ+FjxodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv -bi9wb2xpY2llcy94NTA5cG9saWN5Lmh0bWwwOAYJYIZIAYb4QgENBCsWKVRoZSBE -Rk4gVG9wLUxldmVsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MGQGA1UdIARdMFsw -WQYLKwYBBAHZGoIsAQEwSjBIBggrBgEFBQcCARY8aHR0cDovL3d3dy5kZm4tcGNh -LmRlL2NlcnRpZmljYXRpb24vcG9saWNpZXMveDUwOXBvbGljeS5odG1sMA0GCSqG -SIb3DQEBBQUAA4IBAQAmbai6JMt7nkuavyvxKzLGn04Gyt0zKrp8zmERp4inktvY -7p+vkaomYu2QYC7cHq0tlrPXQQhhetjiXGb+36aJtHDkEA0NwrJzYnHgPsvx7z0w -ysENP4wxf97KsSWm07RY+f6/gIQF7Je7CW30Rzq7N6R0NMBs32mJgdn3ntqlFNw3 -Nbs050FEjPNq54RdawlJo85x+w+QJd7uQM4yZjHpRhvwgte9Ge1UqCUdpMsLHzeM -KJ0B9GhwIIqOJCMiPgKjcUBrn6ehSX70POvXvjjE2+FzhPGTyTkS474d2UCAnL9q -hPrdWXzBjOumOjhJutT1aecm9eljlshmh1cNen00 ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDwzCCAyygAwIBAgIBADANBgkqhkiG9w0BAQQFADCBmDELMAkGA1UEBhMCQVQx -EDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAGA1UEChM5QXJn -ZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBmdWVyIERhdGVu -c2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVuLmF0MB4XDTAx -MDIxMjExMzAzMFoXDTA5MDIxMjExMzAzMFowgZgxCzAJBgNVBAYTAkFUMRAwDgYD -VQQIEwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExQjBABgNVBAoTOUFyZ2UgRGF0 -ZW4gT2VzdGVycmVpY2hpc2NoZSBHZXNlbGxzY2hhZnQgZnVlciBEYXRlbnNjaHV0 -ejEiMCAGCSqGSIb3DQEJARYTYS1jZXJ0QGFyZ2VkYXRlbi5hdDCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAwgsHqoNtmmrJ86+e1I4hOVBaL4kokqKN2IPOIL+1 -XwY8vfOOUfPEdhWpaC0ldt7VYrksgDiUccgH0FROANWK2GkfKMDzjjXHysR04uEb -Om7Kqjqn0nproOGkFG+QvBZgs+Ws+HXNFJA6V76fU4+JXq4452LSK4Lr5YcBquu3 -NJECAwEAAaOCARkwggEVMB0GA1UdDgQWBBQ0j59zH/G31zRjgK1y2P//tSAWZjCB -xQYDVR0jBIG9MIG6gBQ0j59zH/G31zRjgK1y2P//tSAWZqGBnqSBmzCBmDELMAkG -A1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTFCMEAG -A1UEChM5QXJnZSBEYXRlbiBPZXN0ZXJyZWljaGlzY2hlIEdlc2VsbHNjaGFmdCBm -dWVyIERhdGVuc2NodXR6MSIwIAYJKoZIhvcNAQkBFhNhLWNlcnRAYXJnZWRhdGVu -LmF0ggEAMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQE -AwICBDANBgkqhkiG9w0BAQQFAAOBgQBFuJYncqMYB6gXQS3eDOI90BEHfFTKy/dV -AV+K7QdAYikWmqgBheRdPKddJdccPy/Zl/p3ZT7GhDyC5f3wZjcuu8AJ27BNwbCA -x54dgxgCNcyPm79nY8MRtEdEpoRGdSsFKJemz6hpXM++MWFciyrRWIIA44XB0Gv3 -US0spjsDPQ== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD -VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT -IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD -Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz -MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE -ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw -FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu -aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY -XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1 -gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4 -Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY -JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU -dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14 -cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB -ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt -TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 -NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD -VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS -Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 -N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH -iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe -YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 -axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g -yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD -AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh -ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V -VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB -BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y -IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs -QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 -ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM -YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb -QErNaLly7HF27FSOH4UMAWr6pjisH8SE ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB -kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw -IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD -VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu -dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 -E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ -D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK -4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq -lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW -bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB -o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT -MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js -LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr -BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB -AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj -j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH -KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv -2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 -mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp -ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow -fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV -BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM -cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S -HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 -CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk -3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz -6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV -HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv -Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw -Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww -DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 -5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj -Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI -gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ -aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl -izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 -aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla -MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD -VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW -fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt -TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL -fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW -1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 -kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G -A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v -ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo -dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu -Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ -HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 -pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS -jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ -xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn -dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx -MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG -29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk -oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk -3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL -qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN -nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX -ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H -DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO -TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv -kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w -zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx -MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o -Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt -5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s -3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej -vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu -8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil -zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ -3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD -FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 -Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 -ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe -MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v -d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh -cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn -0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ -M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a -MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd -oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI -DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy -oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 -dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy -bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF -BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli -CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE -CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t -3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS -KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB -kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw -IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD -VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu -dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 -E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ -D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK -4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq -lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW -bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB -o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT -MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js -LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr -BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB -AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj -j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH -KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv -2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 -mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB -rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt -Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa -Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV -BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l -dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE -AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B -YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 -hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l -L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm -SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM -1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws -6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw -Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 -aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH -AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u -7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 -xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ -rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim -eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk -USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB -lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt -T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc -BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 -dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP -HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO -KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo -5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ -pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb -kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC -AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov -L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV -HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN -AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw -NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB -mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU -4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 -81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR -Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD -EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X -DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw -DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u -c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr -TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA -OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC -2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW -RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P -AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW -ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 -YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz -b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO -ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB -IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs -b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs -ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s -YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg -a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g -SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 -aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg -YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg -Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY -ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g -pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 -Fp1hBWeAyNDYpQcCNJgEjTME1A== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV -MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe -TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 -dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB -KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 -N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC -dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu -MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL -b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD -zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi -3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 -WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY -Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi -NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC -ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 -QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 -YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz -aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu -IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm -ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg -ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs -amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv -IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 -Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 -ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 -YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg -dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs -b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G -CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO -xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP -0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ -QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk -f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK -8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD -EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 -OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l -dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG -SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK -gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX -iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc -Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E -BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G -SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu -b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh -bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv -Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln -aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 -IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh -c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph -biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo -ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP -UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj -YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo -dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA -bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 -sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa -n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS -NitjrFgBazMpUIaD8QFI ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIICiTCCAfKgAwIBAgIEN4dnrDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJi -ZTERMA8GA1UEChMIQmVsZ2Fjb20xDDAKBgNVBAsTA01UTTEkMCIGA1UEAxMbQmVs -Z2Fjb20gRS1UcnVzdCBQcmltYXJ5IENBMR8wHQYKCZImiZPyLGQBAxQPaW5mb0Bl -LXRydXN0LmJlMB4XDTk4MTEwNDEzMDQzOVoXDTEwMDEyMTEzMDQzOVowdTELMAkG -A1UEBhMCYmUxETAPBgNVBAoTCEJlbGdhY29tMQwwCgYDVQQLEwNNVE0xJDAiBgNV -BAMTG0JlbGdhY29tIEUtVHJ1c3QgUHJpbWFyeSBDQTEfMB0GCgmSJomT8ixkAQMU -D2luZm9AZS10cnVzdC5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqtm5 -s9VPak3FQdB7BGFqi3GBB9pk41huJ1XCrc4XsPz6ko0I8Bxy/7LDMf7gaoeXTMxD -V6coeTq1g12kHWrxasU+FCIdWQZv8KYxd9ywSTjmywwP/qpyNIjaKDohWu50Kxuk -21sTFrVzX8OujNLAPj2wy/Dsi4YLwsFEGFpjqNUCAwEAAaMmMCQwDwYDVR0TBAgw -BgEB/wIBATARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEFBQADgYEAerKx -pbF9M+nC4RvO05OMfwH9Gx1amq6rB1Ev7Ymr3VBCux//SrWknLFhKQpM6oNZSY2v -hmnXgaxHqqRxblnvynxqblSK2qiSyfVms3lf1IsBniFjRjWTpcJfImIDcB1jI+hr -SB0jECfY9t9HorrsgFBKbMRwpnrkdCJ/9oRiMn8= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE -SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw -ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU -REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr -2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s -2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU -GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj -dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r -TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB -AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv -c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl -ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu -MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg -T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud -HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD -VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny -bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy -MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ -J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG -SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom -JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO -inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y -caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB -mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ -YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 -BKNDLdr8C2LqL19iUw== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE -SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg -Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV -BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl -cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA -vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu -Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a -0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 -4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN -eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD -R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG -A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu -dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME -Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 -WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw -HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ -KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO -Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX -wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ -2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 -9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 -jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 -aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD -EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz -aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w -MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l -dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh -bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq -eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe -r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 -3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd -vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l -mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC -wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg -hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 -TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh -biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg -ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg -dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 -b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl -c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 -ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 -dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu -ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh -bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo -ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 -Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u -ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA -A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ -MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ -NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR -VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY -83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 -macqaJVmlaut74nLYKkGEsaUR+ko ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO -TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy -MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk -ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn -ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 -9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO -hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U -tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o -BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh -SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww -OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv -cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA -7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k -/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm -eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 -u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy -7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR -iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs -IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg -R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A -PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 -Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL -TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL -5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 -S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe -2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap -EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td -EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv -/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN -A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 -abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF -I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz -4iIprn2DQKi6bA== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy -c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 -IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV -VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 -cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT -QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh -F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v -c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w -mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd -VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX -teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ -f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe -Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ -nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY -MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG -9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX -IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn -ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z -uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN -Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja -QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW -koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 -ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt -DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm -bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy -c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD -VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 -c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 -WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG -FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq -XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL -se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb -KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd -IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 -y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt -hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc -QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 -Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV -HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ -KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ -L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr -Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo -ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY -T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz -GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m -1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV -OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH -6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX -QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx -DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 -Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG -cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS -YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 -OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp -bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp -dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x -18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 -yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI -LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G -A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW -zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT -BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x -GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh -cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV -HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G -CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy -BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j -cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ -YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ -YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 -ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p -00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb -cCOxgN8aIDjnfg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz -MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw -IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR -dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp -li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D -rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ -WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug -F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU -xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC -Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv -dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw -ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl -IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh -c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy -ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI -KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T -KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq -y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p -dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD -VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk -fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 -7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R -cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y -mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW -xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK -SnQ2+Q== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- diff --git a/test/fixture/ca_path/72fa7371.0 b/test/fixture/ca_path/72fa7371.0 deleted file mode 120000 index 208530a..0000000 --- a/test/fixture/ca_path/72fa7371.0 +++ /dev/null @@ -1 +0,0 @@ -verisign.pem \ No newline at end of file diff --git a/test/fixture/ca_path/verisign.pem b/test/fixture/ca_path/verisign.pem deleted file mode 100644 index 2202c69..0000000 --- a/test/fixture/ca_path/verisign.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 -pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 -13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk -U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i -F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY -oJ2daZH9 ------END CERTIFICATE----- diff --git a/test/fixture/cacert.pem b/test/fixture/cacert.pem deleted file mode 100644 index 96282de..0000000 --- a/test/fixture/cacert.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID3DCCAsSgAwIBAgIBADANBgkqhkiG9w0BAQUFADBAMQswCQYDVQQGEwJVUzEJ -MAcGA1UECgwAMRkwFwYDVQQLDBBwb2xhcmZveC1sYXB0b3AKMQswCQYDVQQDDAJD -QTAeFw0wODA0MjkxNTIzNDlaFw0xMzA0MjgxNTIzNDlaMEAxCzAJBgNVBAYTAlVT -MQkwBwYDVQQKDAAxGTAXBgNVBAsMEHBvbGFyZm94LWxhcHRvcAoxCzAJBgNVBAMM -AkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUxEs2y3huzcV+Z9 -VqCJ7CZQn3pE25Gmc+mHyrDfjX65hUsfd0oTWMlGGXHTH3kas25rq4s7iznhLJRM -b4OUAdSjlIdWLQVe/N9i3MuekHKIcNoiKKtN2IDjIdnveMr65p2BaGKPYrwVASWE -tj2T4tLplfWqUYv1TPJBcpLSt1zxlAeXhUn7z5h1gMrN0YUCWwPnz8gEhnMsmW8n -Ev5um8niq8cqC1BDtHtYpKgLNJ5TKG7dnsquX9PIe22xVz936Ga20ScS9VU8QYod -rPjDq9aT4tGqOJVv2HhUPlRqv3pVahxLQoi8fFXOzuCgzYJZFswqo8KijXlQrYfB -7sIU0wIDAQABo4HgMIHdMA8GA1UdEwEB/wQFMAMBAf8wMQYJYIZIAYb4QgENBCQW -IlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOA5 -LUlqCS/CSv0hsB1yVrvE/SfNMA4GA1UdDwEB/wQEAwIBBjBoBgNVHSMEYTBfgBTg -OS1Jagkvwkr9IbAdcla7xP0nzaFEpEIwQDELMAkGA1UEBhMCVVMxCTAHBgNVBAoM -ADEZMBcGA1UECwwQcG9sYXJmb3gtbGFwdG9wCjELMAkGA1UEAwwCQ0GCAQAwDQYJ -KoZIhvcNAQEFBQADggEBAAVa+1G09IwMedFGWGp7mHr8NS+xcXGmQq4g2NsJV0f4 -Aw+K6F7Km65xIUTjO9rfiFmuggT3KeSo/gsRwmRwPRQQWv3Lxv3bvcWyhZ9RMo3V -5PMQRwJnc5cM4CGACjmusK62v36zrtXJlvNM8fGNSn7tF5i+1Wo4hKJoDwIpKN9X -tjg1FfQdUsqnLWCFU50vZFM2UwLJczVk+8TAcd9LfZpakMNY7RbGxL4izhAojTow -M3LieY0bNg9T+8R0A/QtAgImx3SzrLJqKspPZK7cAaXrfvnRQuOzEdTnTloS9VbE -jjwmik9rpqUfcCtTS2gzqhKaR/HJ4nUiiNbT9pwRp68= ------END CERTIFICATE----- diff --git a/test/fixture/cert_localhost.pem b/test/fixture/cert_localhost.pem deleted file mode 100644 index dcb00d6..0000000 --- a/test/fixture/cert_localhost.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDETCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMQswCQYDVQQGEwJVUzEJ -MAcGA1UECgwAMRkwFwYDVQQLDBBwb2xhcmZveC1sYXB0b3AKMQswCQYDVQQDDAJD -QTAeFw0wODA0MjkxNTIzNTBaFw0wOTA0MjkxNTIzNTBaMFQxCzAJBgNVBAYTAlVT -MQkwBwYDVQQKDAAxGTAXBgNVBAsMEHBvbGFyZm94LWxhcHRvcAoxCzAJBgNVBAsM -AkNBMRIwEAYDVQQDDAlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ -AoGBALwjGdTLBORgDSx56V5Pr2eykXmxNeZ6/MG/KZcjHxE8F5v5MWrwqIE1RURv -WGruSh3KNjusP/EeofmHYlgXGMsED5JSVMe9jRH+ewG4dNwcqQPbeGhUE0L3F7Ls -AaR9m9jsDT5ZIu5uNipbbCf3Z7Z3VkDu5RMn0QYt3gP3Y0TTAgMBAAGjgYUwgYIw -DAYDVR0TAQH/BAIwADAxBglghkgBhvhCAQ0EJBYiUnVieS9PcGVuU1NMIEdlbmVy -YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUHoNAq7GhjaikqPHGtiwGCPMoDysw -CwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUA -A4IBAQAgPF1pOQCLFr4YlXzrXV8ieptCNBPMfSjx1V6sxf+1RYhfPabnvV7vaRvj -0WiPdtdUjBTqaDPohHI9ucyrX6CgcPqtmXcH0XxHkPNZB71DIE78DO+DbFtxKt3I -tAEGLooERC1ZFiWbWkCdKFcwfqn+5CoN/PYulWmhwOoHrEeQU41coLHFZZjwPYga -cJSKY4YoCkyYW28MrjMwA4DnGDCgUPENSxZumbW+XEt9IbtZ5eWou9w33BAa33L8 -L6p7CISUJmghVyfVIjVii3fC/CpS6lnL1XB1TNN9P4W3QRJR18gOlXWkPCS7vKF0 -03tfXiG1SDx4vShLX3Go9++cYUVj ------END CERTIFICATE----- diff --git a/test/fixture/common.pem b/test/fixture/common.pem deleted file mode 100644 index 1a05a26..0000000 --- a/test/fixture/common.pem +++ /dev/null @@ -1,48 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIIgTCCB2mgAwIBAgICGuwwDQYJKoZIhvcNAQEFBQAwgeAxCzAJBgNVBAYTAkVT -MS4wLAYJKoZIhvcNAQkBFh9hY19jYW1lcmZpcm1hX2NjQGNhbWVyZmlybWEuY29t -MUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh -bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGTAXBgNV -BAoTEEFDIENhbWVyZmlybWEgU0ExLTArBgNVBAMTJEFDIENhbWVyZmlybWEgQ2Vy -dGlmaWNhZG9zIENhbWVyYWxlczAeFw0wNTA0MDgxMDUxMDBaFw0wOTA0MDcxMDUx -MDBaMIIBsDELMAkGA1UEBhMCRVMxHzAdBgNVBAMTFkNlcnRpZmljYWRvIGRlIFBy -dWViYXMxIjAgBgkqhkiG9w0BCQEWE2luZm9AY2FtZXJmaXJtYS5jb20xEjAQBgNV -BAUTCTEyMzQ1Njc4WjETMBEGA1UEBBMKZGUgUHJ1ZWJhczEUMBIGA1UEKhMLQ2Vy -dGlmaWNhZG8xTjBMBgorBgEEAYGHLh4CEz5DSUYgSVZBIChWQVQgbnVtYmVyIGFz -IGJ5IGFydGljbGUgMjhoIG9mIERpcmVjdGl2ZSA3Ny8zODgvRUVDKTEbMBkGCisG -AQQBgYcuHgMTC0VTQTAwMTIzNDU2MR0wGwYDVQQKExRPIERFTU8gQUMgQ2FtZXJm -aXJtYTEeMBwGA1UECxMVT1UgREVNTyBBQyBDYW1lcmZpcm1hMR0wGwYDVQQMExRU -IERFTU8gQUMgQ2FtZXJmaXJtYTFSMFAGA1UEDRNJQ2hhbWJlcnMgb2YgQ29tbWVy -Y2UgUXVhbGlmaWVkIENlcnRpZmljYXRlOiBOYXR1cmFsIFBlcnNvbiBDQU0tUEYt -U1ctS1BTQzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwmt+Ul58DwnCmPvZ -NiLJ7nXSIGBfb5hFEph7sP4NRFCVzLDOGpzIYTJ9CR+m0LVaUVTXgeLANjw1DEPC -kplWfpQejO4/nPVfRalg2GosrmqnaN3Y1lurnpQGdCz7nLOYJdS1ME52mzau8OFZ -1fSuM+/jHfLvABuwaLXb0OvWlVMCAwEAAaOCA/QwggPwMAwGA1UdEwEB/wQCMAAw -DgYDVR0PAQH/BAQDAgO4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAR -BglghkgBhvhCAQEEBAMCBaAwQgYJYIZIAYb4QgEDBDUWM1VSSTpodHRwOi8vY3Js -LmNhbWVyZmlybWEuY29tL2FjX2NhbWVyZmlybWFfY2MuY2dpPzBGBglghkgBhvhC -AQgEORY3VVJJOmh0dHA6Ly9jcHMuY2FtZXJmaXJtYS5jb20vY3BzL2FjX2NhbWVy -ZmlybWFfY2MuaHRtbDA5BglghkgBhvhCAQ0ELBYqQ2VydGlmaWNhZG8gZGUgcHJ1 -ZWJhcyBzaW4gcmVzcG9uc2FiaWxpZGFkMB0GA1UdDgQWBBS0rINdIfvWilZ+sklt -abvkb9harDB4BggrBgEFBQcBAQRsMGowQAYIKwYBBQUHMAKGNGh0dHA6Ly93d3cu -Y2FtZXJmaXJtYS5jb20vY2VydHMvYWNfY2FtZXJmaXJtYV9jYy5jcnQwJgYIKwYB -BQUHMAGGGmh0dHA6Ly9vY3NwLmNhbWVyZmlybWEuY29tMIGrBgNVHSMEgaMwgaCA -FLYfTp0caJEuN3Jg4UaPWqUqMTG5oYGEpIGBMH8xCzAJBgNVBAYTAkVVMScwJQYD -VQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0 -dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIwIAYDVQQDExlDaGFtYmVycyBvZiBD -b21tZXJjZSBSb290ggEFMHYGA1UdHwRvMG0wNKAyoDCGLmh0dHA6Ly9jcmwuY2Ft -ZXJmaXJtYS5jb20vYWNfY2FtZXJmaXJtYV9jYy5jcmwwNaAzoDGGL2h0dHA6Ly9j -cmwxLmNhbWVyZmlybWEuY29tL2FjX2NhbWVyZmlybWFfY2MuY3JsMB4GA1UdEQQX -MBWBE2luZm9AY2FtZXJmaXJtYS5jb20wKgYDVR0SBCMwIYEfYWNfY2FtZXJmaXJt -YV9jY0BjYW1lcmZpcm1hLmNvbTCBmgYDVR0gBIGSMIGPMIGMBg0rBgEEAYGHLgoJ -AgEBMHswPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2FtZXJmaXJtYS5jb20vY3Bz -L2FjX2NhbWVyZmlybWFfY2MuaHRtbDA4BggrBgEFBQcCAjAsGipDZXJ0aWZpY2Fk -byBkZSBwcnVlYmFzIHNpbiByZXNwb25zYWJpbGlkYWQwLwYIKwYBBQUHAQMEIzAh -MAgGBgQAjkYBATAVBgYEAI5GAQIwCxMDRVVSAgEAAgEBMA0GCSqGSIb3DQEBBQUA -A4IBAQBBfXUkreSi+Zr696+HxCpZmwhko/JmF25C3rECXvZ7L2OXEBELxiygOBpm -hs3EgRRTVA6tdWliPbI9m0Vp61qOYD566ilQspBS7MeGvNQoyyuk43EQakSCNZcl -dE6mqjXl3OT4At57vvJOnlzeidqmrPM2ULfFMBD2K6oce3PelRdOvM8stYEwqpCu -7/jC/F+Y8ZKJTroqOYv5saHozKSooq4QP9Xd1YOFrZlh5oP7B5lpfUmphQwi/+M5 -dUJywr3f+s5aaHlhkoPhNEmuhDK834PT6OekkSFCt3P/MBs71ERvSWgf1GcG+Vcm -f9cJTANAF/i6XDLRAJPsvFkNpMfc ------END CERTIFICATE----- diff --git a/test/fixture/ids_in_subject_rdn_set.pem b/test/fixture/ids_in_subject_rdn_set.pem deleted file mode 100644 index 9e0be47..0000000 --- a/test/fixture/ids_in_subject_rdn_set.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFTDCCBDSgAwIBAgIESx/XYjANBgkqhkiG9w0BAQUFADCBsTELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9ycGEgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDkgRW50cnVzdCwgSW5jLjEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAtIEwxRTAeFw0xMDAxMjExNzU2NDhaFw0xMjAzMDEx -ODI1MzhaMIHxMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG -A1UEBxMNTW91bnRhaW4gVmlldzETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysG -AQQBgjc8AgECEwhEZWxhd2FyZTEgMB4GA1UEChMXQ3liZXJzb3VyY2UgQ29ycG9y -YXRpb24xGzAZBgNVBA8TElYxLjAsIENsYXVzZSA1LihiKTEdMBsGA1UECxMUVGVj -aG5pY2FsIE9wZXJhdGlvbnMxJzAOBgNVBAUTBzI4Mzg5MjEwFQYDVQQDEw5pY3My -d3MuaWMzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJuWvZiS -4PjHFT3uSJIQ4JLHIiMyH6a5UrWv3fvfcrhrzuIpmeZMrQeInVDohU6pWIlfYhgh -/FKXA2uJI2deKZLu0Iw7x45EVNbtt2I0oSoAyvukJ0/4SSWsYbPw2AzKxvMxiDuW -6aWHHVXAZ6XRRg+F8mrH8qyMKsZPPzEn5p6Wgr8W/W0k1jveznxPrXHOqqg8V3uF -gQohMHlyk7ybCFyThbF2Vn3ri21ZZoUSjjU/1J2LWkYpplWkGatkv9R7TRHMsVFK -mZiVCRi1dVK90rq5efaAf28WrweA9reUaigMFfVG0f0QoV9eZ8syqwUBwVqUJaq4 -bAKTQIz75jJ8xKsCAwEAAaOCASgwggEkMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAU -BggrBgEFBQcDAQYIKwYBBQUHAwIwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB -hhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRw -Oi8vY3JsLmVudHJ1c3QubmV0L2xldmVsMWUuY3JsMEEGA1UdIAQ6MDgwNgYKYIZI -AYb6bAoBAjAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3Jw -YTAfBgNVHSMEGDAWgBRbQYqyxEPBvb/IVEFVneCWrf+5oTAdBgNVHQ4EFgQUxwn0 -c2hWU57BkDqWQIHAQMMEW1UwCQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEA -JyyyuN5xhmn60ikyQ38xCEFIglghuteljnKzUDz0++7wSlP/4qkD7/y2dk3dPY1x -BzS4nfAtqlUV6cr2atQZkG12F+qc58o3qTfdh3WSQBk4bhb0kl18hNnOQHWVUQg3 -H728BqwAbuSyal9VAAExdIhIx2l70+g1BiEcEUswfFIZJ7PEkeafmlRmLjhOb8MF -y4JdYmZ82+4lDM5ScME9F/5782cRscYDbn5ODXkMp6YdN3aurMWYYmCRGzkj0UfL -UhGX2EWjEi0PZSJN0dNpckHEu8rxth/4gf6rUEUXXG2yrvUD6t+keelH9LEttyf4 -5b7k0dbmTWmgjkgoi1gqWg== ------END CERTIFICATE----- diff --git a/test/fixture/imaps/cacert.pem b/test/fixture/imaps/cacert.pem deleted file mode 100644 index bd7e68a..0000000 --- a/test/fixture/imaps/cacert.pem +++ /dev/null @@ -1,60 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 9f:dc:f7:94:98:05:43:4c - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org - Validity - Not Before: Dec 23 10:21:33 2010 GMT - Not After : Jan 1 10:21:33 2014 GMT - Subject: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:ce:be:2c:9f:47:ba:db:9c:9c:5b:f0:38:3b:f3: - 74:20:37:76:23:9f:84:1c:81:90:b4:3e:00:20:34: - 98:7e:81:69:50:a1:c3:65:96:ea:fa:00:da:8c:cc: - 53:3f:ba:3c:d0:50:7a:5a:b4:6b:ac:d3:2e:18:ca: - 2a:69:b3:6a:6f:38:c2:32:a8:06:b6:0a:30:a9:ee: - 03:38:e9:05:a5:19:23:54:a8:3c:b9:08:ad:2b:72: - 23:df:93:22:c4:46:a8:ea:f1:a6:e9:30:4a:3f:83: - 39:e9:62:8e:8b:a3:5e:67:89:1d:7c:75:de:05:aa: - 58:b1:b7:79:7c:10:80:6d:87 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 41:C9:49:37:B1:FA:61:E3:BA:D7:19:3D:D9:DA:8C:B9:82:C9:B4:6A - X509v3 Authority Key Identifier: - keyid:41:C9:49:37:B1:FA:61:E3:BA:D7:19:3D:D9:DA:8C:B9:82:C9:B4:6A - - X509v3 Basic Constraints: - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - 86:00:33:b9:dd:ff:5f:83:59:5f:c3:29:3c:d7:11:db:10:b3: - d7:d1:70:fb:0a:c6:74:85:c6:ea:e1:15:c4:92:f8:0e:11:cc: - ff:a6:3c:31:c2:2c:66:d8:fe:63:93:9f:b0:97:e6:f5:bc:5c: - 80:68:96:5d:eb:77:b9:23:dd:68:a7:49:03:ff:22:48:55:f1: - 39:7c:20:21:ff:64:52:e1:f6:cf:3c:b3:4d:2c:5c:03:62:ea: - c5:49:99:07:fa:8d:ff:7b:c2:75:0c:ca:24:b5:0b:f5:b7:57: - 3a:10:f0:8a:bb:9a:e8:92:4d:d5:6f:c2:a2:29:36:61:78:a4: - dc:7b ------BEGIN CERTIFICATE----- -MIIC6DCCAlGgAwIBAgIJAJ/c95SYBUNMMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD -VQQGEwJKUDEQMA4GA1UECAwHU2hpbWFuZTEUMBIGA1UEBwwLTWF0ei1lIGNpdHkx -FzAVBgNVBAoMDlJ1YnkgQ29yZSBUZWFtMRUwEwYDVQQDDAxSdWJ5IFRlc3QgQ0Ex -JTAjBgkqhkiG9w0BCQEWFnNlY3VyaXR5QHJ1YnktbGFuZy5vcmcwHhcNMTAxMjIz -MTAyMTMzWhcNMTQwMTAxMTAyMTMzWjCBjDELMAkGA1UEBhMCSlAxEDAOBgNVBAgM -B1NoaW1hbmUxFDASBgNVBAcMC01hdHotZSBjaXR5MRcwFQYDVQQKDA5SdWJ5IENv -cmUgVGVhbTEVMBMGA1UEAwwMUnVieSBUZXN0IENBMSUwIwYJKoZIhvcNAQkBFhZz -ZWN1cml0eUBydWJ5LWxhbmcub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDOviyfR7rbnJxb8Dg783QgN3Yjn4QcgZC0PgAgNJh+gWlQocNllur6ANqMzFM/ -ujzQUHpatGus0y4Yyipps2pvOMIyqAa2CjCp7gM46QWlGSNUqDy5CK0rciPfkyLE -Rqjq8abpMEo/gznpYo6Lo15niR18dd4Fqlixt3l8EIBthwIDAQABo1AwTjAdBgNV -HQ4EFgQUQclJN7H6YeO61xk92dqMuYLJtGowHwYDVR0jBBgwFoAUQclJN7H6YeO6 -1xk92dqMuYLJtGowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCGADO5 -3f9fg1lfwyk81xHbELPX0XD7CsZ0hcbq4RXEkvgOEcz/pjwxwixm2P5jk5+wl+b1 -vFyAaJZd63e5I91op0kD/yJIVfE5fCAh/2RS4fbPPLNNLFwDYurFSZkH+o3/e8J1 -DMoktQv1t1c6EPCKu5rokk3Vb8KiKTZheKTcew== ------END CERTIFICATE----- diff --git a/test/fixture/imaps/server.crt b/test/fixture/imaps/server.crt deleted file mode 100644 index d848b26..0000000 --- a/test/fixture/imaps/server.crt +++ /dev/null @@ -1,61 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 0 (0x0) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=JP, ST=Shimane, L=Matz-e city, O=Ruby Core Team, CN=Ruby Test CA/emailAddress=security@ruby-lang.org - Validity - Not Before: Dec 23 10:23:52 2010 GMT - Not After : Jan 1 10:23:52 2014 GMT - Subject: C=JP, ST=Shimane, O=Ruby Core Team, OU=Ruby Test, CN=localhost - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:db:75:d0:45:de:b1:df:bf:71:a0:0e:b0:a5:e6: - bc:f4:1c:9d:e5:25:67:64:c5:7b:cb:f1:af:c6:be: - 9a:aa:ea:7e:0f:cc:05:af:ef:40:69:06:b2:c9:13: - 9d:7e:eb:a2:06:e2:ea:7d:07:c7:c7:99:c7:fb:d5: - b8:eb:63:77:62:2b:18:12:c3:53:58:d0:f5:c7:40: - 0c:01:d1:26:82:34:16:09:e3:dc:65:f4:dc:bb:5d: - a5:41:60:e7:a9:74:ba:d7:4c:b6:a3:9c:c5:8c:89: - af:cb:e8:9f:05:fe:ea:fe:64:24:bf:e7:ed:e3:f6: - d0:fc:d6:eb:fc:06:82:10:fb - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - Netscape Comment: - OpenSSL Generated Certificate - X509v3 Subject Key Identifier: - E8:7E:58:AC:13:7B:03:22:8D:9E:AF:32:0B:84:89:80:80:0C:1E:C2 - X509v3 Authority Key Identifier: - keyid:41:C9:49:37:B1:FA:61:E3:BA:D7:19:3D:D9:DA:8C:B9:82:C9:B4:6A - - Signature Algorithm: sha1WithRSAEncryption - ae:ee:cd:fe:c9:af:48:0b:50:37:ac:6a:f6:68:90:9b:67:df: - 6f:2d:17:c9:3c:a5:da:ad:39:dc:2a:5b:07:88:26:38:19:30: - d6:95:cf:10:69:c7:92:14:83:be:f1:b5:8e:6f:d9:91:51:c5: - 63:ae:1c:89:ac:27:bf:4f:2a:8f:4e:0c:57:42:0a:c9:8e:0c: - f4:f3:02:f7:ea:44:b6:e4:47:05:af:4e:74:e4:87:87:d9:c8: - 76:ed:ab:32:7c:f0:31:34:10:14:bc:a6:37:cd:d7:dc:33:da: - 82:d3:d4:9b:e9:d5:cd:38:cc:fa:81:5f:4e:fd:5f:53:05:5d: - 76:f9 ------BEGIN CERTIFICATE----- -MIIC3jCCAkegAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSlAx -EDAOBgNVBAgMB1NoaW1hbmUxFDASBgNVBAcMC01hdHotZSBjaXR5MRcwFQYDVQQK -DA5SdWJ5IENvcmUgVGVhbTEVMBMGA1UEAwwMUnVieSBUZXN0IENBMSUwIwYJKoZI -hvcNAQkBFhZzZWN1cml0eUBydWJ5LWxhbmcub3JnMB4XDTEwMTIyMzEwMjM1MloX -DTE0MDEwMTEwMjM1MlowYDELMAkGA1UEBhMCSlAxEDAOBgNVBAgMB1NoaW1hbmUx -FzAVBgNVBAoMDlJ1YnkgQ29yZSBUZWFtMRIwEAYDVQQLDAlSdWJ5IFRlc3QxEjAQ -BgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23XQ -Rd6x379xoA6wpea89Byd5SVnZMV7y/Gvxr6aqup+D8wFr+9AaQayyROdfuuiBuLq -fQfHx5nH+9W462N3YisYEsNTWND1x0AMAdEmgjQWCePcZfTcu12lQWDnqXS610y2 -o5zFjImvy+ifBf7q/mQkv+ft4/bQ/Nbr/AaCEPsCAwEAAaN7MHkwCQYDVR0TBAIw -ADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUw -HQYDVR0OBBYEFOh+WKwTewMijZ6vMguEiYCADB7CMB8GA1UdIwQYMBaAFEHJSTex -+mHjutcZPdnajLmCybRqMA0GCSqGSIb3DQEBBQUAA4GBAK7uzf7Jr0gLUDesavZo -kJtn328tF8k8pdqtOdwqWweIJjgZMNaVzxBpx5IUg77xtY5v2ZFRxWOuHImsJ79P -Ko9ODFdCCsmODPTzAvfqRLbkRwWvTnTkh4fZyHbtqzJ88DE0EBS8pjfN19wz2oLT -1Jvp1c04zPqBX079X1MFXXb5 ------END CERTIFICATE----- diff --git a/test/fixture/imaps/server.key b/test/fixture/imaps/server.key deleted file mode 100644 index 7c57546..0000000 --- a/test/fixture/imaps/server.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDbddBF3rHfv3GgDrCl5rz0HJ3lJWdkxXvL8a/Gvpqq6n4PzAWv -70BpBrLJE51+66IG4up9B8fHmcf71bjrY3diKxgSw1NY0PXHQAwB0SaCNBYJ49xl -9Ny7XaVBYOepdLrXTLajnMWMia/L6J8F/ur+ZCS/5+3j9tD81uv8BoIQ+wIDAQAB -AoGAGtYHR+P5gFDaxiXFuCPFC1zMeg7e29XCU6gURIteQnQ2QhxCvcbV64HkLu51 -HeYWhB0Pa4aeCWxmpgb2e+JH4MEoIjeJSGyZQeqwkQLgWJDdvkgWx5am58QzA60I -ipkZ9QHcPffSs5RiGx4yfr58KqAmwFphGCY8W7v4LqaENdECQQD9H5VTW9g4gj1c -j3uNYvSI/D7a9P7gfI+ziczuwMm5xsBx3D/t5TAr3SJKNne3sl1E6ZERCUbzxf+C -k58EiHx1AkEA3fRLGqDOq7EcQhbjTcA/v/t5MwlGEUsS9+XrqOWn50YuoIwRZJ3v -qHRQzfQfFNklGtfBvwQ4md3irXjMeGVprwJBAMEAuwiDiHuV+xm/ofKtmE13IKot -ksYy1BOOp/8IawhHXueyi+BmF/PqOkIiA+jCjNGF0oIN89beizPSQbbgJx0CQG/K -qL1bu1ys0y/SeWBi8XkP/0aeaCUzq/UiYCTsrzoEll2UzvnftqMhGsXxLGqCyHaR -r2s3hA6zvIVlL4+AfM8CQQClq+WDrC5VKciLYakZNWJjV1m+H2Ut/0fXdUjKHajE -FWLcsrOhADf6bkTb71GwPxnKRkkRmud5upP0ZYYTqM4X ------END RSA PRIVATE KEY----- diff --git a/test/fixture/key_then_cert.pem b/test/fixture/key_then_cert.pem deleted file mode 100644 index 9e448e0..0000000 --- a/test/fixture/key_then_cert.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDc7Lu/9x5FSdmq2tHkUy7qx+83PchU5iiFY20rWrH2yRBLGfbB -GgmEXimSo2VdNG3QhHgg/Pvr5ZydtJX/z6Yb9NK8h+a5/mHfMS1mkXaM3PXgCLtk -E/Ra91uQYR5nhTg8h8gepnXULXJEld//jYw+rqIWsj7VSPmSm5+sD1RL1wIDAQAB -AoGAf//9S9zOwhBmt/IuV97GOSt78wKt1lq/sYEI2Gyk3bpi4VB6wijmyLWR2q8m -5Jii44RM4bgR8fxIAKuHmP5jW42BMmconeeviMgGGKdnJ+U1kJcO4LuE7dg7RRbk -6nhu56a8R/+ACaiMmqOl4TxpLxVqjho+BjFredn7YBpuRWECQQD2Hl1/DFT1nrFQ -47NW2rTNZGj50J607uFBVevo8daTsbWAlBEvqA63r2+aTkd/TEvJPbIxTXMm7470 -hGJGPRKHAkEA5ctsNnghOKXVvbj41+TUqskwXv7IWTSQ1b/CdOkyoloQQA8YReB/ -3zsfCPSOqiYQIBHytQDw3w9I4FunRW5AMQJAOY0+NcBPeaQjOJQWUsAPuVu6hHg5 -NHwLpniOEsnCcIUEuU1me2tkDaXzhfS6GVVg/2zy5z6CJ9+q4Ri31k7frwJBAJxu -fL4fzU3I5tZ+wzgFWRjiWQFyJGVFuYspPXFlBskq0oEpRXbcO3B1yMzJ3wzJWJTc -YwMBHvhaaVwCSL6lLSECQDSyqJ4CUp6jZcb9oYJs+xymiY954lPlWeSiYLwFWFUB -7yhmFaUAbqscQLpqddS292gyaDbOsIkOBynrJd99b/s= ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDEjCCAfqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEP -MA0GA1UECgwGU2FyaW9uMRQwEgYDVQQLDAtEZXZlbG9wbWVudDENMAsGA1UEAwwE -U3ViMTAeFw0xMDEyMDcwNDM0NTRaFw0xMjEyMDYwNDM0NTRaMFIxCzAJBgNVBAYT -AkpQMQ8wDQYDVQQKDAZTYXJpb24xFDASBgNVBAsMC0RldmVsb3BtZW50MRwwGgYD -VQQDDBNzZXJ2ZXIxLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDc7Lu/9x5FSdmq2tHkUy7qx+83PchU5iiFY20rWrH2yRBLGfbBGgmEXimS -o2VdNG3QhHgg/Pvr5ZydtJX/z6Yb9NK8h+a5/mHfMS1mkXaM3PXgCLtkE/Ra91uQ -YR5nhTg8h8gepnXULXJEld//jYw+rqIWsj7VSPmSm5+sD1RL1wIDAQABo4GFMIGC -MAwGA1UdEwEB/wQCMAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5l -cmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOF3EGASJTlqfvwR6KJlgBdNiPOP -MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUF -AAOCAQEAQC9ZrlG9oayqKQ5HPq0QZVi+w7tb6HtErP39JEr0BsH+Wsja9/SND/bK -VnbjmyiGXnazSPQRHkDWoEV1z8Tq8QwRoA5RgjDD5u1NU1wHQ95Um7NxhMcsjBMo -0J/0dCI99XD8No4epKBWJNbTNB+C/3ZvF8gB/E7o9XNtj/hut6vpOXKRXDNwzz3g -vQYPyKld+aKov9+9+AqXhZkpzVFc3CaKrOiYCnEIRmz6YLeWgN0xrBuqRCIpMNA5 -upUY06kQ9cuj4xpQwfxz8dx9DP6ht+W7bJOAFUGN8VcMca1vkcsQIWYf2Vf4Yrgi -gLfQZXvROdjvHM4atTr0JVEPOEw2yw== ------END CERTIFICATE----- diff --git a/test/fixture/keypair.pem b/test/fixture/keypair.pem deleted file mode 100644 index 05e494a..0000000 --- a/test/fixture/keypair.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAoMKQs2G2GLpdHCp07ZR7fYAim3BcHhx1PM3cscrYLXaVCGqH -PtZLJQDDseuvQur1VMGjHOneUJzsfdXJcRN8WfH9AD5KXJbTpzt134BpqrMhJcov -G4e54oVNzvlQ1P2xwZt7QXYg2hyCIqH6r7wBtaW8g8e5dUGb3vuZW4OC2s/KSKue -71LnqsolKuINt9OTs0R6+4oxyLRIBU/8gG/PD+bnjXB3JUm9/JYOxh4mN3goRhbZ -61kTu6vHI9DcWI3I81rS4hzbvArnBsbmKkQOZRc8YkNqAQtyC+V/0xyv/w5jJXpT -xlT4ZJaUfcO3KtGHvP9JkxT3F4whN5whwdcRxwIDAQABAoIBAQCR7o00iWqoH+UO -AGyMjtFbJ8pCmEjG/MZgH/BLZPvAqXi4XxvOqvEj8gGzrWM3t9pkyjKruJEbVJhJ -0pw+jZXAgK9OXT1bt38CvDNQZF2Hm3xntZX1w8u2GZR8Yk5CStnmCqJk1jsUQ/TO -Q4QxqtVSc9UhO1jbXGeGj5azQDq1LaLDOePfH4XtM/GcoPKtu+Lghx+5JfOVMI+/ -cOcm65cK+APPObySe0x7r6Q45UhFW5q0UMFGaMFfkMauYyzhuliD8BS5XV9gDSGH -Ozr8GDEroGuJr3oTKSMKZg+S8N/8SQ1g4RL9IEZZ6MIIJZrWkqhY7jwY5v1ywrSY -OBE4pNxBAoGBANI30R3WthH/iWq1xyQVQCD1XwxYO66iWk2U0fxhhn/3lSkNTq/a -cIs+2IY9vnXT7yJSY4xHejbmgJmdfNXnjwaKwDvyh/M8fesFNQLPWKufl0l4LPwH -qWlxgcmff1VxtP4xrGSEBG51oo60heqWgRACL+xan98PNUiB113UE9M5AoGBAMPF -VwXMo8RIA+wLPOSUjdWXPusZfzzKCm+NdTYDdoc7F6hVjxzNeU/44bJs5XVxM9JV -EsGjWG9KprgAhzw1gy6UJg8OErF2zf0j/czg8FIB5Cm+ecNsH8pzfBfcRursvGAt -HHVIUyyvODN/kus3dta6CqOj4kd6yKhdcu5wuQz/AoGAaRnbBW4Z7XmzPJTRkarG -OzQyZzud6zvkpjEno2UnF8ey3al3k9hEuHmdS9CG7uYdAy3p83KxGc24shTZGyEA -kya/4bjqW6P82Inr7RG5pWTPAL6CzycNflhvqVyDDzcgZI51QHP4uzk5ItwCsDy7 -HkPZrfPJRn6WB0BTaufjWZECgYEAvIxATu6Tv4QYeusr336Px+neCDHLULHKMTwN -alMVghLQqyiUKAphTzuFrAGjUWQQo/+Zi/OVRcKhJVAk70EeseqvaQqFyHOC2s4i -L4NpEaKOrAGuZh+p0qM9HgHiL3qHxx1Lbk2VBdFQEJFK383QX+hYPNinI27G+Rjf -i3P3VeMCgYBhXO1Tgge4J7UPYRCT7WOsvpXdcZdwOx75fBAR9g7FrPSjiXgYPZlK -TZ1/Gv0c1WGeW4sJ+XdnFexWENh+mdJGmWsMkyPnkRNaAbRqz5Isq+eZcVNSXNEz -QBCT+THNIIPCjkZCdjwXNClVkGfePJ3i3ON43ioyrouex9D5kvU7uA== ------END RSA PRIVATE KEY----- diff --git a/test/fixture/localhost_keypair.pem b/test/fixture/localhost_keypair.pem deleted file mode 100644 index cd2e1a6..0000000 --- a/test/fixture/localhost_keypair.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,A4D3615618A2B1CF - -FPXTNlUO1RcNmNhLp+oNC0JIAInRE7p6OWBBuBGSyfRr891IZnFkGMzxlnZsvHmh -TKTq2rVcN3yHK4bc+6vQkc2JZMp7nB04RHU3vBwy29k7Tyz8Ee+RQwBSOahNfDt+ -mJTArnDidmMcpxb3lCLbuxjM9IqCC4PWaNloCGslZb/qlwNUdAeFdQsiFBrdn2SY -XQySczZnVBzQJv0YjlVJ6guBFtCjnCp8yUaOfIOfOUEgC1hCpjv41tfGDF2+eCiq -4gEVB4D7Wy0s0kFf3icuhxSYcZLavpLa3dg8pG5YhoX9a+M+1164cTo+fbIdMUp7 -zrzIVSWPcgPzypjGPj/Vfo3K6B/XygLhxhL3Nf+3UVixLRERk0yBksLqPDsfifkj -BDzMsD3vI4BteZUsbnae/w+LT3VFP+BrkhTUxvPZMzDlS8KKr50cm9Ubbx1R/beY -uNPx7YyH8oqt70VAciqKL0G2q9DFAfjpqnLaH2toM0vp6iVG4JmI49DFgrV1AHBb -hrn1FcmkhATfEFMbnm+hpadQxnMzPh/YB1yg7yiuicrJdTs5CJQPp5H0ES0AQhlg -dYxGoggTic7T586JIpF9YG1yvrau5kVsbP0kqOfHR6BB7hU1XXvQeIa6GSfZVNZY -zG6u715WH7hrQoXFAGxF6/wd575M2mLQpOWKRKvE/jrsSQHUy4vryQfozaPwPskx -r+vXVZp9T5XiGx9Bm9m0wwTYYIRo2b7KsD5rjY0D0ZhemjPhKy6B89Y2NLYxuF8j -kH0ockiSgexYGvWAkhh/5dxR+zCzqmKI6KFpYPkAfOfuvGqggJ3g2Q== ------END RSA PRIVATE KEY----- diff --git a/test/fixture/max.pem b/test/fixture/max.pem deleted file mode 100644 index 84964fd..0000000 --- a/test/fixture/max.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIE4zCCA8ugAwIBAgIDBbhlMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYDVQQGEwJB -VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp -bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMR4wHAYDVQQLDBVhLXNpZ24tUHJl -bWl1bS1FbmMtMDIxHjAcBgNVBAMMFWEtc2lnbi1QcmVtaXVtLUVuYy0wMjAeFw0w -OTA2MjYwOTExMzZaFw0xNDA2MjYwOTExMzZaMGAxCzAJBgNVBAYTAkFUMRcwFQYD -VQQDDA5NYXggTXVzdGVybWFubjETMBEGA1UEBAwKTXVzdGVybWFubjEMMAoGA1UE -KgwDTWF4MRUwEwYDVQQFEww3NTkzNjIxNTE2MTYwgd8wDQYJKoZIhvcNAQEBBQAD -gc0AMIHJAoHBAO+1eEcrMoYJ2S2iybcqUEzIxKQ9yJJL0XRNQSrKo/bDOBibfQ3H -E/TExiivgdXG2p0UjuPO1NEFgxhT5gtdaLthV2Kuokb+vbp3mWoUGz+uHIILT2zJ -TG6Yz6sooi/ppNIagFx3qAdFes8QMAereZQp0zzphK/a21FTLk0GVHpw+DWn7NRn -ynDVY0XgFkHXS4uHSfZDhzMGXVef3+SJLQzsV8R1ThMYQeoizA7tj6hT3YeBID2E -lh86V1Z8XuznUQIDAQABo4IBsDCCAawwEwYDVR0jBAwwCoAIRyFHjpdh4x4wewYI -KwYBBQUHAQEEbzBtMEIGCCsGAQUFBzAChjZodHRwOi8vd3d3LmEtdHJ1c3QuYXQv -Y2VydHMvYS1zaWduLVByZW1pdW0tRW5jLTAyYS5jcnQwJwYIKwYBBQUHMAGGG2h0 -dHA6Ly9vY3NwLmEtdHJ1c3QuYXQvb2NzcDBNBgNVHSAERjBEMEIGBiooABEBDDA4 -MDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmEtdHJ1c3QuYXQvZG9jcy9jcC9hLXNp -Z24tdG9rZW4wgZoGA1UdHwSBkjCBjzCBjKCBiaCBhoaBg2xkYXA6Ly9sZGFwLmEt -dHJ1c3QuYXQvb3U9YS1zaWduLVByZW1pdW0tRW5jLTAyLG89QS1UcnVzdCxjPUFU -P2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3Q/YmFzZT9vYmplY3RjbGFzcz1laWRD -ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MBEGA1UdDgQKBAhMueHceqw1zzAOBgNVHQ8B -Af8EBAMCBLAwCQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEASLyAbafKFN5h -0Mkk0QQoUl4Uvl+yy2ECe/QWNmDQpd7UCw1UAKrMvR8p6OcBiTnvbvg1HnbWI3Hy -BaEhGAhb1tziWkbV93z1NQCIt8hmdqE7GEp58ptYSuzwev6rgO/RZIxI9FCQn9kJ -ruGTM8hOIkh3QEy7Mq6utquMOEO0hQSUOvZkJdaSqHAoh2I3SzsxGr3juAa61x+0 -K8kW1ZgIsc0jhhb3NOyso48AqDK6oqwfiC6fp/HzSB5gycLllWrgUnMeae6Axbag -dImyOtaoxhIwZCr1tjTaQmaNK49kpvDGlIuDIQHf8uZgAoyduQfAvwiQ0llu5Ns2 -AOs41se+Gg== ------END CERTIFICATE----- diff --git a/test/fixture/purpose/b70a5bc1.0 b/test/fixture/purpose/b70a5bc1.0 deleted file mode 120000 index 1310cfc..0000000 --- a/test/fixture/purpose/b70a5bc1.0 +++ /dev/null @@ -1 +0,0 @@ -cacert.pem \ No newline at end of file diff --git a/test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234 b/test/fixture/purpose/ca/PASSWD_OF_CA_KEY_IS_1234 deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixture/purpose/ca/ca_config.rb b/test/fixture/purpose/ca/ca_config.rb deleted file mode 100644 index 378655e..0000000 --- a/test/fixture/purpose/ca/ca_config.rb +++ /dev/null @@ -1,37 +0,0 @@ -class CAConfig - BASE_DIR = File.dirname(__FILE__) - KEYPAIR_FILE = "#{BASE_DIR}/private/cakeypair.pem" - CERT_FILE = "#{BASE_DIR}/cacert.pem" - SERIAL_FILE = "#{BASE_DIR}/serial" - NEW_CERTS_DIR = "#{BASE_DIR}/newcerts" - NEW_KEYPAIR_DIR = "#{BASE_DIR}/private/keypair_backup" - CRL_DIR = "#{BASE_DIR}/crl" - - NAME = [['C', 'JP'], ['O', 'www.ruby-lang.org'], ['OU', 'development']] - CA_CERT_DAYS = 20 * 365 - CA_RSA_KEY_LENGTH = 2048 - - CERT_DAYS = 18 * 365 - CERT_KEY_LENGTH_MIN = 1024 - CERT_KEY_LENGTH_MAX = 2048 - CDP_LOCATION = nil - OCSP_LOCATION = nil - - CRL_FILE = "#{CRL_DIR}/jruby.crl" - CRL_PEM_FILE = "#{CRL_DIR}/jruby.pem" - CRL_DAYS = 14 - - PASSWD_CB = Proc.new { |flag| - print "Enter password: " - pass = $stdin.gets.chop! - # when the flag is true, this passphrase - # will be used to perform encryption; otherwise it will - # be used to perform decryption. - if flag - print "Verify password: " - pass2 = $stdin.gets.chop! - raise "verify failed." if pass != pass2 - end - pass - } -end diff --git a/test/fixture/purpose/ca/cacert.pem b/test/fixture/purpose/ca/cacert.pem deleted file mode 100644 index 0f85e76..0000000 --- a/test/fixture/purpose/ca/cacert.pem +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBATANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa -MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 -MQswCQYDVQQDDAJDQTAeFw0wOTExMTkxMDI5MjBaFw0yOTExMTQxMDI5MjBaMEwx -CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzEUMBIGA1UE -CwwLZGV2ZWxvcG1lbnQxCzAJBgNVBAMMAkNBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA2nXhXZxXUs1Sfxqi8sReyzPHRcAHQM9RqDAGG9Nt1zYrLXwg -MmUhOr4yBeW2KAxJGxdRQSzI38jyT6mrDRBpTl/OeU9zBG4p6AtFGkoMnRvUonB3 -CvgYJXhmrFjnHn34JNaRSORjaZDBmI9/fMGvaYndEM3wJ2b3jEOeizDIG60kZxA6 -XQ+X7ral+aABsjomubvjEQ9dlcDhQlssKjbjaN3NZ/kL/i/75jc6rzT05XYYkj+Z -9rPRfT+HH3c5EYLtxcRTEHVWXMC8/of7oOFgZwwI3Cx9/v1s2Z6gdJ8J0kIkEoUL -ziYsLIOmVB2tx0rKkmeivJB4PTM5QyHb7d1xUwIDAQABo4HsMIHpMA8GA1UdEwEB -/wQFMAMBAf8wMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQg -Q2VydGlmaWNhdGUwHQYDVR0OBBYEFBOZGvHkAfn+0Ct33rQ6tW2UmF5TMA4GA1Ud -DwEB/wQEAwIBBjB0BgNVHSMEbTBrgBQTmRrx5AH5/tArd960OrVtlJheU6FQpE4w -TDELMAkGA1UEBhMCSlAxGjAYBgNVBAoMEXd3dy5ydWJ5LWxhbmcub3JnMRQwEgYD -VQQLDAtkZXZlbG9wbWVudDELMAkGA1UEAwwCQ0GCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBACfgSl3pA+e3JyjgS/zscaJHHNDwXIIoH0KY6pcrZnl7Zh8CW+Gdba621Lek -aAy0YhAAM9bF87QZG1+sL7B2H1oSTt7F67SwQfq079oNWjhEdV5dxBKk6XaU0R31 -KXSsmLR4pMxcFdPzGM0FTiSj9FNKk2pydVySsa5jJeG0qvXVFMqsRUUwklQHl9Kx -9GZiknt4PEGj/ThUwarhRbRjV5z7ZxXKexkangBlRWPX7TjvlpZPgLzAODG4fiRW -ZUo8Ng7QolTJuPAhlVxhdi9n5hItm6mt21RTpQcP49KoGe8x+T4EzPO0PPdCMliD -fH3udDO+bq2F8H4ts6ZJAYWFo8U= ------END CERTIFICATE----- diff --git a/test/fixture/purpose/ca/newcerts/2_cert.pem b/test/fixture/purpose/ca/newcerts/2_cert.pem deleted file mode 100644 index e957d05..0000000 --- a/test/fixture/purpose/ca/newcerts/2_cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAe6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa -MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 -MQswCQYDVQQDDAJDQTAeFw0wOTExMTkxMDMwMTdaFw0yODExMTQxMDMwMTdaMD0x -CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzESMBAGA1UE -AwwJc3Nsc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgYsazavfR -a72yK4qfnIjOrDT9Uv2ToL4swbE86PXY5N+YvUig3fVmNJo72rT5JlAODs+MtJJU -aJ8HsczlGdrhjTWyT/0fyoY/rC4mi5UFASBCbaoaviDPgbhI6ehBY6d5vEYQOW79 -fL95KIa+OyGzUNYy+EkSxJmvt/8EJYtqIwIDAQABo4GFMIGCMAwGA1UdEwEB/wQC -MAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm -aWNhdGUwHQYDVR0OBBYEFJsUyGU/R4muSKVIeckJElcBNbipMAsGA1UdDwQEAwIF -oDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEAAc49qdDC -TzFoWy794TYEx/uSAFQPMxp/dktYuMvtMSqhOfkDAaX7YFAD40R9tQljm6Vb7uEB -afAecveSyBN2EPZas8NdohJJcTT/pu39E9iMuvAoxz+R8RV7S/RikFOtoet79owa -6lnD3893tz5RR5BloRX7yRii87U5LUdxd3CvEmA7ycNTO8ZEaAuLDitsTMxhPiIJ -DeGW5L8DCyiWuDt9K6S13XdnDxTvYUmafVPU59BncdSoY/3BebappMzDM8QM0yCZ -GWh7ItY4sncMur1fc9ZuSsyplT3d3jysmVXolz2khxboMPVBoRSTtgBOn1PSsVma -FWULbrbYBK5Cqg== ------END CERTIFICATE----- diff --git a/test/fixture/purpose/ca/newcerts/3_cert.pem b/test/fixture/purpose/ca/newcerts/3_cert.pem deleted file mode 100644 index 05a5f62..0000000 --- a/test/fixture/purpose/ca/newcerts/3_cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEDCCAfigAwIBAgIBAzANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa -MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 -MQswCQYDVQQDDAJDQTAeFw0wOTExMTkxMDMwMjdaFw0yODExMTQxMDMwMjdaMD0x -CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzESMBAGA1UE -AwwJc3NsY2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgemBPByEo -KbxaYnHXJxslyYsdWWCKf6j2mVIoxzC0b7W4TS5loBzOkZ05rkuapZ7O5flSMjtH -5NMJ2h7/zsgK5XBkNRCPFK+8HMXVFdSs+euKY+2qE01P0NIuCrkvKjJgsrXdy3sG -2UVUEoYEt5MHDR6aBL0Km+nVKc6T7O+KtQIDAQABo4GPMIGMMAwGA1UdEwEB/wQC -MAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm -aWNhdGUwHQYDVR0OBBYEFOFnq0r6adftxM/7aApl0DDrLTNWMAsGA1UdDwQEAwIF -4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQAD -ggEBACiRGC9KvUP2PaU7JmcIzJHMJtz0mUsO8KJeFWmBCSkfQErF3egOzE47WcRM -0lGy0e4fjJB3at/O2V4RgwkFpsBpGXv9LJ5ZVXkEu9PwzwLTGZ4VfSPNIXgse1lK -9EYOXgL8XhL7c9XPJLRFOWt6Odwp1VjQ2RqkpYLYnsHZam+5gsRd5K2yS0VO8A1Q -otxH1D4evwpoSAaRHSff71Qh7046g2jGvCvdEVqBXuAoOuY8IRvf6YpTKEcPuOOo -t7h5kLIVKuG4/AikVZ62Xh7DjdRFxy/Pxg3uIhrvkHkG8QtEFgBBMHoQR6iSGf6N -1SNrs9tpu1oqTSzoKFG72BsEA6M= ------END CERTIFICATE----- diff --git a/test/fixture/purpose/ca/newcerts/4_cert.pem b/test/fixture/purpose/ca/newcerts/4_cert.pem deleted file mode 100644 index 6961c84..0000000 --- a/test/fixture/purpose/ca/newcerts/4_cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAe6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa -MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 -MQswCQYDVQQDDAJDQTAeFw0xMTEyMTQwNDQxNTNaFw0yOTEyMDkwNDQxNTNaMD0x -CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzESMBAGA1UE -AwwJc3Nsc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgYsazavfR -a72yK4qfnIjOrDT9Uv2ToL4swbE86PXY5N+YvUig3fVmNJo72rT5JlAODs+MtJJU -aJ8HsczlGdrhjTWyT/0fyoY/rC4mi5UFASBCbaoaviDPgbhI6ehBY6d5vEYQOW79 -fL95KIa+OyGzUNYy+EkSxJmvt/8EJYtqIwIDAQABo4GFMIGCMAwGA1UdEwEB/wQC -MAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm -aWNhdGUwHQYDVR0OBBYEFJsUyGU/R4muSKVIeckJElcBNbipMAsGA1UdDwQEAwIF -IDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEArdmTvG5H -elHkiHWp/yFdiIrbUHfDsAmB1jN7Zhte9yWzUuaVKR6GS6FzL4zU6dgAA3UNroVK -MuyeL5Cejsck2+HgOvAtwTJFjP4c8YwdlYuycvMkk5EbaByY1h59ZvV1J+GxmoDA -uO3iTqGrKwrFDK59yuxhdn1yyGTwYTBAdvllfSmTmfnbOkV/faF8gpRvrenx3lLK -eAVhBCzAw2cblXKJEvly+wzAXykS6jagtrnHm5ilt2R5zPzS1wNJlzBq4laI+pZU -timqb2wMA9TLd4FCKqK4HwiUKyAR7eknxtdskQ0/2DBAiOoh1Gl5hwnrDAlb73vA -DDOusxgmoBZS4w== ------END CERTIFICATE----- diff --git a/test/fixture/purpose/ca/private/cakeypair.pem b/test/fixture/purpose/ca/private/cakeypair.pem deleted file mode 100644 index a84ead9..0000000 --- a/test/fixture/purpose/ca/private/cakeypair.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,1381BA5304F6971E - -NmDiHjP3Kn3gG7q0oG8n5nyCM8wp5PYeEpuwrZmnNzpdsTTxpPV2Px8wy9EBrR4k -SeZufUHA7T+zOLc1mSGMm+LOSSV2CMcUnby+yVRuV7CTtw7AwD+et7asff/HU1v6 -GE4SbX0tnZskiAR00zZTN/C17w27HIG7qNHrEjCng/S4fKFVNe6riQbmQqvykYQS -8bZsQzzlB8e8kxNV5EDvYag3oevgY7RpIWUXEwTHd46o+8GsExuhs+8WpiO1az1D -vu0u0MpO5t6PKyafp5vdiLTiwoY8VUdCF627FbyCWFkSuRbYxXNiRZzIvgwtZS7d -wHOr5aVA2ROli2S7W5Mmx00tww05mPdzQbk5q6ZMxD+lK9bIuHEGwBY0IaWjkJtt -a0RyBilLatVE9866D40dmNKA4mzAqtADdq6vwzoEqd7kVdwjdk7EMvaZgACrBypH -NfadJ+HG2TW+4gnZLG60y6YaMPXAbObCUHCUYVhJe/E4mGdSkKOGgiQks9hT448T -+/YBt2TqCq3UQU2rfxLVV6AlD/tywTwPTb0Leu40oTNEQyJ9aaQXmcZHZlDWI+Sl -xdvGule84RenlV+GnC5UlBxUopTKbVSI7tw10grJtz5/TWx7ubOQ4pCNHzxksQH7 -YqygX5F6jlR6GbZFYUozNf57Frh9zUmhc6YWGFeTz1uc6rRqTCrKcyqvRD9QCYPY -P+8MhvztbbYOr+XRStVeuDXzMwS6/HUrlPTt0IvO3Hq9dFDaTg1bW4mzgdKuYotV -VF5DRenkF8lalTFpMppNsfpldazrZ8VvW5qRwbKF4mu7AWsBh9IpZMW15LtI7fUA -L+JQO8aBUq6gyXTzaJxx8kxpdcIRtubOIultptj2m/XPXNNFSsI5DMv7V5jh58sC -ju2RwxwivcWh1XtQxc4RNzvP3/Ek85at+cO9Q74Tu4f8alJZiWT51PZRwaucdQ8y -rYT32rsqoWw1MvkDDENHbEt1QZ7AFmO3zFeGYXbPNHoi2gKzCo7xQtCm+QXQAh7B -87KoKqwS9BO9QA/F+htVW9mbA+Yc5a2vcykxYbGlGqyMleI8cU5AeIbGoZdyYaun -cDX/NtyV3HGPD5aHUPcz/sP7KAbdLzwh72CzRqQQo8yxOmQEWdd7W8jtxt0on2cs -AXj59c9jKRJl5XlXMQO+VWnWO04bWxs8PAgop5Y4ePY766/mL1bAr02kdI6DJ9mx -Opmpqk4gPZpnksnCQWJelPPYad0S49QxbOIWf5bI9FMi+6cgVh76iC5nMGVGI+gw -lS64zEHhSRXuAC9Nsw5d+owc3aCG15DzUjpEBhDJ8EYKP9kgiJU0rnqPqGrriyrb -f6kNOisGvAbI3RldVDLvvZbZEffPu60yA1rP7XaBRPn4K3g+3KTiEcn00wwJaoc3 -rddzmUCbx6fOluN+34BiPdJzHBZsROEvCcT4KGw1/nZIp/GgX3f3nPW40go2RLFP -THQ5L0tuEvyhtJWaiLzjoZ3kCiwWZUzUwYCSfP9raVVXAxLoS4wU+qqKPl6/AaLI -NDgIDJtZ0hrnptZuCkBUzVGQzxpMr8IVK/zQDq8uSXI53heZhLQoww== ------END RSA PRIVATE KEY----- diff --git a/test/fixture/purpose/ca/serial b/test/fixture/purpose/ca/serial deleted file mode 100644 index 5aa937e..0000000 --- a/test/fixture/purpose/ca/serial +++ /dev/null @@ -1 +0,0 @@ -0005 \ No newline at end of file diff --git a/test/fixture/purpose/cacert.pem b/test/fixture/purpose/cacert.pem deleted file mode 100644 index 0f85e76..0000000 --- a/test/fixture/purpose/cacert.pem +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBATANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJKUDEa -MBgGA1UECgwRd3d3LnJ1YnktbGFuZy5vcmcxFDASBgNVBAsMC2RldmVsb3BtZW50 -MQswCQYDVQQDDAJDQTAeFw0wOTExMTkxMDI5MjBaFw0yOTExMTQxMDI5MjBaMEwx -CzAJBgNVBAYTAkpQMRowGAYDVQQKDBF3d3cucnVieS1sYW5nLm9yZzEUMBIGA1UE -CwwLZGV2ZWxvcG1lbnQxCzAJBgNVBAMMAkNBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA2nXhXZxXUs1Sfxqi8sReyzPHRcAHQM9RqDAGG9Nt1zYrLXwg -MmUhOr4yBeW2KAxJGxdRQSzI38jyT6mrDRBpTl/OeU9zBG4p6AtFGkoMnRvUonB3 -CvgYJXhmrFjnHn34JNaRSORjaZDBmI9/fMGvaYndEM3wJ2b3jEOeizDIG60kZxA6 -XQ+X7ral+aABsjomubvjEQ9dlcDhQlssKjbjaN3NZ/kL/i/75jc6rzT05XYYkj+Z -9rPRfT+HH3c5EYLtxcRTEHVWXMC8/of7oOFgZwwI3Cx9/v1s2Z6gdJ8J0kIkEoUL -ziYsLIOmVB2tx0rKkmeivJB4PTM5QyHb7d1xUwIDAQABo4HsMIHpMA8GA1UdEwEB -/wQFMAMBAf8wMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQg -Q2VydGlmaWNhdGUwHQYDVR0OBBYEFBOZGvHkAfn+0Ct33rQ6tW2UmF5TMA4GA1Ud -DwEB/wQEAwIBBjB0BgNVHSMEbTBrgBQTmRrx5AH5/tArd960OrVtlJheU6FQpE4w -TDELMAkGA1UEBhMCSlAxGjAYBgNVBAoMEXd3dy5ydWJ5LWxhbmcub3JnMRQwEgYD -VQQLDAtkZXZlbG9wbWVudDELMAkGA1UEAwwCQ0GCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBACfgSl3pA+e3JyjgS/zscaJHHNDwXIIoH0KY6pcrZnl7Zh8CW+Gdba621Lek -aAy0YhAAM9bF87QZG1+sL7B2H1oSTt7F67SwQfq079oNWjhEdV5dxBKk6XaU0R31 -KXSsmLR4pMxcFdPzGM0FTiSj9FNKk2pydVySsa5jJeG0qvXVFMqsRUUwklQHl9Kx -9GZiknt4PEGj/ThUwarhRbRjV5z7ZxXKexkangBlRWPX7TjvlpZPgLzAODG4fiRW -ZUo8Ng7QolTJuPAhlVxhdi9n5hItm6mt21RTpQcP49KoGe8x+T4EzPO0PPdCMliD -fH3udDO+bq2F8H4ts6ZJAYWFo8U= ------END CERTIFICATE----- diff --git a/test/fixture/purpose/scripts/gen_cert.rb b/test/fixture/purpose/scripts/gen_cert.rb deleted file mode 100755 index 011c2d3..0000000 --- a/test/fixture/purpose/scripts/gen_cert.rb +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env ruby - -require 'openssl' -require 'ca_config' -require 'fileutils' -require 'getopts' - -include OpenSSL - -def usage - myname = File::basename($0) - $stderr.puts "Usage: #{myname} [--type (client|server|ca|ocsp)] [--out certfile] csr_file" - exit -end - -getopts nil, 'type:client', 'out:', 'force' - -cert_type = $OPT_type -out_file = $OPT_out || 'cert.pem' -csr_file = ARGV.shift or usage -ARGV.empty? or usage - -csr = X509::Request.new(File.open(csr_file).read) -unless csr.verify(csr.public_key) - raise "CSR sign verification failed." -end -p csr.public_key -if csr.public_key.n.num_bits < CAConfig::CERT_KEY_LENGTH_MIN - raise "Key length too short" -end -if csr.public_key.n.num_bits > CAConfig::CERT_KEY_LENGTH_MAX - raise "Key length too long" -end -if csr.subject.to_a[0, CAConfig::NAME.size] != CAConfig::NAME - unless $OPT_force - p csr.subject.to_a - p CAConfig::NAME - raise "DN does not match" - end -end - -# Only checks signature here. You must verify CSR according to your CP/CPS. - -$stdout.sync = true - -# CA setup - -ca_file = CAConfig::CERT_FILE -puts "Reading CA cert (from #{ca_file})" -ca = X509::Certificate.new(File.read(ca_file)) - -ca_keypair_file = CAConfig::KEYPAIR_FILE -puts "Reading CA keypair (from #{ca_keypair_file})" -ca_keypair = PKey::RSA.new(File.read(ca_keypair_file), &CAConfig::PASSWD_CB) - -serial = File.open(CAConfig::SERIAL_FILE, "r").read.chomp.hex -File.open(CAConfig::SERIAL_FILE, "w") do |f| - f << sprintf("%04X", serial + 1) -end - -# Generate new cert - -cert = X509::Certificate.new -from = Time.now # + 30 * 60 # Wait 30 minutes. -cert.subject = csr.subject -cert.issuer = ca.subject -cert.not_before = from -cert.not_after = from + CAConfig::CERT_DAYS * 24 * 60 * 60 -cert.public_key = csr.public_key -cert.serial = serial -cert.version = 2 # X509v3 - -basic_constraint = nil -key_usage = [] -ext_key_usage = [] -case cert_type -when "ca" - basic_constraint = "CA:TRUE" - key_usage << "cRLSign" << "keyCertSign" -when "terminalsubca" - basic_constraint = "CA:TRUE,pathlen:0" - key_usage << "cRLSign" << "keyCertSign" -when "server" - basic_constraint = "CA:FALSE" - key_usage << "digitalSignature" << "keyEncipherment" - ext_key_usage << "serverAuth" -when "ocsp" - basic_constraint = "CA:FALSE" - key_usage << "nonRepudiation" << "digitalSignature" - ext_key_usage << "serverAuth" << "OCSPSigning" -when "client" - basic_constraint = "CA:FALSE" - key_usage << "nonRepudiation" << "digitalSignature" << "keyEncipherment" - ext_key_usage << "clientAuth" << "emailProtection" -else - raise "unknonw cert type \"#{cert_type}\" is specified." -end - -ef = X509::ExtensionFactory.new -ef.subject_certificate = cert -ef.issuer_certificate = ca -ex = [] -ex << ef.create_extension("basicConstraints", basic_constraint, true) -ex << ef.create_extension("nsComment","Ruby/OpenSSL Generated Certificate") -ex << ef.create_extension("subjectKeyIdentifier", "hash") -#ex << ef.create_extension("nsCertType", "client,email") -ex << ef.create_extension("keyUsage", key_usage.join(",")) unless key_usage.empty? -#ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") -#ex << ef.create_extension("authorityKeyIdentifier", "keyid:always") -ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) unless ext_key_usage.empty? - -ex << ef.create_extension("crlDistributionPoints", CAConfig::CDP_LOCATION) if CAConfig::CDP_LOCATION -ex << ef.create_extension("authorityInfoAccess", "OCSP;" << CAConfig::OCSP_LOCATION) if CAConfig::OCSP_LOCATION -cert.extensions = ex -cert.sign(ca_keypair, OpenSSL::Digest::SHA1.new) - -# For backup - -cert_file = CAConfig::NEW_CERTS_DIR + "/#{cert.serial}_cert.pem" -File.open(cert_file, "w", 0644) do |f| - f << cert.to_pem -end - -puts "Writing cert.pem..." -FileUtils.copy(cert_file, out_file) - -puts "DONE. (Generated certificate for '#{cert.subject}')" diff --git a/test/fixture/purpose/scripts/gen_csr.rb b/test/fixture/purpose/scripts/gen_csr.rb deleted file mode 100755 index f0b157f..0000000 --- a/test/fixture/purpose/scripts/gen_csr.rb +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env ruby - -require 'getopts' -require 'openssl' - -include OpenSSL - -def usage - myname = File::basename($0) - $stderr.puts < -Date: Tue, 31 Oct 2000 12:00:52 -0600 (Central Standard Time) -From: User1 -To: User2 -Subject: Example 5.3 -Content-Type: application/pkcs7-mime; - name=smime.p7m; - smime-type=enveloped-data -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename=smime.p7m - - -MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEwdDYXJ -sUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAC3EN5nGIiJi2lsGPcP -2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FBs3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadC -DgO8/nUkUNYeNxJtuzubGgzoyEd8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHR -LFf02hosdR8wQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43 -LrY4OxUk660cu1lXeCSFOSOpOJ7FuVyU= diff --git a/test/java/pkcs7_mime_signed.message b/test/java/pkcs7_mime_signed.message deleted file mode 100644 index 438fa59..0000000 --- a/test/java/pkcs7_mime_signed.message +++ /dev/null @@ -1,30 +0,0 @@ -MIME-Version: 1.0 -To: User2@examples.com -From: aliceDss@examples.com -Subject: Example 4.9 -Message-Id: <021031164540300.304@examples.com> -Date: Thu, 31 Oct 2002 16:45:14 -0300 -Content-Type: application/pkcs7-mime; smime-type=signed-data; - name=smime.p7m -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename=smime.p7m - - -MIIDmQYJKoZIhvcNAQcCoIIDijCCA4YCAQExCTAHBgUrDgMCGjAtBgkqhkiG9w0BBwGgIAQ -eDQpUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIIC4DCCAtwwggKboAMCAQICAgDIMA -kGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUzAeFw05OTA4MTcwMTEwNDlaFw0zOTEyM -zEyMzU5NTlaMBMxETAPBgNVBAMTCEFsaWNlRFNTMIIBtjCCASsGByqGSM44BAEwggEeAoGB -AIGNze2D6gqeOT7CSCij5EeT3Q7XqA7sU8WrhAhP/5Thc0h+DNbzREjR/p+vpKGJL+HZMMg -23j+bv7dM3F9piuR10DcMkQiVm96nXvn89J8v3UOoi1TxP7AHCEdNXYjDw7Wz41UIddU5dh -DEeL3/nbCElzfy5FEbteQJllzzflvbAhUA4kemGkVmuBPG2o+4NyErYov3k80CgYAmONAUi -TKqOfs+bdlLWWpMdiM5BAI1XPLLGjDDHlBd3ZtZ4s2qBT1YwHuiNrhuB699ikIlp/R1z0oI -Xks+kPht6pzJIYo7dhTpzi5dowfNI4W4LzABfG1JiRGJNkS9+MiVSlNWteL5c+waYTYfEX/ -Cve3RUP+YdMLRgUpgObo2OQOBhAACgYBc47ladRSWC6l63eM/qeysXty9txMRNKYWiSgRI9 -k0hmd1dRMSPUNbb+VRv/qJ8qIbPiR9PQeNW2PIu0WloErjhdbOBoA/6CN+GvIkq1MauCcNH -u8Iv2YUgFxirGX6FYvxuzTU0pY39mFHssQyhPB+QUD9RqdjTjPypeL08oPluKOBgTB/MAwG -A1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMB8GA1UdIwQYMBaAFHBEPoIub4feStN14z0 -gvEMrk/EfMB0GA1UdDgQWBBS+bKGz48H37UNwpM4TAeL945f+zTAfBgNVHREEGDAWgRRBbG -ljZURTU0BleGFtcGxlLmNvbTAJBgcqhkjOOAQDAzAAMC0CFFUMpBkfQiuJcSIzjYNqtT1na -79FAhUAn2FTUlQLXLLd2ud2HeIQUltDXr0xYzBhAgEBMBgwEjEQMA4GA1UEAxMHQ2FybERT -UwICAMgwBwYFKw4DAhowCQYHKoZIzjgEAwQuMCwCFD1cSW6LIUFzeXle3YI5SKSBer/sAhQ -mCq7s/CTFHOEjgASeUjbMpx5g6A== diff --git a/test/java/pkcs7_multipart_signed.message b/test/java/pkcs7_multipart_signed.message deleted file mode 100644 index c6ce3be..0000000 --- a/test/java/pkcs7_multipart_signed.message +++ /dev/null @@ -1,45 +0,0 @@ -MIME-Version: 1.0 -To: User2@examples.com -From: aliceDss@examples.com -Subject: Example 4.8 -Message-Id: <020906002550300.249@examples.com> -Date: Fri, 06 Sep 2002 00:25:21 -0300 -Content-Type: multipart/signed; - micalg=SHA1; - boundary="----=_NextBoundry____Fri,_06_Sep_2002_00:25:21"; - protocol="application/pkcs7-signature" - - -This is a multi-part message in MIME format. - - -------=_NextBoundry____Fri,_06_Sep_2002_00:25:21 - -This is some sample content. - -------=_NextBoundry____Fri,_06_Sep_2002_00:25:21 -Content-Type: application/pkcs7-mime; name=smime.p7s -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename=smime.p7s - - -MIIDdwYJKoZIhvcNAQcCoIIDaDCCA2QCAQExCTAHBgUrDgMCGjALBgkqhkiG9w0BBwGgggL -gMIIC3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4XDT -k5MDgxNzAxMTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1MwggG2M -IIBKwYHKoZIzjgEATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauECE//lOFz -SH4M1vNESNH+n6+koYkv4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny/dQ6iLVPE -/sAcIR01diMPDtbPjVQh11Tl2EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDiR6YaRWa4E8 -baj7g3IStii/eTzQKBgCY40BSJMqo5+z5t2UtZakx2IzkEAjVc8ssaMMMeUF3dm1nizaoFP -VjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3qnMkhijt2FOnOLl2jB80jhbgvMAF8bUmJEYk2 -RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGBSmA5ujY5A4GEAAKBgFzjuVp1FJYLqXr -d4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/+onyohs+JH09B41bY8i7RaWgSu -OF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTSljf2YUeyxDKE8H5BQP1Gp -2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBsAwHwYDVR0j -BBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sobPjwfftQ3CkzhMB4v3 -jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkGByqGSM44BAMDMAAwLQ -IUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4hBSW0NevTFjMGECAQEwG -DASMRAwDgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGjAJBgcqhkjOOAQDBC4wLAIUM/mG -f6gkgp9Z0XtRdGimJeB/BxUCFGFFJqwYRt1WYcIOQoGiaowqGzVI - - -------=_NextBoundry____Fri,_06_Sep_2002_00:25:21-- diff --git a/test/java/test_java_attribute.rb b/test/java/test_java_attribute.rb deleted file mode 100644 index 95bd412..0000000 --- a/test/java/test_java_attribute.rb +++ /dev/null @@ -1,25 +0,0 @@ -module PKCS7Test - class TestJavaAttribute < Test::Unit::TestCase - def test_attributes - val = ASN1::OctetString.new("foo".to_java_bytes) - val2 = ASN1::OctetString.new("bar".to_java_bytes) - attr = Attribute.create(123, 444, val) - assert_raise NoMethodError do - attr.type = 12 - end - assert_raise NoMethodError do - attr.value = val2 - end - - assert_equal 123, attr.type - assert_equal val, attr.set.get(0) - - attr2 = Attribute.create(123, 444, val) - - assert_equal attr, attr2 - - assert_not_equal Attribute.create(124, 444, val), attr - assert_not_equal Attribute.create(123, 444, val2), attr - end - end -end diff --git a/test/java/test_java_bio.rb b/test/java/test_java_bio.rb deleted file mode 100644 index a01eb4a..0000000 --- a/test/java/test_java_bio.rb +++ /dev/null @@ -1,42 +0,0 @@ -module PKCS7Test - class TestJavaBIO < Test::Unit::TestCase - def test_string_bio_simple - bio = BIO::from_string("abc") - arr = Java::byte[20].new - read = bio.gets(arr, 10) - assert_equal 3, read - assert_equal "abc".to_java_bytes.to_a, arr.to_a[0...read] - end - - def test_string_bio_simple_with_newline - bio = BIO::from_string("abc\n") - arr = Java::byte[20].new - read = bio.gets(arr, 10) - assert_equal 4, read - assert_equal "abc\n".to_java_bytes.to_a, arr.to_a[0...read] - end - - def test_string_bio_simple_with_newline_and_more_data - bio = BIO::from_string("abc\nfoo\n\nbar") - arr = Java::byte[20].new - read = bio.gets(arr, 10) - assert_equal 4, read - assert_equal "abc\n".to_java_bytes.to_a, arr.to_a[0...read] - - read = bio.gets(arr, 10) - assert_equal 4, read - assert_equal "foo\n".to_java_bytes.to_a, arr.to_a[0...read] - - read = bio.gets(arr, 10) - assert_equal 1, read - assert_equal "\n".to_java_bytes.to_a, arr.to_a[0...read] - - read = bio.gets(arr, 10) - assert_equal 3, read - assert_equal "bar".to_java_bytes.to_a, arr.to_a[0...read] - - read = bio.gets(arr, 10) - assert_equal 0, read - end - end -end diff --git a/test/java/test_java_mime.rb b/test/java/test_java_mime.rb deleted file mode 100644 index 93e2831..0000000 --- a/test/java/test_java_mime.rb +++ /dev/null @@ -1,173 +0,0 @@ -module PKCS7Test - class TestJavaMime < Test::Unit::TestCase - def test_find_header_returns_null_on_nonexisting_header - headers = [] - assert_nil Mime::DEFAULT.find_header(headers, "foo") - - headers = [MimeHeader.new("blarg", "bluff")] - assert_nil Mime::DEFAULT.find_header(headers, "foo") - end - - def test_find_header_returns_the_header_with_the_same_name - hdr = MimeHeader.new("one", "two") - assert_equal hdr, Mime::DEFAULT.find_header([hdr], "one") - end - - def test_find_param_returns_null_on_nonexisting_param - assert_nil Mime::DEFAULT.find_param(MimeHeader.new("one", "two", []), "foo") - assert_nil Mime::DEFAULT.find_param(MimeHeader.new("one", "two", [MimeParam.new("hi", "ho")]), "foo") - end - - def test_find_param_returns_the_param_with_the_same_name - par = MimeParam.new("hox", "box") - hdr = MimeHeader.new("one", "two", [par]) - assert_equal par, Mime::DEFAULT.find_param(hdr, "hox") - end - - def test_simple_parse_headers - bio = BIO::from_string("Foo: bar") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers2 - bio = BIO::from_string("Foo:bar") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers3 - bio = BIO::from_string("Foo: bar") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers4 - bio = BIO::from_string("Foo: bar\n") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers5 - bio = BIO::from_string(" Foo : bar \n") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - - def test_simple_parse_headers6 - bio = BIO::from_string("Foo: bar;\n") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers7 - bio = BIO::from_string("Foo: bar;\nFlurg: blarg") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 2, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal MimeHeader.new("Flurg", "blarg"), result[1] - assert_equal "foo", result[0].name - assert_equal "flurg", result[1].name - end - - def test_simple_parse_headers_quotes - bio = BIO::from_string("Foo: \"bar\"") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "bar"), result[0] - assert_equal "foo", result[0].name - end - - def test_simple_parse_headers_comment - bio = BIO::from_string("Foo: (this is the right thing)ba(and this is the wrong one)r") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - assert_equal MimeHeader.new("Foo", "(this is the right thing)ba(and this is the wrong one)r"), result[0] - assert_equal "foo", result[0].name - end - - def test_parse_headers_with_param - bio = BIO::from_string("Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - header = result[0] - assert_equal "content-type", header.name - assert_equal "multipart/related", header.value - assert_equal [MimeParam.new("boundary","MIME_boundary"), - MimeParam.new("type","text/xml")], header.params.to_a - end - - def test_parse_headers_with_param_newline - bio = BIO::from_string("Content-Type: Multipart/Related\n boundary=MIME_boundary; type=text/xml") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - header = result[0] - assert_equal "content-type", header.name - assert_equal "multipart/related", header.value - assert_equal [MimeParam.new("boundary","MIME_boundary"), - MimeParam.new("type","text/xml")], header.params.to_a - end - - def test_parse_headers_with_param_newline_and_semicolon - bio = BIO::from_string("Content-Type: Multipart/Related;\n boundary=MIME_boundary;\n Type=text/xml") - result = Mime::DEFAULT.parse_headers(bio) - assert_equal 1, result.size - header = result[0] - assert_equal "content-type", header.name - assert_equal "multipart/related", header.value - assert_equal [MimeParam.new("boundary","MIME_boundary"), - MimeParam.new("type","text/xml")], header.params.to_a - end - - def test_advanced_mime_message - bio = BIO::from_string(MultipartSignedString) - result = Mime::DEFAULT.parse_headers(bio) - - assert_equal "mime-version", result[0].name - assert_equal "1.0", result[0].value - - assert_equal "to", result[1].name - assert_equal "user2@examples.com", result[1].value - - assert_equal "from", result[2].name - assert_equal "alicedss@examples.com", result[2].value - - assert_equal "subject", result[3].name - assert_equal "example 4.8", result[3].value - - assert_equal "message-id", result[4].name - assert_equal "<020906002550300.249@examples.com>", result[4].value - - assert_equal "date", result[5].name - assert_equal "fri, 06 sep 2002 00:25:21 -0300", result[5].value - - assert_equal "content-type", result[6].name - assert_equal "multipart/signed", result[6].value - - assert_equal "micalg", result[6].params[0].param_name - assert_equal "SHA1", result[6].params[0].param_value - - assert_equal "boundary", result[6].params[1].param_name - assert_equal "----=_NextBoundry____Fri,_06_Sep_2002_00:25:21", result[6].params[1].param_value - - assert_equal "protocol", result[6].params[2].param_name - assert_equal "application/pkcs7-signature", result[6].params[2].param_value - - assert_equal 3, result[6].params.length - assert_equal 7, result.length - end - end -end diff --git a/test/java/test_java_pkcs7.rb b/test/java/test_java_pkcs7.rb deleted file mode 100644 index ab22f61..0000000 --- a/test/java/test_java_pkcs7.rb +++ /dev/null @@ -1,772 +0,0 @@ -module PKCS7Test - class TestJavaPKCS7 < Test::Unit::TestCase - def test_is_signed - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - assert p7.signed? - assert !p7.encrypted? - assert !p7.enveloped? - assert !p7.signed_and_enveloped? - assert !p7.data? - assert !p7.digest? - end - - def test_is_encrypted - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert !p7.signed? - assert p7.encrypted? - assert !p7.enveloped? - assert !p7.signed_and_enveloped? - assert !p7.data? - assert !p7.digest? - end - - def test_is_enveloped - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert !p7.signed? - assert !p7.encrypted? - assert p7.enveloped? - assert !p7.signed_and_enveloped? - assert !p7.data? - assert !p7.digest? - end - - def test_is_signed_and_enveloped - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - assert !p7.signed? - assert !p7.encrypted? - assert !p7.enveloped? - assert p7.signed_and_enveloped? - assert !p7.data? - assert !p7.digest? - end - - def test_is_data - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert !p7.signed? - assert !p7.encrypted? - assert !p7.enveloped? - assert !p7.signed_and_enveloped? - assert p7.data? - assert !p7.digest? - end - - def test_is_digest - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert !p7.signed? - assert !p7.encrypted? - assert !p7.enveloped? - assert !p7.signed_and_enveloped? - assert !p7.data? - assert p7.digest? - end - - def test_set_detached - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - sign = Signed.new - p7.sign = sign - - test_p7 = PKCS7.new - test_p7.type = ASN1Registry::NID_pkcs7_data - test_p7.data = ASN1::OctetString.new("foo".to_java_bytes) - sign.contents = test_p7 - - p7.detached = 2 - assert_equal 1, p7.get_detached - assert_equal nil, test_p7.get_data - end - - def test_set_not_detached - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - sign = Signed.new - p7.sign = sign - - test_p7 = PKCS7.new - test_p7.type = ASN1Registry::NID_pkcs7_data - data = ASN1::OctetString.new("foo".to_java_bytes) - test_p7.data = data - sign.contents = test_p7 - - p7.detached = 0 - assert_equal 0, p7.get_detached - assert_equal data, test_p7.get_data - end - - def test_is_detached - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - sign = Signed.new - p7.sign = sign - - test_p7 = PKCS7.new - test_p7.type = ASN1Registry::NID_pkcs7_data - data = ASN1::OctetString.new("foo".to_java_bytes) - test_p7.data = data - sign.contents = test_p7 - - p7.detached = 1 - assert p7.detached? - end - - def test_is_detached_with_wrong_type - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - - assert !p7.detached? - end - - def _test_encrypt_generates_enveloped_PKCS7_object - p7 = PKCS7.encrypt([], "".to_java_bytes, nil, 0) - assert !p7.signed? - assert !p7.encrypted? - assert p7.enveloped? - assert !p7.signed_and_enveloped? - assert !p7.data? - assert !p7.digest? - end - - def test_set_type_throws_exception_on_wrong_argument - assert_raise NativeException do - # 42 is a value that is not one of the valid NID's for type - PKCS7.new.type = 42 - end - end - - def test_set_type_signed - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - assert p7.signed? - assert_equal 1, p7.get_sign.version - - assert_nil p7.get_data - assert_nil p7.get_enveloped - assert_nil p7.get_signed_and_enveloped - assert_nil p7.get_digest - assert_nil p7.get_encrypted - assert_nil p7.get_other - end - - def test_set_type_data - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - - assert p7.data? - assert_equal ASN1::OctetString.new("".to_java_bytes), p7.get_data - - assert_nil p7.get_sign - assert_nil p7.get_enveloped - assert_nil p7.get_signed_and_enveloped - assert_nil p7.get_digest - assert_nil p7.get_encrypted - assert_nil p7.get_other - end - - def test_set_type_signed_and_enveloped - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - - assert p7.signed_and_enveloped? - assert_equal 1, p7.get_signed_and_enveloped.version - assert_equal ASN1Registry::NID_pkcs7_data, p7.get_signed_and_enveloped.enc_data.content_type - - assert_nil p7.get_sign - assert_nil p7.get_enveloped - assert_nil p7.get_data - assert_nil p7.get_digest - assert_nil p7.get_encrypted - assert_nil p7.get_other - end - - def test_set_type_enveloped - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - - assert p7.enveloped? - assert_equal 0, p7.get_enveloped.version - assert_equal ASN1Registry::NID_pkcs7_data, p7.get_enveloped.enc_data.content_type - - assert_nil p7.get_sign - assert_nil p7.get_signed_and_enveloped - assert_nil p7.get_data - assert_nil p7.get_digest - assert_nil p7.get_encrypted - assert_nil p7.get_other - end - - def test_set_type_encrypted - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - - assert p7.encrypted? - assert_equal 0, p7.get_encrypted.version - assert_equal ASN1Registry::NID_pkcs7_data, p7.get_encrypted.enc_data.content_type - - assert_nil p7.get_sign - assert_nil p7.get_signed_and_enveloped - assert_nil p7.get_data - assert_nil p7.get_digest - assert_nil p7.get_enveloped - assert_nil p7.get_other - end - - def test_set_type_digest - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - - assert p7.digest? - assert_equal 0, p7.get_digest.version - - assert_nil p7.get_sign - assert_nil p7.get_signed_and_enveloped - assert_nil p7.get_data - assert_nil p7.get_encrypted - assert_nil p7.get_enveloped - assert_nil p7.get_other - end - - def test_set_cipher_on_non_enveloped_object - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - - assert_raise NativeException do - p7.cipher = nil - end - - p7.type = ASN1Registry::NID_pkcs7_encrypted - - assert_raise NativeException do - p7.cipher = nil - end - - p7.type = ASN1Registry::NID_pkcs7_data - - assert_raise NativeException do - p7.cipher = nil - end - - p7.type = ASN1Registry::NID_pkcs7_signed - - assert_raise NativeException do - p7.cipher = nil - end - end - - def test_set_cipher_on_enveloped_object - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - - c = javax.crypto.Cipher.getInstance("RSA") - cipher = CipherSpec.new(c, "RSA", 128) - - p7.cipher = cipher - - assert_equal cipher, p7.get_enveloped.enc_data.cipher - end - - - def test_set_cipher_on_signedAndEnveloped_object - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - - c = javax.crypto.Cipher.getInstance("RSA") - cipher = CipherSpec.new(c, "RSA", 128) - - p7.cipher = cipher - - assert_equal cipher, p7.get_signed_and_enveloped.enc_data.cipher - end - - def test_add_recipient_info_to_something_that_cant_have_recipients - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - assert_raise NativeException do - p7.add_recipient(X509Cert) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.add_recipient(X509Cert) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.add_recipient(X509Cert) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert_raise NativeException do - p7.add_recipient(X509Cert) - end - end - - def test_add_recipient_info_to_enveloped_should_add_that_to_stack - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - - ri = p7.add_recipient(X509Cert) - - assert_equal 1, p7.get_enveloped.recipient_info.size - assert_equal ri, p7.get_enveloped.recipient_info.iterator.next - end - - - def test_add_recipient_info_to_signedAndEnveloped_should_add_that_to_stack - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - - ri = p7.add_recipient(X509Cert) - - assert_equal 1, p7.get_signed_and_enveloped.recipient_info.size - assert_equal ri, p7.get_signed_and_enveloped.recipient_info.iterator.next - end - - def test_add_signer_to_something_that_cant_have_signers - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_raise NativeException do - p7.add_signer(SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil)) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.add_signer(SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil)) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.add_signer(SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil)) - end - - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert_raise NativeException do - p7.add_signer(SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil)) - end - end - - def test_add_signer_to_signed_should_add_that_to_stack - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - si = SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil) - p7.add_signer(si) - - assert_equal 1, p7.get_sign.signer_info.size - assert_equal si, p7.get_sign.signer_info.iterator.next - end - - - def test_add_signer_to_signedAndEnveloped_should_add_that_to_stack - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - - si = SignerInfoWithPkey.new(nil, nil, nil, nil, nil, nil, nil) - p7.add_signer(si) - - assert_equal 1, p7.get_signed_and_enveloped.signer_info.size - assert_equal si, p7.get_signed_and_enveloped.signer_info.iterator.next - end - - def create_signer_info_with_algo(algo) - md5 = AlgorithmIdentifier.new(ASN1Registry.nid2obj(4)) - SignerInfoWithPkey.new(DERInteger.new(BigInteger::ONE), - IssuerAndSerialNumber.new(X509Name.new("C=SE"), DERInteger.new(BigInteger::ONE)), - algo, - DERSet.new, - md5, - DEROctetString.new([].to_java(:byte)), - DERSet.new) - end - - def test_add_signer_to_signed_with_new_algo_should_add_that_algo_to_the_algo_list - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - - # YES, these numbers are correct. Don't change them. They are OpenSSL internal NIDs - md5 = AlgorithmIdentifier.new(ASN1Registry.nid2obj(4)) - md4 = AlgorithmIdentifier.new(ASN1Registry.nid2obj(5)) - - si = create_signer_info_with_algo(md5) - p7.add_signer(si) - - assert_equal md5, p7.get_sign.md_algs.iterator.next - assert_equal 1, p7.get_sign.md_algs.size - - si = create_signer_info_with_algo(md5) - p7.add_signer(si) - - assert_equal md5, p7.get_sign.md_algs.iterator.next - assert_equal 1, p7.get_sign.md_algs.size - - si = create_signer_info_with_algo(md4) - p7.add_signer(si) - - assert_equal 2, p7.get_sign.md_algs.size - assert p7.get_sign.md_algs.contains(md4) - assert p7.get_sign.md_algs.contains(md5) - end - - - def test_add_signer_to_signedAndEnveloped_with_new_algo_should_add_that_algo_to_the_algo_list - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - - # YES, these numbers are correct. Don't change them. They are OpenSSL internal NIDs - md5 = AlgorithmIdentifier.new(ASN1Registry.nid2obj(4)) - md4 = AlgorithmIdentifier.new(ASN1Registry.nid2obj(5)) - - si = create_signer_info_with_algo(md5) - p7.add_signer(si) - - assert_equal md5, p7.get_signed_and_enveloped.md_algs.iterator.next - assert_equal 1, p7.get_signed_and_enveloped.md_algs.size - - si = create_signer_info_with_algo(md5) - p7.add_signer(si) - - assert_equal md5, p7.get_signed_and_enveloped.md_algs.iterator.next - assert_equal 1, p7.get_signed_and_enveloped.md_algs.size - - si = create_signer_info_with_algo(md4) - p7.add_signer(si) - - assert_equal 2, p7.get_signed_and_enveloped.md_algs.size - assert p7.get_signed_and_enveloped.md_algs.contains(md4) - assert p7.get_signed_and_enveloped.md_algs.contains(md5) - end - - def test_set_content_on_data_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.setContent(PKCS7.new) - end - end - - def test_set_content_on_enveloped_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_raise NativeException do - p7.setContent(PKCS7.new) - end - end - - def test_set_content_on_signedAndEnveloped_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - assert_raise NativeException do - p7.setContent(PKCS7.new) - end - end - - def test_set_content_on_encrypted_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.setContent(PKCS7.new) - end - end - - def test_set_content_on_signed_sets_the_content - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - p7new = PKCS7.new - p7.setContent(p7new) - - assert_equal p7new, p7.get_sign.contents - end - - def test_set_content_on_digest_sets_the_content - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - p7new = PKCS7.new - p7.setContent(p7new) - - assert_equal p7new, p7.get_digest.contents - end - - def test_get_signer_info_on_digest_returns_null - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert_nil p7.signer_info - end - - def test_get_signer_info_on_data_returns_null - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_nil p7.signer_info - end - - def test_get_signer_info_on_encrypted_returns_null - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_nil p7.signer_info - end - - def test_get_signer_info_on_enveloped_returns_null - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_nil p7.signer_info - end - - def test_get_signer_info_on_signed_returns_signer_info - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - assert_equal p7.get_sign.signer_info.object_id, p7.signer_info.object_id - end - - def test_get_signer_info_on_signedAndEnveloped_returns_signer_info - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - assert_equal p7.get_signed_and_enveloped.signer_info.object_id, p7.signer_info.object_id - end - - def test_content_new_on_data_raises_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.content_new(ASN1Registry::NID_pkcs7_data) - end - end - - def test_content_new_on_encrypted_raises_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.content_new(ASN1Registry::NID_pkcs7_data) - end - end - - def test_content_new_on_enveloped_raises_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_raise NativeException do - p7.content_new(ASN1Registry::NID_pkcs7_data) - end - end - - def test_content_new_on_signedAndEnveloped_raises_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - assert_raise NativeException do - p7.content_new(ASN1Registry::NID_pkcs7_data) - end - end - - def test_content_new_on_digest_creates_new_content - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - p7.content_new(ASN1Registry::NID_pkcs7_signedAndEnveloped) - assert p7.get_digest.contents.signed_and_enveloped? - - p7.content_new(ASN1Registry::NID_pkcs7_encrypted) - assert p7.get_digest.contents.encrypted? - end - - def test_content_new_on_signed_creates_new_content - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - p7.content_new(ASN1Registry::NID_pkcs7_signedAndEnveloped) - assert p7.get_sign.contents.signed_and_enveloped? - - p7.content_new(ASN1Registry::NID_pkcs7_encrypted) - assert p7.get_sign.contents.encrypted? - end - - - def test_add_certificate_on_data_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.add_certificate(X509Cert) - end - end - - def test_add_certificate_on_enveloped_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_raise NativeException do - p7.add_certificate(X509Cert) - end - end - - def test_add_certificate_on_encrypted_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.add_certificate(X509Cert) - end - end - - def test_add_certificate_on_digest_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert_raise NativeException do - p7.add_certificate(X509Cert) - end - end - - def test_add_certificate_on_signed_adds_the_certificate - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - p7.add_certificate(X509Cert) - assert_equal 1, p7.get_sign.cert.size - assert_equal X509Cert, p7.get_sign.cert.iterator.next - end - - def test_add_certificate_on_signedAndEnveloped_adds_the_certificate - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - p7.add_certificate(X509Cert) - assert_equal 1, p7.get_signed_and_enveloped.cert.size - assert_equal X509Cert, p7.get_signed_and_enveloped.cert.get(0) - end - - def test_add_crl_on_data_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_data - assert_raise NativeException do - p7.add_crl(X509CRL) - end - end - - def test_add_crl_on_enveloped_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_enveloped - assert_raise NativeException do - p7.add_crl(X509CRL) - end - end - - def test_add_crl_on_encrypted_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_encrypted - assert_raise NativeException do - p7.add_crl(X509CRL) - end - end - - def test_add_crl_on_digest_throws_exception - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_digest - assert_raise NativeException do - p7.add_crl(X509CRL) - end - end - - def test_add_crl_on_signed_adds_the_crl - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signed - p7.add_crl(X509CRL) - assert_equal 1, p7.get_sign.crl.size - assert_equal X509CRL, p7.get_sign.crl.iterator.next - end - - def test_add_crl_on_signedAndEnveloped_adds_the_crl - p7 = PKCS7.new - p7.type = ASN1Registry::NID_pkcs7_signedAndEnveloped - p7.add_crl(X509CRL) - assert_equal 1, p7.get_signed_and_enveloped.crl.size - assert_equal X509CRL, p7.get_signed_and_enveloped.crl.get(0) - end - - EXISTING_PKCS7_DEF = "0\202\002 \006\t*\206H\206\367\r\001\a\003\240\202\002\0210\202\002\r\002\001\0001\202\001\2700\201\331\002\001\0000B0=1\0230\021\006\n\t\222&\211\223\362,d\001\031\026\003org1\0310\027\006\n\t\222&\211\223\362,d\001\031\026\truby-lang1\v0\t\006\003U\004\003\f\002CA\002\001\0020\r\006\t*\206H\206\367\r\001\001\001\005\000\004\201\200\213kF\330\030\362\237\363$\311\351\207\271+_\310sr\344\233N\200\233)\272\226\343\003\224OOf\372 \r\301{\206\367\241\270\006\240\254\3179F\232\231Q\232\225\347\373\233\032\375\360\035o\371\275p\306\v5Z)\263\037\302|\307\300\327\a\375\023G'Ax\313\346\261\254\227K\026\364\242\337\367\362rk\276\023\217m\326\343F\366I1\263\nLuNf\234\203\261\300\030\232Q\277\231\f0\030\001\332\021\0030\201\331\002\001\0000B0=1\0230\021\006\n\t\222&\211\223\362,d\001\031\026\003org1\0310\027\006\n\t\222&\211\223\362,d\001\031\026\truby-lang1\v0\t\006\003U\004\003\f\002CA\002\001\0030\r\006\t*\206H\206\367\r\001\001\001\005\000\004\201\200\215\223\3428\2440]\0278\016\230,\315\023Tg\325`\376~\353\304\020\243N{\326H\003\005\361q\224OI\310\2324-\341?\355&r\215\233\361\245jF\255R\271\203D\304v\325\265\243\321$\bSh\031i\eS\240\227\362\221\364\232\035\202\f?x\031\223D\004ZHD\355'g\243\037\236mJ\323\210\347\274m\324-\351\332\353#A\273\002\"h\aM\202\347\236\265\aI$@\240bt=<\212\2370L\006\t*\206H\206\367\r\001\a\0010\035\006\t`\206H\001e\003\004\001\002\004\020L?\325\372\\\360\366\372\237|W\333nnI\255\200 \253\234\252\263\006\335\037\320\350{s\352r\337\304\305\216\223k\003\376f\027_\201\035#*\002yM\334" - - EXISTING_PKCS7_1 = PKCS7::from_asn1(ASN1InputStream.new(EXISTING_PKCS7_DEF.to_java_bytes).read_object) - - def test_encrypt_integration_test - certs = [X509Cert] - c = Cipher.get_instance("AES", BCP.new) - cipher = CipherSpec.new(c, "AES-128-CBC", 128) - data = "aaaaa\nbbbbb\nccccc\n".to_java_bytes - PKCS7::encrypt(certs, data, cipher, PKCS7::BINARY) -# puts -# puts PKCS7::encrypt(certs, data, cipher, PKCS7::BINARY) -# puts -# puts EXISTING_PKCS7_1 - end - - EXISTING_PKCS7_PEM = < e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_MIME_PARSE_ERROR, e.cause.get_reason - end - end - - def test_read_pkcs7_should_raise_error_when_content_type_is_not_there - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(nil) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - assert false - rescue PKCS7Exception => e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_NO_CONTENT_TYPE, e.cause.get_reason - end - - - - - mime = Mime.new - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(MimeHeader.new("content-type", nil)) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - assert false - rescue PKCS7Exception => e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_NO_CONTENT_TYPE, e.cause.get_reason - end - end - - def test_read_pkcs7_should_set_the_second_arguments_contents_to_null_if_its_there - mime = Mime.new - mime.stubs(:parseHeaders).raises("getOutOfJailForFree") - - bio2 = BIO.new - arr = [bio2].to_java BIO - - begin - SMIME.new(mime).readPKCS7(nil, arr) - rescue - end - - assert_nil arr[0] - - - arr = [bio2, bio2].to_java BIO - begin - SMIME.new(mime).readPKCS7(nil, arr) - rescue - end - - assert_nil arr[0] - assert_equal bio2, arr[1] - end - - def test_read_pkcs7_should_call_methods_on_mime - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(MimeHeader.new("content-type", "application/pkcs7-mime")) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - rescue java.lang.UnsupportedOperationException - # This error is expected, since the bio used is not a real one - end - end - - def test_read_pkcs7_throws_correct_exception_if_wrong_content_type - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(MimeHeader.new("content-type", "foo")) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - assert false - rescue PKCS7Exception => e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_INVALID_MIME_TYPE, e.cause.get_reason - assert_equal "type: foo", e.cause.error_data - end - end - - def test_read_pkcs7_with_multipart_should_fail_if_no_boundary_found - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - hdr = MimeHeader.new("content-type", "multipart/signed") - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(hdr) - - mime.expects(:findParam).with(hdr, "boundary").returns(nil) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - assert false - rescue PKCS7Exception => e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_NO_MULTIPART_BOUNDARY, e.cause.get_reason - end - end - - def test_read_pkcs7_with_multipart_should_fail_if_null_boundary_value - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - hdr = MimeHeader.new("content-type", "multipart/signed") - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(hdr) - - mime.expects(:findParam).with(hdr, "boundary").returns(MimeParam.new("boundary", nil)) - - begin - SMIME.new(mime).readPKCS7(bio, nil) - assert false - rescue PKCS7Exception => e - assert_equal PKCS7::F_SMIME_READ_PKCS7, e.cause.get_method - assert_equal PKCS7::R_NO_MULTIPART_BOUNDARY, e.cause.get_reason - end - end - - # TODO: redo this test to be an integration test - def _test_read_pkcs7_happy_path_without_multipart - bio = BIO.new - mime = Mime.new - - headers = ArrayList.new - mime.expects(:parseHeaders).with(bio).returns(headers) - mime.expects(:findHeader).with(headers, "content-type").returns(MimeHeader.new("content-type", "application/pkcs7-mime")) - - SMIME.new(mime).readPKCS7(bio, nil) - end - - def test_read_pkcs7_happy_path_multipart - bio = BIO::from_string(MultipartSignedString) - mime = Mime::DEFAULT - p7 = SMIME.new(mime).readPKCS7(bio, nil) - end - - def test_read_pkcs7_happy_path_without_multipart_enveloped - bio = BIO::from_string(MimeEnvelopedString) - mime = Mime::DEFAULT - p7 = SMIME.new(mime).readPKCS7(bio, nil) - end - - def test_read_pkcs7_happy_path_without_multipart_signed - bio = BIO::from_string(MimeSignedString) - mime = Mime::DEFAULT - p7 = SMIME.new(mime).readPKCS7(bio, nil) - end - end -end diff --git a/test/ref/a.out b/test/ref/a.out deleted file mode 100755 index e69de29..0000000 diff --git a/test/ref/compile.rb b/test/ref/compile.rb deleted file mode 100755 index d5fb3e0..0000000 --- a/test/ref/compile.rb +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby - -name = ARGV[0] -system("rm -rf #{name}") -system("gcc -lssl -lcrypto -o #{name} #{name}.c") -system("chmod +x #{name}") -system("./#{name}") - diff --git a/test/ref/pkcs1 b/test/ref/pkcs1 deleted file mode 100755 index 9b3c6eb511bdaf016e350ce5d292b1a9b4c616fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12720 zcmeHO&x;#%6#u3>+Nf(AOAdlk=MXPKv#kiLJ?+*Fy7tG0?h1=r`I5|hH=EsLGR#bB z0|ggC4h4;wId*Anc zzrLTD!wkIn_0gaI9u-1NfRBKm2j?vzZa`+hZ-S*P&%RUopmccwi-dBCvR_i%HdxA~ z((+PjpJI|YNUHl3nCcQq8L4ZL*7bTk-aUzaklZ~siiy1~v6)0k>4Z^G_iD!Qcn>#U zK|J(-vaW^^AKgkfYO} z1`R!)BX0}wGWPO^hqgQc9mSYEh1x&o(RM4Yg-B>aiVpGeB}cGH(prP@$>y+0n8 zAdY{Uq@k=3xMTFSq+I%*xiEj}d}(ezsXl`Zs*N6Q!6{uA))C|szqnWf&VYjeR&X3jW@t_ zF1p@FpV7Qm7q!E%Q9NCIt2kXm6ZNW~7{c$c7$@lXQEMzLj!W0lr^t-Xh~zcLkzw(S zsU-HrWHK#O9*7y(9r5jYHibS+;jJ1T z%=?=g_#fWWw*KZyyn4U)V6po!9~)QtrEH&~t*!3Ql*cLzUPBr(&sf_2o3Wor>{)I9 z%h(^`@jv#T)OLC$pgg}P_8hIYvC{h|%>ECsbnoO>e%jF;6?8{~FUhmCyVd>76!<(& zv`blLhQndM6sr-ex8Z>t1>~@=+m+BeV-uaVUk#rXur!nx8_43umN2SB%J^uDtD=gt zrreQF)bV2%V>xxIs#aTpI!ndI2`z}+y-%}XdI_4e@xBGNz=D{G5nu!u0Y-okU<4Qe zMt~7u1Q-EEfDvE>o;U<{52YvWINUHJzz8q`i~u9R2rvSS03*N%FanGKBftn8fB?-U zpTzXSSD0ab$>_JC7oi`+uyxKBVg~wg=rjxPuF+{Gplo!S3%CM(f(8cg^NpQm20El8 z|1#$8KQ{W0$p4AaX?B{1A~GTqkHmkG(!WmW-)KFaGygWF-%05-D^By%^bG^edDDnL z+Ch6X;4QDArW jTh(LY=yb$G_XtB~y|#996W(aBw* diff --git a/test/ref/pkcs1.c b/test/ref/pkcs1.c deleted file mode 100644 index 783dc86..0000000 --- a/test/ref/pkcs1.c +++ /dev/null @@ -1,21 +0,0 @@ - -#include - -void print_pkcs7(PKCS7* p7) { - printf(" | asn1 : %s\n", p7->asn1); - printf(" | len : %d\n", p7->length); - printf(" | state : %d\n", p7->state); - printf(" | detached : %d\n", p7->detached); - printf(" | type : %d\n", OBJ_nid2obj(p7->type)); -} - -int main(int argc, char** argv) { - PKCS7* p7; - p7 = PKCS7_new(); - - printf("--before:\n"); - print_pkcs7(p7); - - PKCS7_free(p7); - return 0; -} diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb deleted file mode 100644 index 4a8451a..0000000 --- a/test/ruby/envutil.rb +++ /dev/null @@ -1,208 +0,0 @@ -require "open3" -require "timeout" - -module EnvUtil - def rubybin - unless ENV["RUBYOPT"] - - end - if ruby = ENV["RUBY"] - return ruby - end - ruby = "ruby" - rubyexe = ruby+".exe" - 3.times do - if File.exist? ruby and File.executable? ruby and !File.directory? ruby - return File.expand_path(ruby) - end - if File.exist? rubyexe and File.executable? rubyexe - return File.expand_path(rubyexe) - end - ruby = File.join("..", ruby) - end - if defined?(RbConfig.ruby) - RbConfig.ruby - else - "ruby" - end - end - module_function :rubybin - - LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" - - def invoke_ruby(args, stdin_data="", capture_stdout=false, capture_stderr=false, opt={}) - in_c, in_p = IO.pipe - out_p, out_c = IO.pipe if capture_stdout - err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout - opt = opt.dup - opt[:in] = in_c - opt[:out] = out_c if capture_stdout - opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr - if enc = opt.delete(:encoding) - out_p.set_encoding(enc) if out_p - err_p.set_encoding(enc) if err_p - end - c = "C" - child_env = {} - LANG_ENVS.each {|lc| child_env[lc] = c} - if Array === args and Hash === args.first - child_env.update(args.shift) - end - args = [args] if args.kind_of?(String) - pid = spawn(child_env, EnvUtil.rubybin, *args, opt) - in_c.close - out_c.close if capture_stdout - err_c.close if capture_stderr && capture_stderr != :merge_to_stdout - if block_given? - return yield in_p, out_p, err_p - else - th_stdout = Thread.new { out_p.read } if capture_stdout - th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout - in_p.write stdin_data.to_str - in_p.close - timeout = opt.fetch(:timeout, 10) - if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) - stdout = th_stdout.value if capture_stdout - stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout - else - raise Timeout::Error - end - out_p.close if capture_stdout - err_p.close if capture_stderr && capture_stderr != :merge_to_stdout - Process.wait pid - status = $? - return stdout, stderr, status - end - ensure - [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| - io.close if io && !io.closed? - end - [th_stdout, th_stderr].each do |th| - (th.kill; th.join) if th - end - end - module_function :invoke_ruby - - alias rubyexec invoke_ruby - class << self - alias rubyexec invoke_ruby - end - - def verbose_warning - class << (stderr = "") - alias write << - end - stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true - yield stderr - ensure - stderr, $stderr, $VERBOSE = $stderr, stderr, verbose - return stderr - end - module_function :verbose_warning - - def suppress_warning - verbose, $VERBOSE = $VERBOSE, nil - yield - ensure - $VERBOSE = verbose - end - module_function :suppress_warning - - def under_gc_stress - stress, GC.stress = GC.stress, true - yield - ensure - GC.stress = stress - end - module_function :under_gc_stress -end - -module Test - module Unit - module Assertions - public - def assert_normal_exit(testsrc, message = '', opt = {}) - if opt.include?(:child_env) - opt = opt.dup - child_env = [opt.delete(:child_env)] || [] - else - child_env = [] - end - out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt) - pid = status.pid - faildesc = proc do - signo = status.termsig - signame = Signal.list.invert[signo] - sigdesc = "signal #{signo}" - if signame - sigdesc = "SIG#{signame} (#{sigdesc})" - end - if status.coredump? - sigdesc << " (core dumped)" - end - full_message = '' - if !message.empty? - full_message << message << "\n" - end - full_message << "pid #{pid} killed by #{sigdesc}" - if !out.empty? - out << "\n" if /\n\z/ !~ out - full_message << "\n#{out.gsub(/^/, '| ')}" - end - full_message - end - assert !status.signaled?, faildesc - end - - def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, opt={}) - stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt) - if block_given? - yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }) - else - if test_stdout.is_a?(Regexp) - assert_match(test_stdout, stdout, message) - else - assert_equal(test_stdout, stdout.lines.map {|l| l.chomp }, message) - end - if test_stderr.is_a?(Regexp) - assert_match(test_stderr, stderr, message) - else - assert_equal(test_stderr, stderr.lines.map {|l| l.chomp }, message) - end - status - end - end - - def assert_ruby_status(args, test_stdin="", message=nil, opt={}) - _, _, status = EnvUtil.invoke_ruby(args, test_stdin, false, false, opt) - m = message ? "#{message} (#{status.inspect})" : "ruby exit status is not success: #{status.inspect}" - assert(status.success?, m) - end - - def assert_warn(msg) - stderr = EnvUtil.verbose_warning { yield } - assert(msg === stderr, "warning message #{stderr.inspect} is expected to match #{msg.inspect}") - end - - end - end -end - -begin - require 'rbconfig' -rescue LoadError -else - module RbConfig - @ruby = EnvUtil.rubybin - class << self - undef ruby if method_defined?(:ruby) - attr_reader :ruby - end - dir = File.dirname(ruby) - name = File.basename(ruby, CONFIG['EXEEXT']) - CONFIG['bindir'] = dir - CONFIG['ruby_install_name'] = name - CONFIG['RUBY_INSTALL_NAME'] = name - Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap) - end -end diff --git a/test/ruby/ut_eof.rb b/test/ruby/ut_eof.rb deleted file mode 100644 index b7219dd..0000000 --- a/test/ruby/ut_eof.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'test/unit' - -module TestEOF - def test_eof_0 - open_file("") {|f| - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - } - open_file("") {|f| - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("") {|f| - s = "x" - assert_equal("", f.read(nil, s)) - assert_equal("", s) - } - open_file("") {|f| - s = "x" - assert_nil(f.read(10, s)) - assert_equal("", s) - } - end - - def test_eof_0_rw - return unless respond_to? :open_file_rw - open_file_rw("") {|f| - assert_equal("", f.read) - assert_equal("", f.read) - assert_equal(0, f.syswrite("")) - assert_equal("", f.read) - } - end - - def test_eof_1 - open_file("a") {|f| - assert_equal("", f.read(0)) - assert_equal("a", f.read(1)) - assert_equal("" , f.read(0)) - assert_equal("" , f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - } - open_file("a") {|f| - assert_equal("a", f.read(1)) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_equal("", f.read(0)) - } - open_file("a") {|f| - s = "x" - assert_equal("a", f.read(nil, s)) - assert_equal("a", s) - } - open_file("a") {|f| - s = "x" - assert_equal("a", f.read(10, s)) - assert_equal("a", s) - } - end - - def test_eof_2 - open_file("") {|f| - assert_equal("", f.read) - assert(f.eof?) - } - end - - def test_eof_3 - open_file("") {|f| - assert(f.eof?) - } - end - - module Seek - def open_file_seek(content, pos) - open_file(content) do |f| - f.seek(pos) - yield f - end - end - - def test_eof_0_seek - open_file_seek("", 10) {|f| - assert_equal(10, f.pos) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_equal("", f.read(0)) - assert_equal("", f.read) - } - end - - def test_eof_1_seek - open_file_seek("a", 10) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file_seek("a", 1) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - end - end -end diff --git a/test/test_all.rb b/test/test_all.rb deleted file mode 100644 index 2f4e833..0000000 --- a/test/test_all.rb +++ /dev/null @@ -1 +0,0 @@ -Dir.glob("test/test_*.rb").sort.reject{|t| t =~ /test_all/}.each {|t| require t } diff --git a/test/test_certificate.rb b/test/test_certificate.rb deleted file mode 100644 index 364ae18..0000000 --- a/test/test_certificate.rb +++ /dev/null @@ -1,132 +0,0 @@ -require 'openssl' -require "test/unit" - -class TestCertificate < Test::Unit::TestCase - def setup - cert_file = File.expand_path('fixture/selfcert.pem', File.dirname(__FILE__)) - key_file = File.expand_path('fixture/keypair.pem', File.dirname(__FILE__)) - @cert = OpenSSL::X509::Certificate.new(File.read(cert_file)) - @key = OpenSSL::PKey::RSA.new(File.read(key_file)) - end - - def test_sign_for_pem_initialized_certificate - pem = @cert.to_pem - exts = @cert.extensions - assert_nothing_raised do - @cert.sign(@key, OpenSSL::Digest::SHA1.new) - end - # TODO: for now, jruby-openssl cannot keep order of extensions after sign. - # assert_equal(pem, @cert.to_pem) - assert_equal(exts.size, @cert.extensions.size) - exts.each do |ext| - found = @cert.extensions.find { |e| e.oid == ext.oid } - assert_not_nil(found) - assert_equal(ext.value, found.value) - end - end - - def test_set_public_key - pkey = @cert.public_key - newkey = OpenSSL::PKey::RSA.new(1024) - @cert.public_key = newkey - assert_equal(newkey.public_key.to_pem, @cert.public_key.to_pem) - end - - # JRUBY-3468 - def test_jruby3468 - pem_cert = < OpenSSL::SSL::VERIFY_PEER, - :SSLCACertificateFile => File.join(File.dirname(__FILE__), "fixture", "cacert.pem"), - :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(File.join(File.dirname(__FILE__), "fixture", "localhost_keypair.pem"))), - :SSLCertificate => OpenSSL::X509::Certificate.new(File.read(File.join(File.dirname(__FILE__), "fixture", "cert_localhost.pem"))), - } - p config - DRb.start_service(nil, nil, config) - end - - # JRUBY-2913 - # Warning - this test actually uses the internet connection. - # If there is no connection, it will fail. - def test_ca_path_name - uri = URI.parse('https://www.amazon.com') - http = Net::HTTP.new(uri.host, uri.port) - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - http.ca_path = path("fixture/ca_path/") - http.use_ssl = true - response = http.start do |s| - assert s.get(uri.request_uri).length > 0 - end - end - - # Warning - this test actually uses the internet connection. - # If there is no connection, it will fail. - def test_ssl_verify - uri = URI.parse('https://www.amazon.com/') - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - # right trust anchor for www.amazon.com - http.ca_file = path('fixture/verisign.pem') - response = http.start do |s| - assert s.get(uri.request_uri).length > 0 - end - # wrong trust anchor for www.amazon.com - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - http.ca_file = path('fixture/verisign_c3.pem') - assert_raise(OpenSSL::SSL::SSLError) do - # it must cause SSLError for verification failure. - response = http.start do |s| - s.get(uri.request_uri) - end - end - # round trip - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - http.ca_file = path('fixture/verisign.pem') - response = http.start do |s| - assert s.get(uri.request_uri).length > 0 - end - end - - # Warning - this test actually uses the internet connection. - # If there is no connection, it will fail. - def test_pathlen_does_not_appear - uri = URI.parse('https://www.paypal.com/') - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - # right trust anchor for www.amazon.com - http.ca_file = path('fixture/verisign_c3.pem') - response = http.start do |s| - assert s.get(uri.request_uri).length > 0 - end - end - - # JRUBY-2178 and JRUBY-1307 - # Warning - this test actually uses the internet connection. - # If there is no connection, it will fail. - # This test generally throws an exception - # about illegal_parameter when - # it can't use the cipher string correctly - def test_cipher_strings - socket = TCPSocket.new('rubyforge.org', 443) - ctx = OpenSSL::SSL::SSLContext.new - ctx.cert_store = OpenSSL::X509::Store.new - ctx.verify_mode = 0 - ctx.cert = nil - ctx.key = nil - ctx.client_ca = nil - ctx.ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" - - ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx) - ssl_socket.connect - ssl_socket.close - end - - # JRUBY-1194 - def test_des_encryption - iv = "IVIVIVIV" - key = "KEYKEYKE" - alg = "des" - str = "string abc foo bar baxz" - - cipher = OpenSSL::Cipher::Cipher.new(alg) - cipher.encrypt - cipher.key = key - cipher.iv = iv - cipher.padding = 32 - cipher.key = key - cipher.iv = iv - - encrypted = cipher.update(str) - encrypted << cipher.final - - assert_equal "\253\305\306\372;\374\235\302\357/\006\360\355XO\232\312S\356* #\227\217", encrypted - end - - def _test_perf_of_nil -# require 'net/https' -# require 'benchmark' - -# def request(data) -# connection = Net::HTTP.new("www.google.com", 443) -# connection.use_ssl = true -# connection.verify_mode = OpenSSL::SSL::VERIFY_NONE -# connection.start do |connection| -# connection.request_post("/tbproxy/spell?lang=en", data, { 'User-Agent' => "Test", 'Accept' => 'text/xml' }) -# end -# end - -# puts "is not: #{Benchmark.measure { request("") }.to_s.chomp}" -# puts "is nil: #{Benchmark.measure { request(nil) }.to_s.chomp}" - end -end diff --git a/test/test_java.rb b/test/test_java.rb deleted file mode 100644 index eceec11..0000000 --- a/test/test_java.rb +++ /dev/null @@ -1,98 +0,0 @@ -$:.unshift File.join(File.dirname(__FILE__), '..', 'build_lib', 'mocha', 'lib') - -require "test/unit" -require 'mocha' - -if defined?(JRUBY_VERSION) - require "java" - $CLASSPATH << 'pkg/classes' - $CLASSPATH << Dir["build_lib/bcprov-*"].first - - module PKCS7Test - module ASN1 - OctetString = org.bouncycastle.asn1.DEROctetString - end - - PKCS7 = org.jruby.ext.openssl.impl.PKCS7 unless defined?(PKCS7) - Attribute = org.jruby.ext.openssl.impl.Attribute unless defined?(Attribute) - CipherSpec = org.jruby.ext.openssl.impl.CipherSpec unless defined?(CipherSpec) - Digest = org.jruby.ext.openssl.impl.Digest unless defined?(Digest) - EncContent = org.jruby.ext.openssl.impl.EncContent unless defined?(EncContent) - Encrypt = org.jruby.ext.openssl.impl.Encrypt unless defined?(Encrypt) - Envelope = org.jruby.ext.openssl.impl.Envelope unless defined?(Envelope) - IssuerAndSerial = org.jruby.ext.openssl.impl.IssuerAndSerial unless defined?(IssuerAndSerial) - RecipInfo = org.jruby.ext.openssl.impl.RecipInfo unless defined?(RecipInfo) - SignEnvelope = org.jruby.ext.openssl.impl.SignEnvelope unless defined?(SignEnvelope) - Signed = org.jruby.ext.openssl.impl.Signed unless defined?(Signed) - SMIME = org.jruby.ext.openssl.impl.SMIME unless defined?(SMIME) - Mime = org.jruby.ext.openssl.impl.Mime unless defined?(Mime) - MimeHeader = org.jruby.ext.openssl.impl.MimeHeader unless defined?(MimeHeader) - MimeParam = org.jruby.ext.openssl.impl.MimeParam unless defined?(MimeParam) - BIO = org.jruby.ext.openssl.impl.BIO unless defined?(BIO) - PKCS7Exception = org.jruby.ext.openssl.impl.PKCS7Exception unless defined?(PKCS7Exception) - ASN1Registry = org.jruby.ext.openssl.impl.ASN1Registry unless defined?(ASN1Registry) - AlgorithmIdentifier = org.bouncycastle.asn1.x509.AlgorithmIdentifier unless defined?(AlgorithmIdentifier) - SignerInfoWithPkey = org.jruby.ext.openssl.impl.SignerInfoWithPkey unless defined?(SignerInfoWithPkey) - IssuerAndSerialNumber = org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber unless defined?(IssuerAndSerialNumber) - ASN1InputStream = org.bouncycastle.asn1.ASN1InputStream unless defined?(ASN1InputStream) - X509AuxCertificate = org.jruby.ext.openssl.x509store.X509AuxCertificate unless defined?(X509AuxCertificate) - - ArrayList = java.util.ArrayList unless defined?(ArrayList) - CertificateFactory = java.security.cert.CertificateFactory unless defined?(CertificateFactory) - BCP = org.bouncycastle.jce.provider.BouncyCastleProvider unless defined?(BCP) - ByteArrayInputStream = java.io.ByteArrayInputStream unless defined?(ByteArrayInputStream) - BigInteger = java.math.BigInteger unless defined?(BigInteger) - Cipher = javax.crypto.Cipher unless defined?(Cipher) - - DERInteger = org.bouncycastle.asn1.DERInteger - DERSet = org.bouncycastle.asn1.DERSet - DEROctetString = org.bouncycastle.asn1.DEROctetString - X509Name = org.bouncycastle.asn1.x509.X509Name - - - MimeEnvelopedString = File::read(File.join(File.dirname(__FILE__), 'java', 'pkcs7_mime_enveloped.message')) - MimeSignedString = File::read(File.join(File.dirname(__FILE__), 'java', 'pkcs7_mime_signed.message')) - MultipartSignedString = File::read(File.join(File.dirname(__FILE__), 'java', 'pkcs7_multipart_signed.message')) - - X509CertString = <= '1.9.0' ? '1.9' : '1.8'), 'test_*.rb') -Dir.glob(files).sort.each do |tc| - require tc -end diff --git a/test/test_parse_certificate.rb b/test/test_parse_certificate.rb deleted file mode 100644 index 11b49b3..0000000 --- a/test/test_parse_certificate.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'openssl' -require "test/unit" - -class TestParseCertificate < Test::Unit::TestCase - CERT = File.dirname(__FILE__) + '/cert_with_ec_pk.cer' - - def test_certificate_parse_works_with_ec_pk_cert - cer = OpenSSL::X509::Certificate.new(File.read(CERT)) - assert cer.to_s != nil - assert cer.issuer.to_s != nil - assert cer.subject.to_s != nil - assert cer.extensions.to_s != nil - end - - def test_certificate_with_ec_pk_cert_fails_requesting_pk - cer = OpenSSL::X509::Certificate.new(File.read(CERT)) - assert_raise(OpenSSL::X509::CertificateError) { cer.public_key } - end - - def test_loading_key_raise_certificate_error - key_file = File.expand_path('fixture/keypair.pem', File.dirname(__FILE__)) - assert_raises(OpenSSL::X509::CertificateError) do - OpenSSL::X509::Certificate.new(File.read(key_file)) - end - end -end - diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb deleted file mode 100644 index 93b62ce..0000000 --- a/test/test_pkcs7.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'openssl' -require "test/unit" - -class TestPkcs7 < Test::Unit::TestCase - - CERT_PEM = < to_pem returned 65 bytes with 'MAA=' - def test_generate_pkey_dsa_length - assert(OpenSSL::PKey::DSA.new(512).to_pem.size > 100) - end - - # jruby-openssl/0.6 returns nil for DSA#to_text - def test_generate_pkey_dsa_to_text - assert_match( - /Private-Key: \(512 bit\)/, - OpenSSL::PKey::DSA.new(512).to_text - ) - end - - def test_load_pkey_dsa - pkey = OpenSSL::PKey::DSA.new(512) - assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) - end - - def test_load_pkey_dsa_public - pkey = OpenSSL::PKey::DSA.new(512).public_key - assert_equal(pkey.to_pem, OpenSSL::PKey::DSA.new(pkey.to_pem).to_pem) - end - - def test_load_pkey_dsa_der - pkey = OpenSSL::PKey::DSA.new(512) - assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) - end - - def test_load_pkey_dsa_public_der - pkey = OpenSSL::PKey::DSA.new(512).public_key - assert_equal(pkey.to_der, OpenSSL::PKey::DSA.new(pkey.to_der).to_der) - end - - def test_load_pkey_dsa_net_ssh - blob = "0\201\367\002\001\000\002A\000\203\316/\037u\272&J\265\003l3\315d\324h\372{\t8\252#\331_\026\006\035\270\266\255\343\353Z\302\276\335\336\306\220\375\202L\244\244J\206>\346\b\315\211\302L\246x\247u\a\376\366\345\302\016#\002\025\000\244\274\302\221Og\275/\302+\356\346\360\024\373wI\2573\361\002@\027\215\270r*\f\213\350C\245\021:\350 \006\\\376\345\022`\210b\262\3643\023XLKS\320\370\002\276\347A\nU\204\276\324\256`=\026\240\330\306J\316V\213\024\e\030\215\355\006\037q\337\356ln\002@\017\257\034\f\260\333'S\271#\237\230E\321\312\027\021\226\331\251Vj\220\305\316\036\v\266+\000\230\270\177B\003?t\a\305]e\344\261\334\023\253\323\251\223M\2175)a(\004\"lI8\312\303\307\a\002\024_\aznW\345\343\203V\326\246ua\203\376\201o\350\302\002" - pkey = OpenSSL::PKey::DSA.new(blob) - assert_equal(blob, pkey.to_der) - end - - def test_load_dsa_des_encrypted - password = 'pass' - pkey = OpenSSL::PKey::DSA.generate(512) - cipher = OpenSSL::Cipher::Cipher.new('des-cbc') - pem = pkey.to_pem(cipher, password) - assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) - end - - def test_load_dsa_3des_encrypted - password = 'pass' - pkey = OpenSSL::PKey::DSA.generate(512) - cipher = OpenSSL::Cipher::Cipher.new('des-ede3-cbc') - pem = pkey.to_pem(cipher, password) - assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) - end - - def test_load_dsa_aes_encrypted - password = 'pass' - pkey = OpenSSL::PKey::DSA.generate(512) - cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') - pem = pkey.to_pem(cipher, password) - assert_equal(pkey.g, OpenSSL::PKey::DSA.new(pem, password).g) - end - - CRUBY_DES_DSA_PEM = <= '1.9.0' ? '1.9' : '1.8'), "utils.rb") - - -class TestSSL < Test::Unit::TestCase - PORT = 17171 - DIR = File.dirname(File.expand_path(__FILE__)) - - def setup - @server = @server_thread = nil - @verbose, $VERBOSE = $VERBOSE, nil - setup_server - end - - def teardown - $VERBOSE = @verbose - teardown_server - end - - def test_jruby_4826 - assert_nothing_raised do - 100.times do - http = Net::HTTP.new('localhost', PORT) - http.use_ssl = true - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - req = Net::HTTP::Post.new('/post') - http.request(req).body - end - end - end - -private - - def make_certificate(key, cn) - subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=#{cn}") - exts = [ - ["keyUsage", "keyEncipherment,digitalSignature", true], - ] - OpenSSL::TestUtils.issue_cert( - subject, key, 1, Time.now, Time.now + 3600, exts, - nil, nil, OpenSSL::Digest::SHA1.new - ) - end - - def setup_server - key = OpenSSL::TestUtils::TEST_KEY_RSA1024 - cert = make_certificate(key, "localhost") - logger = Logger.new(STDERR) - logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level) - @server = WEBrick::HTTPServer.new( - :Logger => logger, - :Port => PORT, - :AccessLog => [], - :SSLEnable => true, - :ServerName => "localhost", - :SSLCertificate => cert, - :SSLPrivateKey => key - ) - @server.mount( - "/post", - WEBrick::HTTPServlet::ProcHandler.new(method("do_post").to_proc) - ) - @server_thread = start_server_thread(@server) - end - - def do_post(req, res) - res.chunked = true - res['content-type'] = 'text/plain' - piper, pipew = IO.pipe - res.body = piper - 10.times { pipew << "A" * 10 } - pipew.close - end - - def start_server_thread(server) - t = Thread.new { - Thread.current.abort_on_exception = true - server.start - } - while server.status != :Running - Thread.pass - unless t.alive? - t.join - raise - end - end - t - end - - def teardown_server - @server.shutdown if @server - end -end diff --git a/test/test_x509store.rb b/test/test_x509store.rb deleted file mode 100644 index a6e7ecf..0000000 --- a/test/test_x509store.rb +++ /dev/null @@ -1,168 +0,0 @@ -begin - require "openssl" -rescue LoadError -end - -require "test/unit" -require "tempfile" - -class TestX509Store < Test::Unit::TestCase - def setup - @store = OpenSSL::X509::Store.new - end - - def path(file) - File.expand_path(file, File.dirname(__FILE__)) - end - - def teardown - end - - def test_ns_cert_type - f = Tempfile.new("globalsign-root.pem") - f << GLOBALSIGN_ROOT_CA - f.close - @store.add_file(f.path) - f.unlink - - # CAUTION ! - # - # sgc is an issuing CA certificate so we should not verify it for the - # purpose 'PURPOSE_SSL_SERVER'. It's not a SSL server certificate. - # We're just checking the code for 'PURPOSE_SSL_SERVER'. - # jruby-openssl/0.5.2 raises the following exception around ASN.1 - # nsCertType handling. - # Purpose.java:344:in `call': java.lang.ClassCastException: org.bouncycastle.asn1.DEROctetString cannot be cast to org.bouncycastle.asn1.DERBitString - sgc = OpenSSL::X509::Certificate.new(GLOBALSIGN_ORGANIZATION_VALIDATION_CA) - - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_nothing_raised do - @store.verify(sgc) # => should be false - end - end - - def test_purpose_ssl_client - @store.add_file(path("fixture/purpose/cacert.pem")) - cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslclient.pem"))) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(true, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(false, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(true, @store.verify(cert)) - end - - def test_purpose_ssl_server - @store.add_file(path("fixture/purpose/cacert.pem")) - cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslserver.pem"))) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(true, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(false, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(true, @store.verify(cert)) - end - - # keyUsage: no digitalSignature bit, keyEncipherment bit only. - def test_purpose_ssl_server_no_dsig_in_keyUsage - @store.add_file(path("fixture/purpose/cacert.pem")) - cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslserver_no_dsig_in_keyUsage.pem"))) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(true, @store.verify(cert)) - end - - def test_add_file_multiple - f = Tempfile.new("globalsign-root.pem") - f << GLOBALSIGN_ROOT_CA - f << "junk junk\n" - f << "junk junk\n" - f << "junk junk\n" - f << File.read(path("fixture/purpose/cacert.pem")) - f.close - @store.add_file(f.path) - f.unlink - - cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslserver.pem"))) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(true, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT - assert_equal(false, @store.verify(cert)) - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - assert_equal(true, @store.verify(cert)) - end - - # jruby-openssl/0.6 raises "can't store certificate" because of duplicated - # subject. ruby-openssl just ignores the second certificate. - def test_add_file_JRUBY_4409 - assert_nothing_raised do - @store.add_file(path("fixture/ca-bundle.crt")) - end - end - - def test_set_default_paths - @store.purpose = OpenSSL::X509::PURPOSE_SSL_SERVER - cert = OpenSSL::X509::Certificate.new(File.read(path("fixture/purpose/sslserver.pem"))) - assert_equal(false, @store.verify(cert)) - begin - backup = ENV['SSL_CERT_DIR'] - ENV['SSL_CERT_DIR'] = path('fixture/purpose/') - @store.set_default_paths - assert_equal(true, @store.verify(cert)) - ensure - ENV['SSL_CERT_DIR'] = backup if backup - end - end - - GLOBALSIGN_ROOT_CA = <<__EOS__ ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- -__EOS__ - - GLOBALSIGN_ORGANIZATION_VALIDATION_CA = <<__EOS__ ------BEGIN CERTIFICATE----- -MIIEZzCCA0+gAwIBAgILBAAAAAABHkSl9SowDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0wNzA0MTExMjAw -MDBaFw0xNzA0MTExMjAwMDBaMGoxIzAhBgNVBAsTGk9yZ2FuaXphdGlvbiBWYWxp -ZGF0aW9uIENBMRMwEQYDVQQKEwpHbG9iYWxTaWduMS4wLAYDVQQDEyVHbG9iYWxT -aWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAoS/EvM6HA+lnwYnI5ZP8fbStnvZjTmronCxziaIB9I8h -+P0lnVgWbYb27klXdX516iIRfj37x0JB3PzFDJFVgHvrZDMdm/nKOOmrxiVDUSVA -9OR+GFVqqY8QOkAe1leD738vNC8t0vZTwhkNt+3JgfVGLLQjQl6dEwN17Opq/Fd8 -yTaXO5jcExPs7EH6XTTquZPnEBZlzJyS/fXFnT5KuQn85F8eaV9N9FZyRLEdIwPI -NvZliMi/ORZFjh4mbFEWxSoAOMWkE2mVfasBO6jEFLSA2qwaRCDV/qkGexQnr+Aw -Id2Q9KnVIxkuHgPmwd+VKeTBlEPdPpCqy0vJvorTOQIDAQABo4IBHzCCARswDgYD -VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFH1tKuxm -q6dRNqsCafFwj8RZC5ofMEsGA1UdIAREMEIwQAYJKwYBBAGgMgEUMDMwMQYIKwYB -BQUHAgEWJWh0dHA6Ly93d3cuZ2xvYmFsc2lnbi5uZXQvcmVwb3NpdG9yeS8wMwYD -VR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNy -bDARBglghkgBhvhCAQEEBAMCAgQwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZI -AYb4QgQBMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA0GCSqGSIb3 -DQEBBQUAA4IBAQB5R/wV10x53w96ns7UfEtjyYm1ez+ZEuicjJpJL+BOlUrtx7y+ -8aLbjpMdunFUqkvZiSIkh8UEqKyCUqBS+LjhT6EnZmMhSjnnx8VOX7LWHRNtMOnO -16IcvCkKczxbI0n+1v/KsE/18meYwEcR+LdIppAJ1kK+6rG5U0LDnCDJ+6FbtVZt -h4HIYKzEuXInCo4eqLEuzTKieFewnPiVu0OOjDGGblMNxhIFukFuqDUwCRgdAmH/ -/e413mrDO9BNS05QslY2DERd2hplKuaYVqljMy4E567o9I63stp9wMjirqYoL+PJ -c738B0E0t6pu7qfb0ZM87ZDsMpKI2cgjbHQh ------END CERTIFICATE----- -__EOS__ -end diff --git a/test/ut_eof.rb b/test/ut_eof.rb deleted file mode 100644 index e6f6edd..0000000 --- a/test/ut_eof.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'test/unit' - -module TestEOF - def test_eof_0 - open_file("") {|f| - assert_equal("", f.read(0)) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_nil(f.read(0)) - assert_nil(f.read(0)) - } - open_file("") {|f| - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("") {|f| - s = "x" - assert_equal("", f.read(nil, s)) - assert_equal("", s) - } - open_file("") {|f| - s = "x" - assert_nil(f.read(10, s)) - assert_equal("", s) - } - end - - def test_eof_0_rw - return unless respond_to? :open_file_rw - open_file_rw("") {|f| - assert_equal("", f.read) - assert_equal("", f.read) - assert_equal(0, f.syswrite("")) - assert_equal("", f.read) - } - end - - def test_eof_1 - open_file("a") {|f| - assert_equal("", f.read(0)) - assert_equal("a", f.read(1)) - assert_equal("" , f.read(0)) - assert_equal("" , f.read(0)) - assert_equal("", f.read) - assert_nil(f.read(0)) - assert_nil(f.read(0)) - } - open_file("a") {|f| - assert_equal("a", f.read(1)) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_nil(f.read(1)) - assert_equal("", f.read) - assert_nil(f.read(1)) - } - open_file("a") {|f| - assert_equal("a", f.read(2)) - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file("a") {|f| - assert_equal("a", f.read) - assert_nil(f.read(0)) - } - open_file("a") {|f| - s = "x" - assert_equal("a", f.read(nil, s)) - assert_equal("a", s) - } - open_file("a") {|f| - s = "x" - assert_equal("a", f.read(10, s)) - assert_equal("a", s) - } - end - - def test_eof_2 - open_file("") {|f| - assert_equal("", f.read) - assert(f.eof?) - } - end - - def test_eof_3 - open_file("") {|f| - assert(f.eof?) - } - end - - module Seek - def open_file_seek(content, pos) - open_file(content) do |f| - f.seek(pos) - yield f - end - end - - def test_eof_0_seek - open_file_seek("", 10) {|f| - assert_equal(10, f.pos) - assert_equal("", f.read(0)) - assert_equal("", f.read) - assert_nil(f.read(0)) - assert_equal("", f.read) - } - end - - def test_eof_1_seek - open_file_seek("a", 10) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - open_file_seek("a", 1) {|f| - assert_equal("", f.read) - assert_equal("", f.read) - } - end - end -end From d45ca6dd10eb1beb9ab1e9d659e249843b9a439a Mon Sep 17 00:00:00 2001 From: John Bachir Date: Tue, 30 Jun 2015 13:26:28 -0400 Subject: [PATCH 66/66] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b68d6fd..bd38fab 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -This repository is now defunct. Builds of jruby-openssl are done from -the JRuby repository under the gems/jruby-openssl directory. See -https://jira.codehaus.org/browse/JRUBY-6973 +This repository is now defunct, and has been replaced by: + + https://github.com/jruby/jruby-openssl

    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%0De6-MRf4gR47JTtspkp08%zy-iLnxBU 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%0D7= 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