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
15 changes: 13 additions & 2 deletions RSA.xs
Original file line number Diff line number Diff line change
Expand Up @@ -908,14 +908,25 @@ PPCODE:
iqmp = rsa->iqmp;
#else
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e);
/* n and e are mandatory for every RSA key — croak on failure. */
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n))
croakSsl(__FILE__, __LINE__);
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e)) {
BN_free(n);
croakSsl(__FILE__, __LINE__);
}
/* Private components are absent for public keys — EVP_PKEY_get_bn_param()
returns 0 and may push errors onto the queue, but the pointer stays NULL
so cor_bn2sv() will return undef. This matches the pre-3.x behaviour
where RSA_get0_key/factors/crt_params simply set NULL for missing fields. */
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_D, &d);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR1, &p);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR2, &q);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1);
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp);
/* Drain any errors pushed by expected failures on public keys. */
ERR_clear_error();
#else
RSA_get0_key(rsa, &n, &e, &d);
RSA_get0_factors(rsa, &p, &q);
Expand Down
46 changes: 46 additions & 0 deletions t/get_key_parameters.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use strict;
use warnings;
use Test::More;

use Crypt::OpenSSL::Random;
use Crypt::OpenSSL::RSA;

Crypt::OpenSSL::Random::random_seed("OpenSSL needs at least 32 bytes.");
Crypt::OpenSSL::RSA->import_random_seed();

plan tests => 10;

my $rsa_priv = Crypt::OpenSSL::RSA->generate_key(2048);
my $pub_pem = $rsa_priv->get_public_key_string();
my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($pub_pem);

# --- Private key: all 8 parameters must be defined ---

my @priv_params = eval { $rsa_priv->get_key_parameters() };
ok( !$@, "get_key_parameters on private key does not croak" )
or diag "Error: $@";
is( scalar @priv_params, 8, "get_key_parameters returns 8 values" );

my ($n, $e, $d, $p, $q, $dmp1, $dmq1, $iqmp) = @priv_params;
ok( defined $n && defined $e,
"private key: n and e are defined (mandatory public components)" );
ok( defined $d,
"private key: d is defined (private exponent)" );
ok( defined $p && defined $q,
"private key: p and q are defined (prime factors)" );
ok( defined $dmp1 && defined $dmq1 && defined $iqmp,
"private key: CRT parameters are defined" );

# --- Public key: n and e defined, private components are undef ---

my @pub_params = eval { $rsa_pub->get_key_parameters() };
ok( !$@, "get_key_parameters on public key does not croak" )
or diag "Error: $@";
is( scalar @pub_params, 8, "get_key_parameters returns 8 values for public key" );

my ($pn, $pe, $pd, $pp, $pq, $pdmp1, $pdmq1, $piqmp) = @pub_params;
ok( defined $pn && defined $pe,
"public key: n and e are defined" );
ok( !defined $pd && !defined $pp && !defined $pq
&& !defined $pdmp1 && !defined $pdmq1 && !defined $piqmp,
"public key: private components (d, p, q, CRT) are undef" );
Loading