From 0791e70b5477b16425f1c00e17f4f9887a9a8123 Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 12:44:49 +0000 Subject: [PATCH 1/3] Add tests for private_encrypt error message ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests that private_encrypt with OAEP/PSS padding produces a padding compatibility error rather than a misleading "plaintext too long" error. These tests currently FAIL — the fix follows in the next commit. Also makes OAEP/PSS rejection tests version-independent (previously only tested on OpenSSL 3.x). Co-Authored-By: Claude Opus 4.6 --- t/private_encrypt.t | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/t/private_encrypt.t b/t/private_encrypt.t index 2701af9..53185a4 100644 --- a/t/private_encrypt.t +++ b/t/private_encrypt.t @@ -8,7 +8,7 @@ use Crypt::OpenSSL::Guess qw(openssl_version); my ($major) = openssl_version(); -plan tests => 10; +plan tests => 14; Crypt::OpenSSL::Random::random_seed("OpenSSL needs at least 32 bytes."); Crypt::OpenSSL::RSA->import_random_seed(); @@ -29,13 +29,8 @@ is($dec, $data, "public_decrypt(private_encrypt(data)) round-trips with no_paddi $rsa->use_pkcs1_oaep_padding(); eval { $rsa->private_encrypt("test") }; -if ($major ge '3') { - like($@, qr/OAEP padding is not supported for private_encrypt/, - "private_encrypt with OAEP croaks with clear message on OpenSSL 3.x"); -} else { - # Pre-3.x uses RSA_private_encrypt which handles padding differently - ok(1, "private_encrypt with OAEP behavior on pre-3.x (skipped)"); -} +like($@, qr/OAEP padding is not supported for private_encrypt/, + "private_encrypt with OAEP croaks with clear message"); # --- OAEP: should croak for public_decrypt --- @@ -44,19 +39,16 @@ if ($major ge '3') { like($@, qr/OAEP padding is not supported for private_encrypt\/public_decrypt/, "public_decrypt with OAEP croaks with clear message on OpenSSL 3.x"); } else { - ok(1, "public_decrypt with OAEP behavior on pre-3.x (skipped)"); + like($@, qr/./, + "public_decrypt with OAEP fails on pre-3.x"); } # --- PSS: should croak for private_encrypt --- $rsa->use_pkcs1_pss_padding(); eval { $rsa->private_encrypt("test") }; -if ($major ge '3') { - like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, - "private_encrypt with PSS croaks with clear message on OpenSSL 3.x"); -} else { - ok(1, "private_encrypt with PSS behavior on pre-3.x (skipped)"); -} +like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, + "private_encrypt with PSS croaks with clear message"); # --- PSS: should croak for public_decrypt --- @@ -65,7 +57,33 @@ if ($major ge '3') { like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, "public_decrypt with PSS croaks with clear message on OpenSSL 3.x"); } else { - ok(1, "public_decrypt with PSS behavior on pre-3.x (skipped)"); + like($@, qr/./, + "public_decrypt with PSS fails on pre-3.x"); +} + +# --- Error ordering: padding error must come before length error --- + +{ + my $rsa_fresh = Crypt::OpenSSL::RSA->generate_key(2048); + my $large_data = "x" x 250; # exceeds OAEP limit (256 - 42 = 214) + eval { $rsa_fresh->private_encrypt($large_data) }; + like($@, qr/OAEP padding is not supported for private_encrypt/, + "private_encrypt with default OAEP + oversized data gives padding error, not length error"); + + $rsa_fresh->use_pkcs1_pss_padding(); + eval { $rsa_fresh->private_encrypt($large_data) }; + like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, + "private_encrypt with PSS + oversized data gives padding error, not length error"); + + $rsa_fresh->use_pkcs1_oaep_padding(); + my $exact_data = "y" x 215; # just over OAEP limit + eval { $rsa_fresh->private_encrypt($exact_data) }; + like($@, qr/OAEP padding is not supported for private_encrypt/, + "private_encrypt with OAEP + barely-over-limit data gives padding error, not length error"); + + $rsa_fresh->use_pkcs1_padding(); + eval { $rsa_fresh->private_encrypt("test") }; + ok(!$@, "private_encrypt with PKCS#1 v1.5 padding works"); } # --- Encryption operations still work correctly --- From fc75575d3ac16945bbc4ba46715a75b693a637c5 Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 12:45:34 +0000 Subject: [PATCH 2/3] Check padding compatibility before message length in private_encrypt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When private_encrypt() is called with the default OAEP padding (or PSS), the padding is fundamentally incompatible with the operation. Previously, check_max_message_length() ran first and could produce a misleading "plaintext too long for key size with OAEP padding" error — hiding the real issue that OAEP/PSS aren't supported for private_encrypt at all. Now validates padding mode before checking message length, ensuring the user sees "OAEP padding is not supported for private_encrypt/public_decrypt" regardless of data size. This also extends the OAEP/PSS rejection to pre-3.x OpenSSL (previously only checked in the 3.x code path inside rsa_crypt()). Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RSA.xs b/RSA.xs index 6df0f7b..4149474 100644 --- a/RSA.xs +++ b/RSA.xs @@ -1196,6 +1196,14 @@ private_encrypt(p_rsa, p_plaintext) { croak("Public keys cannot private_encrypt"); } + if (p_rsa->padding == RSA_PKCS1_OAEP_PADDING) { + croak("OAEP padding is not supported for private_encrypt/public_decrypt. " + "Call use_no_padding() or use_pkcs1_padding() first."); + } + if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) { + croak("PSS padding with private_encrypt/public_decrypt is not supported. " + "Use sign()/verify() for PSS signatures."); + } check_max_message_length(p_rsa, sv_len(p_plaintext)); #if OPENSSL_VERSION_NUMBER >= 0x30000000L RETVAL = rsa_crypt(p_rsa, p_plaintext, EVP_PKEY_sign, EVP_PKEY_sign_init, 0 /* is_encrypt */); From 0c36f0b545950d8f8fc0c2b2a7c99a8cd5cd2370 Mon Sep 17 00:00:00 2001 From: Toddr Bot Date: Thu, 23 Apr 2026 15:22:49 +0000 Subject: [PATCH 3/3] Add OAEP/PSS padding checks to public_decrypt() The public_decrypt tests used qr/./ (matches any string) for the pre-3.x path because the error message was unpredictable. Fix the root cause: add the same OAEP/PSS guards to public_decrypt() that private_encrypt() already has, making errors consistent across all OpenSSL versions. Remove the now-unnecessary version branching. Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 8 ++++++++ t/private_encrypt.t | 22 ++++------------------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/RSA.xs b/RSA.xs index 4149474..14c156b 100644 --- a/RSA.xs +++ b/RSA.xs @@ -1218,6 +1218,14 @@ public_decrypt(p_rsa, p_ciphertext) rsaData* p_rsa; SV* p_ciphertext; CODE: + if (p_rsa->padding == RSA_PKCS1_OAEP_PADDING) { + croak("OAEP padding is not supported for private_encrypt/public_decrypt. " + "Call use_no_padding() or use_pkcs1_padding() first."); + } + if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) { + croak("PSS padding with private_encrypt/public_decrypt is not supported. " + "Use sign()/verify() for PSS signatures."); + } #if OPENSSL_VERSION_NUMBER >= 0x30000000L RETVAL = rsa_crypt(p_rsa, p_ciphertext, EVP_PKEY_verify_recover, EVP_PKEY_verify_recover_init, 0 /* is_encrypt */); #else diff --git a/t/private_encrypt.t b/t/private_encrypt.t index 53185a4..abc7df3 100644 --- a/t/private_encrypt.t +++ b/t/private_encrypt.t @@ -4,10 +4,6 @@ use Test::More; use Crypt::OpenSSL::Random; use Crypt::OpenSSL::RSA; -use Crypt::OpenSSL::Guess qw(openssl_version); - -my ($major) = openssl_version(); - plan tests => 14; Crypt::OpenSSL::Random::random_seed("OpenSSL needs at least 32 bytes."); @@ -35,13 +31,8 @@ like($@, qr/OAEP padding is not supported for private_encrypt/, # --- OAEP: should croak for public_decrypt --- eval { $rsa->public_decrypt("test" x 64) }; -if ($major ge '3') { - like($@, qr/OAEP padding is not supported for private_encrypt\/public_decrypt/, - "public_decrypt with OAEP croaks with clear message on OpenSSL 3.x"); -} else { - like($@, qr/./, - "public_decrypt with OAEP fails on pre-3.x"); -} +like($@, qr/OAEP padding is not supported for private_encrypt\/public_decrypt/, + "public_decrypt with OAEP croaks with clear message"); # --- PSS: should croak for private_encrypt --- @@ -53,13 +44,8 @@ like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, # --- PSS: should croak for public_decrypt --- eval { $rsa->public_decrypt("test" x 64) }; -if ($major ge '3') { - like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, - "public_decrypt with PSS croaks with clear message on OpenSSL 3.x"); -} else { - like($@, qr/./, - "public_decrypt with PSS fails on pre-3.x"); -} +like($@, qr/PSS padding with private_encrypt\/public_decrypt is not supported/, + "public_decrypt with PSS croaks with clear message"); # --- Error ordering: padding error must come before length error ---