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
12 changes: 11 additions & 1 deletion RSA.pm
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Encrypting user data directly with RSA is insecure.

PKCS #1 v1.5 padding has been disabled as it is nearly impossible to use this
padding method in a secure manner. It is known to be vulnerable to timing
based side channel attacks. use_pkcs1_padding() results in a fatal error.
based side channel attacks. use_pkcs1_padding() results in a fatal error.

L<Marvin Attack|https://github.com/tomato42/marvin-toolkit/blob/master/README.md>

Expand All @@ -256,6 +256,16 @@ an empty encoding parameter. This mode of padding is recommended for
all new applications. It is the default mode used by
C<Crypt::OpenSSL::RSA>.

=item use_pkcs1_pss_padding

Use C<RSA-PSS> padding as defined in PKCS#1 v2.1. In general, RSA-PSS
should be used as a replacement for RSA-PKCS#1 v1.5. The module specifies
the message digest being requested and the appropriate mgf1 setting and
salt length for the digest.

B<Note>: RSA-PSS cannot be used for encryption/decryption and results in a
fatal error. Call C<use_pkcs1_oaep_padding> for encryption operations.

=item use_sslv23_padding

Use C<PKCS #1 v1.5> padding with an SSL-specific modification that
Expand Down
19 changes: 18 additions & 1 deletion RSA.xs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ SV* rsa_crypt(rsaData* p_rsa, SV* p_from,
size = EVP_PKEY_get_size(p_rsa->rsa);
CHECK_NEW(to, size, UNSIGNED_CHAR);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L

if(p_rsa->padding == RSA_PKCS1_PSS_PADDING)
croak("PKCS#1 v2.1 RSA-PSS cannot be used for encryption operations call \"use_pkcs1_oaep_padding\" instead.");

EVP_PKEY_CTX *ctx;

OSSL_LIB_CTX *ossllibctx = OSSL_LIB_CTX_new();
Expand Down Expand Up @@ -935,6 +939,12 @@ use_pkcs1_oaep_padding(p_rsa)
CODE:
p_rsa->padding = RSA_PKCS1_OAEP_PADDING;

void
use_pkcs1_pss_padding(p_rsa)
rsaData* p_rsa;
CODE:
p_rsa->padding = RSA_PKCS1_PSS_PADDING;

#if OPENSSL_VERSION_NUMBER < 0x30000000L

void
Expand Down Expand Up @@ -977,7 +987,10 @@ sign(p_rsa, text_SV)

int md_status;
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0);

if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) {
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md)) > 0);
CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) > 0);
}
CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, NULL, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1);

//signature = OPENSSL_malloc(signature_length);
Expand Down Expand Up @@ -1034,6 +1047,10 @@ PPCODE:

int md_status;
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0);
if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) {
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md)) > 0);
CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) > 0);
}

switch (EVP_PKEY_verify(ctx, sig, sig_length, digest, get_digest_length(p_rsa->hashMode)))
#else
Expand Down
48 changes: 28 additions & 20 deletions t/rsa.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use Crypt::OpenSSL::RSA;
use Crypt::OpenSSL::Guess qw(openssl_version);

BEGIN {
plan tests => 37 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ? 1 * 5 : 0 );
plan tests => 67 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ? 1 * 5 : 0 );
}

sub _Test_Encrypt_And_Decrypt {
Expand Down Expand Up @@ -37,16 +37,17 @@ sub _Test_Sign_And_Verify {
my $sig = eval { $rsa->sign($plaintext) };
SKIP: {
skip "OpenSSL error: illegal or unsupported padding mode - $hash", 5 if $@ =~ /illegal or unsupported padding mode/i;
ok( $rsa_pub->verify( $plaintext, $sig ) );
skip "OpenSSL error: invalid digest - $hash", 5 if $@ =~ /invalid digest/i;
ok( $rsa_pub->verify( $plaintext, $sig ), "rsa_pub verify $hash");

my $false_sig = unpack "H*", $sig;
$false_sig =~ tr/[a-f]/[0a-d]/;
ok( !$rsa_pub->verify( $plaintext, pack( "H*", $false_sig ) ) );
ok( !$rsa->verify( $plaintext, pack( "H*", $false_sig ) ) );
ok( !$rsa_pub->verify( $plaintext, pack( "H*", $false_sig ) ), "rsa_pub do not verify invalid $hash" );
ok( !$rsa->verify( $plaintext, pack( "H*", $false_sig ) ), "rsa do not verify invalid $hash" );

my $sig_of_other = $rsa->sign("different");
ok( !$rsa_pub->verify( $plaintext, $sig_of_other ) );
ok( !$rsa->verify( $plaintext, $sig_of_other ) );
ok( !$rsa_pub->verify( $plaintext, $sig_of_other ), "rsa_pub do not verify unmatching message" );
ok( !$rsa->verify( $plaintext, $sig_of_other ), "rsa do not verify unmatching message");
}
}

Expand All @@ -69,8 +70,8 @@ Crypt::OpenSSL::RSA->import_random_seed();

ok( Crypt::OpenSSL::RSA->generate_key(512)->size() * 8 == 512 );

my $rsa = Crypt::OpenSSL::RSA->generate_key(1024);
ok( $rsa->size() * 8 == 1024 );
my $rsa = Crypt::OpenSSL::RSA->generate_key(2048);
ok( $rsa->size() * 8 == 2048 );
ok( $rsa->check_key() );

$rsa->use_no_padding();
Expand Down Expand Up @@ -121,31 +122,38 @@ _check_for_croak(

$plaintext .= $plaintext x 5;

# check signature algorithms
$rsa->use_md5_hash();
$rsa_pub->use_md5_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "md5" );
my @paddings = qw/pkcs1_oaep pkcs1_pss/;
foreach my $padding (@paddings) {
my $p = "use_$padding\_padding";

$rsa->use_sha1_hash();
$rsa_pub->use_sha1_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha1" );
$rsa->$p;
$rsa_pub->$p;
# check signature algorithms
$rsa->use_md5_hash();
$rsa_pub->use_md5_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "md5 with $padding padding" );

if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) {
$rsa->use_sha1_hash();
$rsa_pub->use_sha1_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha1 with $padding padding" );

if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) {
$rsa->use_sha224_hash();
$rsa_pub->use_sha224_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha224" );
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha224 with $padding padding" );

$rsa->use_sha256_hash();
$rsa_pub->use_sha256_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha256" );
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha256 with $padding padding" );

$rsa->use_sha384_hash();
$rsa_pub->use_sha384_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha384" );
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha384 with $padding padding" );

$rsa->use_sha512_hash();
$rsa_pub->use_sha512_hash();
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512" );
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512 with $padding padding" );
}
}

my ( $major, $minor, $patch ) = openssl_version();
Expand Down
Loading