mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
As documented, the #public_key methods on OpenSSL::PKey::{DH,DSA,RSA}
are obsolete, as their behavior is inconsistent and better alternatives
are available. Remove unnecessary uses from RDoc comments for other
methods.
Also add dedicated tests for these methods to confirm the current
behavior.
https://github.com/ruby/openssl/commit/13d5616d17
274 lines
9.0 KiB
Ruby
274 lines
9.0 KiB
Ruby
# 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 = OpenSSL::PKey::DSA.new(key.public_to_der)
|
|
assert_equal false, key3.private?
|
|
end
|
|
|
|
def test_new
|
|
key = OpenSSL::PKey::DSA.new(1024)
|
|
assert_predicate(key, :private?)
|
|
assert_equal(1024, key.p.num_bits)
|
|
assert_equal(160, key.q.num_bits)
|
|
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_public_key
|
|
key = Fixtures.pkey("dsa2048")
|
|
pub = key.public_key
|
|
assert_not_predicate(pub, :private?)
|
|
assert_predicate(pub, :public?)
|
|
assert_equal(key.p, pub.p)
|
|
assert_equal(key.q, pub.q)
|
|
assert_equal(key.g, pub.g)
|
|
assert_equal(key.pub_key, pub.pub_key)
|
|
assert_nil(pub.priv_key)
|
|
assert_equal(key.public_to_der, pub.to_der)
|
|
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
|