Skip to content

Commit f3b02be

Browse files
authored
Merge pull request #159 from atoomic/koan.atoomic/fix-issue-155
2 parents 1f32d81 + b4ec4ff commit f3b02be

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

RSA.xs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -908,14 +908,25 @@ PPCODE:
908908
iqmp = rsa->iqmp;
909909
#else
910910
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
911-
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n);
912-
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e);
911+
/* n and e are mandatory for every RSA key — croak on failure. */
912+
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n))
913+
croakSsl(__FILE__, __LINE__);
914+
if (!EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e)) {
915+
BN_free(n);
916+
croakSsl(__FILE__, __LINE__);
917+
}
918+
/* Private components are absent for public keys — EVP_PKEY_get_bn_param()
919+
returns 0 and may push errors onto the queue, but the pointer stays NULL
920+
so cor_bn2sv() will return undef. This matches the pre-3.x behaviour
921+
where RSA_get0_key/factors/crt_params simply set NULL for missing fields. */
913922
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_D, &d);
914923
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR1, &p);
915924
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR2, &q);
916925
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1);
917926
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1);
918927
EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp);
928+
/* Drain any errors pushed by expected failures on public keys. */
929+
ERR_clear_error();
919930
#else
920931
RSA_get0_key(rsa, &n, &e, &d);
921932
RSA_get0_factors(rsa, &p, &q);

t/get_key_parameters.t

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use strict;
2+
use warnings;
3+
use Test::More;
4+
5+
use Crypt::OpenSSL::Random;
6+
use Crypt::OpenSSL::RSA;
7+
8+
Crypt::OpenSSL::Random::random_seed("OpenSSL needs at least 32 bytes.");
9+
Crypt::OpenSSL::RSA->import_random_seed();
10+
11+
plan tests => 10;
12+
13+
my $rsa_priv = Crypt::OpenSSL::RSA->generate_key(2048);
14+
my $pub_pem = $rsa_priv->get_public_key_string();
15+
my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($pub_pem);
16+
17+
# --- Private key: all 8 parameters must be defined ---
18+
19+
my @priv_params = eval { $rsa_priv->get_key_parameters() };
20+
ok( !$@, "get_key_parameters on private key does not croak" )
21+
or diag "Error: $@";
22+
is( scalar @priv_params, 8, "get_key_parameters returns 8 values" );
23+
24+
my ($n, $e, $d, $p, $q, $dmp1, $dmq1, $iqmp) = @priv_params;
25+
ok( defined $n && defined $e,
26+
"private key: n and e are defined (mandatory public components)" );
27+
ok( defined $d,
28+
"private key: d is defined (private exponent)" );
29+
ok( defined $p && defined $q,
30+
"private key: p and q are defined (prime factors)" );
31+
ok( defined $dmp1 && defined $dmq1 && defined $iqmp,
32+
"private key: CRT parameters are defined" );
33+
34+
# --- Public key: n and e defined, private components are undef ---
35+
36+
my @pub_params = eval { $rsa_pub->get_key_parameters() };
37+
ok( !$@, "get_key_parameters on public key does not croak" )
38+
or diag "Error: $@";
39+
is( scalar @pub_params, 8, "get_key_parameters returns 8 values for public key" );
40+
41+
my ($pn, $pe, $pd, $pp, $pq, $pdmp1, $pdmq1, $piqmp) = @pub_params;
42+
ok( defined $pn && defined $pe,
43+
"public key: n and e are defined" );
44+
ok( !defined $pd && !defined $pp && !defined $pq
45+
&& !defined $pdmp1 && !defined $pdmq1 && !defined $piqmp,
46+
"public key: private components (d, p, q, CRT) are undef" );

0 commit comments

Comments
 (0)