Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions RSA.xs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,16 @@ typedef struct
void croakSsl(char* p_file, int p_line)
{
const char* errorReason;
/* Just return the top error on the stack */
errorReason = ERR_reason_error_string(ERR_get_error());
ERR_clear_error();
unsigned long last_err = 0;
unsigned long err;
/* Drain the error queue and use the last (most recent) error,
which is typically the most descriptive. This also prevents
stale errors from a previous eval-caught failure from leaking
into the next croak message. */
while ((err = ERR_get_error()) != 0) {
last_err = err;
}
errorReason = ERR_reason_error_string(last_err);
croak("%s:%d: OpenSSL error: %s", p_file, p_line,
errorReason ? errorReason : "(unknown error)");
}
Expand Down
4 changes: 2 additions & 2 deletions t/bignum.t
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ sub check_key_parameters # runs 8 tests
$e, $d, undef, $q
);
};
like( $@, qr/OpenSSL error: p not prime/, "bad n with q triggers 'p not prime' error" );
like( $@, qr/OpenSSL error: (?:p not prime|d e not congruent to 1)/, "bad n with q triggers key validation error" );

#try again, to make sure the error queue was properly flushed
eval {
Expand All @@ -98,5 +98,5 @@ sub check_key_parameters # runs 8 tests
$e, $d, undef, $q
);
};
like( $@, qr/OpenSSL error: p not prime/, "error queue flushed: repeat triggers same error" );
like( $@, qr/OpenSSL error: (?:p not prime|d e not congruent to 1)/, "error queue flushed: repeat triggers same error" );
}
32 changes: 32 additions & 0 deletions t/error_queue.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use strict;
use warnings;
use Test::More;

use Crypt::OpenSSL::RSA;

plan tests => 4;

# Test that eval-caught OpenSSL failures don't pollute subsequent error messages.
# Bug: croakSsl() used ERR_get_error() once (oldest error) instead of draining
# the queue to the last (most recent/descriptive) error.

my $rsa = Crypt::OpenSSL::RSA->generate_key(2048);

# Trigger a decrypt failure inside eval
eval { $rsa->decrypt("not valid ciphertext that is too short") };
my $first_error = $@;
ok($first_error, "decrypt failure with short input caught in eval");

# Trigger a different decrypt failure
eval { $rsa->decrypt("x" x 256) };
my $second_error = $@;
ok($second_error, "decrypt failure with full-length garbage caught in eval");

# The second error should be a real decryption error, not stale from the first
like($second_error, qr/OpenSSL error: \S/, "second error has a meaningful OpenSSL message");

# Trigger yet another failure after two eval-caught ones — error queue should be clean
eval { $rsa->encrypt("A" x 500) };
my $third_error = $@;
like($third_error, qr/too large|data greater|asym cipher failure/i,
"third error reports actual problem (data too large), not stale from earlier failures");
Loading