Skip to content

Commit 1789207

Browse files
authored
Merge pull request #63 from timlegge/pss_padding
Pss padding
2 parents dbf24f4 + cb6435e commit 1789207

File tree

3 files changed

+57
-22
lines changed

3 files changed

+57
-22
lines changed

RSA.pm

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Encrypting user data directly with RSA is insecure.
245245
246246
PKCS #1 v1.5 padding has been disabled as it is nearly impossible to use this
247247
padding method in a secure manner. It is known to be vulnerable to timing
248-
based side channel attacks. use_pkcs1_padding() results in a fatal error.
248+
based side channel attacks. use_pkcs1_padding() results in a fatal error.
249249
250250
L<Marvin Attack|https://github.com/tomato42/marvin-toolkit/blob/master/README.md>
251251
@@ -256,6 +256,16 @@ an empty encoding parameter. This mode of padding is recommended for
256256
all new applications. It is the default mode used by
257257
C<Crypt::OpenSSL::RSA>.
258258
259+
=item use_pkcs1_pss_padding
260+
261+
Use C<RSA-PSS> padding as defined in PKCS#1 v2.1. In general, RSA-PSS
262+
should be used as a replacement for RSA-PKCS#1 v1.5. The module specifies
263+
the message digest being requested and the appropriate mgf1 setting and
264+
salt length for the digest.
265+
266+
B<Note>: RSA-PSS cannot be used for encryption/decryption and results in a
267+
fatal error. Call C<use_pkcs1_oaep_padding> for encryption operations.
268+
259269
=item use_sslv23_padding
260270
261271
Use C<PKCS #1 v1.5> padding with an SSL-specific modification that

RSA.xs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ SV* rsa_crypt(rsaData* p_rsa, SV* p_from,
323323
size = EVP_PKEY_get_size(p_rsa->rsa);
324324
CHECK_NEW(to, size, UNSIGNED_CHAR);
325325
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
326+
327+
if(p_rsa->padding == RSA_PKCS1_PSS_PADDING)
328+
croak("PKCS#1 v2.1 RSA-PSS cannot be used for encryption operations call \"use_pkcs1_oaep_padding\" instead.");
329+
326330
EVP_PKEY_CTX *ctx;
327331

328332
OSSL_LIB_CTX *ossllibctx = OSSL_LIB_CTX_new();
@@ -935,6 +939,12 @@ use_pkcs1_oaep_padding(p_rsa)
935939
CODE:
936940
p_rsa->padding = RSA_PKCS1_OAEP_PADDING;
937941

942+
void
943+
use_pkcs1_pss_padding(p_rsa)
944+
rsaData* p_rsa;
945+
CODE:
946+
p_rsa->padding = RSA_PKCS1_PSS_PADDING;
947+
938948
#if OPENSSL_VERSION_NUMBER < 0x30000000L
939949

940950
void
@@ -977,7 +987,10 @@ sign(p_rsa, text_SV)
977987

978988
int md_status;
979989
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0);
980-
990+
if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) {
991+
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md)) > 0);
992+
CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) > 0);
993+
}
981994
CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, NULL, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1);
982995

983996
//signature = OPENSSL_malloc(signature_length);
@@ -1034,6 +1047,10 @@ PPCODE:
10341047

10351048
int md_status;
10361049
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0);
1050+
if (p_rsa->padding == RSA_PKCS1_PSS_PADDING) {
1051+
CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md)) > 0);
1052+
CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) > 0);
1053+
}
10371054

10381055
switch (EVP_PKEY_verify(ctx, sig, sig_length, digest, get_digest_length(p_rsa->hashMode)))
10391056
#else

t/rsa.t

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use Crypt::OpenSSL::RSA;
66
use Crypt::OpenSSL::Guess qw(openssl_version);
77

88
BEGIN {
9-
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 );
9+
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 );
1010
}
1111

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

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

4748
my $sig_of_other = $rsa->sign("different");
48-
ok( !$rsa_pub->verify( $plaintext, $sig_of_other ) );
49-
ok( !$rsa->verify( $plaintext, $sig_of_other ) );
49+
ok( !$rsa_pub->verify( $plaintext, $sig_of_other ), "rsa_pub do not verify unmatching message" );
50+
ok( !$rsa->verify( $plaintext, $sig_of_other ), "rsa do not verify unmatching message");
5051
}
5152
}
5253

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

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

72-
my $rsa = Crypt::OpenSSL::RSA->generate_key(1024);
73-
ok( $rsa->size() * 8 == 1024 );
73+
my $rsa = Crypt::OpenSSL::RSA->generate_key(2048);
74+
ok( $rsa->size() * 8 == 2048 );
7475
ok( $rsa->check_key() );
7576

7677
$rsa->use_no_padding();
@@ -121,31 +122,38 @@ _check_for_croak(
121122

122123
$plaintext .= $plaintext x 5;
123124

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

129-
$rsa->use_sha1_hash();
130-
$rsa_pub->use_sha1_hash();
131-
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha1" );
129+
$rsa->$p;
130+
$rsa_pub->$p;
131+
# check signature algorithms
132+
$rsa->use_md5_hash();
133+
$rsa_pub->use_md5_hash();
134+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "md5 with $padding padding" );
132135

133-
if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) {
136+
$rsa->use_sha1_hash();
137+
$rsa_pub->use_sha1_hash();
138+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha1 with $padding padding" );
139+
140+
if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) {
134141
$rsa->use_sha224_hash();
135142
$rsa_pub->use_sha224_hash();
136-
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha224" );
143+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha224 with $padding padding" );
137144

138145
$rsa->use_sha256_hash();
139146
$rsa_pub->use_sha256_hash();
140-
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha256" );
147+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha256 with $padding padding" );
141148

142149
$rsa->use_sha384_hash();
143150
$rsa_pub->use_sha384_hash();
144-
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha384" );
151+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha384 with $padding padding" );
145152

146153
$rsa->use_sha512_hash();
147154
$rsa_pub->use_sha512_hash();
148-
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512" );
155+
_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512 with $padding padding" );
156+
}
149157
}
150158

151159
my ( $major, $minor, $patch ) = openssl_version();

0 commit comments

Comments
 (0)