diff options
author | Hiroshi SHIBATA <[email protected]> | 2020-02-16 15:21:29 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-16 15:21:29 +0900 |
commit | b99775b163ce44079c1f8727ce9b4ed8bb03489d (patch) | |
tree | 4f9fd53f21c94dfeb05fefe1143bbe770228733a /test | |
parent | 0bfa479c52963b95a47ceab3d453f21b646366a2 (diff) |
Import openssl-2.2.0 (#2693)
Import the master branch of ruby/openssl for preparing to release openssl-2.2.0
Notes
Notes:
Merged-By: hsbt <[email protected]>
Diffstat (limited to 'test')
37 files changed, 1451 insertions, 103 deletions
diff --git a/test/openssl/fixtures/chain/dh512.pem b/test/openssl/fixtures/chain/dh512.pem new file mode 100644 index 0000000000..fec138c7a9 --- /dev/null +++ b/test/openssl/fixtures/chain/dh512.pem @@ -0,0 +1,4 @@ +-----BEGIN DH PARAMETERS----- +MEYCQQCjDVzTg9C4u43MV0TKDGsBuYdChrPMczr4IYjy+jHQvXm2DDadNNWBIDau +4zNtwfLCg2gMwOc7t18m4Ten/NOLAgEC +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/chain/server.crt b/test/openssl/fixtures/chain/server.crt new file mode 100644 index 0000000000..d6b814f450 --- /dev/null +++ b/test/openssl/fixtures/chain/server.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICATCCAWoCCQDbxIRGgXeWaDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJO +WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE5MDYxMzA1MDU0MloXDTI5MDYxMDA1MDU0MlowRTELMAkG +A1UEBhMCTloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA29Vu +Y6m8pRrsXxUhlK2BX48CDChr8D53SqZozcQI26BCm+05TBnQxKAHOknR3y/ige2U +2zftSwbSoK/zKUC8o5pKVL+l36anDEnZ6RWc9Z9CvmaCFjlcP4nXZO+yD1Is/jCy +KqGGC8lQ920VXOCFflJj6AWg88+4C3GLjxJe6bMCAwEAATANBgkqhkiG9w0BAQsF +AAOBgQCDaqKGBkYxNxnv37vEKp7zi/cov8LvEsZaAD1pcSU+ysBiBes/B7a/Qjcj +PTZsH/hedn9mVynLkjc7LrztUWngTeW9gk5EB9YSwJdPhwLntV1TdaBlf/tu0n/c +s7QxaZhFMUyo1Eof28zXVHhs1OEhlSjwJ8lxuC3vBE4F1BjSNQ== +-----END CERTIFICATE----- diff --git a/test/openssl/fixtures/chain/server.csr b/test/openssl/fixtures/chain/server.csr new file mode 100644 index 0000000000..51b38e33f2 --- /dev/null +++ b/test/openssl/fixtures/chain/server.csr @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBhDCB7gIBADBFMQswCQYDVQQGEwJOWjETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb +7TlMGdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ +ZoIWOVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswID +AQABoAAwDQYJKoZIhvcNAQELBQADgYEAONaTWYVfyMmd8irCtognRoM4tFF4xvDg +PTcnHjVb/6oPPMU+mtQVD9qNf8SOdhNuYVTZ61mDLQGeq45CLM5qWjZkqFPHnngf +ajfZRE7Y3vA8ZaWFvsTJYcU+R3/FRS0XnFYj99+q9Yi3JExSY+arElyAW3tFYlcs +RWOCk1pT2Yc= +-----END CERTIFICATE REQUEST----- diff --git a/test/openssl/fixtures/chain/server.key b/test/openssl/fixtures/chain/server.key new file mode 100644 index 0000000000..9590235db8 --- /dev/null +++ b/test/openssl/fixtures/chain/server.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDb1W5jqbylGuxfFSGUrYFfjwIMKGvwPndKpmjNxAjboEKb7TlM +GdDEoAc6SdHfL+KB7ZTbN+1LBtKgr/MpQLyjmkpUv6XfpqcMSdnpFZz1n0K+ZoIW +OVw/iddk77IPUiz+MLIqoYYLyVD3bRVc4IV+UmPoBaDzz7gLcYuPEl7pswIDAQAB +AoGAGO+q5+83ENtu+JIjDwRnanmEV/C13biYO4WI2d5kytTw+VL9bt52yfcFGt2I +yvJZlTdn7T340svhVIzg3ksTmp1xQk3zh6zR00zQy45kYwY8uyd8Xfh2IsnpByoc +h2jWVX6LSqi1Iy3RxanHmMYPSMy15otsjwlwnnTAHLnnvzECQQDvw3TL90DucQSD +S0h6DWAGakaiOMhY/PpFbTsjzw+uG+Up65tpz4QqPbsXfoReeK0CQIuyE/LlYoJl +VOlIsL6HAkEA6rh4zsWi6KVTGa7qd5x70TEgxeMMAW1qUbak1THxeZTFYnyvucBz +i+VQvHEVnCadhVpHIwbBNUeOyS5DXjj6dQJAA0Caf/3Noq5jykgmJomx6MReSusM +RLDB0FlH+Rdg9hKozCXHCOtoto350LrFnuZyKlqnynWc0OHCNQ+uzm6fVwJAbtyW +YsNCQLPlXhoZsEj+yj10B0NH5lyxfMrRa8jdDtnPqMbPkOJvMMIssfSPimNKvzN2 +qfqEww97R1ZMh3JOCQJBAIIwGHBN5rDGIb4CgR+PLsh8bve1X+gO8UnOYJXa/Uzx +gAXE0uzHNH6rNSG0V/IQnFYlSHpNJGgcdSl+MZNLldQ= +-----END RSA PRIVATE KEY----- diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index cc11301804..5f4575516a 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -167,7 +167,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase 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 + str = +"\000"; str[0] = 0b00000110.chr assert_equal(str, extv.value) ext = extensions.value[0].value[2] # subjetKeyIdentifier @@ -332,6 +332,32 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ raise end + + aki = [ + OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier"), + OpenSSL::ASN1::ObjectId.new("X509v3 Authority Key Identifier"), + OpenSSL::ASN1::ObjectId.new("2.5.29.35") + ] + + ski = [ + OpenSSL::ASN1::ObjectId.new("subjectKeyIdentifier"), + OpenSSL::ASN1::ObjectId.new("X509v3 Subject Key Identifier"), + OpenSSL::ASN1::ObjectId.new("2.5.29.14") + ] + + aki.each do |a| + aki.each do |b| + assert a == b + end + + ski.each do |b| + refute a == b + end + end + + assert_raise(TypeError) { + OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier") == nil + } end def test_sequence @@ -635,10 +661,10 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_equal data, seq.entries end - def test_gc_stress - skip "very time consuming test" - assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire "openssl.so"']) - end + # Very time consuming test. + # def test_gc_stress + # assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire "openssl.so"']) + # end private diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb index 0b5cd84241..547d334c64 100644 --- a/test/openssl/test_bn.rb +++ b/test/openssl/test_bn.rb @@ -1,5 +1,5 @@ # coding: us-ascii -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' require "prime" @@ -15,6 +15,10 @@ class OpenSSL::TestBN < OpenSSL::TestCase end def test_new + assert_raise(ArgumentError) { OpenSSL::BN.new } + assert_raise(ArgumentError) { OpenSSL::BN.new(nil) } + assert_raise(ArgumentError) { OpenSSL::BN.new(nil, 2) } + assert_equal(@e1, OpenSSL::BN.new("999")) assert_equal(@e1, OpenSSL::BN.new("999", 10)) assert_equal(@e1, OpenSSL::BN.new("\x03\xE7", 2)) @@ -273,9 +277,9 @@ class OpenSSL::TestBN < OpenSSL::TestCase assert_instance_of(String, @e1.hash.to_s) end - def test_type_error + def test_argument_error bug15760 = '[ruby-core:92231] [Bug #15760]' - assert_raise(TypeError, bug15760) { OpenSSL::BN.new(nil, 2) } + assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) } end end diff --git a/test/openssl/test_buffering.rb b/test/openssl/test_buffering.rb index c85a6f020b..7575c5b4fe 100644 --- a/test/openssl/test_buffering.rb +++ b/test/openssl/test_buffering.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -10,7 +10,7 @@ class OpenSSL::TestBuffering < OpenSSL::TestCase attr_accessor :sync def initialize - @io = "" + @io = Buffer.new def @io.sync true end @@ -41,6 +41,13 @@ class OpenSSL::TestBuffering < OpenSSL::TestCase @io = IO.new end + def test_encoding + @io.write '😊' + @io.flush + + assert_equal @io.string.encoding, Encoding::BINARY + end + def test_flush @io.write 'a' diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index d83fa4ec3d..f6ec498087 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -305,6 +305,21 @@ class OpenSSL::TestCipher < OpenSSL::TestCase } end + def test_crypt_after_key + key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*") + %w'ecb cbc cfb ctr gcm'.each do |c| + cipher = OpenSSL::Cipher.new("aes-128-#{c}") + cipher.key = key + cipher.encrypt + assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } + + cipher = OpenSSL::Cipher.new("aes-128-#{c}") + cipher.key = key + cipher.decrypt + assert_raise(OpenSSL::Cipher::CipherError) { cipher.update("") } + end + end + private def new_encryptor(algo, **kwargs) diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb index 3606c67d65..dba66b0802 100644 --- a/test/openssl/test_config.rb +++ b/test/openssl/test_config.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -61,14 +61,14 @@ foo\\bar::foo\\bar = baz [default1 default2]\t\t # space is allowed in section name fo =b ar # space allowed in value [emptysection] - [dollar ] + [doller ] foo=bar bar = $(foo) baz = 123$(default::bar)456${foo}798 qux = ${baz} quxx = $qux.$qux __EOC__ - assert_equal(['default', 'default1 default2', 'dollar', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort) + 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']) @@ -84,12 +84,12 @@ __EOC__ assert_equal('baz', c['foo\\bar']['foo\\bar']) assert_equal('b ar', c['default1 default2']['fo']) - # dollar - assert_equal('bar', c['dollar']['foo']) - assert_equal('bar', c['dollar']['bar']) - assert_equal('123baz456bar798', c['dollar']['baz']) - assert_equal('123baz456bar798', c['dollar']['qux']) - assert_equal('123baz456bar798.123baz456bar798', c['dollar']['quxx']) + # 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") diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb index 2cb878b6fa..e47fc0a356 100644 --- a/test/openssl/test_digest.rb +++ b/test/openssl/test_digest.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -53,14 +53,21 @@ class OpenSSL::TestDigest < OpenSSL::TestCase assert_equal(dig1, dig2, "reset") end - def test_digest_constants - algs = %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512) - if !libressl? && !openssl?(1, 1, 0) - algs += %w(DSS1 SHA) + def test_required_digests + algorithms = OpenSSL::Digest::ALGORITHMS + required = %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512} + + required.each do |name| + assert_include(algorithms, name) end - algs.each do |alg| - assert_not_nil(OpenSSL::Digest.new(alg)) - klass = OpenSSL::Digest.const_get(alg) + end + + def test_digest_constants + algorithms = OpenSSL::Digest::ALGORITHMS + + algorithms.each do |name| + assert_not_nil(OpenSSL::Digest.new(name)) + klass = OpenSSL::Digest.const_get(name.tr('-', '_')) assert_not_nil(klass.new) end end @@ -91,6 +98,18 @@ class OpenSSL::TestDigest < OpenSSL::TestCase assert_equal(sha512_a, encode16(OpenSSL::Digest::SHA512.digest("a"))) end + def test_sha3 + pend "SHA3 is not implemented" unless OpenSSL::Digest.const_defined?(:SHA3_224) + s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7' + s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a' + s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004' + s512 = 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26' + assert_equal(OpenSSL::Digest::SHA3_224.hexdigest(""), s224) + assert_equal(OpenSSL::Digest::SHA3_256.hexdigest(""), s256) + assert_equal(OpenSSL::Digest::SHA3_384.hexdigest(""), s384) + assert_equal(OpenSSL::Digest::SHA3_512.hexdigest(""), s512) + end + def test_digest_by_oid_and_name_sha2 check_digest(OpenSSL::ASN1::ObjectId.new("SHA224")) check_digest(OpenSSL::ASN1::ObjectId.new("SHA256")) diff --git a/test/openssl/test_engine.rb b/test/openssl/test_engine.rb index bb1123d516..232ba866a5 100644 --- a/test/openssl/test_engine.rb +++ b/test/openssl/test_engine.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) && defined?(OpenSSL::Engine) diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb index a577d7891e..8cd474f9a3 100644 --- a/test/openssl/test_fips.rb +++ b/test/openssl/test_fips.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb index 831a5b6b37..9cb3c5a864 100644 --- a/test/openssl/test_hmac.rb +++ b/test/openssl/test_hmac.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -39,6 +39,16 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase second = h1.update("test").hexdigest assert_equal first, second end + + def test_eq + h1 = OpenSSL::HMAC.new("KEY", "MD5") + h2 = OpenSSL::HMAC.new("KEY", OpenSSL::Digest.new("MD5")) + h3 = OpenSSL::HMAC.new("FOO", "MD5") + + assert_equal h1, h2 + refute_equal h1, h2.digest + refute_equal h1, h3 + end end end diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb index 5e1db80c5f..f4790c96af 100644 --- a/test/openssl/test_kdf.rb +++ b/test/openssl/test_kdf.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb index aa1e61824f..052507de5b 100644 --- a/test/openssl/test_ns_spki.rb +++ b/test/openssl/test_ns_spki.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -9,7 +9,7 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase # 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 = +"MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV" @b64 << "WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID" @b64 << "AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S" @b64 << "r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW" diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb index 50ad6c31f5..a490a1539e 100644 --- a/test/openssl/test_ocsp.rb +++ b/test/openssl/test_ocsp.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -84,6 +84,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal [cid.issuer_key_hash].pack("H*"), asn1.value[2].value assert_equal @cert.serial, asn1.value[3].value assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der + assert_equal der, OpenSSL::OCSP::CertificateId.new(asn1).to_der end def test_certificate_id_dup diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb new file mode 100644 index 0000000000..f517b1d83d --- /dev/null +++ b/test/openssl/test_ossl.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true +require_relative "utils" + +require 'benchmark' + +if defined?(OpenSSL) + +class OpenSSL::OSSL < OpenSSL::SSLTestCase + def test_fixed_length_secure_compare + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "a") } + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aa") } + + assert OpenSSL.fixed_length_secure_compare("aaa", "aaa") + assert OpenSSL.fixed_length_secure_compare( + OpenSSL::Digest::SHA256.digest("aaa"), OpenSSL::Digest::SHA256.digest("aaa") + ) + + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaaa") } + refute OpenSSL.fixed_length_secure_compare("aaa", "baa") + refute OpenSSL.fixed_length_secure_compare("aaa", "aba") + refute OpenSSL.fixed_length_secure_compare("aaa", "aab") + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "aaab") } + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "b") } + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bb") } + refute OpenSSL.fixed_length_secure_compare("aaa", "bbb") + assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bbbb") } + end + + def test_secure_compare + refute OpenSSL.secure_compare("aaa", "a") + refute OpenSSL.secure_compare("aaa", "aa") + + assert OpenSSL.secure_compare("aaa", "aaa") + + refute OpenSSL.secure_compare("aaa", "aaaa") + refute OpenSSL.secure_compare("aaa", "baa") + refute OpenSSL.secure_compare("aaa", "aba") + refute OpenSSL.secure_compare("aaa", "aab") + refute OpenSSL.secure_compare("aaa", "aaab") + refute OpenSSL.secure_compare("aaa", "b") + refute OpenSSL.secure_compare("aaa", "bb") + refute OpenSSL.secure_compare("aaa", "bbb") + refute OpenSSL.secure_compare("aaa", "bbbb") + end + + def test_memcmp_timing + # Ensure using fixed_length_secure_compare takes almost exactly the same amount of time to compare two different strings. + # Regular string comparison will short-circuit on the first non-matching character, failing this test. + # NOTE: this test may be susceptible to noise if the system running the tests is otherwise under load. + a = "x" * 512_000 + b = "#{a}y" + c = "y#{a}" + a = "#{a}x" + + n = 10_000 + a_b_time = Benchmark.measure { n.times { OpenSSL.fixed_length_secure_compare(a, b) } }.real + a_c_time = Benchmark.measure { n.times { OpenSSL.fixed_length_secure_compare(a, c) } }.real + assert_in_delta(a_b_time, a_c_time, 1, "fixed_length_secure_compare timing test failed") + end +end + +end diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index 08c15a0f75..e9cf98df15 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' require_relative 'ut_eof' @@ -128,11 +128,11 @@ module OpenSSL::TestPairM ssl_pair {|s1, s2| s2.write "a\nbcd" assert_equal("a\n", s1.gets) - result = "" + result = String.new result << s1.readpartial(10) until result.length == 3 assert_equal("bcd", result) s2.write "efg" - result = "" + result = String.new result << s1.readpartial(10) until result.length == 3 assert_equal("efg", result) s2.close @@ -242,22 +242,22 @@ module OpenSSL::TestPairM def test_read_with_outbuf ssl_pair { |s1, s2| s1.write("abc\n") - buf = "" + buf = String.new ret = s2.read(2, buf) assert_same ret, buf assert_equal "ab", ret - buf = "garbage" + buf = +"garbage" ret = s2.read(2, buf) assert_same ret, buf assert_equal "c\n", ret - buf = "garbage" + buf = +"garbage" assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false) assert_equal "", buf s1.close - buf = "garbage" + buf = +"garbage" assert_equal nil, s2.read(100, buf) assert_equal "", buf } diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb index de8e35ed79..fdbe753b17 100644 --- a/test/openssl/test_pkcs12.rb +++ b/test/openssl/test_pkcs12.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb index 6437112b74..d0d9dcaf81 100644 --- a/test/openssl/test_pkcs7.rb +++ b/test/openssl/test_pkcs7.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -172,6 +172,28 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase assert_equal(:encrypted, p7.type) end + def test_smime + 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) + smime = OpenSSL::PKCS7.write_smime(p7) + assert_equal(true, smime.start_with?(<<END)) +MIME-Version: 1.0 +Content-Disposition: attachment; filename="smime.p7m" +Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m" +Content-Transfer-Encoding: base64 + +END + assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der) + + smime = OpenSSL::PKCS7.write_smime(p7, nil, 0) + assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der) + end + def test_degenerate_pkcs7 ca_cert_pem = <<END -----BEGIN CERTIFICATE----- diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index 8c8fbaeefb..6397e76d3f 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index d651949842..2c839b7dfb 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 95b5a6426e..1278a8b1ba 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) && defined?(OpenSSL::PKey::EC) @@ -289,6 +289,22 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal true, point.on_curve? end + def test_ec_point_add + group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2) + group.point_conversion_form = :uncompressed + gen = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 })) + group.set_generator(gen, 19, 1) + + point_a = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 })) + point_b = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 10 0D })) + + result = point_a.add(point_b) + assert_equal B(%w{ 04 0D 07 }), result.to_octet_string(:uncompressed) + + assert_raise(TypeError) { point_a.add(nil) } + assert_raise(ArgumentError) { point_a.add } + end + def test_ec_point_mul begin # y^2 = x^3 + 2x + 2 over F_17 diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index ef02717d8b..a9587aa1a4 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -1,9 +1,18 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase + def test_no_private_exp + key = OpenSSL::PKey::RSA.new + rsa = Fixtures.pkey("rsa2048") + key.set_key(rsa.n, rsa.e, nil) + key.set_factors(rsa.p, rsa.q) + assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt("foo") } + assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") } + end + def test_padding key = OpenSSL::PKey::RSA.new(512, 3) @@ -31,14 +40,32 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase end def test_private + # Generated by key size and public exponent key = OpenSSL::PKey::RSA.new(512, 3) assert(key.private?) + + # Generated by DER key2 = OpenSSL::PKey::RSA.new(key.to_der) assert(key2.private?) + + # public key key3 = key.public_key assert(!key3.private?) + + # Generated by public key DER key4 = OpenSSL::PKey::RSA.new(key3.to_der) assert(!key4.private?) + rsa1024 = Fixtures.pkey("rsa1024") + + # Generated by RSA#set_key + key5 = OpenSSL::PKey::RSA.new + key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert(key5.private?) + + # Generated by RSA#set_key, without d + key6 = OpenSSL::PKey::RSA.new + key6.set_key(rsa1024.n, rsa1024.e, nil) + assert(!key6.private?) end def test_new @@ -153,6 +180,40 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase } end + def test_export + rsa1024 = Fixtures.pkey("rsa1024") + key = OpenSSL::PKey::RSA.new + + # key has only n, e and d + key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert_equal rsa1024.public_key.export, key.export + + # key has only n, e, d, p and q + key.set_factors(rsa1024.p, rsa1024.q) + assert_equal rsa1024.public_key.export, key.export + + # key has n, e, d, p, q, dmp1, dmq1 and iqmp + key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) + assert_equal rsa1024.export, key.export + end + + def test_to_der + rsa1024 = Fixtures.pkey("rsa1024") + key = OpenSSL::PKey::RSA.new + + # key has only n, e and d + key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert_equal rsa1024.public_key.to_der, key.to_der + + # key has only n, e, d, p and q + key.set_factors(rsa1024.p, rsa1024.q) + assert_equal rsa1024.public_key.to_der, key.to_der + + # key has n, e, d, p, q, dmp1, dmq1 and iqmp + key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) + assert_equal rsa1024.to_der, key.to_der + end + def test_RSAPrivateKey rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ @@ -295,6 +356,85 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase } end + def test_private_encoding + rsa1024 = Fixtures.pkey("rsa1024") + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(0), + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId("rsaEncryption"), + OpenSSL::ASN1::Null(nil) + ]), + OpenSSL::ASN1::OctetString(rsa1024.to_der) + ]) + assert_equal asn1.to_der, rsa1024.private_to_der + assert_same_rsa rsa1024, OpenSSL::PKey.read(asn1.to_der) + + pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMvCxLDUQKc+1P4+ + Q6AeFwYDvWfALb+cvzlUEadGoPE6qNWHsLFoo8RFgeyTgE8KQTduu1OE9Zz2SMcR + BDu5/1jWtsLPSVrI2ofLLBARUsWanVyki39DeB4u/xkP2mKGjAokPIwOI3oCthSZ + lzO9bj3voxTf6XngTqUX8l8URTmHAgMBAAECgYEApKX8xBqvJ7XI7Kypfo/x8MVC + 3rxW+1eQ2aVKIo4a7PKGjQz5RVIVyzqTUvSZoMTbkAxlSIbO5YfJpTnl3tFcOB6y + QMxqQPW/pl6Ni3EmRJdsRM5MsPBRZOfrXxOCdvXu1TWOS1S1TrvEr/TyL9eh2WCd + CGzpWgdO4KHce7vs7pECQQDv6DGoG5lHnvbvj9qSJb9K5ebRJc8S+LI7Uy5JHC0j + zsHTYPSqBXwPVQdGbgCEycnwwKzXzT2QxAQmJBQKun2ZAkEA2W3aeAE7Xi6zo2eG + 4Cx4UNMHMIdfBRS7VgoekwybGmcapqV0aBew5kHeWAmxP1WUZ/dgZh2QtM1VuiBA + qUqkHwJBAOJLCRvi/JB8N7z82lTk2i3R8gjyOwNQJv6ilZRMyZ9vFZFHcUE27zCf + Kb+bX03h8WPwupjMdfgpjShU+7qq8nECQQDBrmyc16QVyo40sgTgblyiysitvviy + ovwZsZv4q5MCmvOPnPUrwGbRRb2VONUOMOKpFiBl9lIv7HU//nj7FMVLAkBjUXED + 83dA8JcKM+HlioXEAxCzZVVhN+D63QwRwkN08xAPklfqDkcqccWDaZm2hdCtaYlK + funwYkrzI1OikQSs + -----END PRIVATE KEY----- + EOF + assert_equal pem, rsa1024.private_to_pem + assert_same_rsa rsa1024, OpenSSL::PKey.read(pem) + end + + def test_private_encoding_encrypted + rsa1024 = Fixtures.pkey("rsa1024") + encoded = rsa1024.private_to_der("aes-128-cbc", "abcdef") + asn1 = OpenSSL::ASN1.decode(encoded) # PKCS #8 EncryptedPrivateKeyInfo + assert_kind_of OpenSSL::ASN1::Sequence, asn1 + assert_equal 2, asn1.value.size + assert_not_equal rsa1024.private_to_der, encoded + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded, "abcdef") + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded) { "abcdef" } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(encoded, "abcxyz") } + + encoded = rsa1024.private_to_pem("aes-128-cbc", "abcdef") + assert_match (/BEGIN ENCRYPTED PRIVATE KEY/), encoded.lines[0] + assert_same_rsa rsa1024, OpenSSL::PKey.read(encoded, "abcdef") + + # certtool --load-privkey=test/fixtures/pkey/rsa1024.pem --to-p8 --password=abcdef + pem = <<~EOF + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIICojAcBgoqhkiG9w0BDAEDMA4ECLqajUdSNfzwAgIEkQSCAoCDWhxr1HUrKLXA + FsFGGQfPT0aKH4gZipaSXXQRl0KwifHwHoDtfo/mAkJVZMnUVOm1AQ4LTFS3EdTy + JUwICGEQHb7QAiokIRoi0K2yHhOxVO8qgbnWuisWpiT6Ru1jCqTs/wcqlqF7z2jM + oXDk/vuekKst1DDXDcHrzhDkwhCQWj6jt1r2Vwaryy0FyeqsWAgBDiK2LsnCgkGD + 21uhNZ/iWMG6tvY9hB8MDdiBJ41YdSG/AKLulAxQ1ibJz0Tasu66TmwFvWhBlME+ + QbqfgmkgWg5buu53SvDfCA47zXihclbtdfW+U3CJ9OJkx0535TVdZbuC1QgKXvG7 + 4iKGFRMWYJqZvZM3GL4xbC75AxjXZsdCfV81VjZxjeU6ung/NRzCuCUcmBOQzo1D + Vv6COwAa6ttQWM0Ti8oIQHdu5Qi+nuOEHDLxCxD962M37H99sEO5cESjmrGVxhEo + 373L4+11geGSCajdp0yiAGnXQfwaKta8cL693bRObN+b1Y+vqtDKH26N9a4R3qgg + 2XwgQ5GH5CODoXZpi0wxncXO+3YuuhGeArtzKSXLNxHzIMlY7wZX+0e9UU03zfV/ + aOe4/q5DpkNxgHePt0oEpamSKY5W3jzVi1dlFWsRjud1p/Grt2zjSWTYClBlJqG1 + A/3IeDZCu+acaePJjFyv5dFffIj2l4bAYB+LFrZlSu3F/EimO/dCDWJ9JGlMK0aF + l9brh7786Mo+YfyklaqMMEHBbbR2Es7PR6Gt7lrcIXmzy9XSsxT6IiD1rG9KKR3i + CQxTup6JAx9w1q+adL+Ypikoy3gGD/ccUY6TtPoCmkQwSCS+JqQnFlCiThDJbu+V + eqqUNkZq + -----END ENCRYPTED PRIVATE KEY----- + EOF + assert_same_rsa rsa1024, OpenSSL::PKey.read(pem, "abcdef") + end + + def test_public_encoding + rsa1024 = Fixtures.pkey("rsa1024") + assert_equal dup_public(rsa1024).to_der, rsa1024.public_to_der + assert_equal dup_public(rsa1024).to_pem, rsa1024.public_to_pem + end + def test_dup key = Fixtures.pkey("rsa1024") key2 = key.dup diff --git a/test/openssl/test_random.rb b/test/openssl/test_random.rb index d5a374540d..33af375720 100644 --- a/test/openssl/test_random.rb +++ b/test/openssl/test_random.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 940bc135ed..eb5b77be02 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -56,6 +56,52 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_socket_open + start_server { |port| + begin + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port) + ssl.sync_close = true + ssl.connect + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + + def test_socket_open_with_context + start_server { |port| + begin + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, context: ctx) + ssl.sync_close = true + ssl.connect + + assert_equal ssl.context, ctx + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + + def test_socket_open_with_local_address_port_context + start_server { |port| + begin + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, "127.0.0.1", 8000, context: ctx) + ssl.sync_close = true + ssl.connect + + assert_equal ssl.context, ctx + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + ensure + ssl&.close + end + } + end + def test_add_certificate ctx_proc = -> ctx { # Unset values set by start_server @@ -139,15 +185,20 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end + def test_add_certificate_chain_file + ctx = OpenSSL::SSL::SSLContext.new + assert ctx.add_certificate_chain_file(Fixtures.file_path("chain", "server.crt")) + end + def test_sysread_and_syswrite start_server { |port| server_connect(port) { |ssl| - str = "x" * 100 + "\n" + str = +("x" * 100 + "\n") ssl.syswrite(str) newstr = ssl.sysread(str.bytesize) assert_equal(str, newstr) - buf = "" + buf = String.new ssl.syswrite(str) assert_same buf, ssl.sysread(str.size, buf) assert_equal(str, buf) @@ -155,23 +206,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end - def test_sysread_nonblock_and_syswrite_nonblock_keywords - start_server(ignore_listener_error: true) do |port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - - assert_warn ("") do - ssl.send(:syswrite_nonblock, "1", exception: false) - ssl.send(:sysread_nonblock, 1, exception: false) rescue nil - ssl.send(:sysread_nonblock, 1, String.new, exception: false) rescue nil - end - ensure - sock&.close - end - end + # TODO fix this test + # def test_sysread_nonblock_and_syswrite_nonblock_keywords + # start_server do |port| + # server_connect(port) do |ssl| + # assert_warning("") do + # ssl.send(:syswrite_nonblock, "12", exception: false) + # ssl.send(:sysread_nonblock, 1, exception: false) rescue nil + # ssl.send(:sysread_nonblock, 1, String.new, exception: false) rescue nil + # end + # end + # end + # end def test_sync_close - start_server { |port| + start_server do |port| begin sock = TCPSocket.new("127.0.0.1", port) ssl = OpenSSL::SSL::SSLSocket.new(sock) @@ -194,7 +243,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ensure sock&.close end - } + end end def test_copy_stream @@ -434,6 +483,29 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_finished_messages + server_finished = nil + server_peer_finished = nil + client_finished = nil + client_peer_finished = nil + + start_server(accept_proc: proc { |server| + server_finished = server.finished_message + server_peer_finished = server.peer_finished_message + }) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE + server_connect(port, ctx) { |ssl| + client_finished = ssl.finished_message + client_peer_finished = ssl.peer_finished_message + sleep 0.05 + ssl.send :stop + } + } + assert_equal(server_finished, client_peer_finished) + assert_equal(server_peer_finished, client_finished) + end + def test_sslctx_set_params ctx = OpenSSL::SSL::SSLContext.new ctx.set_params @@ -1565,6 +1637,20 @@ end } end + def test_fileno + ctx = OpenSSL::SSL::SSLContext.new + sock1, sock2 = socketpair + + socket = OpenSSL::SSL::SSLSocket.new(sock1) + server = OpenSSL::SSL::SSLServer.new(sock2, ctx) + + assert_equal socket.fileno, socket.to_io.fileno + assert_equal server.fileno, server.to_io.fileno + ensure + sock1.close + sock2.close + end + private def start_server_version(version, ctx_proc = nil, @@ -1597,8 +1683,8 @@ end def assert_handshake_error # different OpenSSL versions react differently when facing a SSL/TLS version - # that has been marked as forbidden, therefore either of these may be raised - assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET) { + # that has been marked as forbidden, therefore any of these may be raised + assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::EPIPE) { yield } end diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb index e199f86d2b..89726d4463 100644 --- a/test/openssl/test_ssl_session.rb +++ b/test/openssl/test_ssl_session.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb new file mode 100644 index 0000000000..c57f08cf7a --- /dev/null +++ b/test/openssl/test_ts.rb @@ -0,0 +1,667 @@ +require_relative "utils" + +if defined?(OpenSSL) && defined?(OpenSSL::Timestamp) + +class OpenSSL::TestTimestamp < OpenSSL::TestCase + def intermediate_key + @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH +0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1 +ziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB +AoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6 +D7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE +pfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP +o2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa +/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5 +3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY +FspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh +oicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa +X5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv +y8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ== +-----END RSA PRIVATE KEY----- +_end_of_pem_ + end + + def ee_key + @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9 +P8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl +xCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB +AoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4 +nh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K +b3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR +8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP +5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs +mT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU +n2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2 +UoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X +EWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey +GaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA== +-----END RSA PRIVATE KEY----- +_end_of_pem_ + end + + def ca_cert + @ca_cert ||= OpenSSL::Certs.ca_cert + end + + def ca_store + @ca_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(ca_cert) } + end + + def ts_cert_direct + @ts_cert_direct ||= OpenSSL::Certs.ts_cert_direct(ee_key, ca_cert) + end + + def intermediate_cert + @intermediate_cert ||= OpenSSL::Certs.intermediate_cert(intermediate_key, ca_cert) + end + + def intermediate_store + @intermediate_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(intermediate_cert) } + end + + def ts_cert_ee + @ts_cert_ee ||= OpenSSL::Certs.ts_cert_ee(ee_key, intermediate_cert, intermediate_key) + end + + def test_create_request + req = OpenSSL::Timestamp::Request.new + assert_equal(true, req.cert_requested?) + assert_equal(1, req.version) + assert_nil(req.algorithm) + assert_equal("", req.message_imprint) + assert_nil(req.policy_id) + assert_nil(req.nonce) + end + + def test_request_mandatory_fields + req = OpenSSL::Timestamp::Request.new + assert_raise(OpenSSL::Timestamp::TimestampError) do + tmp = req.to_der + pp OpenSSL::ASN1.decode(tmp) + end + req.algorithm = "sha1" + assert_raise(OpenSSL::Timestamp::TimestampError) do + req.to_der + end + req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") + req.to_der + end + + def test_request_assignment + req = OpenSSL::Timestamp::Request.new + + req.version = 2 + assert_equal(2, req.version) + assert_raise(TypeError) { req.version = nil } + assert_raise(TypeError) { req.version = "foo" } + + req.algorithm = "SHA1" + assert_equal("SHA1", req.algorithm) + assert_raise(TypeError) { req.algorithm = nil } + assert_raise(OpenSSL::ASN1::ASN1Error) { req.algorithm = "xxx" } + + req.message_imprint = "test" + assert_equal("test", req.message_imprint) + assert_raise(TypeError) { req.message_imprint = nil } + + req.policy_id = "1.2.3.4.5" + assert_equal("1.2.3.4.5", req.policy_id) + assert_raise(TypeError) { req.policy_id = 123 } + assert_raise(TypeError) { req.policy_id = nil } + + req.nonce = 42 + assert_equal(42, req.nonce) + assert_raise(TypeError) { req.nonce = "foo" } + assert_raise(TypeError) { req.nonce = nil } + + req.cert_requested = false + assert_equal(false, req.cert_requested?) + req.cert_requested = nil + assert_equal(false, req.cert_requested?) + req.cert_requested = 123 + assert_equal(true, req.cert_requested?) + req.cert_requested = "asdf" + assert_equal(true, req.cert_requested?) + end + + def test_request_serialization + req = OpenSSL::Timestamp::Request.new + + req.version = 2 + req.algorithm = "SHA1" + req.message_imprint = "test" + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = true + + req = OpenSSL::Timestamp::Request.new(req.to_der) + + assert_equal(2, req.version) + assert_equal("SHA1", req.algorithm) + assert_equal("test", req.message_imprint) + assert_equal("1.2.3.4.5", req.policy_id) + assert_equal(42, req.nonce) + assert_equal(true, req.cert_requested?) + + end + + def test_request_re_assignment + #tests whether the potential 'freeing' of previous values in C works properly + req = OpenSSL::Timestamp::Request.new + req.version = 2 + req.version = 3 + req.algorithm = "SHA1" + req.algorithm = "SHA256" + req.message_imprint = "test" + req.message_imprint = "test2" + req.policy_id = "1.2.3.4.5" + req.policy_id = "1.2.3.4.6" + req.nonce = 42 + req.nonce = 24 + req.cert_requested = false + req.cert_requested = true + req.to_der + end + + def test_request_encode_decode + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + qer = OpenSSL::Timestamp::Request.new(req.to_der) + assert_equal(1, qer.version) + assert_equal("SHA1", qer.algorithm) + assert_equal(digest, qer.message_imprint) + assert_equal("1.2.3.4.5", qer.policy_id) + assert_equal(42, qer.nonce) + + #put OpenSSL::ASN1.decode inbetween + qer2 = OpenSSL::Timestamp::Request.new(OpenSSL::ASN1.decode(req.to_der)) + assert_equal(1, qer2.version) + assert_equal("SHA1", qer2.algorithm) + assert_equal(digest, qer2.message_imprint) + assert_equal("1.2.3.4.5", qer2.policy_id) + assert_equal(42, qer2.nonce) + end + + def test_response_constants + assert_equal(0, OpenSSL::Timestamp::Response::GRANTED) + assert_equal(1, OpenSSL::Timestamp::Response::GRANTED_WITH_MODS) + assert_equal(2, OpenSSL::Timestamp::Response::REJECTION) + assert_equal(3, OpenSSL::Timestamp::Response::WAITING) + assert_equal(4, OpenSSL::Timestamp::Response::REVOCATION_WARNING) + assert_equal(5, OpenSSL::Timestamp::Response::REVOCATION_NOTIFICATION) + end + + def test_response_creation + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + + fac = OpenSSL::Timestamp::Factory.new + time = Time.now + fac.gen_time = time + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + resp = OpenSSL::Timestamp::Response.new(resp) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_nil(resp.failure_info) + assert_equal([], resp.status_text) + assert_equal(1, resp.token_info.version) + assert_equal("1.2.3.4.5", resp.token_info.policy_id) + assert_equal("SHA1", resp.token_info.algorithm) + assert_equal(digest, resp.token_info.message_imprint) + assert_equal(1, resp.token_info.serial_number) + assert_equal(time.to_i, resp.token_info.gen_time.to_i) + assert_equal(false, resp.token_info.ordering) + assert_nil(resp.token_info.nonce) + assert_cert(ts_cert_ee, resp.tsa_certificate) + #compare PKCS7 + token = OpenSSL::ASN1.decode(resp.to_der).value[1] + assert_equal(token.to_der, resp.token.to_der) + end + + def test_response_mandatory_fields + fac = OpenSSL::Timestamp::Factory.new + req = OpenSSL::Timestamp::Request.new + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.algorithm = "sha1" + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.message_imprint = OpenSSL::Digest::SHA1.new.digest("data") + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.gen_time = Time.now + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + fac.default_policy_id = "1.2.3.4.5" + assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status + fac.default_policy_id = nil + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + req.policy_id = "1.2.3.4.5" + assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status + end + + def test_response_allowed_digests + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + req.message_imprint = OpenSSL::Digest::SHA1.digest("test") + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.default_policy_id = "1.2.3.4.6" + + # None allowed by default + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Explicitly allow SHA1 (string) + fac.allowed_digests = ["sha1"] + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status + + # Explicitly allow SHA1 (object) + fac.allowed_digests = [OpenSSL::Digest::SHA1.new] + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status + + # Others not allowed + req.algorithm = "SHA256" + req.message_imprint = OpenSSL::Digest::SHA256.digest("test") + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Non-Array + fac.allowed_digests = 123 + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status + + # Non-String, non-Digest Array element + fac.allowed_digests = ["sha1", OpenSSL::Digest::SHA1.new, 123] + assert_raise(TypeError) do + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + end + + def test_response_default_policy + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.6" + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_equal("1.2.3.4.6", resp.token_info.policy_id) + end + + def test_response_bad_purpose + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + + assert_raise(OpenSSL::Timestamp::TimestampError) do + fac.create_timestamp(ee_key, intermediate_cert, req) + end + end + + def test_no_cert_requested + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.5" + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status) + assert_nil(resp.tsa_certificate) + end + + def test_response_no_policy_defined + assert_raise(OpenSSL::Timestamp::TimestampError) do + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + fac.create_timestamp(ee_key, ts_cert_ee, req) + end + end + + def test_verify_ee_no_req + assert_raise(TypeError) do + ts, _ = timestamp_ee + ts.verify(nil, ca_cert) + end + end + + def test_verify_ee_no_store + assert_raise(TypeError) do + ts, req = timestamp_ee + ts.verify(req, nil) + end + end + + def test_verify_ee_wrong_root_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, intermediate_store) + end + end + + def test_verify_ee_wrong_root_wrong_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, intermediate_store, [ca_cert]) + end + end + + def test_verify_ee_nonce_mismatch + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + req.nonce = 1 + ts.verify(req, ca_store, [intermediate_cert]) + end + end + + def test_verify_ee_intermediate_missing + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee + ts.verify(req, ca_store) + end + end + + def test_verify_ee_intermediate + ts, req = timestamp_ee + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_ee_intermediate_type_error + ts, req = timestamp_ee + assert_raise(TypeError) { ts.verify(req, [ca_cert], 123) } + end + + def test_verify_ee_def_policy + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.default_policy_id = "1.2.3.4.5" + + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_direct + ts, req = timestamp_direct + ts.verify(req, ca_store) + end + + def test_verify_direct_redundant_untrusted + ts, req = timestamp_direct + ts.verify(req, ca_store, [ts.tsa_certificate, ts.tsa_certificate]) + end + + def test_verify_direct_unrelated_untrusted + ts, req = timestamp_direct + ts.verify(req, ca_store, [intermediate_cert]) + end + + def test_verify_direct_wrong_root + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_direct + ts.verify(req, intermediate_store) + end + end + + def test_verify_direct_no_cert_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_direct_no_cert + ts.verify(req, ca_store) + end + end + + def test_verify_ee_no_cert + ts, req = timestamp_ee_no_cert + ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) + end + + def test_verify_ee_no_cert_no_intermediate + assert_raise(OpenSSL::Timestamp::TimestampError) do + ts, req = timestamp_ee_no_cert + ts.verify(req, ca_store, [ts_cert_ee]) + end + end + + def test_verify_ee_additional_certs_array + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [intermediate_cert] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(2, ts.token.certificates.size) + fac.additional_certs = nil + ts.verify(req, ca_store) + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(1, ts.token.certificates.size) + end + + def test_verify_ee_additional_certs_with_root + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [intermediate_cert, ca_cert] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_equal(3, ts.token.certificates.size) + ts.verify(req, ca_store) + end + + def test_verify_ee_cert_inclusion_not_requested + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.nonce = 42 + req.cert_requested = false + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + #needed because the Request contained no policy identifier + fac.default_policy_id = '1.2.3.4.5' + fac.additional_certs = [ ts_cert_ee, intermediate_cert ] + ts = fac.create_timestamp(ee_key, ts_cert_ee, req) + assert_nil(ts.token.certificates) #since cert_requested? == false + ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]) + end + + def test_reusable + #test if req and faq are reusable, i.e. the internal + #CTX_free methods don't mess up e.g. the certificates + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + fac.additional_certs = [ intermediate_cert ] + ts1 = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts1.verify(req, ca_store) + ts2 = fac.create_timestamp(ee_key, ts_cert_ee, req) + ts2.verify(req, ca_store) + refute_nil(ts1.tsa_certificate) + refute_nil(ts2.tsa_certificate) + end + + def test_token_info_creation + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = OpenSSL::BN.new(123) + + fac = OpenSSL::Timestamp::Factory.new + time = Time.now + fac.gen_time = time + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + + resp = fac.create_timestamp(ee_key, ts_cert_ee, req) + info = resp.token_info + info = OpenSSL::Timestamp::TokenInfo.new(info.to_der) + + assert_equal(1, info.version) + assert_equal("1.2.3.4.5", info.policy_id) + assert_equal("SHA1", info.algorithm) + assert_equal(digest, info.message_imprint) + assert_equal(1, info.serial_number) + assert_equal(time.to_i, info.gen_time.to_i) + assert_equal(false, info.ordering) + assert_equal(123, info.nonce) + end + + private + + def assert_cert expected, actual + assert_equal expected.to_der, actual.to_der + end + + def timestamp_ee + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_ee, req), req + end + + def timestamp_ee_no_cert + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_ee, req), req + end + + def timestamp_direct + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_direct, req), req + end + + def timestamp_direct_no_cert + req = OpenSSL::Timestamp::Request.new + req.algorithm = "SHA1" + digest = OpenSSL::Digest::SHA1.new.digest("test") + req.message_imprint = digest + req.policy_id = "1.2.3.4.5" + req.nonce = 42 + req.cert_requested = false + + fac = OpenSSL::Timestamp::Factory.new + fac.gen_time = Time.now + fac.serial_number = 1 + fac.allowed_digests = ["sha1"] + return fac.create_timestamp(ee_key, ts_cert_direct, req), req + end +end + +end diff --git a/test/openssl/test_x509attr.rb b/test/openssl/test_x509attr.rb index c6c48e86ab..2919d23d2d 100644 --- a/test/openssl/test_x509attr.rb +++ b/test/openssl/test_x509attr.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -79,6 +79,16 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase assert_equal true, attr1 == attr2 assert_equal false, attr1 == attr3 end + + def test_marshal + val = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr = OpenSSL::X509::Attribute.new("challengePassword", val) + deserialized = Marshal.load(Marshal.dump(attr)) + + assert_equal attr.to_der, deserialized.to_der + end end end diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index 40a5b0ad74..ed0758a6b3 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -73,9 +73,12 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase ["basicConstraints","CA:TRUE",true], ["keyUsage","keyCertSign, cRLSign",true], ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], + ["authorityKeyIdentifier","issuer:always,keyid:always",false], ] ca_cert = issue_cert(@ca, @rsa2048, 1, ca_exts, nil, nil) + keyid = get_subject_key_id(ca_cert.to_der, hex: false) + assert_equal keyid, ca_cert.authority_key_identifier + assert_equal keyid, ca_cert.subject_key_identifier ca_cert.extensions.each_with_index{|ext, i| assert_equal(ca_exts[i].first, ext.oid) assert_equal(ca_exts[i].last, ext.critical?) @@ -84,9 +87,10 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase ee1_exts = [ ["keyUsage","Non Repudiation, Digital Signature, Key Encipherment",true], ["subjectKeyIdentifier","hash",false], - ["authorityKeyIdentifier","keyid:always",false], + ["authorityKeyIdentifier","issuer:always,keyid:always",false], ["extendedKeyUsage","clientAuth, emailProtection, codeSigning",false], ["subjectAltName","email:[email protected]",false], + ["authorityInfoAccess","caIssuers;URI:http://www.example.com/caIssuers,OCSP;URI:http://www.example.com/ocsp",false], ] ee1_cert = issue_cert(@ee1, @rsa1024, 2, ee1_exts, ca_cert, @rsa2048) assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der) @@ -94,6 +98,78 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase assert_equal(ee1_exts[i].first, ext.oid) assert_equal(ee1_exts[i].last, ext.critical?) } + assert_nil(ee1_cert.crl_uris) + + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_cnf_) + [crlDistPts] + URI.1 = http://www.example.com/crl + URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + _cnf_ + cdp_cert = generate_cert(@ee1, @rsa1024, 3, ca_cert) + ef.subject_certificate = cdp_cert + cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "@crlDistPts")) + cdp_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"], + cdp_cert.crl_uris + ) + + ef = OpenSSL::X509::ExtensionFactory.new + aia_cert = generate_cert(@ee1, @rsa1024, 4, ca_cert) + ef.subject_certificate = aia_cert + aia_cert.add_extension( + ef.create_extension( + "authorityInfoAccess", + "caIssuers;URI:http://www.example.com/caIssuers," \ + "caIssuers;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary," \ + "OCSP;URI:http://www.example.com/ocsp," \ + "OCSP;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary", + false + ) + ) + aia_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/caIssuers", "ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary"], + aia_cert.ca_issuer_uris + ) + assert_equal( + ["http://www.example.com/ocsp", "ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary"], + aia_cert.ocsp_uris + ) + + no_exts_cert = issue_cert(@ca, @rsa2048, 5, [], nil, nil) + assert_equal nil, no_exts_cert.authority_key_identifier + assert_equal nil, no_exts_cert.subject_key_identifier + assert_equal nil, no_exts_cert.crl_uris + assert_equal nil, no_exts_cert.ca_issuer_uris + assert_equal nil, no_exts_cert.ocsp_uris + end + + def test_invalid_extension + integer = OpenSSL::ASN1::Integer.new(0) + invalid_exts_cert = generate_cert(@ee1, @rsa1024, 1, nil) + ["subjectKeyIdentifier", "authorityKeyIdentifier", "crlDistributionPoints", "authorityInfoAccess"].each do |ext| + invalid_exts_cert.add_extension( + OpenSSL::X509::Extension.new(ext, integer.to_der) + ) + end + + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.authority_key_identifier + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.subject_key_identifier + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.crl_uris + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.ca_issuer_uris + } + assert_raise(OpenSSL::ASN1::ASN1Error, "invalid extension") { + invalid_exts_cert.ocsp_uris + } end def test_sign_and_verify_rsa_sha1 @@ -189,6 +265,17 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase assert_equal false, cert3 == cert4 end + def test_marshal + now = Time.now + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, + not_before: now, not_after: now + 3600) + cert = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + deserialized = Marshal.load(Marshal.dump(cert)) + + assert_equal cert.to_der, deserialized.to_der + end + private def certificate_error_returns_false diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb index 03fdf64dd4..a6d0adc592 100644 --- a/test/openssl/test_x509crl.rb +++ b/test/openssl/test_x509crl.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -118,7 +118,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase ["keyUsage", "cRLSign, keyCertSign", true], ] crl_exts = [ - ["authorityKeyIdentifier", "keyid:always", false], + ["authorityKeyIdentifier", "issuer:always,keyid:always", false], ["issuerAltName", "issuer:copy", false], ] @@ -131,6 +131,9 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal("crlNumber", exts[0].oid) assert_equal(false, exts[0].critical?) + expected_keyid = OpenSSL::TestUtils.get_subject_key_id(cert, hex: false) + assert_equal expected_keyid, crl.authority_key_identifier + assert_equal("authorityKeyIdentifier", exts[1].oid) keyid = OpenSSL::TestUtils.get_subject_key_id(cert) assert_match(/^keyid:#{keyid}/, exts[1].value) @@ -155,6 +158,10 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal("issuerAltName", exts[2].oid) assert_equal("email:[email protected]", exts[2].value) assert_equal(false, exts[2].critical?) + + no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, @rsa2048, OpenSSL::Digest::SHA1.new) + assert_equal nil, no_ext_crl.authority_key_identifier end def test_crlnumber @@ -249,6 +256,22 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal true, rev2 == crl2.revoked[1] end + def test_marshal + now = Time.now + + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) + crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") + rev = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 1 + rev.time = now + } + crl.add_revoked(rev) + deserialized = Marshal.load(Marshal.dump(crl)) + + assert_equal crl.to_der, deserialized.to_der + assert_equal crl.revoked[0].to_der, deserialized.revoked[0].to_der + end + private def crl_error_returns_false diff --git a/test/openssl/test_x509ext.rb b/test/openssl/test_x509ext.rb index 91ce202fec..7ad010d1ed 100644 --- a/test/openssl/test_x509ext.rb +++ b/test/openssl/test_x509ext.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -86,6 +86,19 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase assert_equal true, ext1 == ext2 assert_equal false, ext1 == ext3 end + + def test_marshal + ef = OpenSSL::X509::ExtensionFactory.new + ext = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + deserialized = Marshal.load(Marshal.dump(ext)) + + assert_equal ext.to_der, deserialized.to_der + end + + def test_value_der + ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + assert_equal @basic_constraints_value.to_der, ext.value_der + end end end diff --git a/test/openssl/test_x509name.rb b/test/openssl/test_x509name.rb index 8a4596ea6e..4ec5db2018 100644 --- a/test/openssl/test_x509name.rb +++ b/test/openssl/test_x509name.rb @@ -1,5 +1,5 @@ # coding: ASCII-8BIT -# frozen_string_literal: false +# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) @@ -242,16 +242,15 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message) } - bad_dc = "exa#{"pm"}le" # <- typo of "example" [ - ["DC=org,DC=#{bad_dc},CN", "CN"], + ["DC=org,DC=exapmle,CN", "CN"], ["DC=org,DC=example,", ""], - ["DC=org,DC=#{bad_dc},CN=www.example.org;", "CN=www.example.org;"], - ["DC=org,DC=#{bad_dc},CN=#www.example.org", "CN=#www.example.org"], - ["DC=org,DC=#{bad_dc},CN=#777777.example.org", "CN=#777777.example.org"], - ["DC=org,DC=#{bad_dc},CN=\"www.example\".org", "CN=\"www.example\".org"], - ["DC=org,DC=#{bad_dc},CN=www.\"example.org\"", "CN=www.\"example.org\""], - ["DC=org,DC=#{bad_dc},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"], + ["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) @@ -390,7 +389,7 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase dn.each { |x| name.add_entry(*x) } str = name.to_utf8 - expected = "CN=フー\\, バー,DC=ruby-lang,DC=org".force_encoding("UTF-8") + expected = String.new("CN=フー\\, バー,DC=ruby-lang,DC=org").force_encoding("UTF-8") assert_equal expected, str assert_equal Encoding.find("UTF-8"), str.encoding @@ -403,6 +402,9 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' assert_equal n1, n2 + + assert_equal(false, n1 == 'abc') + assert_equal(false, n2 == nil) end def test_spaceship @@ -416,6 +418,9 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_equal(-1, n2 <=> n3) assert_equal(1, n3 <=> n1) assert_equal(1, n3 <=> n2) + assert_equal(nil, n1 <=> 'abc') + assert_equal(nil, n2 <=> 123) + assert_equal(nil, n3 <=> nil) end def name_hash(name) @@ -448,6 +453,13 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_equal false, name0.eql?(name2) end + def test_marshal + name = OpenSSL::X509::Name.new([["DC", "org"], ["DC", "ruby-lang"], ["CN", "bar.ruby-lang.org"]]) + deserialized = Marshal.load(Marshal.dump(name)) + + assert_equal name.to_der, deserialized.to_der + end + def test_dup name = OpenSSL::X509::Name.parse("/CN=ruby-lang.org") assert_equal(name.to_der, name.dup.to_der) diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index 2c447ccdd5..bace06b347 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) @@ -151,6 +151,13 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal false, req1 == req3 end + def test_marshal + req = issue_csr(0, @dn, @rsa1024, "sha256") + deserialized = Marshal.load(Marshal.dump(req)) + + assert_equal req.to_der, deserialized.to_der + end + private def request_error_returns_false diff --git a/test/openssl/test_x509store.rb b/test/openssl/test_x509store.rb index 6412249b93..8223c9b7ac 100644 --- a/test/openssl/test_x509store.rb +++ b/test/openssl/test_x509store.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require_relative "utils" if defined?(OpenSSL) diff --git a/test/openssl/ut_eof.rb b/test/openssl/ut_eof.rb index bd62fd50f9..cf1f2d423e 100644 --- a/test/openssl/ut_eof.rb +++ b/test/openssl/ut_eof.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require 'test/unit' if defined?(OpenSSL) @@ -18,12 +18,12 @@ module OpenSSL::TestEOF assert_nil(f.read(1)) } open_file("") {|f| - s = "x" + s = +"x" assert_equal("", f.read(nil, s)) assert_equal("", s) } open_file("") {|f| - s = "x" + s = +"x" assert_nil(f.read(10, s)) assert_equal("", s) } @@ -75,12 +75,12 @@ module OpenSSL::TestEOF assert_equal("", f.read(0)) } open_file("a") {|f| - s = "x" + s = +"x" assert_equal("a", f.read(nil, s)) assert_equal("a", s) } open_file("a") {|f| - s = "x" + s = +"x" assert_equal("a", f.read(10, s)) assert_equal("a", s) } diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb index bf19163052..acece97911 100644 --- a/test/openssl/utils.rb +++ b/test/openssl/utils.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true begin require "openssl" @@ -52,15 +52,18 @@ module OpenSSL::TestUtils @file_cache[[category, name]] ||= File.read(File.join(__dir__, "fixtures", category, name + ".pem")) end + + def file_path(category, name) + File.join(__dir__, "fixtures", category, name) + end end module_function - def issue_cert(dn, key, serial, extensions, issuer, issuer_key, - not_before: nil, not_after: nil, digest: "sha256") + def generate_cert(dn, key, serial, issuer, + not_before: nil, not_after: nil) cert = OpenSSL::X509::Certificate.new issuer = cert unless issuer - issuer_key = key unless issuer_key cert.version = 2 cert.serial = serial cert.subject = dn @@ -69,6 +72,16 @@ module OpenSSL::TestUtils now = Time.now cert.not_before = not_before || now - 3600 cert.not_after = not_after || now + 3600 + cert + end + + + def issue_cert(dn, key, serial, extensions, issuer, issuer_key, + not_before: nil, not_after: nil, digest: "sha256") + cert = generate_cert(dn, key, serial, issuer, + not_before: not_before, not_after: not_after) + issuer = cert unless issuer + issuer_key = key unless issuer_key ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = issuer @@ -107,13 +120,18 @@ module OpenSSL::TestUtils crl end - def get_subject_key_id(cert) + def get_subject_key_id(cert, hex: true) 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 + digest = OpenSSL::Digest::SHA1.digest(pkvalue) + if hex + digest.unpack("H2"*20).join(":").upcase + else + digest + end end def openssl?(major = nil, minor = nil, fix = nil, patch = 0) @@ -189,6 +207,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE, start_immediately: true, ctx_proc: nil, server_proc: method(:readwrite_loop), + accept_proc: proc{}, ignore_listener_error: false, &block) IO.pipe {|stop_pipe_r, stop_pipe_w| store = OpenSSL::X509::Store.new @@ -222,6 +241,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase readable, = IO.select([ssls, stop_pipe_r]) break if readable.include? stop_pipe_r ssl = ssls.accept + accept_proc.call(ssl) rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET retry if ignore_listener_error @@ -268,7 +288,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase begin timeout = EnvUtil.apply_timeout_scale(30) th.join(timeout) or - th.raise(RuntimeError, "[start_server] thread did not exit in #{ timeout } secs") + th.raise(RuntimeError, "[start_server] thread did not exit in #{timeout} secs") rescue (defined?(MiniTest::Skip) ? MiniTest::Skip : Test::Unit::PendedError) # MiniTest::Skip is for the Ruby tree pend = $! @@ -316,4 +336,62 @@ class OpenSSL::PKeyTestCase < OpenSSL::TestCase end end +module OpenSSL::Certs + include OpenSSL::TestUtils + + module_function + + def ca_cert + ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Timestamp Root CA") + + ca_exts = [ + ["basicConstraints","CA:TRUE,pathlen:1",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + OpenSSL::TestUtils.issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) + end + + def ts_cert_direct(key, ca_cert) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server Direct") + + exts = [ + ["basicConstraints","CA:FALSE",true], + ["keyUsage","digitalSignature, nonRepudiation", true], + ["subjectKeyIdentifier", "hash",false], + ["authorityKeyIdentifier","keyid,issuer", false], + ["extendedKeyUsage", "timeStamping", true] + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 2, exts, ca_cert, Fixtures.pkey("rsa2048")) + end + + def intermediate_cert(key, ca_cert) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Timestamp Intermediate CA") + + exts = [ + ["basicConstraints","CA:TRUE,pathlen:0",true], + ["keyUsage","keyCertSign, cRLSign",true], + ["subjectKeyIdentifier","hash",false], + ["authorityKeyIdentifier","keyid:always",false], + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 3, exts, ca_cert, Fixtures.pkey("rsa2048")) + end + + def ts_cert_ee(key, intermediate, im_key) + dn = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server End Entity") + + exts = [ + ["keyUsage","digitalSignature, nonRepudiation", true], + ["subjectKeyIdentifier", "hash",false], + ["authorityKeyIdentifier","keyid,issuer", false], + ["extendedKeyUsage", "timeStamping", true] + ] + + OpenSSL::TestUtils.issue_cert(dn, key, 4, exts, intermediate, im_key) + end +end + end |