# frozen_string_literal: true require_relative 'utils' if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def setup # May not be available in FIPS mode as DSA has been deprecated in FIPS 186-5 omit_on_fips end def test_private key = Fixtures.pkey("dsa2048") assert_equal true, key.private? key2 = OpenSSL::PKey::DSA.new(key.to_der) assert_equal true, key2.private? key3 = key.public_key assert_equal false, key3.private? key4 = OpenSSL::PKey::DSA.new(key3.to_der) assert_equal false, key4.private? end def test_new key = OpenSSL::PKey::DSA.new(2048) pem = key.public_key.to_pem OpenSSL::PKey::DSA.new pem end def test_new_break assert_nil(OpenSSL::PKey::DSA.new(2048) { break }) assert_raise(RuntimeError) do OpenSSL::PKey::DSA.new(2048) { raise } end end def test_new_empty # pkeys are immutable with OpenSSL >= 3.0 if openssl?(3, 0, 0) assert_raise(ArgumentError) { OpenSSL::PKey::DSA.new } else key = OpenSSL::PKey::DSA.new assert_nil(key.p) assert_raise(OpenSSL::PKey::PKeyError) { key.to_der } 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 key1024 = OpenSSL::PKey::DSA.generate(1024) assert_predicate key1024, :private? assert_equal 1024, key1024.p.num_bits assert_equal 160, key1024.q.num_bits if ENV["OSSL_TEST_ALL"] == "1" # slow key2048 = OpenSSL::PKey::DSA.generate(2048) assert_equal 2048, key2048.p.num_bits assert_equal 256, key2048.q.num_bits key3072 = OpenSSL::PKey::DSA.generate(3072) assert_equal 3072, key3072.p.num_bits assert_equal 256, key3072.q.num_bits end end def test_sign_verify # 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 = dsa.sign(OpenSSL::Digest.new('DSS1'), data) assert_equal true, dsa.verify(OpenSSL::Digest.new('DSS1'), signature, data) end signature = dsa.sign("SHA256", data) assert_equal true, dsa.verify("SHA256", signature, data) signature0 = (<<~'end;').unpack1("m") MD4CHQC0zmRkVOAHJTm28fS5PVUv+4LtBeNaKqr/yfmVAh0AsTcLqofWHoW8X5oWu8AOvngOcFVZ cLTvhY3XNw== end; assert_equal true, dsa.verify("SHA256", signature0, data) signature1 = signature0.succ assert_equal false, dsa.verify("SHA256", signature1, data) end def test_sign_verify_raw key = Fixtures.pkey("dsa2048") data = 'Sign me!' digest = OpenSSL::Digest.digest('SHA1', data) invalid_sig = key.sign_raw(nil, digest.succ) malformed_sig = "*" * invalid_sig.bytesize # Sign by #syssign sig = key.syssign(digest) assert_equal true, key.sysverify(digest, sig) assert_equal false, key.sysverify(digest, invalid_sig) assert_sign_verify_false_or_error { key.sysverify(digest, malformed_sig) } assert_equal true, key.verify_raw(nil, sig, digest) assert_equal false, key.verify_raw(nil, invalid_sig, digest) assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, digest) } # Sign by #sign_raw sig = key.sign_raw(nil, digest) assert_equal true, key.sysverify(digest, sig) assert_equal false, key.sysverify(digest, invalid_sig) assert_sign_verify_false_or_error { key.sysverify(digest, malformed_sig) } assert_equal true, key.verify_raw(nil, sig, digest) assert_equal false, key.verify_raw(nil, invalid_sig, digest) assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, digest) } end def test_DSAPrivateKey # OpenSSL DSAPrivateKey format; similar to RSAPrivateKey orig = Fixtures.pkey("dsa2048") asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(0), OpenSSL::ASN1::Integer(orig.p), OpenSSL::ASN1::Integer(orig.q), OpenSSL::ASN1::Integer(orig.g), OpenSSL::ASN1::Integer(orig.pub_key), OpenSSL::ASN1::Integer(orig.priv_key) ]) key = OpenSSL::PKey::DSA.new(asn1.to_der) assert_predicate key, :private? assert_same_dsa orig, key pem = der_to_pem(asn1.to_der, "DSA PRIVATE KEY") key = OpenSSL::PKey::DSA.new(pem) assert_same_dsa orig, key assert_equal asn1.to_der, orig.to_der assert_equal pem, orig.export end def test_DSAPrivateKey_encrypted # OpenSSL DSAPrivateKey with OpenSSL encryption orig = Fixtures.pkey("dsa2048") pem = der_to_encrypted_pem(orig.to_der, "DSA PRIVATE KEY", "abcdef") key = OpenSSL::PKey::DSA.new(pem, "abcdef") assert_same_dsa orig, key key = OpenSSL::PKey::DSA.new(pem) { "abcdef" } assert_same_dsa orig, key cipher = OpenSSL::Cipher.new("aes-128-cbc") exported = orig.to_pem(cipher, "abcdef\0\1") assert_same_dsa orig, OpenSSL::PKey::DSA.new(exported, "abcdef\0\1") assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey::DSA.new(exported, "abcdef") } end def test_PUBKEY orig = Fixtures.pkey("dsa2048") pub = OpenSSL::PKey::DSA.new(orig.public_to_der) asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::ObjectId("DSA"), OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(orig.p), OpenSSL::ASN1::Integer(orig.q), OpenSSL::ASN1::Integer(orig.g) ]) ]), OpenSSL::ASN1::BitString( OpenSSL::ASN1::Integer(orig.pub_key).to_der ) ]) key = OpenSSL::PKey::DSA.new(asn1.to_der) assert_not_predicate key, :private? assert_same_dsa pub, key pem = der_to_pem(asn1.to_der, "PUBLIC KEY") key = OpenSSL::PKey::DSA.new(pem) assert_same_dsa pub, key assert_equal asn1.to_der, key.to_der assert_equal pem, key.export assert_equal asn1.to_der, orig.public_to_der assert_equal asn1.to_der, key.public_to_der assert_equal pem, orig.public_to_pem assert_equal pem, key.public_to_pem end def test_read_DSAPublicKey_pem # TODO: where is the standard? PKey::DSA.new can read only PEM p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699 q = 979494906553787301107832405790107343409973851677 g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845 y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695 pem = <<-EOF -----BEGIN DSA PUBLIC KEY----- MIHfAkEAyJSJ+g+P/knVcgDwwTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4 VUC/phySExY0PdcqItkR/xYAYNMbNwJBAOoV57X0FxKO/PrNa/MkoWzkCKV/hzhE p0zbFdsicw+hIjJ7S6Sd/FlDlo89HQZ2FuvWJ6wGLM1j00r39+F2qbMCFQCrkhIX SG+is37hz1IaBeEudjB2HQJAR0AloavBvtsng8obsjLb7EKnB+pSeHr/BdIQ3VH7 fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== -----END DSA PUBLIC KEY----- EOF key = OpenSSL::PKey::DSA.new(pem) assert(key.public?) assert(!key.private?) assert_equal(p, key.p) assert_equal(q, key.q) assert_equal(g, key.g) assert_equal(y, key.pub_key) assert_equal(nil, key.priv_key) end def test_params key = Fixtures.pkey("dsa2048") assert_kind_of(OpenSSL::BN, key.p) assert_equal(key.p, key.params["p"]) assert_kind_of(OpenSSL::BN, key.q) assert_equal(key.q, key.params["q"]) assert_kind_of(OpenSSL::BN, key.g) assert_equal(key.g, key.params["g"]) assert_kind_of(OpenSSL::BN, key.pub_key) assert_equal(key.pub_key, key.params["pub_key"]) assert_kind_of(OpenSSL::BN, key.priv_key) assert_equal(key.priv_key, key.params["priv_key"]) pubkey = OpenSSL::PKey.read(key.public_to_der) assert_equal(key.params["p"], pubkey.params["p"]) assert_equal(key.pub_key, pubkey.pub_key) assert_equal(key.pub_key, pubkey.params["pub_key"]) assert_nil(pubkey.priv_key) assert_nil(pubkey.params["priv_key"]) end def test_dup key = Fixtures.pkey("dsa2048") key2 = key.dup assert_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 key = Fixtures.pkey("dsa2048") deserialized = Marshal.load(Marshal.dump(key)) assert_equal key.to_der, deserialized.to_der end private def assert_same_dsa(expected, key) check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key]) end end end