From 8e50919f57d46ed9cd1aa1f8601f79f7af9f7ffa Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 12:32:10 +0000 Subject: [PATCH 1/3] Add test for non-RSA DER key rejection in _new_public_key_x509_der On OpenSSL 3.x, d2i_PUBKEY_bio() accepts any key type (EC, DSA, etc.) but _new_public_key_x509_der() has no type validation, unlike _load_rsa_key() which checks EVP_PKEY_get_base_id(). This test demonstrates the gap: an EC public key in X.509 DER format is silently accepted, creating a corrupt rsaData object. The test intentionally fails against the current code to document the vulnerability before the fix is applied. Co-Authored-By: Claude Opus 4.6 --- t/der.t | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/t/der.t b/t/der.t index 1d919d5..92eafc5 100644 --- a/t/der.t +++ b/t/der.t @@ -4,7 +4,9 @@ use Test::More; use MIME::Base64; use Crypt::OpenSSL::RSA; -BEGIN { plan tests => 22 } +use File::Temp qw(tempfile); + +BEGIN { plan tests => 24 } # --- Generate a key pair for testing --- @@ -127,3 +129,26 @@ like( $@, qr/unrecognized key format/, eval { Crypt::OpenSSL::RSA->new_public_key("-----BEGIN CERTIFICATE-----\nfoo\n-----END CERTIFICATE-----\n") }; like( $@, qr/unrecognized key format/, "new_public_key gives helpful error on certificate PEM" ); + +# --- Non-RSA DER key rejection --- +# On OpenSSL 3.x, d2i_PUBKEY_bio() accepts any key type. +# _new_public_key_x509_der must reject non-RSA keys. + +SKIP: { + my $ec_pem = `openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 2>/dev/null`; + skip "EC key generation not available", 2 + unless ($? >> 8) == 0 && $ec_pem =~ /-----BEGIN PRIVATE KEY-----/; + + my ($tmpfh, $tmpfile) = tempfile(UNLINK => 1); + print $tmpfh $ec_pem; + close $tmpfh; + my $ec_pub_pem = `openssl pkey -in $tmpfile -pubout -outform PEM 2>/dev/null`; + skip "EC public key export failed", 2 + unless ($? >> 8) == 0 && $ec_pub_pem =~ /-----BEGIN PUBLIC KEY-----/; + + my $ec_pub_der = pem_to_der($ec_pub_pem); + eval { Crypt::OpenSSL::RSA->_new_public_key_x509_der($ec_pub_der) }; + ok($@, "_new_public_key_x509_der rejects EC DER key"); + like($@, qr/not an RSA key|ASN1/i, + "_new_public_key_x509_der gives appropriate error for non-RSA DER key"); +} From 5259b2733f371ed7a060d40038fbf0aba4ec56ac Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 12:32:58 +0000 Subject: [PATCH 2/3] Reject non-RSA keys in _new_public_key_x509_der() on OpenSSL 3.x On OpenSSL 3.x, d2i_PUBKEY_bio() accepts any key type (EC, DSA, etc.), unlike the pre-3.x d2i_RSA_PUBKEY_bio() which only accepts RSA keys. Without validation, a non-RSA DER key would be stored in the rsaData struct, leading to corrupt state and confusing failures on subsequent operations. Add the same EVP_PKEY_get_base_id() != EVP_PKEY_RSA guard already present in _load_rsa_key() (line 401) to give a clear "not an RSA key" error at load time. Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RSA.xs b/RSA.xs index fd80267..014250a 100644 --- a/RSA.xs +++ b/RSA.xs @@ -580,6 +580,12 @@ _new_public_key_x509_der(proto, key_string_SV) #endif BIO_free(bio); CHECK_OPEN_SSL(pkey); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (EVP_PKEY_get_base_id(pkey) != EVP_PKEY_RSA) { + EVP_PKEY_free(pkey); + croak("The key loaded is not an RSA key"); + } +#endif RETVAL = make_rsa_obj(proto, pkey); OUTPUT: RETVAL From f915552fd023875a03c56e1dd465099aceaa4992 Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 13:32:59 +0000 Subject: [PATCH 3/3] Fix DER key rejection test regex for OpenSSL 1.1.1 (Bullseye) On pre-3.x OpenSSL, d2i_RSA_PUBKEY_bio() rejects EC keys with "expecting an rsa key" rather than "not an RSA key" (our croak) or an ASN1 error. Add this variant to the regex so the test passes across all supported OpenSSL versions. Co-Authored-By: Claude Opus 4.6 --- t/der.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/der.t b/t/der.t index 92eafc5..cc64c88 100644 --- a/t/der.t +++ b/t/der.t @@ -149,6 +149,6 @@ SKIP: { my $ec_pub_der = pem_to_der($ec_pub_pem); eval { Crypt::OpenSSL::RSA->_new_public_key_x509_der($ec_pub_der) }; ok($@, "_new_public_key_x509_der rejects EC DER key"); - like($@, qr/not an RSA key|ASN1/i, + like($@, qr/not an RSA key|ASN1|expecting an rsa key/i, "_new_public_key_x509_der gives appropriate error for non-RSA DER key"); }