diff options
Diffstat (limited to 'test/openssl')
33 files changed, 1372 insertions, 732 deletions
diff --git a/test/openssl/fixtures/pkey/dh1024.pem b/test/openssl/fixtures/pkey/dh1024.pem deleted file mode 100644 index f99c757f21..0000000000 --- a/test/openssl/fixtures/pkey/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 -pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG -AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC ------END DH PARAMETERS----- diff --git a/test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem b/test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem new file mode 100644 index 0000000000..9b182b7201 --- /dev/null +++ b/test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- diff --git a/test/openssl/fixtures/pkey/dsa2048.pem b/test/openssl/fixtures/pkey/dsa2048.pem new file mode 100644 index 0000000000..3f22b22b58 --- /dev/null +++ b/test/openssl/fixtures/pkey/dsa2048.pem @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICXgIBADCCAjYGByqGSM44BAEwggIpAoIBAQDXZhJ/dQoWkQELzjzlx8FtIp96 +voCYe5NY0H8j0jz7GyHpXt41+MteqkZK3/Ah+cNR9uG8iEYArAZ71LcWotfee2Gz +xdxozr9bRt0POYhO2YIsfMpBrEskPsDH2g/2nFV8l4OJgxU2qZUrF4PN5ha+Mu6u +sVtN8hjvAvnbf4Pxn0b8NN9f4PJncroUa8acv5WsV85E1RW7NYCefggU4LytYIHg +euRF9eY9gVCX5MkUgW2xODHIYJhwk/+5lJxG7qUsSahD/nPHO/yoWgdVHq2DkdTq +KYXkAxx2PJcTBOHTglhE6mgCbEKp8vcfElnBWyCT6QykclZiPXXD2JV829J/Ah0A +vYa+/G/gUZiomyejVje6UsGoCc+vInxmovOL8QKCAQEAhnKEigYPw6u8JY7v5iGo +Ylz8qiMFYmaJCwevf3KCjWeEXuNO4OrKdfzkQl1tPuGLioYFfP1A2yGosjdUdLEB +0JqnzlKxUp+G6RfBj+WYzbgc5hr7t0M+reAJh09/hDzqfxjcgiHstq7mpRXBP8Y7 +iu27s7TRYJNSAYRvWcXNSBEUym3mHBBbZn7VszYooSrn60/iZ8I+VY1UF/fgqhbj +JfaaZNQCDO9K3Vb3rsXoYd8+bOZIen9uHB+pNjMqhpl4waysqrlpGFeeqdxivH6S +vkrHLs6/eWVMnS08RdcryoCrI3Bm8mMBKQglDwKLnWLfzG565qEhslzyCd/l9k9a +cwQfAh0Ao8/g72fSFmo04FizM7DZJSIPqDLjfZu9hLvUFA== +-----END PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/p256_too_large.pem b/test/openssl/fixtures/pkey/p256_too_large.pem new file mode 100644 index 0000000000..a73ac37f87 --- /dev/null +++ b/test/openssl/fixtures/pkey/p256_too_large.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIP+TT0V8Fndsnacji9tyf6hmhHywcOWTee9XkiBeJoVloAoGCCqGSM49 +AwEHoUQDQgAEBkhhJIU/2/YdPSlY2I1k25xjK4trr5OXSgXvBC21PtY0HQ7lor7A +jzT0giJITqmcd81fwGw5+96zLcdxTF1hVQ== +-----END EC PRIVATE KEY----- diff --git a/test/openssl/fixtures/pkey/p384_invalid.pem b/test/openssl/fixtures/pkey/p384_invalid.pem new file mode 100644 index 0000000000..d5cdc9a3af --- /dev/null +++ b/test/openssl/fixtures/pkey/p384_invalid.pem @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDDA1Tm0m7YhkfeVpFuarAJYVlHp2tQj+1fOBiLa10t9E8TiQO/hVfxB +vGaVEQwOheWgBwYFK4EEACKhZANiAASyGqmryZGqdpsq5gEDIfNvgC3AwSJxiBCL +XKHBTFRp+tCezLDOK/6V8KK/vVGBJlGFW6/I7ahyXprxS7xs7hPA9iz5YiuqXlu+ +lbrIpZOz7b73hyQQCkvbBO/Avg+hPAk= +-----END EC PRIVATE KEY----- diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index 6bd847806b..7b1722e5df 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -14,7 +14,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase ["keyUsage","keyCertSign, cRLSign",true], ["subjectKeyIdentifier","hash",false], ] - dgst = OpenSSL::Digest.new('SHA1') + dgst = OpenSSL::Digest.new('SHA256') cert = OpenSSL::TestUtils.issue_cert( subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600) @@ -42,7 +42,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase 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("1.2.840.113549.1.1.11", sig.value[0].oid) assert_equal(OpenSSL::ASN1::Null, sig.value[1].class) dn = tbs_cert.value[3] # issuer @@ -170,7 +170,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase str = +"\000"; str[0] = 0b00000110.chr assert_equal(str, extv.value) - ext = extensions.value[0].value[2] # subjetKeyIdentifier + ext = extensions.value[0].value[2] # subjectKeyIdentifier assert_equal(OpenSSL::ASN1::Sequence, ext.class) assert_equal(2, ext.value.size) assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class) @@ -189,7 +189,7 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase 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.new('SHA1'), tbs_cert.to_der) + cululated_sig = key.sign(OpenSSL::Digest.new('SHA256'), tbs_cert.to_der) assert_equal(cululated_sig, sig_val.value) end @@ -323,14 +323,9 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("3.0".b).to_der } assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("0.40".b).to_der } - begin - oid = (0...100).to_a.join(".").b - obj = OpenSSL::ASN1::ObjectId.new(oid) - assert_equal oid, obj.oid - rescue OpenSSL::ASN1::ASN1Error - pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ - raise - end + oid = (0...100).to_a.join(".").b + obj = OpenSSL::ASN1::ObjectId.new(oid) + assert_equal oid, obj.oid aki = [ OpenSSL::ASN1::ObjectId.new("authorityKeyIdentifier"), @@ -404,9 +399,6 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase def test_utctime encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b, OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39)) - # Seconds is omitted - decode_test B(%w{ 17 0B }) + "1609082343Z".b, - OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 0)) begin # possible range of UTCTime is 1969-2068 currently encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b, @@ -432,8 +424,6 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29)) encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b, OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39)) - decode_test B(%w{ 18 0D }) + "201612081934Z".b, - OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0)) # not implemented # decode_test B(%w{ 18 13 }) + "20161208193439+0930".b, # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30")) diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb index c36d6b89d8..ea88ff06ce 100644 --- a/test/openssl/test_bn.rb +++ b/test/openssl/test_bn.rb @@ -174,6 +174,14 @@ class OpenSSL::TestBN < OpenSSL::TestCase assert_equal(0, 59.to_bn.mod_sqr(59)) end + def test_mod_sqrt + assert_equal(4, 4.to_bn.mod_sqrt(5).mod_sqr(5)) + # One of 189484 or 326277 is returned as a square root of 2 (mod 515761). + assert_equal(2, 2.to_bn.mod_sqrt(515761).mod_sqr(515761)) + assert_equal(0, 5.to_bn.mod_sqrt(5)) + assert_raise(OpenSSL::BNError) { 3.to_bn.mod_sqrt(5) } + end + def test_mod_inverse assert_equal(2, 3.to_bn.mod_inverse(5)) assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } @@ -248,6 +256,10 @@ class OpenSSL::TestBN < OpenSSL::TestCase r5 = OpenSSL::BN.rand_range(256) assert_include(0..255, r5) } + + # Aliases + assert_include(128..255, OpenSSL::BN.pseudo_rand(8)) + assert_include(0..255, OpenSSL::BN.pseudo_rand_range(256)) end begin @@ -330,6 +342,31 @@ class OpenSSL::TestBN < OpenSSL::TestCase e.set_flags(0) assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME)) end + + if respond_to?(:ractor) + ractor + def test_ractor + assert_equal(@e1, Ractor.new { OpenSSL::BN.new("999") }.take) + assert_equal(@e3, Ractor.new { OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2) }.take) + assert_equal("999", Ractor.new(@e1) { |e1| e1.to_s }.take) + assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", Ractor.new(@e3) { |e3| e3.to_s(16) }.take) + assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take) + assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take) + assert_equal(false, Ractor.new { 1.to_bn.zero? }.take) + assert_equal(true, Ractor.new { 1.to_bn.one? }.take) + assert_equal(true, Ractor.new(@e2) { _1.negative? }.take) + assert_equal("-03E7", Ractor.new(@e2) { _1.to_s(16) }.take) + assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take) + assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take) + assert_equal(true, Ractor.new { 0.to_bn.zero? }.take) + assert_equal(true, Ractor.new { 1.to_bn.one? }.take ) + assert_equal(false,Ractor.new { 2.to_bn.odd? }.take) + assert_equal(true, Ractor.new(@e2) { _1.negative? }.take) + assert_include(128..255, Ractor.new { OpenSSL::BN.rand(8)}.take) + assert_include(0...2**32, Ractor.new { OpenSSL::BN.generate_prime(32) }.take) + assert_equal(0, Ractor.new { OpenSSL::BN.new(999).get_flags(OpenSSL::BN::CONSTTIME) }.take) + end + end end end diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index 6d18c0c85c..41885fd59b 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -108,12 +108,6 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_not_equal s1, s2 end - def test_empty_data - cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt - cipher.random_key - assert_raise(ArgumentError) { cipher.update("") } - end - def test_initialize cipher = OpenSSL::Cipher.new("DES-EDE3-CBC") assert_raise(RuntimeError) { cipher.__send__(:initialize, "DES-EDE3-CBC") } @@ -135,14 +129,11 @@ class OpenSSL::TestCipher < OpenSSL::TestCase end def test_ciphers - OpenSSL::Cipher.ciphers.each{|name| - next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name - begin - assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) - rescue OpenSSL::Cipher::CipherError => e - raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message - end - } + ciphers = OpenSSL::Cipher.ciphers + assert_kind_of Array, ciphers + assert_include ciphers, "aes-128-cbc" + assert_include ciphers, "aes128" # alias of aes-128-cbc + assert_include ciphers, "aes-128-gcm" end def test_AES @@ -214,7 +205,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct2) } end if has_cipher?("aes-128-ccm") && OpenSSL::Cipher.new("aes-128-ccm").authenticated? && - OpenSSL::OPENSSL_VERSION_NUMBER >= 0x1010103f # version >= 1.1.1c + openssl?(1, 1, 1, 0x03, 0xf) # version >= 1.1.1c def test_aes_gcm # GCM spec Appendix B Test Case 4 @@ -340,6 +331,22 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal tag1, tag2 end + def test_aes_keywrap_pad + # RFC 5649 Section 6; The second example + kek = ["5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"].pack("H*") + key = ["466f7250617369"].pack("H*") + wrap = ["afbeb0f07dfbf5419200f2ccb50bb24f"].pack("H*") + + begin + cipher = OpenSSL::Cipher.new("id-aes192-wrap-pad").encrypt + rescue OpenSSL::Cipher::CipherError, RuntimeError + omit "id-aes192-wrap-pad is not supported: #$!" + end + cipher.key = kek + ct = cipher.update(key) << cipher.final + assert_equal wrap, ct + end + def test_non_aead_cipher_set_auth_data assert_raise(OpenSSL::Cipher::CipherError) { cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt diff --git a/test/openssl/test_config.rb b/test/openssl/test_config.rb index 769e65ceb5..6dbb9c6138 100644 --- a/test/openssl/test_config.rb +++ b/test/openssl/test_config.rb @@ -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] - [doller ] + [dollar ] 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(['default', 'default1 default2', 'dollar', '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,29 +84,26 @@ __EOC__ 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']) + # 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']) - excn = assert_raise(OpenSSL::ConfigError) do + assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: variable has no value/) 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 + assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: no close brace/) do OpenSSL::Config.parse("foo = $(bar") end - assert_equal("error in line 1: no close brace", excn.message) - excn = assert_raise(OpenSSL::ConfigError) do + assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: missing equal sign/) 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 + assert_raise_with_message(OpenSSL::ConfigError, /error in line 7: missing close square bracket/) do OpenSSL::Config.parse(<<__EOC__) # comment 1 # comments @@ -117,7 +114,6 @@ __EOC__ [third # section not terminated __EOC__ end - assert_equal("error in line 7: missing close square bracket", excn.message) end def test_s_parse_include diff --git a/test/openssl/test_digest.rb b/test/openssl/test_digest.rb index 8d7046e831..988330e405 100644 --- a/test/openssl/test_digest.rb +++ b/test/openssl/test_digest.rb @@ -54,7 +54,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def test_digest_constants - %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name| + %w{MD5 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name| assert_not_nil(OpenSSL::Digest.new(name)) klass = OpenSSL::Digest.const_get(name.tr('-', '_')) assert_not_nil(klass.new) @@ -67,7 +67,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def encode16(str) - str.unpack("H*").first + str.unpack1("H*") end def test_sha2 @@ -88,7 +88,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def test_sha512_truncate - pend "SHA512_224 is not implemented" unless digest_available?('SHA512-224') + pend "SHA512_224 is not implemented" unless digest_available?('sha512-224') sha512_224_a = "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327" sha512_256_a = "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8" @@ -100,7 +100,7 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def test_sha3 - pend "SHA3 is not implemented" unless digest_available?('SHA3-224') + pend "SHA3 is not implemented" unless digest_available?('sha3-224') s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7' s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a' s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004' @@ -126,6 +126,15 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end end + def test_digests + digests = OpenSSL::Digest.digests + assert_kind_of Array, digests + assert_include digests, "md5" + assert_include digests, "sha1" + assert_include digests, "sha256" + assert_include digests, "sha512" + end + private def check_digest(oid) @@ -138,11 +147,8 @@ class OpenSSL::TestDigest < OpenSSL::TestCase end def digest_available?(name) - begin - OpenSSL::Digest.new(name) - rescue RuntimeError - false - end + @digests ||= OpenSSL::Digest.digests + @digests.include?(name) end end diff --git a/test/openssl/test_engine.rb b/test/openssl/test_engine.rb index 1ede6ed086..b6025f915b 100644 --- a/test/openssl/test_engine.rb +++ b/test/openssl/test_engine.rb @@ -26,7 +26,7 @@ class OpenSSL::TestEngine < OpenSSL::TestCase with_openssl <<-'end;' orig = OpenSSL::Engine.engines pend "'openssl' is already loaded" if orig.any? { |e| e.id == "openssl" } - engine = get_engine + engine = OpenSSL::Engine.by_id("openssl") assert_not_nil(engine) assert_equal(1, OpenSSL::Engine.engines.size - orig.size) end; @@ -34,7 +34,7 @@ class OpenSSL::TestEngine < OpenSSL::TestCase def test_openssl_engine_id_name_inspect with_openssl <<-'end;' - engine = get_engine + engine = OpenSSL::Engine.by_id("openssl") assert_equal("openssl", engine.id) assert_not_nil(engine.name) assert_not_nil(engine.inspect) @@ -43,7 +43,7 @@ class OpenSSL::TestEngine < OpenSSL::TestCase def test_openssl_engine_digest_sha1 with_openssl <<-'end;' - engine = get_engine + engine = OpenSSL::Engine.by_id("openssl") digest = engine.digest("SHA1") assert_not_nil(digest) data = "test" @@ -59,12 +59,21 @@ class OpenSSL::TestEngine < OpenSSL::TestCase end with_openssl(<<-'end;', ignore_stderr: true) - engine = get_engine + engine = OpenSSL::Engine.by_id("openssl") algo = "RC4" data = "a" * 1000 key = OpenSSL::Random.random_bytes(16) - encrypted = crypt_data(data, key, :encrypt) { engine.cipher(algo) } - decrypted = crypt_data(encrypted, key, :decrypt) { OpenSSL::Cipher.new(algo) } + + cipher = engine.cipher(algo) + cipher.encrypt + cipher.key = key + encrypted = cipher.update(data) + cipher.final + + cipher = OpenSSL::Cipher.new(algo) + cipher.decrypt + cipher.key = key + decrypted = cipher.update(encrypted) + cipher.final + assert_equal(data, decrypted) end; end @@ -73,25 +82,10 @@ class OpenSSL::TestEngine < OpenSSL::TestCase # this is required because OpenSSL::Engine methods change global state def with_openssl(code, **opts) - assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;", **opts) - require #{__FILE__.dump} - include OpenSSL::TestEngine::Utils + assert_separately(["-ropenssl"], <<~"end;", **opts) #{code} end; end - - module Utils - def get_engine - OpenSSL::Engine.by_id("openssl") - end - - def crypt_data(data, key, mode) - cipher = yield - cipher.send mode - cipher.key = key - cipher.update(data) + cipher.final - end - end end end diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb index 8cd474f9a3..4a3dd43a41 100644 --- a/test/openssl/test_fips.rb +++ b/test/openssl/test_fips.rb @@ -4,22 +4,46 @@ require_relative 'utils' if defined?(OpenSSL) class OpenSSL::TestFIPS < OpenSSL::TestCase + def test_fips_mode_get_is_true_on_fips_mode_enabled + unless ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"] + omit "Only for FIPS mode environment" + end + + assert_separately(["-ropenssl"], <<~"end;") + assert OpenSSL.fips_mode == true, ".fips_mode should return true on FIPS mode enabled" + end; + end + + def test_fips_mode_get_is_false_on_fips_mode_disabled + if ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"] + omit "Only for non-FIPS mode environment" + end + + assert_separately(["-ropenssl"], <<~"end;") + message = ".fips_mode should return false on FIPS mode disabled. " \ + "If you run the test on FIPS mode, please set " \ + "TEST_RUBY_OPENSSL_FIPS_ENABLED=true" + assert OpenSSL.fips_mode == false, message + end; + end + def test_fips_mode_is_reentrant - OpenSSL.fips_mode = false - OpenSSL.fips_mode = false + assert_separately(["-ropenssl"], <<~"end;") + OpenSSL.fips_mode = false + OpenSSL.fips_mode = false + end; end - def test_fips_mode_get - return unless OpenSSL::OPENSSL_FIPS - assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;") - require #{__FILE__.dump} + def test_fips_mode_get_with_fips_mode_set + omit('OpenSSL is not FIPS-capable') unless OpenSSL::OPENSSL_FIPS + assert_separately(["-ropenssl"], <<~"end;") begin OpenSSL.fips_mode = true - assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true" + assert OpenSSL.fips_mode == true, ".fips_mode should return true when .fips_mode=true" OpenSSL.fips_mode = false - assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false" + assert OpenSSL.fips_mode == false, ".fips_mode should return false when .fips_mode=false" rescue OpenSSL::OpenSSLError pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping" end diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb index 2f53a813e1..3cb707448a 100644 --- a/test/openssl/test_hmac.rb +++ b/test/openssl/test_hmac.rb @@ -62,6 +62,14 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase b64digest = OpenSSL::HMAC.base64digest("MD5", key, "Hi There") assert_equal "kpRyejY4uxwT9I74FYv8nQ==", b64digest end + + def test_zero_length_key + # Empty string as the key + hexdigest = OpenSSL::HMAC.hexdigest("SHA256", "\0"*32, "test") + assert_equal "43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb", hexdigest + hexdigest = OpenSSL::HMAC.hexdigest("SHA256", "", "test") + assert_equal "43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb", hexdigest + end end end diff --git a/test/openssl/test_ns_spki.rb b/test/openssl/test_ns_spki.rb index ed3be86e2c..d76fc9e5cf 100644 --- a/test/openssl/test_ns_spki.rb +++ b/test/openssl/test_ns_spki.rb @@ -22,7 +22,7 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase spki = OpenSSL::Netscape::SPKI.new spki.challenge = "RandomString" spki.public_key = key1.public_key - spki.sign(key1, OpenSSL::Digest.new('SHA1')) + spki.sign(key1, OpenSSL::Digest.new('SHA256')) assert(spki.verify(spki.public_key)) assert(spki.verify(key1.public_key)) assert(!spki.verify(key2.public_key)) @@ -38,13 +38,13 @@ class OpenSSL::TestNSSPI < OpenSSL::TestCase 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(@b64.unpack1("m"), 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) + spki = OpenSSL::Netscape::SPKI.new(@b64.unpack1("m")) assert_equal(@b64, spki.to_pem) - assert_equal(@b64.unpack("m").first, spki.to_der) + assert_equal(@b64.unpack1("m"), spki.to_der) assert_equal("MozillaIsMyFriend", spki.challenge) assert_equal(OpenSSL::PKey::RSA, spki.public_key.class) end diff --git a/test/openssl/test_ocsp.rb b/test/openssl/test_ocsp.rb index ef7321abd6..cf96fc22e5 100644 --- a/test/openssl/test_ocsp.rb +++ b/test/openssl/test_ocsp.rb @@ -99,7 +99,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase request.sign(@cert, @cert_key, [@ca_cert], 0) asn1 = OpenSSL::ASN1.decode(request.to_der) assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der - assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der + assert_equal OpenSSL::ASN1.ObjectId("sha256WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der @@ -228,7 +228,7 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason assert_equal now - 400, single.revocation_time - assert_in_delta (now - 301), single.this_update, 1 + assert_in_delta (now - 300), single.this_update, 1 assert_equal nil, single.next_update assert_equal [], single.extensions diff --git a/test/openssl/test_ossl.rb b/test/openssl/test_ossl.rb index e1d86bd40b..979669a003 100644 --- a/test/openssl/test_ossl.rb +++ b/test/openssl/test_ossl.rb @@ -60,6 +60,19 @@ class OpenSSL::OSSL < OpenSSL::SSLTestCase assert_operator(a_b_time, :<, a_c_time * 10, "fixed_length_secure_compare timing test failed") assert_operator(a_c_time, :<, a_b_time * 10, "fixed_length_secure_compare timing test failed") end + + def test_error_data + # X509V3_EXT_nconf_nid() called from OpenSSL::X509::ExtensionFactory#create_ext is a function + # that uses ERR_raise_data() to append additional information about the error. + # + # The generated message should look like: + # "subjectAltName = IP:not.a.valid.ip.address: bad ip address (value=not.a.valid.ip.address)" + # "subjectAltName = IP:not.a.valid.ip.address: error in extension (name=subjectAltName, value=IP:not.a.valid.ip.address)" + ef = OpenSSL::X509::ExtensionFactory.new + assert_raise_with_message(OpenSSL::X509::ExtensionError, /value=(IP:)?not.a.valid.ip.address\)/) { + ef.create_ext("subjectAltName", "IP:not.a.valid.ip.address") + } + end end end diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index 8316ec2a9c..66e36a7ab4 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -2,7 +2,7 @@ require_relative 'utils' require_relative 'ut_eof' -if defined?(OpenSSL) +if defined?(OpenSSL::SSL) module OpenSSL::SSLPairM def setup @@ -23,7 +23,6 @@ module OpenSSL::SSLPairM sctx = OpenSSL::SSL::SSLContext.new sctx.cert = @svr_cert sctx.key = @svr_key - sctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } sctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx) ns = ssls.accept @@ -116,6 +115,17 @@ module OpenSSL::TestPairM } end + def test_gets_chomp + ssl_pair {|s1, s2| + s1 << "line1\r\nline2\r\nline3\r\n" + s1.close + + assert_equal("line1", s2.gets("\r\n", chomp: true)) + assert_equal("line2\r\n", s2.gets("\r\n", chomp: false)) + assert_equal("line3", s2.gets(chomp: true)) + } + end + def test_gets_eof_limit ssl_pair {|s1, s2| s1.write("hello") @@ -240,12 +250,17 @@ module OpenSSL::TestPairM buf = +"garbage" assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false) - assert_equal "", buf + assert_equal "garbage", buf s1.close buf = +"garbage" - assert_equal nil, s2.read(100, buf) + assert_nil s2.read(100, buf) assert_equal "", buf + + buf = +"garbage" + ret = s2.read(0, buf) + assert_same buf, ret + assert_equal "", ret } end @@ -383,7 +398,6 @@ module OpenSSL::TestPairM ctx2 = OpenSSL::SSL::SSLContext.new ctx2.cert = @svr_cert ctx2.key = @svr_key - ctx2.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } sock1, sock2 = tcp_pair @@ -431,7 +445,6 @@ module OpenSSL::TestPairM ctx = OpenSSL::SSL::SSLContext.new ctx.cert = @svr_cert ctx.key = @svr_key - ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::Fixtures.pkey("dh-1") } sock1, sock2 = tcp_pair diff --git a/test/openssl/test_pkcs12.rb b/test/openssl/test_pkcs12.rb index fdbe753b17..e6b91b52af 100644 --- a/test/openssl/test_pkcs12.rb +++ b/test/openssl/test_pkcs12.rb @@ -5,6 +5,9 @@ if defined?(OpenSSL) module OpenSSL class TestPKCS12 < OpenSSL::TestCase + DEFAULT_PBE_PKEYS = "PBE-SHA1-3DES" + DEFAULT_PBE_CERTS = "PBE-SHA1-3DES" + def setup super ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") @@ -14,47 +17,41 @@ module OpenSSL ["subjectKeyIdentifier","hash",false], ["authorityKeyIdentifier","keyid:always",false], ] - @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil) + ca_key = Fixtures.pkey("rsa-1") + @cacert = issue_cert(ca, ca_key, 1, ca_exts, nil, nil) 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, ca_exts, @cacert, Fixtures.pkey("rsa2048")) + inter_ca_key = Fixtures.pkey("rsa-2") + @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, ca_key) exts = [ ["keyUsage","digitalSignature",true], ["subjectKeyIdentifier","hash",false], ] ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate") - @mykey = Fixtures.pkey("rsa1024") + @mykey = Fixtures.pkey("rsa-3") @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key) end - def test_create + def test_create_single_key_single_cert pkcs12 = OpenSSL::PKCS12.create( "omg", "hello", @mykey, - @mycert + @mycert, + nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, ) - assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mycert, pkcs12.certificate assert_equal @mykey.to_der, pkcs12.key.to_der assert_nil pkcs12.ca_certs + + der = pkcs12.to_der + decoded = OpenSSL::PKCS12.new(der, "omg") + assert_equal @mykey.to_der, decoded.key.to_der + assert_equal @mycert, decoded.certificate + assert_equal [], Array(decoded.ca_certs) end def test_create_no_pass @@ -62,14 +59,17 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= nil, "hello", @mykey, - @mycert + @mycert, + nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, ) - assert_equal @mycert.to_der, pkcs12.certificate.to_der + assert_equal @mycert, pkcs12.certificate assert_equal @mykey.to_der, pkcs12.key.to_der assert_nil pkcs12.ca_certs decoded = OpenSSL::PKCS12.new(pkcs12.to_der) - assert_cert @mycert, decoded.certificate + assert_equal @mycert, decoded.certificate end def test_create_with_chain @@ -80,7 +80,9 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= "hello", @mykey, @mycert, - chain + chain, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, ) assert_equal chain, pkcs12.ca_certs end @@ -95,14 +97,16 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= "hello", @mykey, @mycert, - chain + chain, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, ) 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_include decoded.ca_certs, @cacert + assert_include decoded.ca_certs, @inter_cacert + assert_equal @mycert, decoded.certificate assert_equal @mykey.to_der, decoded.key.to_der end @@ -126,8 +130,8 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= @mykey, @mycert, [], - nil, - nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, 2048 ) @@ -138,8 +142,8 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= @mykey, @mycert, [], - nil, - nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, "omg" ) end @@ -152,7 +156,8 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= @mykey, @mycert, [], - nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, nil, nil, 2048 @@ -165,148 +170,144 @@ Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es= @mykey, @mycert, [], - nil, - nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, nil, "omg" ) end end - def test_new_with_one_key_and_one_cert - # generated with: - # openssl version #=> OpenSSL 1.0.2h 3 May 2016 - # openssl pkcs12 -in <@mycert> -inkey <RSA1024> -export -out <out> - str = <<~EOF.unpack("m").first -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 -vyl2WuMdEwQIMWFFphPkIUICAggA - EOF - p12 = OpenSSL::PKCS12.new(str, "abc123") - - assert_equal @mykey.to_der, p12.key.to_der - assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der - assert_equal [], Array(p12.ca_certs) - end - def test_new_with_no_keys # generated with: - # openssl pkcs12 -in <@mycert> -nokeys -export -out <out> - str = <<~EOF.unpack("m").first -MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH -BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W -irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU -0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67 -I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN -Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr -mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd -NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe -lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0 -LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI -aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I -OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB -DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM -Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx -ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4 -mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP -1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA= + # openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export + str = <<~EOF.unpack1("m") +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 +AA== EOF p12 = OpenSSL::PKCS12.new(str, "abc123") assert_equal nil, p12.key assert_equal nil, p12.certificate assert_equal 1, p12.ca_certs.size - assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der + assert_equal @mycert.subject, p12.ca_certs[0].subject end def test_new_with_no_certs # generated with: - # openssl pkcs12 -inkey <RSA1024> -nocerts -export -out <out> - str = <<~EOF.unpack("m").first -MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH -AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN -AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ -V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q -cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh -O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ -7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne -ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg -DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE -7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX -nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN -N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj -Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY -i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft -JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg -GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF -Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== + # openssl pkcs12 -inkey fixtures/openssl/pkey/rsa-1.pem -nocerts -export + str = <<~EOF.unpack1("m") +MIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3 +DQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK +KoZIhvcNAQwBAzAOBAjX5nN8jyRKwQICCAAEgglIBIRLHfiY1mNHpl3FdX6+ +72L+ZOVXnlZ1MY9HSeg0RMkCJcm0mJ2UD7INUOGXvwpK9fr6WJUZM1IqTihQ +1dM0crRC2m23aP7KtAlXh2DYD3otseDtwoN/NE19RsiJzeIiy5TSW1d47weU ++D4Ig/9FYVFPTDgMzdCxXujhvO/MTbZIjqtcS+IOyF+91KkXrHkfkGjZC7KS +WRmYw9BBuIPQEewdTI35sAJcxT8rK7JIiL/9mewbSE+Z28Wq1WXwmjL3oZm9 +lw6+f515b197GYEGomr6LQqJJamSYpwQbTGHonku6Tf3ylB4NLFqOnRCKE4K +zRSSYIqJBlKHmQ4pDm5awoupHYxMZLZKZvXNYyYN3kV8r1iiNVlY7KBR4CsX +rqUkXehRmcPnuqEMW8aOpuYe/HWf8PYI93oiDZjcEZMwW2IZFFrgBbqUeNCM +CQTkjAYxi5FyoaoTnHrj/aRtdLOg1xIJe4KKcmOXAVMmVM9QEPNfUwiXJrE7 +n42gl4NyzcZpxqwWBT++9TnQGZ/lEpwR6dzkZwICNQLdQ+elsdT7mumywP+1 +WaFqg9kpurimaiBu515vJNp9Iqv1Nmke6R8Lk6WVRKPg4Akw0fkuy6HS+LyN +ofdCfVUkPGN6zkjAxGZP9ZBwvXUbLRC5W3N5qZuAy5WcsS75z+oVeX9ePV63 +cue23sClu8JSJcw3HFgPaAE4sfkQ4MoihPY5kezgT7F7Lw/j86S0ebrDNp4N +Y685ec81NRHJ80CAM55f3kGCOEhoifD4VZrvr1TdHZY9Gm3b1RYaJCit2huF +nlOfzeimdcv/tkjb6UsbpXx3JKkF2NFFip0yEBERRCdWRYMUpBRcl3ad6XHy +w0pVTgIjTxGlbbtOCi3siqMOK0GNt6UgjoEFc1xqjsgLwU0Ta2quRu7RFPGM +GoEwoC6VH23p9Hr4uTFOL0uHfkKWKunNN+7YPi6LT6IKmTQwrp+fTO61N6Xh +KlqTpwESKsIJB2iMnc8wBkjXJtmG/e2n5oTqfhICIrxYmEb7zKDyK3eqeTj3 +FhQh2t7cUIiqcT52AckUqniPmlE6hf82yBjhaQUPfi/ExTBtTDSmFfRPUzq+ +Rlla4OHllPRzUXJExyansgCxZbPqlw46AtygSWRGcWoYAKUKwwoYjerqIV5g +JoZICV9BOU9TXco1dHXZQTs/nnTwoRmYiL/Ly5XpvUAnQOhYeCPjBeFnPSBR +R/hRNqrDH2MOV57v5KQIH2+mvy26tRG+tVGHmLMaOJeQkjLdxx+az8RfXIrH +7hpAsoBb+g9jUDY1mUVavPk1T45GMpQH8u3kkzRvChfOst6533GyIZhE7FhN +KanC6ACabVFDUs6P9pK9RPQMp1qJfpA0XJFx5TCbVbPkvnkZd8K5Tl/tzNM1 +n32eRao4MKr9KDwoDL93S1yJgYTlYjy1XW/ewdedtX+B4koAoz/wSXDYO+GQ +Zu6ZSpKSEHTRPhchsJ4oICvpriVaJkn0/Z7H3YjNMB9U5RR9+GiIg1wY1Oa1 +S3WfuwrrI6eqfbQwj6PDNu3IKy6srEgvJwaofQALNBPSYWbauM2brc8qsD+t +n8jC/aD1aMcy00+9t3H/RVCjEOb3yKfUpAldIkEA2NTTnZpoDQDXeNYU2F/W +yhmFjJy8A0O4QOk2xnZK9kcxSRs0v8vI8HivvgWENoVPscsDC4742SSIe6SL +f/T08reIX11f0K70rMtLhtFMQdHdYOTNl6JzhkHPLr/f9MEZsBEQx52depnF +ARb3gXGbCt7BAi0OeCEBSbLr2yWuW4r55N0wRZSOBtgqgjsiHP7CDQSkbL6p +FPlQS1do9gBSHiNYvsmN1LN5bG+mhcVb0UjZub4mL0EqGadjDfDdRJmWqlX0 +r5dyMcOWQVy4O2cPqYFlcP9lk8buc5otcyVI2isrAFdlvBK29oK6jc52Aq5Q +0b2ESDlgX8WRgiOPPxK8dySKEeuIwngCtJyNTecP9Ug06TDsu0znZGCXJ+3P +8JOpykgA8EQdOZOYHbo76ZfB2SkklI5KeRA5IBjGs9G3TZ4PHLy2DIwsbWzS +H1g01o1x264nx1cJ+eEgUN/KIiGFIib42RS8Af4D5e+Vj54Rt3axq+ag3kI+ +53p8uotyu+SpvvXUP7Kv4xpQ/L6k41VM0rfrd9+DrlDVvSfxP2uh6I1TKF7A +CT5n8zguMbng4PGjxvyPBM5k62t6hN5fuw6Af0aZFexh+IjB/5wFQ6onSz23 +fBzMW4St7RgSs8fDg3lrM+5rwXiey1jxY1ddaxOoUsWRMvvdd7rZxRZQoN5v +AcI5iMkK/vvpQgC/sfzhtXtrJ2XOPZ+GVgi7VcuDLKSkdFMcPbGzO8SdxUnS +SLV5XTKqKND+Lrfx7DAoKi5wbDFHu5496/MHK5qP4tBe6sJ5bZc+KDJIH46e +wTV1oWtB5tV4q46hOb5WRcn/Wjz3HSKaGZgx5QbK1MfKTzD5CTUn+ArMockX +2wJhPnFK85U4rgv8iBuh9bRjyw+YaKf7Z3loXRiE1eRG6RzuPF0ZecFiDumk +AC/VUXynJhzePBLqzrQj0exanACdullN+pSfHiRWBxR2VFUkjoFP5X45GK3z +OstSH6FOkMVU4afqEmjsIwozDFIyin5EyWTtdhJe3szdJSGY23Tut+9hUatx +9FDFLESOd8z3tyQSNiLk/Hib+e/lbjxqbXBG/p/oyvP3N999PLUPtpKqtYkV +H0+18sNh9CVfojiJl44fzxe8yCnuefBjut2PxEN0EFRBPv9P2wWlmOxkPKUq +NrCJP0rDj5aONLrNZPrR8bZNdIShkZ/rKkoTuA0WMZ+xUlDRxAupdMkWAlrz +8IcwNcdDjPnkGObpN5Ctm3vK7UGSBmPeNqkXOYf3QTJ9gStJEd0F6+DzTN5C +KGt1IyuGwZqL2Yk51FDIIkr9ykEnBMaA39LS7GFHEDNGlW+fKC7AzA0zfoOr +fXZlHMBuqHtXqk3zrsHRqGGoocigg4ctrhD1UREYKj+eIj1TBiRdf7c6+COf +NIOmej8pX3FmZ4ui+dDA8r2ctgsWHrb4A6iiH+v1DRA61GtoaA/tNRggewXW +VXCZCGWyyTuyHGOqq5ozrv5MlzZLWD/KV/uDsAWmy20RAed1C4AzcXlpX25O +M4SNl47g5VRNJRtMqokc8j6TjZrzMDEwITAJBgUrDgMCGgUABBRrkIRuS5qg +BC8fv38mue8LZVcbHQQIUNrWKEnskCoCAggA EOF p12 = OpenSSL::PKCS12.new(str, "abc123") - assert_equal @mykey.to_der, p12.key.to_der + assert_equal Fixtures.pkey("rsa-1").to_der, p12.key.to_der assert_equal nil, p12.certificate assert_equal [], Array(p12.ca_certs) end def test_dup - p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert) + p12 = OpenSSL::PKCS12.create( + "pass", + "name", + @mykey, + @mycert, + nil, + DEFAULT_PBE_PKEYS, + DEFAULT_PBE_CERTS, + ) assert_equal p12.to_der, p12.dup.to_der 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 diff --git a/test/openssl/test_pkcs7.rb b/test/openssl/test_pkcs7.rb index ba8b93d034..c049ed444a 100644 --- a/test/openssl/test_pkcs7.rb +++ b/test/openssl/test_pkcs7.rb @@ -155,6 +155,21 @@ class OpenSSL::TestPKCS7 < OpenSSL::TestCase assert_equal(data, p7.decrypt(@rsa1024)) end + def test_empty_signed_data_ruby_bug_19974 + data = "-----BEGIN PKCS7-----\nMAsGCSqGSIb3DQEHAg==\n-----END PKCS7-----\n" + assert_raise(ArgumentError) { OpenSSL::PKCS7.new(data) } + + data = <<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 + +#{data} +END + assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.read_smime(data) } + end + def test_graceful_parsing_failure #[ruby-core:43250] contents = File.read(__FILE__) assert_raise(ArgumentError) { OpenSSL::PKCS7.new(contents) } @@ -212,6 +227,12 @@ END assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der) end + def test_to_text + p7 = OpenSSL::PKCS7.new + p7.type = "signed" + assert_match(/signed/, p7.to_text) + end + def test_degenerate_pkcs7 ca_cert_pem = <<END -----BEGIN CERTIFICATE----- diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index 4a539d8c46..aee0546f63 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -27,23 +27,24 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase end def test_s_generate_parameters - # 512 is non-default; 1024 is used if 'dsa_paramgen_bits' is not specified - # with OpenSSL 1.1.0. - pkey = OpenSSL::PKey.generate_parameters("DSA", { - "dsa_paramgen_bits" => 512, - "dsa_paramgen_q_bits" => 256, + pkey = OpenSSL::PKey.generate_parameters("EC", { + "ec_paramgen_curve" => "secp384r1", }) - assert_instance_of OpenSSL::PKey::DSA, pkey - assert_equal 512, pkey.p.num_bits - assert_equal 256, pkey.q.num_bits - assert_equal nil, pkey.priv_key + assert_instance_of OpenSSL::PKey::EC, pkey + assert_equal "secp384r1", pkey.group.curve_name + assert_equal nil, pkey.private_key # Invalid options are checked assert_raise(OpenSSL::PKey::PKeyError) { - OpenSSL::PKey.generate_parameters("DSA", "invalid" => "option") + OpenSSL::PKey.generate_parameters("EC", "invalid" => "option") } # Parameter generation callback is called + if openssl?(3, 0, 0, 0) && !openssl?(3, 0, 0, 6) + # Errors in BN_GENCB were not properly handled. This special pend is to + # suppress failures on Ubuntu 22.04, which uses OpenSSL 3.0.2. + pend "unstable test on OpenSSL 3.0.[0-5]" + end cb_called = [] assert_raise(RuntimeError) { OpenSSL::PKey.generate_parameters("DSA") { |*args| @@ -59,14 +60,13 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase # DSA key pair cannot be generated without parameters OpenSSL::PKey.generate_key("DSA") } - pkey_params = OpenSSL::PKey.generate_parameters("DSA", { - "dsa_paramgen_bits" => 512, - "dsa_paramgen_q_bits" => 256, + pkey_params = OpenSSL::PKey.generate_parameters("EC", { + "ec_paramgen_curve" => "secp384r1", }) pkey = OpenSSL::PKey.generate_key(pkey_params) - assert_instance_of OpenSSL::PKey::DSA, pkey - assert_equal 512, pkey.p.num_bits - assert_not_equal nil, pkey.priv_key + assert_instance_of OpenSSL::PKey::EC, pkey + assert_equal "secp384r1", pkey.group.curve_name + assert_not_equal nil, pkey.private_key end def test_hmac_sign_verify @@ -82,6 +82,9 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase end def test_ed25519 + # Ed25519 is not FIPS-approved. + omit_on_fips + # Test vector from RFC 8032 Section 7.1 TEST 2 priv_pem = <<~EOF -----BEGIN PRIVATE KEY----- @@ -96,9 +99,11 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase begin priv = OpenSSL::PKey.read(priv_pem) pub = OpenSSL::PKey.read(pub_pem) - rescue OpenSSL::PKey::PKeyError + rescue OpenSSL::PKey::PKeyError => e # OpenSSL < 1.1.1 - pend "Ed25519 is not implemented" + pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) + + raise e end assert_instance_of OpenSSL::PKey::PKey, priv assert_instance_of OpenSSL::PKey::PKey, pub @@ -106,6 +111,19 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase assert_equal pub_pem, priv.public_to_pem assert_equal pub_pem, pub.public_to_pem + begin + assert_equal "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + priv.raw_private_key.unpack1("H*") + assert_equal OpenSSL::PKey.new_raw_private_key("ED25519", priv.raw_private_key).private_to_pem, + priv.private_to_pem + assert_equal "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + priv.raw_public_key.unpack1("H*") + assert_equal OpenSSL::PKey.new_raw_public_key("ED25519", priv.raw_public_key).public_to_pem, + pub.public_to_pem + rescue NoMethodError + pend "running OpenSSL version does not have raw public key support" + end + sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") 92a009a9f0d4cab8720e820b5f642540 a2b27b5416503f8fb3762223ebdb69da @@ -126,6 +144,32 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) } end + def test_ed25519_not_approved_on_fips + omit_on_non_fips + # Ed25519 is technically allowed in the OpenSSL 3.0 code as a kind of bug. + # So, we need to omit OpenSSL 3.0. + # + # See OpenSSL providers/fips/fipsprov.c PROV_NAMES_ED25519 entries with + # FIPS_DEFAULT_PROPERTIES on openssl-3.0 branch and + # FIPS_UNAPPROVED_PROPERTIES on openssl-3.1 branch. + # + # See also + # https://github.com/openssl/openssl/issues/20758#issuecomment-1639658102 + # for details. + unless openssl?(3, 1, 0, 0) + omit 'Ed25519 is allowed in the OpenSSL 3.0 FIPS code as a kind of bug' + end + + priv_pem = <<~EOF + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 + -----END PRIVATE KEY----- + EOF + assert_raise(OpenSSL::PKey::PKeyError) do + OpenSSL::PKey.read(priv_pem) + end + end + def test_x25519 # Test vector from RFC 7748 Section 6.1 alice_pem = <<~EOF @@ -150,6 +194,32 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase assert_equal alice_pem, alice.private_to_pem assert_equal bob_pem, bob.public_to_pem assert_equal [shared_secret].pack("H*"), alice.derive(bob) + begin + alice_private = OpenSSL::PKey.new_raw_private_key("X25519", alice.raw_private_key) + bob_public = OpenSSL::PKey.new_raw_public_key("X25519", bob.raw_public_key) + alice_private_raw = alice.raw_private_key.unpack1("H*") + bob_public_raw = bob.raw_public_key.unpack1("H*") + rescue NoMethodError + # OpenSSL < 1.1.1 + pend "running OpenSSL version does not have raw public key support" + end + assert_equal alice_private.private_to_pem, + alice.private_to_pem + assert_equal bob_public.public_to_pem, + bob.public_to_pem + assert_equal "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", + alice_private_raw + assert_equal "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", + bob_public_raw + end + + def raw_initialize + pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) # >= v1.1.1 + + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("foo123", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("ED25519", "xxx") } end def test_compare? diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index f80af8f841..d32ffaf6b1 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -18,53 +18,75 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase assert_key(dh) end if ENV["OSSL_TEST_ALL"] - def test_new_break + def test_new_break_on_non_fips + omit_on_fips + assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break }) assert_raise(RuntimeError) do OpenSSL::PKey::DH.new(NEW_KEYLEN) { raise } end end + def test_new_break_on_fips + omit_on_non_fips + + # The block argument is not executed in FIPS case. + # See https://github.com/ruby/openssl/issues/692 for details. + assert(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break }) + assert(OpenSSL::PKey::DH.new(NEW_KEYLEN) { raise }) + end + def test_derive_key - dh1 = Fixtures.pkey("dh1024").generate_key! - dh2 = Fixtures.pkey("dh1024").generate_key! + params = Fixtures.pkey("dh2048_ffdhe2048") + dh1 = OpenSSL::PKey.generate_key(params) + dh2 = OpenSSL::PKey.generate_key(params) dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) + z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) assert_equal z, dh1.derive(dh2_pub) assert_equal z, dh2.derive(dh1_pub) + assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } + assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } + assert_equal z, dh1.compute_key(dh2.pub_key) assert_equal z, dh2.compute_key(dh1.pub_key) end def test_DHparams - dh1024 = Fixtures.pkey("dh1024") + dh = Fixtures.pkey("dh2048_ffdhe2048") + dh_params = dh.public_key + asn1 = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Integer(dh1024.p), - OpenSSL::ASN1::Integer(dh1024.g) + OpenSSL::ASN1::Integer(dh.p), + OpenSSL::ASN1::Integer(dh.g) ]) key = OpenSSL::PKey::DH.new(asn1.to_der) - assert_same_dh dup_public(dh1024), key + assert_same_dh dh_params, key pem = <<~EOF -----BEGIN DH PARAMETERS----- - MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0 - pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG - AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC + MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz + +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a + 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 + YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi + 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD + ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- EOF + key = OpenSSL::PKey::DH.new(pem) - assert_same_dh dup_public(dh1024), key + assert_same_dh dh_params, key key = OpenSSL::PKey.read(pem) - assert_same_dh dup_public(dh1024), key + assert_same_dh dh_params, key - assert_equal asn1.to_der, dh1024.to_der - assert_equal pem, dh1024.export + assert_equal asn1.to_der, dh.to_der + assert_equal pem, dh.export end def test_public_key - dh = Fixtures.pkey("dh1024") + dh = Fixtures.pkey("dh2048_ffdhe2048") 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) @@ -72,22 +94,28 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_generate_key - dh = Fixtures.pkey("dh1024").public_key # creates a copy + # Deprecated in v3.0.0; incompatible with OpenSSL 3.0 + # Creates a copy with params only + dh = Fixtures.pkey("dh2048_ffdhe2048").public_key assert_no_key(dh) dh.generate_key! assert_key(dh) - end - def test_key_exchange - dh = Fixtures.pkey("dh1024") 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 + end if !openssl?(3, 0, 0) def test_params_ok? - dh0 = Fixtures.pkey("dh1024") + # Skip the tests in old OpenSSL version 1.1.1c or early versions before + # applying the following commits in OpenSSL 1.1.1d to make `DH_check` + # function pass the RFC 7919 FFDHE group texts. + # https://github.com/openssl/openssl/pull/9435 + unless openssl?(1, 1, 1, 4) + pend 'DH check for RFC 7919 FFDHE group texts is not implemented' + end + + dh0 = Fixtures.pkey("dh2048_ffdhe2048") dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(dh0.p), @@ -103,17 +131,36 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_dup - dh = Fixtures.pkey("dh1024") - dh2 = dh.dup - assert_equal dh.to_der, dh2.to_der # params - assert_equal_params dh, dh2 # keys - dh2.set_pqg(dh2.p + 1, nil, dh2.g) - assert_not_equal dh2.p, dh.p - assert_equal dh2.g, dh.g + # Parameters only + dh1 = Fixtures.pkey("dh2048_ffdhe2048") + dh2 = dh1.dup + assert_equal dh1.to_der, dh2.to_der + assert_not_equal nil, dh1.p + assert_not_equal nil, dh1.g + assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g] + assert_equal nil, dh1.pub_key + assert_equal nil, dh1.priv_key + assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key] + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + dh2.set_pqg(dh2.p + 1, nil, dh2.g) + assert_not_equal dh2.p, dh1.p + end + + # With a key pair + dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey("dh2048_ffdhe2048")) + dh4 = dh3.dup + assert_equal dh3.to_der, dh4.to_der + assert_equal dh1.to_der, dh4.to_der # encodes parameters only + assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g] + assert_not_equal nil, dh3.pub_key + assert_not_equal nil, dh3.priv_key + assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key] end def test_marshal - dh = Fixtures.pkey("dh1024") + dh = Fixtures.pkey("dh2048_ffdhe2048") deserialized = Marshal.load(Marshal.dump(dh)) assert_equal dh.to_der, deserialized.to_der @@ -121,11 +168,6 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase 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?) diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index 147e50176b..4c93f2869d 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -28,28 +28,55 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase end end + def test_generate + # DSA.generate used to call DSA_generate_parameters_ex(), which adjusts the + # size of q according to the size of p + key2048 = OpenSSL::PKey::DSA.generate(2048) + assert_equal 2048, key2048.p.num_bits + assert_equal 256, key2048.q.num_bits + + if ENV["OSSL_TEST_ALL"] == "1" # slow + key3072 = OpenSSL::PKey::DSA.generate(3072) + assert_equal 3072, key3072.p.num_bits + assert_equal 256, key3072.q.num_bits + end + end + + def test_generate_on_non_fips + # DSA with 1024 bits is invalid on FIPS 186-4. + # https://github.com/openssl/openssl/commit/49ed5ba8f62875074f04417189147fd3dda072ab + omit_on_fips + + key1024 = OpenSSL::PKey::DSA.generate(1024) + assert_predicate key1024, :private? + assert_equal 1024, key1024.p.num_bits + assert_equal 160, key1024.q.num_bits + end + def test_sign_verify - dsa512 = Fixtures.pkey("dsa512") + # The DSA valid size is 2048 or 3072 on FIPS. + # https://github.com/openssl/openssl/blob/7649b5548e5c0352b91d9d3ed695e42a2ac1e99c/providers/common/securitycheck.c#L185-L188 + dsa = Fixtures.pkey("dsa2048") data = "Sign me!" if defined?(OpenSSL::Digest::DSS1) - signature = dsa512.sign(OpenSSL::Digest.new('DSS1'), data) - assert_equal true, dsa512.verify(OpenSSL::Digest.new('DSS1'), signature, data) + signature = dsa.sign(OpenSSL::Digest.new('DSS1'), data) + assert_equal true, dsa.verify(OpenSSL::Digest.new('DSS1'), signature, data) end - signature = dsa512.sign("SHA1", data) - assert_equal true, dsa512.verify("SHA1", signature, data) + signature = dsa.sign("SHA256", data) + assert_equal true, dsa.verify("SHA256", signature, data) - signature0 = (<<~'end;').unpack("m")[0] - MCwCFH5h40plgU5Fh0Z4wvEEpz0eE9SnAhRPbkRB8ggsN/vsSEYMXvJwjGg/ - 6g== + signature0 = (<<~'end;').unpack1("m") + MD4CHQC0zmRkVOAHJTm28fS5PVUv+4LtBeNaKqr/yfmVAh0AsTcLqofWHoW8X5oWu8AOvngOcFVZ + cLTvhY3XNw== end; - assert_equal true, dsa512.verify("SHA256", signature0, data) + assert_equal true, dsa.verify("SHA256", signature0, data) signature1 = signature0.succ - assert_equal false, dsa512.verify("SHA256", signature1, data) + assert_equal false, dsa.verify("SHA256", signature1, data) end def test_sign_verify_raw - key = Fixtures.pkey("dsa512") + key = Fixtures.pkey("dsa2048") data = 'Sign me!' digest = OpenSSL::Digest.digest('SHA1', data) @@ -108,6 +135,8 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase end def test_DSAPrivateKey_encrypted + omit_on_fips + # key = abcdef dsa512 = Fixtures.pkey("dsa512") pem = <<~EOF @@ -138,6 +167,8 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def test_PUBKEY dsa512 = Fixtures.pkey("dsa512") + dsa512pub = OpenSSL::PKey::DSA.new(dsa512.public_to_der) + asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("DSA"), @@ -153,7 +184,7 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase ]) key = OpenSSL::PKey::DSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_dsa dup_public(dsa512), key + assert_same_dsa dsa512pub, key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -166,10 +197,15 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::DSA.new(pem) - assert_same_dsa dup_public(dsa512), key + assert_same_dsa dsa512pub, key - assert_equal asn1.to_der, dup_public(dsa512).to_der - assert_equal pem, dup_public(dsa512).export + assert_equal asn1.to_der, key.to_der + assert_equal pem, key.export + + assert_equal asn1.to_der, dsa512.public_to_der + assert_equal asn1.to_der, key.public_to_der + assert_equal pem, dsa512.public_to_pem + assert_equal pem, key.public_to_pem end def test_read_DSAPublicKey_pem @@ -201,8 +237,12 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== key = Fixtures.pkey("dsa1024") key2 = key.dup assert_equal key.params, key2.params - key2.set_pqg(key2.p + 1, key2.q, key2.g) - assert_not_equal key.params, key2.params + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key2.set_pqg(key2.p + 1, key2.q, key2.g) + assert_not_equal key.params, key2.params + end end def test_marshal diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 0a460bd536..2cb8e287ab 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -1,34 +1,22 @@ # frozen_string_literal: true require_relative 'utils' -if defined?(OpenSSL) && defined?(OpenSSL::PKey::EC) +if defined?(OpenSSL) class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_ec_key - builtin_curves = OpenSSL::PKey::EC.builtin_curves - assert_not_empty builtin_curves - - builtin_curves.each do |curve_name, comment| - # Oakley curves and X25519 are not suitable for signing and causes - # FIPS-selftest failure on some environment, so skip for now. - next if ["Oakley", "X25519"].any? { |n| curve_name.start_with?(n) } - - key = OpenSSL::PKey::EC.new(curve_name) - key.generate_key! - - assert_predicate key, :private? - assert_predicate key, :public? - assert_nothing_raised { key.check_key } + key1 = OpenSSL::PKey::EC.generate("prime256v1") + + # PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is + # deprecated + if !openssl?(3, 0, 0) + key2 = OpenSSL::PKey::EC.new + key2.group = key1.group + key2.private_key = key1.private_key + key2.public_key = key1.public_key + assert_equal key1.to_der, key2.to_der end - key1 = OpenSSL::PKey::EC.new("prime256v1").generate_key! - - key2 = OpenSSL::PKey::EC.new - key2.group = key1.group - key2.private_key = key1.private_key - key2.public_key = key1.public_key - assert_equal key1.to_der, key2.to_der - key3 = OpenSSL::PKey::EC.new(key1) assert_equal key1.to_der, key3.to_der @@ -37,10 +25,25 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase key5 = key1.dup assert_equal key1.to_der, key5.to_der - key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key! - key5.private_key = key_tmp.private_key - key5.public_key = key_tmp.public_key - assert_not_equal key1.to_der, key5.to_der + + # PKey is immutable in OpenSSL >= 3.0; EC object should not be modified + if !openssl?(3, 0, 0) + key_tmp = OpenSSL::PKey::EC.generate("prime256v1") + key5.private_key = key_tmp.private_key + key5.public_key = key_tmp.public_key + assert_not_equal key1.to_der, key5.to_der + end + end + + def test_builtin_curves + builtin_curves = OpenSSL::PKey::EC.builtin_curves + assert_not_empty builtin_curves + assert_equal 2, builtin_curves[0].size + assert_kind_of String, builtin_curves[0][0] + assert_kind_of String, builtin_curves[0][1] + + builtin_curve_names = builtin_curves.map { |name, comment| name } + assert_include builtin_curve_names, "prime256v1" end def test_generate @@ -52,6 +55,15 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal(true, ec.private?) end + def test_generate_key + ec = OpenSSL::PKey::EC.new("prime256v1") + assert_equal false, ec.private? + assert_raise(OpenSSL::PKey::ECError) { ec.to_der } + ec.generate_key! + assert_equal true, ec.private? + assert_nothing_raised { ec.to_der } + end if !openssl?(3, 0, 0) + def test_marshal key = Fixtures.pkey("p256") deserialized = Marshal.load(Marshal.dump(key)) @@ -60,31 +72,42 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_check_key - key = OpenSSL::PKey::EC.new("prime256v1").generate_key! - assert_equal(true, key.check_key) - assert_equal(true, key.private?) - assert_equal(true, key.public?) - key2 = OpenSSL::PKey::EC.new(key.group) - assert_equal(false, key2.private?) - assert_equal(false, key2.public?) - key2.public_key = key.public_key - assert_equal(false, key2.private?) - assert_equal(true, key2.public?) - key2.private_key = key.private_key + key0 = Fixtures.pkey("p256") + assert_equal(true, key0.check_key) + assert_equal(true, key0.private?) + assert_equal(true, key0.public?) + + key1 = OpenSSL::PKey.read(key0.public_to_der) + assert_equal(true, key1.check_key) + assert_equal(false, key1.private?) + assert_equal(true, key1.public?) + + key2 = OpenSSL::PKey.read(key0.private_to_der) assert_equal(true, key2.private?) assert_equal(true, key2.public?) assert_equal(true, key2.check_key) - key2.private_key += 1 - assert_raise(OpenSSL::PKey::ECError) { key2.check_key } + + # Behavior of EVP_PKEY_public_check changes between OpenSSL 1.1.1 and 3.0 + key4 = Fixtures.pkey("p256_too_large") + assert_raise(OpenSSL::PKey::ECError) { key4.check_key } + + key5 = Fixtures.pkey("p384_invalid") + assert_raise(OpenSSL::PKey::ECError) { key5.check_key } + + # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0 + if !openssl?(3, 0, 0) + key2.private_key += 1 + assert_raise(OpenSSL::PKey::ECError) { key2.check_key } + end end def test_sign_verify p256 = Fixtures.pkey("p256") data = "Sign me!" - signature = p256.sign("SHA1", data) - assert_equal true, p256.verify("SHA1", signature, data) + signature = p256.sign("SHA256", data) + assert_equal true, p256.verify("SHA256", signature, data) - signature0 = (<<~'end;').unpack("m")[0] + signature0 = (<<~'end;').unpack1("m") MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq QdBp1B4sxJoA8jvODMMklMyBKVmudboA6A== end; @@ -107,7 +130,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal [zIUT].pack("H*"), a.derive(b) assert_equal a.derive(b), a.dh_compute_key(b.public_key) - end + end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key= def test_sign_verify_raw key = Fixtures.pkey("p256") @@ -136,7 +159,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_dsa_sign_asn1_FIPS186_3 - key = OpenSSL::PKey::EC.new("prime256v1").generate_key! + key = OpenSSL::PKey::EC.generate("prime256v1") size = key.group.order.num_bits / 8 + 1 dgst = (1..size).to_a.pack('C*') sig = key.dsa_sign_asn1(dgst) @@ -145,8 +168,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_dh_compute_key - key_a = OpenSSL::PKey::EC.new("prime256v1").generate_key! - key_b = OpenSSL::PKey::EC.new(key_a.group).generate_key! + key_a = OpenSSL::PKey::EC.generate("prime256v1") + key_b = OpenSSL::PKey::EC.generate(key_a.group) pub_a = key_a.public_key pub_b = key_b.public_key @@ -182,7 +205,32 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal pem, p256.export end + def test_ECPrivateKey_with_parameters + p256 = Fixtures.pkey("p256") + + # The format used by "openssl ecparam -name prime256v1 -genkey -outform PEM" + # + # "EC PARAMETERS" block should be ignored if it is followed by an + # "EC PRIVATE KEY" block + in_pem = <<~EOF + -----BEGIN EC PARAMETERS----- + BggqhkjOPQMBBw== + -----END EC PARAMETERS----- + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49 + AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt + CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg== + -----END EC PRIVATE KEY----- + EOF + + key = OpenSSL::PKey::EC.new(in_pem) + assert_same_ec p256, key + assert_equal p256.to_der, key.to_der + end + def test_ECPrivateKey_encrypted + omit_on_fips + p256 = Fixtures.pkey("p256") # key = abcdef pem = <<~EOF @@ -210,6 +258,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_PUBKEY p256 = Fixtures.pkey("p256") + p256pub = OpenSSL::PKey::EC.new(p256.public_to_der) + asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("id-ecPublicKey"), @@ -221,7 +271,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase ]) key = OpenSSL::PKey::EC.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_ec dup_public(p256), key + assert_same_ec p256pub, key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -230,10 +280,15 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::EC.new(pem) - assert_same_ec dup_public(p256), key + assert_same_ec p256pub, key + + assert_equal asn1.to_der, key.to_der + assert_equal pem, key.export - assert_equal asn1.to_der, dup_public(p256).to_der - assert_equal pem, dup_public(p256).export + assert_equal asn1.to_der, p256.public_to_der + assert_equal asn1.to_der, key.public_to_der + assert_equal pem, p256.public_to_pem + assert_equal pem, key.public_to_pem end def test_ec_group @@ -269,7 +324,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_ec_point group = OpenSSL::PKey::EC::Group.new("prime256v1") - key = OpenSSL::PKey::EC.new(group).generate_key! + key = OpenSSL::PKey::EC.generate(group) point = key.public_key point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn) diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index 5e127f5407..61c55c60b2 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -11,7 +11,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase 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 + end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0 def test_private # Generated by key size and public exponent @@ -31,15 +31,18 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase 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?) + if !openssl?(3, 0, 0) + key = OpenSSL::PKey::RSA.new + # 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 end def test_new @@ -77,10 +80,10 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_sign_verify rsa1024 = Fixtures.pkey("rsa1024") data = "Sign me!" - signature = rsa1024.sign("SHA1", data) - assert_equal true, rsa1024.verify("SHA1", signature, data) + signature = rsa1024.sign("SHA256", data) + assert_equal true, rsa1024.verify("SHA256", signature, data) - signature0 = (<<~'end;').unpack("m")[0] + signature0 = (<<~'end;').unpack1("m") oLCgbprPvfhM4pjFQiDTFeWI9Sk+Og7Nh9TmIZ/xSxf2CGXQrptlwo7NQ28+ WA6YQo8jPH4hSuyWIM4Gz4qRYiYRkl5TDMUYob94zm8Si1HxEiS9354tzvqS zS8MLW2BtNPuTubMxTItHGTnOzo9sUg0LAHVFt8kHG2NfKAw/gQ= @@ -105,15 +108,20 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase salt_length: 20, mgf1_hash: "SHA1") # Defaults to PKCS #1 v1.5 padding => verification failure assert_equal false, key.verify("SHA256", sig_pss, data) + + # option type check + assert_raise_with_message(TypeError, /expected Hash/) { + key.sign("SHA256", data, ["x"]) + } end def test_sign_verify_raw key = Fixtures.pkey("rsa-1") data = "Sign me!" - hash = OpenSSL::Digest.digest("SHA1", data) - signature = key.sign_raw("SHA1", hash) - assert_equal true, key.verify_raw("SHA1", signature, hash) - assert_equal true, key.verify("SHA1", signature, data) + hash = OpenSSL::Digest.digest("SHA256", data) + signature = key.sign_raw("SHA256", hash) + assert_equal true, key.verify_raw("SHA256", signature, hash) + assert_equal true, key.verify("SHA256", signature, data) # Too long data assert_raise(OpenSSL::PKey::PKeyError) { @@ -126,9 +134,9 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase "rsa_pss_saltlen" => 20, "rsa_mgf1_md" => "SHA256" } - sig_pss = key.sign_raw("SHA1", hash, pssopts) - assert_equal true, key.verify("SHA1", sig_pss, data, pssopts) - assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts) + sig_pss = key.sign_raw("SHA256", hash, pssopts) + assert_equal true, key.verify("SHA256", sig_pss, data, pssopts) + assert_equal true, key.verify_raw("SHA256", sig_pss, hash, pssopts) end def test_sign_verify_raw_legacy @@ -201,7 +209,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_encrypt_decrypt rsapriv = Fixtures.pkey("rsa-1") - rsapub = dup_public(rsapriv) + rsapub = OpenSSL::PKey.read(rsapriv.public_to_der) # Defaults to PKCS #1 v1.5 raw = "data" @@ -216,7 +224,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_encrypt_decrypt_legacy rsapriv = Fixtures.pkey("rsa-1") - rsapub = dup_public(rsapriv) + rsapub = OpenSSL::PKey.read(rsapriv.public_to_der) # Defaults to PKCS #1 v1.5 raw = "data" @@ -235,36 +243,52 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase 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 + pub = OpenSSL::PKey.read(rsa1024.public_to_der) + assert_not_equal rsa1024.export, pub.export + assert_equal rsa1024.public_to_pem, pub.export + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + 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 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 + # 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 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 + pub = OpenSSL::PKey.read(rsa1024.public_to_der) + assert_not_equal rsa1024.to_der, pub.to_der + assert_equal rsa1024.public_to_der, pub.to_der + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key = OpenSSL::PKey::RSA.new - # 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 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 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 + # 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 end def test_RSAPrivateKey @@ -306,6 +330,12 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase assert_equal asn1.to_der, rsa1024.to_der assert_equal pem, rsa1024.export + + # Unknown PEM prepended + cert = issue_cert(OpenSSL::X509::Name.new([["CN", "nobody"]]), rsa1024, 1, [], nil, nil) + str = cert.to_text + cert.to_pem + rsa1024.to_pem + key = OpenSSL::PKey::RSA.new(str) + assert_same_rsa rsa1024, key end def test_RSAPrivateKey_encrypted @@ -346,13 +376,15 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_RSAPublicKey rsa1024 = Fixtures.pkey("rsa1024") + rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der) + asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(rsa1024.n), OpenSSL::ASN1::Integer(rsa1024.e) ]) key = OpenSSL::PKey::RSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_rsa dup_public(rsa1024), key + assert_same_rsa rsa1024pub, key pem = <<~EOF -----BEGIN RSA PUBLIC KEY----- @@ -362,11 +394,13 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END RSA PUBLIC KEY----- EOF key = OpenSSL::PKey::RSA.new(pem) - assert_same_rsa dup_public(rsa1024), key + assert_same_rsa rsa1024pub, key end def test_PUBKEY rsa1024 = Fixtures.pkey("rsa1024") + rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der) + asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("rsaEncryption"), @@ -381,7 +415,7 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase ]) key = OpenSSL::PKey::RSA.new(asn1.to_der) assert_not_predicate key, :private? - assert_same_rsa dup_public(rsa1024), key + assert_same_rsa rsa1024pub, key pem = <<~EOF -----BEGIN PUBLIC KEY----- @@ -392,10 +426,15 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase -----END PUBLIC KEY----- EOF key = OpenSSL::PKey::RSA.new(pem) - assert_same_rsa dup_public(rsa1024), key + assert_same_rsa rsa1024pub, key - assert_equal asn1.to_der, dup_public(rsa1024).to_der - assert_equal pem, dup_public(rsa1024).export + assert_equal asn1.to_der, key.to_der + assert_equal pem, key.export + + assert_equal asn1.to_der, rsa1024.public_to_der + assert_equal asn1.to_der, key.public_to_der + assert_equal pem, rsa1024.public_to_pem + assert_equal pem, key.public_to_pem end def test_pem_passwd @@ -482,18 +521,16 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase 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 assert_equal key.params, key2.params - key2.set_key(key2.n, 3, key2.d) - assert_not_equal key.params, key2.params + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key2.set_key(key2.n, 3, key2.d) + assert_not_equal key.params, key2.params + end end def test_marshal diff --git a/test/openssl/test_provider.rb b/test/openssl/test_provider.rb new file mode 100644 index 0000000000..b0ffae9ce7 --- /dev/null +++ b/test/openssl/test_provider.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true +require_relative 'utils' +if defined?(OpenSSL) && defined?(OpenSSL::Provider) && !OpenSSL.fips_mode + +class OpenSSL::TestProvider < OpenSSL::TestCase + def test_openssl_provider_name_inspect + with_openssl <<-'end;' + provider = OpenSSL::Provider.load("default") + assert_equal("default", provider.name) + assert_not_nil(provider.inspect) + end; + end + + def test_openssl_provider_names + with_openssl <<-'end;' + base_provider = OpenSSL::Provider.load("base") + assert_equal(2, OpenSSL::Provider.provider_names.size) + assert_includes(OpenSSL::Provider.provider_names, "base") + + assert_equal(true, base_provider.unload) + assert_equal(1, OpenSSL::Provider.provider_names.size) + assert_not_includes(OpenSSL::Provider.provider_names, "base") + end; + end + + def test_unloaded_openssl_provider + with_openssl <<-'end;' + default_provider = OpenSSL::Provider.load("default") + assert_equal(true, default_provider.unload) + assert_raise(OpenSSL::Provider::ProviderError) { default_provider.name } + assert_raise(OpenSSL::Provider::ProviderError) { default_provider.unload } + end; + end + + def test_openssl_legacy_provider + with_openssl(<<-'end;') + begin + OpenSSL::Provider.load("legacy") + rescue OpenSSL::Provider::ProviderError + omit "Only for OpenSSL with legacy provider" + end + + algo = "RC4" + data = "a" * 1000 + key = OpenSSL::Random.random_bytes(16) + + # default provider does not support RC4 + cipher = OpenSSL::Cipher.new(algo) + cipher.encrypt + cipher.key = key + encrypted = cipher.update(data) + cipher.final + + other_cipher = OpenSSL::Cipher.new(algo) + other_cipher.decrypt + other_cipher.key = key + decrypted = other_cipher.update(encrypted) + other_cipher.final + + assert_equal(data, decrypted) + end; + end + + private + + # this is required because OpenSSL::Provider methods change global state + def with_openssl(code, **opts) + assert_separately(["-ropenssl"], <<~"end;", **opts) + #{code} + end; + end +end + +end diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index 5dccac5fac..1471b0cb36 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -1,9 +1,20 @@ # frozen_string_literal: true require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::SSL) class OpenSSL::TestSSL < OpenSSL::SSLTestCase + def test_bad_socket + bad_socket = Struct.new(:sync).new + assert_raise TypeError do + socket = OpenSSL::SSL::SSLSocket.new bad_socket + # if the socket is not a T_FILE, `connect` will segv because it tries + # to get the underlying file descriptor but the API it calls assumes + # the object type is T_FILE + socket.connect + end + end + def test_ctx_options ctx = OpenSSL::SSL::SSLContext.new @@ -106,6 +117,30 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_socket_close_write + server_proc = proc do |ctx, ssl| + message = ssl.read + ssl.write(message) + ssl.close_write + ensure + ssl.close + end + + start_server(server_proc: server_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ssl = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port, context: ctx) + ssl.sync_close = true + ssl.connect + + message = "abc"*1024 + ssl.write message + ssl.close_write + assert_equal message, ssl.read + ensure + ssl&.close + end + end + def test_add_certificate ctx_proc = -> ctx { # Unset values set by start_server @@ -124,9 +159,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_add_certificate_multiple_certs - pend "EC is not supported" unless defined?(OpenSSL::PKey::EC) - pend "TLS 1.2 is not supported" unless tls12_supported? - ca2_key = Fixtures.pkey("rsa-3") ca2_exts = [ ["basicConstraints", "CA:TRUE", true], @@ -185,6 +217,24 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_read_with_timeout + omit "does not support timeout" unless IO.method_defined?(:timeout) + + start_server do |port| + server_connect(port) do |ssl| + str = +("x" * 100 + "\n") + ssl.syswrite(str) + assert_equal(str, ssl.sysread(str.bytesize)) + + ssl.timeout = 1 + assert_raise(IO::TimeoutError) {ssl.read(1)} + + ssl.syswrite(str) + assert_equal(str, ssl.sysread(str.bytesize)) + end + end + end + def test_getbyte start_server { |port| server_connect(port) { |ssl| @@ -365,59 +415,20 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end - def test_read_nonblock_without_session - EnvUtil.suppress_warning do - start_server(start_immediately: false) { |port| - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.sync_close = true - - assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) - ssl.write("abc\n") - IO.select [ssl] - assert_equal('a', ssl.read_nonblock(1)) - assert_equal("bc\n", ssl.read_nonblock(100)) - assert_equal :wait_readable, ssl.read_nonblock(100, exception: false) - ssl.close - } - end - end - - def test_starttls - server_proc = -> (ctx, ssl) { - while line = ssl.gets - if line =~ /^STARTTLS$/ - ssl.write("x") - ssl.flush - ssl.accept - break - end - ssl.write(line) - end - readwrite_loop(ctx, ssl) - } - - EnvUtil.suppress_warning do # read/write on not started session - start_server(start_immediately: false, - server_proc: server_proc) { |port| - begin - sock = TCPSocket.new("127.0.0.1", port) - ssl = OpenSSL::SSL::SSLSocket.new(sock) - - ssl.puts "plaintext" - assert_equal "plaintext\n", ssl.gets + def test_unstarted_session + start_server do |port| + sock = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(sock) - ssl.puts("STARTTLS") - ssl.read(1) - ssl.connect + assert_raise(OpenSSL::SSL::SSLError) { ssl.syswrite("data") } + assert_raise(OpenSSL::SSL::SSLError) { ssl.sysread(1) } - ssl.puts "over-tls" - assert_equal "over-tls\n", ssl.gets - ensure - ssl&.close - sock&.close - end - } + ssl.connect + ssl.puts "abc" + assert_equal "abc\n", ssl.gets + ensure + ssl&.close + sock&.close end end @@ -512,6 +523,40 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_ca_file + start_server(ignore_listener_error: true) { |port| + # X509_STORE is shared; setting ca_file to SSLContext affects store + store = OpenSSL::X509::Store.new + assert_equal false, store.verify(@svr_cert) + + ctx = Tempfile.create("ca_cert.pem") { |f| + f.puts(@ca_cert.to_pem) + f.close + + ctx = OpenSSL::SSL::SSLContext.new + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.cert_store = store + ctx.ca_file = f.path + ctx.setup + ctx + } + assert_nothing_raised { + server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets } + } + assert_equal true, store.verify(@svr_cert) + } + end + + def test_ca_file_not_found + path = Tempfile.create("ca_cert.pem") { |f| f.path } + ctx = OpenSSL::SSL::SSLContext.new + ctx.ca_file = path + # OpenSSL >= 1.1.0: /no certificate or crl found/ + assert_raise(OpenSSL::SSL::SSLError) { + ctx.setup + } + end + def test_finished_messages server_finished = nil server_peer_finished = nil @@ -526,6 +571,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase }) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE + ctx.max_version = :TLS1_2 if libressl?(3, 2, 0) && !libressl?(3, 3, 0) server_connect(port, ctx) { |ssl| ssl.puts "abc"; ssl.gets @@ -553,11 +599,10 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_post_connect_check_with_anon_ciphers - pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = -> ctx { ctx.ssl_version = :TLSv1_2 ctx.ciphers = "aNULL" + ctx.tmp_dh = Fixtures.pkey("dh-1") ctx.security_level = 0 } @@ -596,8 +641,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase exts = [ ["keyUsage","keyEncipherment,digitalSignature",true], - ["subjectAltName","DNS:localhost.localdomain",false], - ["subjectAltName","IP:127.0.0.1",false], + ["subjectAltName","DNS:localhost.localdomain,IP:127.0.0.1",false], ] @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key) start_server { |port| @@ -671,7 +715,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase assert_equal(true, OpenSSL::SSL.verify_wildcard("xn--qdk4b9b", "xn--qdk4b9b")) end - # Comments in this test is excerpted from http://tools.ietf.org/html/rfc6125#page-27 + # Comments in this test is excerpted from https://www.rfc-editor.org/rfc/rfc6125#page-27 def test_post_connection_check_wildcard_san # case-insensitive ASCII comparison # RFC 6125, section 6.4.1 @@ -708,10 +752,16 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase # buzz.example.net, respectively). ... assert_equal(true, OpenSSL::SSL.verify_certificate_identity( create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com')) + + # LibreSSL 3.5.0+ doesn't support other wildcard certificates + # (it isn't required to, as RFC states MAY, not MUST) + return if libressl?(3, 5, 0) + assert_equal(true, OpenSSL::SSL.verify_certificate_identity( create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com')) assert_equal(true, OpenSSL::SSL.verify_certificate_identity( create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com')) + # Section 6.4.3 of RFC6125 states that client should NOT match identifier # where wildcard is other than left-most label. # @@ -830,9 +880,56 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end + def test_keylog_cb + pend "Keylog callback is not supported" if !openssl?(1, 1, 1) || libressl? + + prefix = 'CLIENT_RANDOM' + context = OpenSSL::SSL::SSLContext.new + context.min_version = context.max_version = OpenSSL::SSL::TLS1_2_VERSION + + cb_called = false + context.keylog_cb = proc do |_sock, line| + cb_called = true + assert_equal(prefix, line.split.first) + end + + start_server do |port| + server_connect(port, context) do |ssl| + ssl.puts "abc" + assert_equal("abc\n", ssl.gets) + assert_equal(true, cb_called) + end + end + + if tls13_supported? + prefixes = [ + 'SERVER_HANDSHAKE_TRAFFIC_SECRET', + 'EXPORTER_SECRET', + 'SERVER_TRAFFIC_SECRET_0', + 'CLIENT_HANDSHAKE_TRAFFIC_SECRET', + 'CLIENT_TRAFFIC_SECRET_0', + ] + context = OpenSSL::SSL::SSLContext.new + context.min_version = context.max_version = OpenSSL::SSL::TLS1_3_VERSION + cb_called = false + context.keylog_cb = proc do |_sock, line| + cb_called = true + assert_not_nil(prefixes.delete(line.split.first)) + end + + start_server do |port| + server_connect(port, context) do |ssl| + ssl.puts "abc" + assert_equal("abc\n", ssl.gets) + assert_equal(true, cb_called) + end + assert_equal(0, prefixes.size) + end + end + end + def test_tlsext_hostname fooctx = OpenSSL::SSL::SSLContext.new - fooctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } fooctx.cert = @cli_cert fooctx.key = @cli_key @@ -884,7 +981,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ctx2 = OpenSSL::SSL::SSLContext.new ctx2.cert = @svr_cert ctx2.key = @svr_key - ctx2.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } ctx2.servername_cb = lambda { |args| Object.new } sock1, sock2 = socketpair @@ -927,14 +1023,12 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - begin - sock = TCPSocket.new("127.0.0.1", port) - sock.puts "abc" - ensure - sock&.close - end + sock = TCPSocket.new("127.0.0.1", port) + sock << "\x00" * 1024 assert t.join + ensure + sock&.close server.close end @@ -1028,14 +1122,17 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase start_server(ignore_listener_error: true) { |port| ctx = OpenSSL::SSL::SSLContext.new ctx.set_params - assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { + # OpenSSL <= 1.1.0: "self signed certificate in certificate chain" + # OpenSSL >= 3.0.0: "self-signed certificate in certificate chain" + assert_raise_with_message(OpenSSL::SSL::SSLError, /self.signed/) { server_connect(port, ctx) } } ctx_proc = proc { |ctx| + now = Time.now ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, - not_before: Time.now-100, not_after: Time.now-10) + not_before: now - 7200, not_after: now - 3600) } start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port| store = OpenSSL::X509::Store.new @@ -1242,46 +1339,51 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_options_disable_versions - # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. + # It's recommended to use SSLContext#{min,max}_version= instead in real + # applications. The purpose of this test case is to check that SSL options + # are properly propagated to OpenSSL library. supported = check_supported_protocol_versions + if !defined?(OpenSSL::SSL::TLS1_3_VERSION) || + !supported.include?(OpenSSL::SSL::TLS1_2_VERSION) || + !supported.include?(OpenSSL::SSL::TLS1_3_VERSION) || + !defined?(OpenSSL::SSL::OP_NO_TLSv1_3) # LibreSSL < 3.4 + pend "this test case requires both TLS 1.2 and TLS 1.3 to be supported " \ + "and enabled by default" + end - if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && - supported.include?(OpenSSL::SSL::TLS1_2_VERSION) - # Server disables ~ TLS 1.1 - ctx_proc = proc { |ctx| - ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | - OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client only supports TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION - assert_handshake_error { server_connect(port, ctx1) { } } + # Server disables TLS 1.2 and earlier + ctx_proc = proc { |ctx| + ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | + OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 | + OpenSSL::SSL::OP_NO_TLSv1_2 + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client only supports TLS 1.2 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION + assert_handshake_error { server_connect(port, ctx1) { } } - # Client only supports TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION - assert_nothing_raised { server_connect(port, ctx2) { } } - } + # Client only supports TLS 1.3 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_3_VERSION + assert_nothing_raised { server_connect(port, ctx2) { } } + } - # Server only supports TLS 1.1 - ctx_proc = proc { |ctx| - ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client disables TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 - assert_handshake_error { server_connect(port, ctx1) { } } + # Server only supports TLS 1.2 + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client doesn't support TLS 1.2 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_2 + assert_handshake_error { server_connect(port, ctx1) { } } - # Client disables TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 - assert_nothing_raised { server_connect(port, ctx2) { } } - } - else - pend "TLS 1.1 and TLS 1.2 must be supported; skipping" - end + # Client supports TLS 1.2 by default + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_3 + assert_nothing_raised { server_connect(port, ctx2) { } } + } end def test_ssl_methods_constant @@ -1331,7 +1433,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase ctx1 = OpenSSL::SSL::SSLContext.new ctx1.cert = @svr_cert ctx1.key = @svr_key - ctx1.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } ctx1.alpn_select_cb = -> (protocols) { nil } ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) @@ -1354,10 +1455,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_npn_protocol_selection_ary - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) advertised = ["http/1.1", "spdy/2"] ctx_proc = proc { |ctx| ctx.npn_protocols = advertised } @@ -1375,10 +1473,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_npn_protocol_selection_enum - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) advertised = Object.new def advertised.each @@ -1400,10 +1495,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_npn_protocol_selection_cancel - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } start_server_version(:TLSv1_2, ctx_proc) { |port| @@ -1414,10 +1506,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_npn_advertised_protocol_too_long - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["a" * 256] } start_server_version(:TLSv1_2, ctx_proc) { |port| @@ -1428,10 +1517,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_npn_selected_protocol_too_long - pend "TLS 1.2 is not supported" unless tls12_supported? - pend "NPN is not supported" unless \ - OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) - pend "LibreSSL 2.6 has broken NPN functions" if libressl?(2, 6, 1) + return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb) ctx_proc = Proc.new { |ctx| ctx.npn_protocols = ["http/1.1"] } start_server_version(:TLSv1_2, ctx_proc) { |port| @@ -1469,56 +1555,51 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_get_ephemeral_key - if tls12_supported? - # kRSA - ctx_proc1 = proc { |ctx| - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "kRSA" - } - start_server(ctx_proc: ctx_proc1, ignore_listener_error: true) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "kRSA" - begin - server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key } - rescue OpenSSL::SSL::SSLError - # kRSA seems disabled - raise unless $!.message =~ /no cipher/ - end + # kRSA + ctx_proc1 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + } + start_server(ctx_proc: ctx_proc1, ignore_listener_error: true) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "kRSA" + begin + server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key } + rescue OpenSSL::SSL::SSLError + # kRSA seems disabled + raise unless $!.message =~ /no cipher/ end end - if defined?(OpenSSL::PKey::DH) && tls12_supported? - # DHE - # TODO: How to test this with TLS 1.3? - ctx_proc2 = proc { |ctx| - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "EDH" + # DHE + # TODO: How to test this with TLS 1.3? + ctx_proc2 = proc { |ctx| + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + ctx.tmp_dh = Fixtures.pkey("dh-1") + } + start_server(ctx_proc: ctx_proc2) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ssl_version = :TLSv1_2 + ctx.ciphers = "EDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key } - start_server(ctx_proc: ctx_proc2) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - ctx.ciphers = "EDH" - server_connect(port, ctx) { |ssl| - assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key - } - end end - if defined?(OpenSSL::PKey::EC) - # ECDHE - ctx_proc3 = proc { |ctx| - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - ctx.ecdh_curves = "P-256" + # ECDHE + ctx_proc3 = proc { |ctx| + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + ctx.ecdh_curves = "P-256" + } + start_server(ctx_proc: ctx_proc3) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.ciphers = "DEFAULT:!kRSA:!kEDH" + server_connect(port, ctx) { |ssl| + assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key + ssl.puts "abc"; assert_equal "abc\n", ssl.gets } - start_server(ctx_proc: ctx_proc3) do |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ciphers = "DEFAULT:!kRSA:!kEDH" - server_connect(port, ctx) { |ssl| - assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key - ssl.puts "abc"; assert_equal "abc\n", ssl.gets - } - end end end @@ -1583,13 +1664,11 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - def test_dh_callback - pend "TLS 1.2 is not supported" unless tls12_supported? - + def test_tmp_dh_callback dh = Fixtures.pkey("dh-1") called = false ctx_proc = -> ctx { - ctx.ssl_version = :TLSv1_2 + ctx.max_version = :TLS1_2 ctx.ciphers = "DH:!NULL" ctx.tmp_dh_callback = ->(*args) { called = true @@ -1604,11 +1683,106 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - def test_connect_works_when_setting_dh_callback_to_nil - pend "TLS 1.2 is not supported" unless tls12_supported? + def test_ciphersuites_method_tls_connection + ssl_ctx = OpenSSL::SSL::SSLContext.new + if !tls13_supported? || !ssl_ctx.respond_to?(:ciphersuites=) + pend 'TLS 1.3 not supported' + end + + csuite = ['TLS_AES_128_GCM_SHA256', 'TLSv1.3', 128, 128] + inputs = [csuite[0], [csuite[0]], [csuite]] + start_server do |port| + inputs.each do |input| + cli_ctx = OpenSSL::SSL::SSLContext.new + cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION + cli_ctx.ciphersuites = input + + server_connect(port, cli_ctx) do |ssl| + assert_equal('TLSv1.3', ssl.ssl_version) + if libressl?(3, 4, 0) && !libressl?(3, 5, 0) + assert_equal("AEAD-AES128-GCM-SHA256", ssl.cipher[0]) + else + assert_equal(csuite[0], ssl.cipher[0]) + end + ssl.puts('abc'); assert_equal("abc\n", ssl.gets) + end + end + end + end + + def test_ciphersuites_method_nil_argument + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) + + assert_nothing_raised { ssl_ctx.ciphersuites = nil } + end + + def test_ciphersuites_method_frozen_object + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) + + ssl_ctx.freeze + assert_raise(FrozenError) { ssl_ctx.ciphersuites = 'TLS_AES_256_GCM_SHA384' } + end + + def test_ciphersuites_method_bogus_csuite + ssl_ctx = OpenSSL::SSL::SSLContext.new + pend 'ciphersuites= method is missing' unless ssl_ctx.respond_to?(:ciphersuites=) + + assert_raise_with_message( + OpenSSL::SSL::SSLError, + /SSL_CTX_set_ciphersuites: no cipher match/i + ) { ssl_ctx.ciphersuites = 'BOGUS' } + end + + def test_ciphers_method_tls_connection + csuite = ['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256, 256] + inputs = [csuite[0], [csuite[0]], [csuite]] + + start_server do |port| + inputs.each do |input| + cli_ctx = OpenSSL::SSL::SSLContext.new + cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + cli_ctx.ciphers = input + + server_connect(port, cli_ctx) do |ssl| + assert_equal('TLSv1.2', ssl.ssl_version) + assert_equal(csuite[0], ssl.cipher[0]) + ssl.puts('abc'); assert_equal("abc\n", ssl.gets) + end + end + end + end + + def test_ciphers_method_nil_argument + ssl_ctx = OpenSSL::SSL::SSLContext.new + assert_nothing_raised { ssl_ctx.ciphers = nil } + end + + def test_ciphers_method_frozen_object + ssl_ctx = OpenSSL::SSL::SSLContext.new + + ssl_ctx.freeze + assert_raise(FrozenError) { ssl_ctx.ciphers = 'ECDHE-RSA-AES128-SHA' } + end + + def test_ciphers_method_bogus_csuite + omit "Old #{OpenSSL::OPENSSL_LIBRARY_VERSION}" if + year = OpenSSL::OPENSSL_LIBRARY_VERSION[/\A OpenSSL\s+[01]\..*\s\K\d+\z/x] and + year.to_i <= 2018 + + ssl_ctx = OpenSSL::SSL::SSLContext.new + + assert_raise_with_message( + OpenSSL::SSL::SSLError, + /SSL_CTX_set_cipher_list: no cipher match/i + ) { ssl_ctx.ciphers = 'BOGUS' } + end + + def test_connect_works_when_setting_dh_callback_to_nil ctx_proc = -> ctx { - ctx.ssl_version = :TLSv1_2 + ctx.max_version = :TLS1_2 ctx.ciphers = "DH:!NULL" # use DH ctx.tmp_dh_callback = nil } @@ -1621,9 +1795,21 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - def test_ecdh_curves_tls12 - pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) + def test_tmp_dh + dh = Fixtures.pkey("dh-1") + ctx_proc = -> ctx { + ctx.max_version = :TLS1_2 + ctx.ciphers = "DH:!NULL" # use DH + ctx.tmp_dh = dh + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |ssl| + assert_equal dh.to_der, ssl.tmp_key.to_der + } + end + end + def test_ecdh_curves_tls12 ctx_proc = -> ctx { # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3 ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION @@ -1659,7 +1845,6 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_ecdh_curves_tls13 - pend "EC is disabled" unless defined?(OpenSSL::PKey::EC) pend "TLS 1.3 not supported" unless tls13_supported? ctx_proc = -> ctx { @@ -1746,6 +1931,19 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase sock2.close end + def test_export_keying_material + start_server do |port| + cli_ctx = OpenSSL::SSL::SSLContext.new + server_connect(port, cli_ctx) do |ssl| + assert_instance_of(String, ssl.export_keying_material('ttls keying material', 64)) + assert_operator(64, :==, ssl.export_keying_material('ttls keying material', 64).b.length) + assert_operator(8, :==, ssl.export_keying_material('ttls keying material', 8).b.length) + assert_operator(5, :==, ssl.export_keying_material('test', 5, 'context').b.length) + ssl.puts "abc"; ssl.gets # workaround to make tests work on windows + end + end + end + private def start_server_version(version, ctx_proc = nil, diff --git a/test/openssl/test_ssl_session.rb b/test/openssl/test_ssl_session.rb index a98efdae2a..89cf672a7b 100644 --- a/test/openssl/test_ssl_session.rb +++ b/test/openssl/test_ssl_session.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true require_relative "utils" -if defined?(OpenSSL) +if defined?(OpenSSL::SSL) class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase def test_session - pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } start_server(ctx_proc: ctx_proc) do |port| server_connect_with_session(port, nil, nil) { |ssl| @@ -24,7 +22,7 @@ class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase 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_equal(session.to_der, pem.unpack1('m')) assert_not_nil(session.to_text) } end @@ -144,8 +142,6 @@ __EOS__ end def test_server_session_cache - pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = Proc.new do |ctx| ctx.ssl_version = :TLSv1_2 ctx.options |= OpenSSL::SSL::OP_NO_TICKET @@ -224,8 +220,6 @@ __EOS__ TEST_SESSION_REMOVE_CB = ENV["OSSL_TEST_ALL"] == "1" def test_ctx_client_session_cb - pend "TLS 1.2 is not supported" unless tls12_supported? - ctx_proc = proc { |ctx| ctx.ssl_version = :TLSv1_2 } start_server(ctx_proc: ctx_proc) do |port| called = {} @@ -257,8 +251,6 @@ __EOS__ end def test_ctx_server_session_cb - pend "TLS 1.2 is not supported" unless tls12_supported? - connections = nil called = {} cctx = OpenSSL::SSL::SSLContext.new diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb index 8e31a7d28d..ac0469ad56 100644 --- a/test/openssl/test_ts.rb +++ b/test/openssl/test_ts.rb @@ -181,6 +181,12 @@ _end_of_pem_ assert_equal(42, qer2.nonce) end + def test_request_invalid_asn1 + assert_raise(OpenSSL::Timestamp::TimestampError) do + OpenSSL::Timestamp::Request.new("*" * 44) + end + end + def test_response_constants assert_equal(0, OpenSSL::Timestamp::Response::GRANTED) assert_equal(1, OpenSSL::Timestamp::Response::GRANTED_WITH_MODS) @@ -317,6 +323,8 @@ _end_of_pem_ 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) + + assert_match(/1\.2\.3\.4\.6/, resp.to_text) end def test_response_bad_purpose @@ -338,6 +346,12 @@ _end_of_pem_ end end + def test_response_invalid_asn1 + assert_raise(OpenSSL::Timestamp::TimestampError) do + OpenSSL::Timestamp::Response.new("*" * 44) + end + end + def test_no_cert_requested req = OpenSSL::Timestamp::Request.new req.algorithm = "SHA1" @@ -590,6 +604,12 @@ _end_of_pem_ assert_equal(123, info.nonce) end + def test_token_info_invalid_asn1 + assert_raise(OpenSSL::Timestamp::TimestampError) do + OpenSSL::Timestamp::TokenInfo.new("*" * 44) + end + end + private def assert_cert expected, actual diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index d696b98c0a..64805504de 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -173,13 +173,14 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase end def test_sign_and_verify_rsa_sha1 - cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "sha1") + cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: "SHA1") 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)) + rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1 end def test_sign_and_verify_rsa_md5 @@ -229,6 +230,7 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") assert_equal("dsaWithSHA1", cert.signature_algorithm) + rescue OpenSSL::X509::CertificateError # RHEL 9 disables SHA1 end def test_check_private_key diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb index bcdb0a697c..146ee07309 100644 --- a/test/openssl/test_x509crl.rb +++ b/test/openssl/test_x509crl.rb @@ -20,7 +20,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) crl = issue_crl([], 1, now, now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) assert_equal(1, crl.version) assert_equal(cert.issuer.to_der, crl.issuer.to_der) assert_equal(now, crl.last_update) @@ -57,7 +57,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase ] cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) revoked = crl.revoked assert_equal(5, revoked.size) assert_equal(1, revoked[0].serial) @@ -98,7 +98,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase revoke_info = (1..1000).collect{|i| [i, now, 0] } crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) revoked = crl.revoked assert_equal(1000, revoked.size) assert_equal(1, revoked[0].serial) @@ -124,7 +124,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase cert = issue_cert(@ca, @rsa2048, 1, cert_exts, nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts, - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) exts = crl.extensions assert_equal(3, exts.size) assert_equal("1", exts[0].value) @@ -160,24 +160,24 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal(false, exts[2].critical?) no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) assert_equal nil, no_ext_crl.authority_key_identifier end def test_crlnumber cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) 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.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) 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.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) assert_match(/X509v3 CRL Number:\s+#{2**100}/m, crl.to_text) assert_match((2**100).to_s, crl.extensions[0].value) end @@ -185,7 +185,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase def test_sign_and_verify cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @rsa2048, OpenSSL::Digest.new('SHA1')) + cert, @rsa2048, OpenSSL::Digest.new('SHA256')) assert_equal(false, crl.verify(@rsa1024)) assert_equal(true, crl.verify(@rsa2048)) assert_equal(false, crl_error_returns_false { crl.verify(@dsa256) }) @@ -195,7 +195,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @dsa512, OpenSSL::Digest.new('SHA1')) + cert, @dsa512, OpenSSL::Digest.new('SHA256')) 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)) diff --git a/test/openssl/test_x509ext.rb b/test/openssl/test_x509ext.rb index 7ad010d1ed..59a41ed736 100644 --- a/test/openssl/test_x509ext.rb +++ b/test/openssl/test_x509ext.rb @@ -50,24 +50,41 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase 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) + assert_include(cdp.value, "URI:http://www.example.com/crl") + assert_include(cdp.value, + "URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary") 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) + assert_include(cdp.value, "URI:http://www.example.com/crl") + assert_include(cdp.value, + "URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary") cp = ef.create_extension("certificatePolicies", "@certPolicies") assert_equal(false, cp.critical?) assert_equal("certificatePolicies", cp.oid) - assert_match(%r{2.23.140.1.2.1}, cp.value) - assert_match(%r{http://cps.example.com}, cp.value) + assert_include(cp.value, "2.23.140.1.2.1") + assert_include(cp.value, "http://cps.example.com") + end + + def test_factory_create_extension_sn_ln + ef = OpenSSL::X509::ExtensionFactory.new + bc_sn = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + bc_ln = ef.create_extension("X509v3 Basic Constraints", "critical, CA:TRUE, pathlen:2") + assert_equal(@basic_constraints.to_der, bc_sn.to_der) + assert_equal(@basic_constraints.to_der, bc_ln.to_der) + end + + def test_factory_create_extension_oid + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_end_of_cnf_) + [basic_constraints] + cA = BOOLEAN:TRUE + pathLenConstraint = INTEGER:2 + _end_of_cnf_ + bc_oid = ef.create_extension("2.5.29.19", "ASN1:SEQUENCE:basic_constraints", true) + assert_equal(@basic_constraints.to_der, bc_oid.to_der) end def test_dup diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index ee9c678fbb..b98754b8c8 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -23,31 +23,26 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase end def test_public_key - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) 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.new('SHA1')) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256')) 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.new('SHA1')) + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) 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.new('SHA1')) - 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.new('SHA1')) + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) 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) @@ -78,9 +73,9 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase OpenSSL::X509::Attribute.new("msExtReq", attrval), ] - req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) + req0 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) attrs.each{|attr| req0.add_attribute(attr) } - req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) + req1 = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) req1.attributes = attrs assert_equal(req0.to_der, req1.to_der) @@ -106,8 +101,9 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase 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 + req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBarFooBar") assert_equal(false, req.verify(@rsa1024)) + rescue OpenSSL::X509::RequestError # RHEL 9 disables SHA1 end def test_sign_and_verify_rsa_md5 @@ -122,7 +118,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase end def test_sign_and_verify_dsa - req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA1')) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256')) 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)) @@ -137,14 +133,14 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase end def test_dup - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA1')) + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) assert_equal(req.to_der, req.dup.to_der) end def test_eq - req1 = issue_csr(0, @dn, @rsa1024, "sha1") - req2 = issue_csr(0, @dn, @rsa1024, "sha1") - req3 = issue_csr(0, @dn, @rsa1024, "sha256") + req1 = issue_csr(0, @dn, @rsa1024, "sha256") + req2 = issue_csr(0, @dn, @rsa1024, "sha256") + req3 = issue_csr(0, @dn, @rsa1024, "sha512") assert_equal false, req1 == 12345 assert_equal true, req1 == req2 diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb index 8ee0116412..f6c84eef67 100644 --- a/test/openssl/utils.rb +++ b/test/openssl/utils.rb @@ -1,38 +1,13 @@ # frozen_string_literal: true begin require "openssl" - - # Disable FIPS mode for tests for installations - # where FIPS mode would be enabled by default. - # Has no effect on all other installations. - OpenSSL.fips_mode=false rescue LoadError end -# Compile OpenSSL with crypto-mdebug and run this test suite with OSSL_MDEBUG=1 -# environment variable to enable memory leak check. -if ENV["OSSL_MDEBUG"] == "1" - if OpenSSL.respond_to?(:print_mem_leaks) - OpenSSL.mem_check_start - - END { - GC.start - case OpenSSL.print_mem_leaks - when nil - warn "mdebug: check what is printed" - when true - raise "mdebug: memory leaks detected" - end - } - else - warn "OSSL_MDEBUG=1 is specified but OpenSSL is not built with crypto-mdebug" - end -end - require "test/unit" +require "core_assertions" require "tempfile" require "socket" -require "envutil" if defined?(OpenSSL) @@ -131,11 +106,12 @@ module OpenSSL::TestUtils end end - def openssl?(major = nil, minor = nil, fix = nil, patch = 0) + def openssl?(major = nil, minor = nil, fix = nil, patch = 0, status = 0) return false if OpenSSL::OPENSSL_VERSION.include?("LibreSSL") return true unless major OpenSSL::OPENSSL_VERSION_NUMBER >= - major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 + major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 + + status * 0x1 end def libressl?(major = nil, minor = nil, fix = nil) @@ -148,6 +124,7 @@ end class OpenSSL::TestCase < Test::Unit::TestCase include OpenSSL::TestUtils extend OpenSSL::TestUtils + include Test::Unit::CoreAssertions def setup if ENV["OSSL_GC_STRESS"] == "1" @@ -162,6 +139,30 @@ class OpenSSL::TestCase < Test::Unit::TestCase # OpenSSL error stack must be empty assert_equal([], OpenSSL.errors) end + + # Omit the tests in FIPS. + # + # For example, the password based encryption used in the PEM format uses MD5 + # for deriving the encryption key from the password, and MD5 is not + # FIPS-approved. + # + # See https://github.com/openssl/openssl/discussions/21830#discussioncomment-6865636 + # for details. + def omit_on_fips + return unless OpenSSL.fips_mode + + omit <<~MESSAGE + Only for OpenSSL non-FIPS with the following possible reasons: + * A testing logic is non-FIPS specific. + * An encryption used in the test is not FIPS-approved. + MESSAGE + end + + def omit_on_non_fips + return if OpenSSL.fips_mode + + omit "Only for OpenSSL FIPS" + end end class OpenSSL::SSLTestCase < OpenSSL::TestCase @@ -189,13 +190,6 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase @server = nil end - def tls12_supported? - ctx = OpenSSL::SSL::SSLContext.new - ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION - true - rescue - end - def tls13_supported? return false unless defined?(OpenSSL::SSL::TLS1_3_VERSION) ctx = OpenSSL::SSL::SSLContext.new @@ -222,7 +216,6 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase ctx.cert_store = store ctx.cert = @svr_cert ctx.key = @svr_key - ctx.tmp_dh_callback = proc { Fixtures.pkey("dh-1") } ctx.verify_mode = verify_mode ctx_proc.call(ctx) if ctx_proc @@ -236,9 +229,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase threads = [] begin server_thread = Thread.new do - if Thread.method_defined?(:report_on_exception=) # Ruby >= 2.4 - Thread.current.report_on_exception = false - end + Thread.current.report_on_exception = false begin loop do @@ -254,9 +245,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase end th = Thread.new do - if Thread.method_defined?(:report_on_exception=) - Thread.current.report_on_exception = false - end + Thread.current.report_on_exception = false begin server_proc.call(ctx, ssl) @@ -273,9 +262,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase end client_thread = Thread.new do - if Thread.method_defined?(:report_on_exception=) - Thread.current.report_on_exception = false - end + Thread.current.report_on_exception = false begin block.call(port) @@ -294,8 +281,7 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase timeout = EnvUtil.apply_timeout_scale(30) th.join(timeout) or 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 + rescue Test::Unit::PendedError pend = $! rescue Exception end @@ -313,32 +299,6 @@ class OpenSSL::PKeyTestCase < OpenSSL::TestCase assert_equal base.send(comp), test.send(comp) } end - - def dup_public(key) - case key - when OpenSSL::PKey::RSA - rsa = OpenSSL::PKey::RSA.new - rsa.set_key(key.n, key.e, nil) - rsa - when OpenSSL::PKey::DSA - dsa = OpenSSL::PKey::DSA.new - dsa.set_pqg(key.p, key.q, key.g) - dsa.set_key(key.pub_key, nil) - dsa - when OpenSSL::PKey::DH - dh = OpenSSL::PKey::DH.new - dh.set_pqg(key.p, nil, key.g) - dh - else - if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key - ec = OpenSSL::PKey::EC.new(key.group) - ec.public_key = key.public_key - ec - else - raise "unknown key type" - end - end - end end module OpenSSL::Certs |