mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 20:19:19 +00:00
Remove the following subclasses of OpenSSL::PKey::PKeyError and make
them aliases of it.
- OpenSSL::PKey::DHError
- OpenSSL::PKey::DSAError
- OpenSSL::PKey::ECError
- OpenSSL::PKey::RSAError
Historically, methods defined on OpenSSL::PKey and OpenSSL::PKey::PKey
raise OpenSSL::PKey::PKeyError, while methods on the subclasses raise
their respective exception classes. However, this distinction is not
particularly useful since all those exception classes represent the
same kind of errors from the underlying EVP_PKEY API.
I think this convention comes from the fact that OpenSSL::PKey::{DH,
DSA,RSA} originally wrapped the corresponding OpenSSL structs DH, DSA,
and RSA, before they were unified to wrap EVP_PKEY, way back in 2002.
OpenSSL::PKey::EC::Group::Error and OpenSSL::PKey::EC::Point::Error
are out of scope of this change, as they are not subclasses of
OpenSSL::PKey::PKeyError and do not represent errors from the EVP_PKEY
API.
https://github.com/ruby/openssl/commit/e74ff3e272
262 lines
8.6 KiB
Ruby
262 lines
8.6 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 = 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
|