diff --git a/RSA.pm b/RSA.pm index 1390852..22ddc09 100644 --- a/RSA.pm +++ b/RSA.pm @@ -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 @@ -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. +=item use_pkcs1_pss_padding + +Use C 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: RSA-PSS cannot be used for encryption/decryption and results in a +fatal error. Call C for encryption operations. + =item use_sslv23_padding Use C padding with an SSL-specific modification that diff --git a/RSA.xs b/RSA.xs index aa8094c..d42c812 100644 --- a/RSA.xs +++ b/RSA.xs @@ -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(); @@ -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 @@ -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); @@ -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 diff --git a/t/rsa.t b/t/rsa.t index 05b2550..2448825 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -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 { @@ -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"); } } @@ -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(); @@ -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();