Skip to content
Merged
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
99 changes: 98 additions & 1 deletion t/key_lifecycle.t
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ Crypt::OpenSSL::RSA->import_random_seed();

my $HAS_BIGNUM = $INC{'Crypt/OpenSSL/Bignum.pm'} ? 1 : 0;

plan tests => 9 + ($HAS_BIGNUM ? 14 : 0);
# skip() reports skipped tests which count toward total, so plan must
# always include them regardless of whether Bignum is available.
plan tests => 9 + 14 + 20 + 2;

# --- Cross-key operations ---
# Sign with key1, verify with key2 — should return false, not croak.
Expand Down Expand Up @@ -109,3 +111,98 @@ SKIP: {
ok( $rsa_pub_params->verify($plaintext, $sig1),
"public-only key from params verifies original signature" );
}

# --- Parameter derivation paths ---
# Tests for deriving missing p or q from n, and constructing keys
# from n/e/d without CRT params.

SKIP: {
skip "Crypt::OpenSSL::Bignum required for derivation tests", 20
unless $HAS_BIGNUM;

my ($n, $e, $d, $p, $q) = $rsa1->get_key_parameters();

# --- Derive q from n and p (pass p, omit q) ---
my $rsa_derive_q = eval {
Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, $d, $p);
};
ok( !$@, "new_key_from_parameters(n,e,d,p) does not croak" )
or diag "Error: $@";
ok( $rsa_derive_q, "derive-q key constructed" );
ok( $rsa_derive_q->is_private(), "derive-q key is private" );
ok( $rsa_derive_q->check_key(), "derive-q key passes check_key()" );

# Verify the derived key can sign and the original can verify
$rsa_derive_q->use_pkcs1_pss_padding();
my $sig_dq = $rsa_derive_q->sign($plaintext);
ok( $rsa1->verify($plaintext, $sig_dq),
"original verifies signature from derive-q key" );

# --- Derive p from n and q (pass q as 5th arg, omit p) ---
my $rsa_derive_p = eval {
Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, $d, undef, $q);
};
ok( !$@, "new_key_from_parameters(n,e,d,undef,q) does not croak" )
or diag "Error: $@";
ok( $rsa_derive_p, "derive-p key constructed" );
ok( $rsa_derive_p->is_private(), "derive-p key is private" );
ok( $rsa_derive_p->check_key(), "derive-p key passes check_key()" );

# Verify the derived key can sign and the original can verify
$rsa_derive_p->use_pkcs1_pss_padding();
my $sig_dp = $rsa_derive_p->sign($plaintext);
ok( $rsa1->verify($plaintext, $sig_dp),
"original verifies signature from derive-p key" );

# --- Private key from n, e, d only (no p, q — the "else" branch) ---
my $rsa_ned = eval {
Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, $d);
};
ok( !$@, "new_key_from_parameters(n,e,d) does not croak" )
or diag "Error: $@";
ok( $rsa_ned, "n/e/d-only key constructed" );
ok( $rsa_ned->is_private(), "n/e/d-only key is private" );
is( $rsa_ned->size(), $rsa1->size(), "n/e/d-only key has correct size" );

# n/e/d key can encrypt/decrypt
$rsa_ned->use_pkcs1_oaep_padding();
$rsa1->use_pkcs1_oaep_padding();
my $ct = $rsa_ned->encrypt("round-trip test");
my $pt = $rsa1->decrypt($ct);
is( $pt, "round-trip test",
"original decrypts ciphertext from n/e/d-only key" );

# Cross-derived key interop: derive-q encrypts, derive-p decrypts
$rsa_derive_q->use_pkcs1_oaep_padding();
$rsa_derive_p->use_pkcs1_oaep_padding();
$ct = $rsa_derive_q->encrypt("cross-derive test");
$pt = $rsa_derive_p->decrypt($ct);
is( $pt, "cross-derive test",
"derive-p decrypts ciphertext from derive-q key" );

# Derive-p signs, derive-q verifies
$rsa_derive_p->use_pkcs1_pss_padding();
$rsa_derive_q->use_pkcs1_pss_padding();
my $sig_cross = $rsa_derive_p->sign("interop");
ok( $rsa_derive_q->verify("interop", $sig_cross),
"derive-q verifies signature from derive-p key" );

# Derive d from p and q (pass p, q but omit d)
my $rsa_derive_d = eval {
Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, undef, $p, $q);
};
ok( !$@, "new_key_from_parameters(n,e,undef,p,q) does not croak" )
or diag "Error: $@";
ok( $rsa_derive_d, "derive-d key constructed" );
ok( $rsa_derive_d->check_key(), "derive-d key passes check_key()" );
}

# --- Error cases (no Bignum needed) ---

eval { Crypt::OpenSSL::RSA->_new_key_from_parameters(0, 0, 0, 0, 0) };
like( $@, qr/modulus and public key must be provided/,
"croak when both n and e are NULL" );

eval { Crypt::OpenSSL::RSA->_new_key_from_parameters(0, 0, 0, 0, 0) };
like( $@, qr/modulus and public key must be provided/,
"croak when n=0 and e=0 (missing required params)" );
Loading