From 6f44e1ed4ada2db094ed0fc46206a8b5bf610e77 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Wed, 12 Jun 2024 21:38:53 -0600 Subject: [PATCH 01/49] Modernize CI pipeline --- .github/workflows/linux.yml | 63 ---------------- .github/workflows/macos.yml | 35 --------- .github/workflows/testsuite.yml | 124 ++++++++++++++++++++++++++++++++ .github/workflows/windows.yml | 47 ------------ 4 files changed, 124 insertions(+), 145 deletions(-) delete mode 100644 .github/workflows/linux.yml delete mode 100644 .github/workflows/macos.yml create mode 100644 .github/workflows/testsuite.yml delete mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index 9e990bd..0000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: linux - -on: - push: - branches: - - '*' - tags-ignore: - - '*' - pull_request: - -jobs: - - ubuntu: - env: - PERL_USE_UNSAFE_INC: 0 - AUTHOR_TESTING: 1 - AUTOMATED_TESTING: 1 - RELEASE_TESTING: 1 - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: perl -V - run: perl -V - - name: uses install-with-cpm - uses: perl-actions/install-with-cpm@stable - with: - cpanfile: "cpanfile" - - name: Makefile.PL - run: perl -I$(pwd) Makefile.PL - - name: make test - run: make test - - perl: - env: - PERL_USE_UNSAFE_INC: 0 - AUTHOR_TESTING: 1 - AUTOMATED_TESTING: 1 - RELEASE_TESTING: 1 - - runs-on: ubuntu-latest - needs: [ubuntu] - - strategy: - fail-fast: false - matrix: - perl-version: [latest, 5.34, 5.32, "5.30", 5.28, 5.26, 5.24, 5.22, "5.20", 5.18, 5.16, 5.14, 5.12, "5.10", 5.8 ] - - container: - image: perl:${{ matrix.perl-version }} - - steps: - - uses: actions/checkout@v2 - - run: perl -V - - name: Deps for testing - run: | - cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess Test::CPAN::Meta Perl::MinimumVersion Test::Pod::Coverage Test::Pod Test::MinimumVersion Crypt::OpenSSL::Bignum || /bin/true - cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess Test::CPAN::Meta Perl::MinimumVersion Test::Pod::Coverage Test::Pod Test::MinimumVersion Crypt::OpenSSL::Bignum - # not available < 5.12 - cpanm --notest Test::Kwalitee ||: - - run: perl Makefile.PL - - run: make test diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml deleted file mode 100644 index 061a12d..0000000 --- a/.github/workflows/macos.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: macos - -on: - push: - branches: - - '*' - tags-ignore: - - '*' - pull_request: - -jobs: - perl: - env: - PERL_USE_UNSAFE_INC: 0 - AUTHOR_TESTING: 1 - AUTOMATED_TESTING: 1 - RELEASE_TESTING: 1 - - runs-on: macOS-latest - - strategy: - fail-fast: false - matrix: - perl-version: [latest] - - steps: - - uses: actions/checkout@v1 - - name: perl -V - run: perl -V - - name: Deps for testing - run: cpan -T Crypt::OpenSSL::Random Crypt::OpenSSL::Guess - - name: Makefile.PL - run: perl Makefile.PL - - name: make test - run: make test diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml new file mode 100644 index 0000000..f9fb3dc --- /dev/null +++ b/.github/workflows/testsuite.yml @@ -0,0 +1,124 @@ +name: linux + +on: + push: + branches: + - '*' + tags-ignore: + - '*' + pull_request: + +jobs: + +# +# A quick and cheap test first before running other jobs +# + + ubuntu: + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 1 + AUTOMATED_TESTING: 1 + RELEASE_TESTING: 1 + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - run: perl -V + - name: uses install-with-cpm + uses: perl-actions/install-with-cpm@v1 + with: + cpanfile: "cpanfile" + - name: Makefile.PL + run: perl -I$(pwd) Makefile.PL + - run: make test + +# +# List of Perl Versions available +# + + perl-versions: + runs-on: ubuntu-latest + name: List Perl versions + outputs: + perl-versions: ${{ steps.action.outputs.perl-versions }} + steps: + - id: action + uses: perl-actions/perl-versions@v1 + with: + since-perl: v5.10 + with-devel: true + +# +# The Perl matrix on linux +# + + perl: + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 1 + AUTOMATED_TESTING: 1 + RELEASE_TESTING: 1 + + runs-on: ubuntu-latest + needs: [ubuntu,perl-versions] + name: "Perl ${{ matrix.perl-version }}" + + strategy: + fail-fast: false + matrix: + perl-version: ${{ fromJson (needs.perl-versions.outputs.perl-versions) }} + + container: perldocker/perl-tester:${{ matrix.perl-version }} + + steps: + - uses: actions/checkout@v4 + - run: perl -V + - name: Deps for testing + run: | + cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess Test::CPAN::Meta Perl::MinimumVersion Test::Pod::Coverage Test::Pod Test::MinimumVersion Crypt::OpenSSL::Bignum ||: + cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess Test::CPAN::Meta Perl::MinimumVersion Test::Pod::Coverage Test::Pod Test::MinimumVersion Crypt::OpenSSL::Bignum + # not available < 5.12 + cpanm --notest Test::Kwalitee ||: + - run: perl Makefile.PL + - run: make test + +# +# Windows +# + + windows: + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 0 + AUTOMATED_TESTING: 1 + RELEASE_TESTING: 0 + + needs: [ubuntu] + runs-on: windows-latest + + strategy: + fail-fast: false + matrix: + perl-version: [latest] + + steps: + - uses: actions/checkout@v4 + - name: Set up Perl + run: | + # skip installing perl if it is already installed. + if (!(Test-Path "C:\strawberry\perl\bin")) { + choco install strawberryperl + } + echo @" + C:\strawberry\c\bin + C:\strawberry\perl\site\bin + C:\strawberry\perl\bin + "@ | + Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - run: perl -V + - name: Deps for testing + run: cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess + - run: perl Makefile.PL + - run: make test diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index a0eb14a..0000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: windows - -on: - push: - branches: - - '*' - tags-ignore: - - '*' - pull_request: - -jobs: - perl: - env: - PERL_USE_UNSAFE_INC: 0 - AUTHOR_TESTING: 0 - AUTOMATED_TESTING: 1 - RELEASE_TESTING: 0 - - runs-on: windows-latest - - strategy: - fail-fast: false - matrix: - perl-version: [latest] - - steps: - - uses: actions/checkout@v2 - - name: Set up Perl - run: | - # skip installing perl if it is already installed. - if (!(Test-Path "C:\strawberry\perl\bin")) { - choco install strawberryperl - } - echo @" - C:\strawberry\c\bin - C:\strawberry\perl\site\bin - C:\strawberry\perl\bin - "@ | - Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: perl -V - run: perl -V - - name: Deps for testing - run: cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess - - name: Makefile.PL - run: perl Makefile.PL - - name: make test - run: make test From 3d75b7d56921bf21e1ea238cac0a8e145962fbc5 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Wed, 12 Jun 2024 21:58:05 -0600 Subject: [PATCH 02/49] Rerun CI on edit and co - opened: pull request is created - synchronize: commit(s) pushed to the pull request - reopened: closed pull request is reopened - edited: title, body, or the base branch of the PR is modified - ready_for_review: pull request is taken out from draft mode --- .github/workflows/testsuite.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index f9fb3dc..666a0e7 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -7,6 +7,7 @@ on: tags-ignore: - '*' pull_request: + types: [ opened, synchronize, reopened, edited, ready_for_review ] jobs: From 3dc930147d92a10b6df013906011ca0a3b608cea Mon Sep 17 00:00:00 2001 From: Tim Legge Date: Thu, 13 Jun 2024 04:52:29 +0200 Subject: [PATCH 03/49] Fix issue when libz is not linked on AIX --- Makefile.PL | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.PL b/Makefile.PL index 3b72fdd..c9399e5 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,5 +1,6 @@ use strict; use warnings; +use Config; use 5.006; use ExtUtils::MakeMaker 6.48; @@ -8,6 +9,11 @@ use Crypt::OpenSSL::Guess qw(openssl_inc_paths openssl_lib_paths); # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. +my $libs = ' -lssl -lcrypto'; +if ( $Config{osname} eq 'aix' ) { + $libs = $libs . ' -lz'; +} + WriteMakefile( 'NAME' => 'Crypt::OpenSSL::RSA', 'AUTHOR' => 'Ian Robertson ', @@ -22,7 +28,7 @@ WriteMakefile( 'Test::More' => 0, }, 'OBJECT' => 'RSA.o', - 'LIBS' => [openssl_lib_paths() . ' -lssl -lcrypto'], + 'LIBS' => [openssl_lib_paths() . $libs], 'DEFINE' => '-DPERL5 -DOPENSSL_NO_KRB5', # perl-5.8/gcc-3.2 needs -DPERL5, and redhat9 likes -DOPENSSL_NO_KRB5 From 8b719c4bd71e7a912320cda1074cf3e650216d24 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Wed, 3 Jul 2024 19:51:41 -0300 Subject: [PATCH 04/49] Fixes #50 - Correct openssl version may not be found --- Makefile.PL | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.PL b/Makefile.PL index 3b72fdd..485cb7d 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,5 +1,6 @@ use strict; use warnings; +use Config; use 5.006; use ExtUtils::MakeMaker 6.48; @@ -23,6 +24,7 @@ WriteMakefile( }, 'OBJECT' => 'RSA.o', 'LIBS' => [openssl_lib_paths() . ' -lssl -lcrypto'], + 'LDDLFLAGS' => openssl_lib_paths() . ' ' . $Config{lddlflags}, 'DEFINE' => '-DPERL5 -DOPENSSL_NO_KRB5', # perl-5.8/gcc-3.2 needs -DPERL5, and redhat9 likes -DOPENSSL_NO_KRB5 From 2d041e9935c81694ab87ad4ce2c2ccfd2d72977c Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Thu, 4 Jul 2024 17:47:52 -0300 Subject: [PATCH 05/49] Fixes #52 - Out of memory on openssl 1.1.1w hpux --- RSA.xs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/RSA.xs b/RSA.xs index 5f5cfae..b6c0509 100644 --- a/RSA.xs +++ b/RSA.xs @@ -165,11 +165,13 @@ SV* cor_bn2sv(const BIGNUM* p_bn) SV* extractBioString(BIO* p_stringBio) { SV* sv; - BUF_MEM* bptr; + char *datap; + long datasize = 0; CHECK_OPEN_SSL(BIO_flush(p_stringBio) == 1); - BIO_get_mem_ptr(p_stringBio, &bptr); - sv = newSVpv(bptr->data, bptr->length); + + datasize = BIO_get_mem_data(p_stringBio, &datap); + sv = newSVpv(datap, datasize); CHECK_OPEN_SSL(BIO_set_close(p_stringBio, BIO_CLOSE) == 1); BIO_free(p_stringBio); From 62356b9186ee35a4114104de4698168f6d8d2108 Mon Sep 17 00:00:00 2001 From: Marcel Telka Date: Fri, 21 Jun 2024 08:01:49 +0200 Subject: [PATCH 06/49] Update FSF address and LGPL name in LICENSE --- LICENSE | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index d4b3b03..af0d572 100644 --- a/LICENSE +++ b/LICENSE @@ -11,9 +11,10 @@ b) the "Artistic License" The General Public License (GPL) Version 2, June 1991 -Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, -Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute -verbatim copies of this license document, but changing it is not allowed. +Copyright (C) 1989, 1991 Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. Preamble @@ -23,7 +24,7 @@ guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is -covered by the GNU Library General Public License instead.) You can apply it to +covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our From 832a73f6df38c18134089c2d92fb44a0f34579bb Mon Sep 17 00:00:00 2001 From: Graham Knop Date: Sat, 12 Oct 2024 10:10:28 +0200 Subject: [PATCH 07/49] stop using AutoLoader AutoLoader serves no purpose for this module and adds complexity. --- RSA.pm | 63 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/RSA.pm b/RSA.pm index 1fefbdf..93506ee 100644 --- a/RSA.pm +++ b/RSA.pm @@ -7,9 +7,6 @@ use Carp; # Removing carp will break the XS code. our $VERSION = '0.33'; -our $AUTOLOAD; -use AutoLoader 'AUTOLOAD'; - use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; @@ -20,6 +17,34 @@ BEGIN { }; } ## no critic qw(RequireCheckingReturnValueOfEval); +sub new_public_key { + my ( $proto, $p_key_string ) = @_; + if ( $p_key_string =~ /^-----BEGIN RSA PUBLIC KEY-----/ ) { + return $proto->_new_public_key_pkcs1($p_key_string); + } + elsif ( $p_key_string =~ /^-----BEGIN PUBLIC KEY-----/ ) { + return $proto->_new_public_key_x509($p_key_string); + } + else { + croak "unrecognized key format"; + } +} + +sub new_key_from_parameters { + my ( $proto, $n, $e, $d, $p, $q ) = @_; + return $proto->_new_key_from_parameters( map { $_ ? $_->pointer_copy() : 0 } $n, $e, $d, $p, $q ); +} + +sub import_random_seed { + until ( _random_status() ) { + _random_seed( Crypt::OpenSSL::Random::random_bytes(20) ); + } +} + +sub get_key_parameters { + return map { $_ ? Crypt::OpenSSL::Bignum->bless_pointer($_) : undef } shift->_get_key_parameters(); +} + 1; __END__ @@ -80,20 +105,6 @@ C<-----BEGIN...-----> and C<-----END...-----> lines. The padding is set to PKCS1_OAEP, but can be changed with the C methods. -=cut -sub new_public_key { - my ( $proto, $p_key_string ) = @_; - if ( $p_key_string =~ /^-----BEGIN RSA PUBLIC KEY-----/ ) { - return $proto->_new_public_key_pkcs1($p_key_string); - } - elsif ( $p_key_string =~ /^-----BEGIN PUBLIC KEY-----/ ) { - return $proto->_new_public_key_x509($p_key_string); - } - else { - croak "unrecognized key format"; - } -} - =item new_private_key Create a new C object by loading a private key in @@ -130,25 +141,12 @@ provided and d is undef, d is computed. Note that while p and q are not necessary for a private key, their presence will speed up computation. -=cut -sub new_key_from_parameters { - my ( $proto, $n, $e, $d, $p, $q ) = @_; - return $proto->_new_key_from_parameters( map { $_ ? $_->pointer_copy() : 0 } $n, $e, $d, $p, $q ); -} - =item import_random_seed Import a random seed from L, since the OpenSSL libraries won't allow sharing of random structures across perl XS modules. -=cut -sub import_random_seed { - until ( _random_status() ) { - _random_seed( Crypt::OpenSSL::Random::random_bytes(20) ); - } -} - =back =head1 Instance Methods @@ -325,11 +323,6 @@ C module must be installed for this to work. Return true if this is a private key, and false if it is private only. -=cut -sub get_key_parameters { - return map { $_ ? Crypt::OpenSSL::Bignum->bless_pointer($_) : undef } shift->_get_key_parameters(); -} - =back =head1 BUGS From ca913387cdf33482eec4b7acf2905ca33296d244 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Mon, 1 Jul 2024 23:15:19 -0300 Subject: [PATCH 08/49] Fixes #48 - Whirlpool is missing the header --- RSA.xs | 3 +++ t/rsa.t | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RSA.xs b/RSA.xs index 5f5cfae..2510bf3 100644 --- a/RSA.xs +++ b/RSA.xs @@ -10,6 +10,9 @@ #include #include #include +#if OPENSSL_VERSION_NUMBER < 0x30000000 +#include +#endif #include #include #include diff --git a/t/rsa.t b/t/rsa.t index d3e7f0b..e97c15d 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -4,7 +4,9 @@ use Test::More; use Crypt::OpenSSL::Random; use Crypt::OpenSSL::RSA; -BEGIN { plan tests => 43 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) } +BEGIN { plan tests => 43 + + ( 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 { my ( $p_plaintext_length, $p_rsa, $p_check_private_encrypt ) = @_; From e9238e6be111af3ea4c553b0201c80eda30becb9 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 11:21:44 +0000 Subject: [PATCH 09/49] Move off personal repo and onto cpan-authors repo --- Makefile.PL | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 5666e7b..76c9b76 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -49,9 +49,9 @@ WriteMakefile( }, resources => { 'license' => 'http://dev.perl.org/licenses/', - 'homepage' => 'http://github.com/toddr/Crypt-OpenSSL-RSA', - 'bugtracker' => 'https://github.com/toddr/Crypt-OpenSSL-RSA/issues', - 'repository' => 'http://github.com/toddr/Crypt-OpenSSL-RSA', + 'homepage' => 'http://github.com/cpan-authors/Crypt-OpenSSL-RSA', + 'bugtracker' => 'https://github.com/cpan-authors/Crypt-OpenSSL-RSA/issues', + 'repository' => 'http://github.com/cpan-authors/Crypt-OpenSSL-RSA', } } ); From 65d65affdccd50d4fe8cfdc022c2e1be2e73139f Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 11:41:41 +0000 Subject: [PATCH 10/49] Update changelog --- Changes | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Changes b/Changes index 25f4c31..ea09019 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,16 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. +0.34 TBD + - docs - plaintext = decrypt(cyphertext) + - #44 - Fix issue when libz is not linked on AIX + - #50 - Correct openssl version may not be found + - #52 - Out of memory on openssl 1.1.1w hpux + - Update FSF address and LGPL name in LICENSE + - stop using AutoLoader + - #48 - Whirlpool is missing the header + - Move github repo to cpan-authors + - Fully support openSSL 3.x API + 0.33 July 7 2022 - Update for windows github CI - Remove duplicit 'LICENSE' key From 69d05610bf02b7468a24141d3d1f7f9fb0eba79e Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 11:45:13 +0000 Subject: [PATCH 11/49] Update PR references in changelog --- Changes | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index ea09019..2154e5e 100644 --- a/Changes +++ b/Changes @@ -5,8 +5,8 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. - #44 - Fix issue when libz is not linked on AIX - #50 - Correct openssl version may not be found - #52 - Out of memory on openssl 1.1.1w hpux - - Update FSF address and LGPL name in LICENSE - - stop using AutoLoader + - #47 - Update FSF address and LGPL name in LICENSE + - #55 - stop using AutoLoader - #48 - Whirlpool is missing the header - Move github repo to cpan-authors - Fully support openSSL 3.x API From 37d569b56342226ea1f25551df5a3a10dd9e8376 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 13:16:41 +0000 Subject: [PATCH 12/49] Verbose failures --- .github/workflows/testsuite.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 666a0e7..4e0e9cc 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -33,7 +33,7 @@ jobs: cpanfile: "cpanfile" - name: Makefile.PL run: perl -I$(pwd) Makefile.PL - - run: make test + - run: make && ( make test || prove -wbvm t/*.t ) # # List of Perl Versions available @@ -83,7 +83,7 @@ jobs: # not available < 5.12 cpanm --notest Test::Kwalitee ||: - run: perl Makefile.PL - - run: make test + - run: make && ( make test || prove -wbvm t/*.t ) # # Windows @@ -122,4 +122,4 @@ jobs: - name: Deps for testing run: cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess - run: perl Makefile.PL - - run: make test + - run: make && ( make test || prove -wbvm t/*.t ) From 47239dc8617b08a4e06c75d5113343d10b45677b Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 13:33:25 +0000 Subject: [PATCH 13/49] Use ubuntu 24 for openssl testing --- .github/workflows/testsuite.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 4e0e9cc..71c00f3 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -22,10 +22,11 @@ jobs: AUTOMATED_TESTING: 1 RELEASE_TESTING: 1 - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - run: openssl version - run: perl -V - name: uses install-with-cpm uses: perl-actions/install-with-cpm@v1 From 2a5aa9d1493fee306e4bd0ace351df96ed428f5b Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 2 May 2025 08:22:28 -0300 Subject: [PATCH 14/49] Fully support openSSL 3.x API --- Makefile.PL | 4 +- RSA.xs | 392 +++++++++++++++++++++++++++++++++++++++++++++------- t/rsa.t | 14 +- 3 files changed, 355 insertions(+), 55 deletions(-) diff --git a/Makefile.PL b/Makefile.PL index 76c9b76..588bd5b 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -4,8 +4,10 @@ use Config; use 5.006; use ExtUtils::MakeMaker 6.48; -use Crypt::OpenSSL::Guess qw(openssl_inc_paths openssl_lib_paths); +use Crypt::OpenSSL::Guess qw(openssl_inc_paths openssl_lib_paths openssl_version); +my ($major, $minor, $patch) = openssl_version(); +print "OpenSSL version: $major.$minor $patch", "\n"; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. diff --git a/RSA.xs b/RSA.xs index 9554126..a3f2ea9 100644 --- a/RSA.xs +++ b/RSA.xs @@ -17,10 +17,41 @@ #include #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define UNSIGNED_CHAR unsigned char +#define SIZE_T_INT size_t +#define SIZE_T_UNSIGNED_INT size_t +#define EVP_PKEY EVP_PKEY +#define EVP_PKEY_free(p) EVP_PKEY_free(p) +#define EVP_PKEY_get_size(p) EVP_PKEY_get_size(p) +#define PEM_read_bio_PrivateKey PEM_read_bio_PrivateKey +#define PEM_read_bio_RSAPublicKey PEM_read_bio_PUBKEY +#define PEM_read_bio_RSA_PUBKEY PEM_read_bio_PUBKEY +#define PEM_write_bio_PUBKEY(o,p) PEM_write_bio_PUBKEY(o,p); +#define PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) +#else +#define UNSIGNED_CHAR char +#define SIZE_T_INT int +#define SIZE_T_UNSIGNED_INT unsigned int +#define EVP_PKEY RSA +#define EVP_PKEY_free(p) RSA_free(p) +#define EVP_PKEY_get_size(p) RSA_size(p) +#define PEM_read_bio_PrivateKey PEM_read_bio_RSAPrivateKey +#define PEM_read_bio_RSAPublicKey PEM_read_bio_RSAPublicKey +#define PEM_read_bio_RSA_PUBKEY PEM_read_bio_RSA_PUBKEY +#define PEM_write_bio_PUBKEY(o,p) PEM_write_bio_RSA_PUBKEY(o,p) +#define PEM_write_bio_PrivateKey_traditional(m, n, o, p, q, r, s) PEM_write_bio_RSAPrivateKey(m, n , o, p, q, r, s) +#endif typedef struct { - RSA* rsa; + EVP_PKEY* rsa; int padding; int hashMode; } rsaData; @@ -55,16 +86,27 @@ void croakSsl(char* p_file, int p_line) char _is_private(rsaData* p_rsa) { - const BIGNUM *d; + char ret = 0; #if OLD_CRUFTY_SSL_VERSION + const BIGNUM* d; d = p_rsa->rsa->d; + ret = (d != NULL); #else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM* d = NULL; + EVP_PKEY_get_bn_param(p_rsa->rsa, OSSL_PKEY_PARAM_RSA_D, &d); + ret = (d != NULL); + BN_clear_free(d); +#else + const BIGNUM* d = NULL; RSA_get0_key(p_rsa->rsa, NULL, NULL, &d); + ret = (d != NULL); +#endif #endif - return(d != NULL); + return ret; } -SV* make_rsa_obj(SV* p_proto, RSA* p_rsa) +SV* make_rsa_obj(SV* p_proto, EVP_PKEY* p_rsa) { rsaData* rsa; @@ -114,18 +156,63 @@ int get_digest_length(int hash_method) break; } } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +EVP_MD *get_md_bynid(int hash_method) +{ + switch(hash_method) + { + case NID_md5: + return EVP_MD_fetch(NULL, "md5", NULL); + break; + case NID_sha1: + return EVP_MD_fetch(NULL, "sha1", NULL); + break; +#ifdef SHA512_DIGEST_LENGTH + case NID_sha224: + return EVP_MD_fetch(NULL, "sha224", NULL); + break; + case NID_sha256: + return EVP_MD_fetch(NULL, "sha256", NULL); + break; + case NID_sha384: + return EVP_MD_fetch(NULL, "sha384", NULL); + break; + case NID_sha512: + return EVP_MD_fetch(NULL, "sha512", NULL); + break; +#endif + case NID_ripemd160: + return EVP_MD_fetch(NULL, "ripemd160", NULL); + break; +#ifdef WHIRLPOOL_DIGEST_LENGTH + case NID_whirlpool: + return EVP_MD_fetch(NULL, "whirlpool", NULL); + break; +#endif + default: + croak("Unknown digest hash mode %u", hash_method); + break; + } +} +#endif unsigned char* get_message_digest(SV* text_SV, int hash_method) { STRLEN text_length; unsigned char* text; - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + static unsigned char md[EVP_MAX_MD_SIZE]; +#endif text = (unsigned char*) SvPV(text_SV, text_length); switch(hash_method) { case NID_md5: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_Q_digest(NULL, "MD5", NULL, text, text_length, md, NULL) ? md : NULL; +#else return MD5(text, text_length, NULL); +#endif break; case NID_sha1: return SHA1(text, text_length, NULL); @@ -145,7 +232,11 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method) break; #endif case NID_ripemd160: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_Q_digest(NULL, "RIPEMD160", NULL, text, text_length, md, NULL) ? md : NULL; +#else return RIPEMD160(text, text_length, NULL); +#endif break; #ifdef WHIRLPOOL_DIGEST_LENGTH case NID_whirlpool: @@ -168,7 +259,7 @@ SV* cor_bn2sv(const BIGNUM* p_bn) SV* extractBioString(BIO* p_stringBio) { SV* sv; - char *datap; + char* datap; long datasize = 0; CHECK_OPEN_SSL(BIO_flush(p_stringBio) == 1); @@ -181,15 +272,15 @@ SV* extractBioString(BIO* p_stringBio) return sv; } -RSA* _load_rsa_key(SV* p_keyStringSv, - RSA*(*p_loader)(BIO*, RSA**, pem_password_cb*, void*), +EVP_PKEY* _load_rsa_key(SV* p_keyStringSv, + EVP_PKEY*(*p_loader)(BIO *, EVP_PKEY**, pem_password_cb*, void*), SV* p_passphaseSv) { STRLEN keyStringLength; char* keyString; - char* passphase = NULL; + UNSIGNED_CHAR *passphase = NULL; - RSA* rsa; + EVP_PKEY* rsa; BIO* stringBIO; keyString = SvPV(p_keyStringSv, keyStringLength); @@ -208,35 +299,60 @@ RSA* _load_rsa_key(SV* p_keyStringSv, CHECK_OPEN_SSL(rsa); return rsa; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +SV* rsa_crypt(rsaData* p_rsa, SV* p_from, + int (*p_crypt)(EVP_PKEY_CTX*, unsigned char*, size_t*, const unsigned char*, size_t), + int (*init_crypt)(EVP_PKEY_CTX*), int public) +#else SV* rsa_crypt(rsaData* p_rsa, SV* p_from, int (*p_crypt)(int, const unsigned char*, unsigned char*, RSA*, int)) +#endif { STRLEN from_length; - int to_length; + SIZE_T_INT to_length; int size; unsigned char* from; - char* to; + UNSIGNED_CHAR *to; SV* sv; from = (unsigned char*) SvPV(p_from, from_length); - size = RSA_size(p_rsa->rsa); - CHECK_NEW(to, size, char); + size = EVP_PKEY_get_size(p_rsa->rsa); + CHECK_NEW(to, size, UNSIGNED_CHAR); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + + OSSL_LIB_CTX *ossllibctx = OSSL_LIB_CTX_new(); + const char* propquery; + if (public) { + ctx = EVP_PKEY_CTX_new_from_pkey(ossllibctx, (EVP_PKEY* )p_rsa->rsa, propquery); + } else { + ctx = EVP_PKEY_CTX_new((EVP_PKEY* )p_rsa->rsa, NULL); + } + + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(init_crypt(ctx) == 1); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); + CHECK_OPEN_SSL(p_crypt(ctx, NULL, &to_length, from, from_length) == 1); + CHECK_OPEN_SSL(p_crypt(ctx, to, &to_length, from, from_length) == 1); + + EVP_PKEY_CTX_free(ctx); +#else to_length = p_crypt( from_length, from, (unsigned char*) to, p_rsa->rsa, p_rsa->padding); - +#endif if (to_length < 0) { Safefree(to); CHECK_OPEN_SSL(0); } - sv = newSVpv(to, to_length); + sv = newSVpv((char* ) to, to_length); Safefree(to); return sv; } - MODULE = Crypt::OpenSSL::RSA PACKAGE = Crypt::OpenSSL::RSA PROTOTYPES: DISABLE @@ -257,7 +373,7 @@ new_private_key(proto, key_string_SV, passphase_SV=&PL_sv_undef) SV* passphase_SV; CODE: RETVAL = make_rsa_obj( - proto, _load_rsa_key(key_string_SV, PEM_read_bio_RSAPrivateKey, passphase_SV)); + proto, _load_rsa_key(key_string_SV, PEM_read_bio_PrivateKey, passphase_SV)); OUTPUT: RETVAL @@ -285,7 +401,7 @@ void DESTROY(p_rsa) rsaData* p_rsa; CODE: - RSA_free(p_rsa->rsa); + EVP_PKEY_free(p_rsa->rsa); Safefree(p_rsa); SV* @@ -318,8 +434,8 @@ get_private_key_string(p_rsa, passphase_SV=&PL_sv_undef, cipher_name_SV=&PL_sv_u } CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); - PEM_write_bio_RSAPrivateKey( - stringBIO, p_rsa->rsa, enc, passphase, passphaseLength, NULL, NULL); + PEM_write_bio_PrivateKey_traditional( + stringBIO, p_rsa->rsa, enc, (unsigned char* ) passphase, passphaseLength, NULL, NULL); RETVAL = extractBioString(stringBIO); OUTPUT: @@ -332,7 +448,19 @@ get_public_key_string(p_rsa) BIO* stringBIO; CODE: CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_ENCODER_CTX *ctx = NULL; + + ctx = OSSL_ENCODER_CTX_new_for_pkey(p_rsa->rsa, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + "PEM", "PKCS1", NULL); + CHECK_OPEN_SSL(ctx != NULL && OSSL_ENCODER_CTX_get_num_encoders(ctx)); + + CHECK_OPEN_SSL(OSSL_ENCODER_to_bio(ctx, stringBIO) == 1); + + OSSL_ENCODER_CTX_free(ctx); +#else PEM_write_bio_RSAPublicKey(stringBIO, p_rsa->rsa); +#endif RETVAL = extractBioString(stringBIO); OUTPUT: @@ -345,7 +473,7 @@ get_public_key_x509_string(p_rsa) BIO* stringBIO; CODE: CHECK_OPEN_SSL(stringBIO = BIO_new(BIO_s_mem())); - PEM_write_bio_RSA_PUBKEY(stringBIO, p_rsa->rsa); + PEM_write_bio_PUBKEY(stringBIO, p_rsa->rsa); RETVAL = extractBioString(stringBIO); OUTPUT: @@ -357,20 +485,38 @@ generate_key(proto, bitsSV, exponent = 65537) SV* bitsSV; unsigned long exponent; PREINIT: - RSA* rsa; + EVP_PKEY* rsa = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; +#endif CODE: -#if OPENSSL_VERSION_NUMBER >= 0x00908000L BIGNUM *e; - int rc; e = BN_new(); BN_set_word(e, exponent); +#if OPENSSL_VERSION_NUMBER < 0x00908000L + rsa = RSA_generate_key(SvIV(bitsSV), exponent, NULL, NULL); + CHECK_OPEN_SSL(rsa != NULL); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x00908000L && OPENSSL_VERSION_NUMBER < 0x30000000L rsa = RSA_new(); - rc = RSA_generate_key_ex(rsa, SvIV(bitsSV), e, NULL); + if (!RSA_generate_key_ex(rsa, SvIV(bitsSV), e, NULL)) + croak("Unable to generate a key"); BN_free(e); + CHECK_OPEN_SSL(rsa != NULL); +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_keygen_init(ctx) == 1); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, SvIV(bitsSV)) > 0); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) >0); + CHECK_OPEN_SSL(EVP_PKEY_generate(ctx, &rsa) == 1); + CHECK_OPEN_SSL(rsa != NULL); + e = NULL; - CHECK_OPEN_SSL(rc != -1); -#else - rsa = RSA_generate_key(SvIV(bitsSV), exponent, NULL, NULL); + BN_free(e); + EVP_PKEY_CTX_free(ctx); #endif CHECK_OPEN_SSL(rsa); RETVAL = make_rsa_obj(proto, rsa); @@ -387,8 +533,8 @@ _new_key_from_parameters(proto, n, e, d, p, q) BIGNUM* p; BIGNUM* q; PREINIT: - RSA* rsa; - BN_CTX* ctx; + EVP_PKEY* rsa = NULL; + BN_CTX* ctx = NULL; BIGNUM* p_minus_1 = NULL; BIGNUM* q_minus_1 = NULL; BIGNUM* dmp1 = NULL; @@ -401,10 +547,23 @@ _new_key_from_parameters(proto, n, e, d, p, q) { croak("At least a modulus and public key must be provided"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + CHECK_OPEN_SSL(pctx != NULL); + CHECK_OPEN_SSL(EVP_PKEY_fromdata_init(pctx) > 0); + OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); + CHECK_OPEN_SSL(params_build) +#else CHECK_OPEN_SSL(rsa = RSA_new()); +#endif #if OLD_CRUFTY_SSL_VERSION rsa->n = n; rsa->e = e; +#endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + CHECK_OPEN_SSL(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_N, n)); + CHECK_OPEN_SSL(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_E, e)); #endif if (p || q) { @@ -423,8 +582,11 @@ _new_key_from_parameters(proto, n, e, d, p, q) #if OLD_CRUFTY_SSL_VERSION rsa->p = p; rsa->q = q; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L #else THROW(RSA_set0_factors(rsa, p, q)); +#endif #endif THROW(p_minus_1 = BN_new()); THROW(BN_sub(p_minus_1, p, BN_value_one())); @@ -438,8 +600,14 @@ _new_key_from_parameters(proto, n, e, d, p, q) } #if OLD_CRUFTY_SSL_VERSION rsa->d = d; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_D, d)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_FACTOR1, p)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_FACTOR2, q)); #else THROW(RSA_set0_key(rsa, n, e, d)); +#endif #endif THROW(dmp1 = BN_new()); THROW(BN_mod(dmp1, d, p_minus_1, ctx)); @@ -451,13 +619,59 @@ _new_key_from_parameters(proto, n, e, d, p, q) rsa->dmp1 = dmp1; rsa->dmq1 = dmq1; rsa->iqmp = iqmp; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1)); + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp)); + + params = OSSL_PARAM_BLD_to_param(params_build); + THROW(params != NULL); + + int status = EVP_PKEY_fromdata(pctx, &rsa, EVP_PKEY_KEYPAIR, params); + THROW( status > 0 && rsa != NULL ); + EVP_PKEY_CTX* test_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, rsa, NULL); + THROW(EVP_PKEY_check(test_ctx) == 1); #else THROW(RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp)); +#endif #endif dmp1 = dmq1 = iqmp = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_PARAM_BLD_free(params_build); + OSSL_PARAM_free(params); +#else THROW(RSA_check_key(rsa) == 1); - err: +#endif + } + else + { +#if OLD_CRUFTY_SSL_VERSION + rsa->d = d; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if(d != NULL) + THROW(OSSL_PARAM_BLD_push_BN(params_build, OSSL_PKEY_PARAM_RSA_D, d)); + params = OSSL_PARAM_BLD_to_param(params_build); + THROW(params != NULL); + + int status = EVP_PKEY_fromdata(pctx, &rsa, EVP_PKEY_KEYPAIR, params); + THROW( status > 0 && rsa != NULL ); +#else + CHECK_OPEN_SSL(RSA_set0_key(rsa, n, e, d)); +#endif +#endif + } + + RETVAL = make_rsa_obj(proto, rsa); + if(RETVAL) + goto end; + + err: + //if (p) BN_clear_free(p); if (p_minus_1) BN_clear_free(p_minus_1); + //if (q) BN_clear_free(q); + //if (d) BN_clear_free(d); if (q_minus_1) BN_clear_free(q_minus_1); if (dmp1) BN_clear_free(dmp1); if (dmq1) BN_clear_free(dmq1); @@ -465,20 +679,12 @@ _new_key_from_parameters(proto, n, e, d, p, q) if (ctx) BN_CTX_free(ctx); if (error) { - RSA_free(rsa); + EVP_PKEY_free(rsa); CHECK_OPEN_SSL(0); } } - else - { -#if OLD_CRUFTY_SSL_VERSION - rsa->d = d; -#else - CHECK_OPEN_SSL(RSA_set0_key(rsa, n, e, d)); -#endif - } - RETVAL = make_rsa_obj(proto, rsa); -} + end: + OUTPUT: RETVAL @@ -486,6 +692,16 @@ void _get_key_parameters(p_rsa) rsaData* p_rsa; PREINIT: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM* n = NULL; + BIGNUM* e = NULL; + BIGNUM* d = NULL; + BIGNUM* p = NULL; + BIGNUM* q = NULL; + BIGNUM* dmp1 = NULL; + BIGNUM* dmq1 = NULL; + BIGNUM* iqmp = NULL; +#else const BIGNUM* n; const BIGNUM* e; const BIGNUM* d; @@ -494,9 +710,10 @@ PREINIT: const BIGNUM* dmp1; const BIGNUM* dmq1; const BIGNUM* iqmp; +#endif PPCODE: { - RSA* rsa; + EVP_PKEY* rsa; rsa = p_rsa->rsa; #if OLD_CRUFTY_SSL_VERSION n = rsa->n; @@ -507,10 +724,21 @@ PPCODE: dmp1 = rsa->dmp1; dmq1 = rsa->dmq1; iqmp = rsa->iqmp; +#else +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_D, &d); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR1, &p); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_FACTOR2, &q); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp); #else RSA_get0_key(rsa, &n, &e, &d); RSA_get0_factors(rsa, &p, &q); RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +#endif #endif XPUSHs(cor_bn2sv(n)); XPUSHs(cor_bn2sv(e)); @@ -527,7 +755,11 @@ encrypt(p_rsa, p_plaintext) rsaData* p_rsa; SV* p_plaintext; CODE: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_plaintext, EVP_PKEY_encrypt, EVP_PKEY_encrypt_init, 1 /* public */); +#else RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_public_encrypt); +#endif OUTPUT: RETVAL @@ -540,7 +772,11 @@ decrypt(p_rsa, p_ciphertext) { croak("Public keys cannot decrypt"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_ciphertext, EVP_PKEY_decrypt, EVP_PKEY_decrypt_init, 0 /* private */); +#else RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_private_decrypt); +#endif OUTPUT: RETVAL @@ -553,7 +789,11 @@ private_encrypt(p_rsa, p_plaintext) { croak("Public keys cannot private_encrypt"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_plaintext, EVP_PKEY_sign, EVP_PKEY_sign_init, 0 /* private */); +#else RETVAL = rsa_crypt(p_rsa, p_plaintext, RSA_private_encrypt); +#endif OUTPUT: RETVAL @@ -562,7 +802,11 @@ public_decrypt(p_rsa, p_ciphertext) rsaData* p_rsa; SV* p_ciphertext; CODE: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + RETVAL = rsa_crypt(p_rsa, p_ciphertext, EVP_PKEY_verify_recover, EVP_PKEY_verify_recover_init, 1 /*public */); +#else RETVAL = rsa_crypt(p_rsa, p_ciphertext, RSA_public_decrypt); +#endif OUTPUT: RETVAL @@ -570,7 +814,7 @@ int size(p_rsa) rsaData* p_rsa; CODE: - RETVAL = RSA_size(p_rsa->rsa); + RETVAL = EVP_PKEY_get_size(p_rsa->rsa); OUTPUT: RETVAL @@ -582,7 +826,12 @@ check_key(p_rsa) { croak("Public keys cannot be checked"); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_pkey(NULL, p_rsa->rsa, NULL); + RETVAL = EVP_PKEY_private_check(pctx); +#else RETVAL = RSA_check_key(p_rsa->rsa); +#endif OUTPUT: RETVAL @@ -702,26 +951,50 @@ sign(p_rsa, text_SV) rsaData* p_rsa; SV* text_SV; PREINIT: - char* signature; + UNSIGNED_CHAR *signature; unsigned char* digest; - unsigned int signature_length; + SIZE_T_UNSIGNED_INT signature_length; CODE: { if (!_is_private(p_rsa)) { croak("Public keys cannot sign messages"); } - - CHECK_NEW(signature, RSA_size(p_rsa->rsa), char); + CHECK_NEW(signature, EVP_PKEY_get_size(p_rsa->rsa), UNSIGNED_CHAR); CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */); + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_sign_init(ctx)); + /* FIXME: Issue setting padding in some cases */ + EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + + EVP_MD* md = get_md_bynid(p_rsa->hashMode); + CHECK_OPEN_SSL(md != NULL); + + int md_status; + CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0); + + CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, NULL, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1); + + //signature = OPENSSL_malloc(signature_length); + Newx(signature, signature_length, char); + + CHECK_OPEN_SSL(signature); + + CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, signature, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1); + CHECK_OPEN_SSL(signature); +#else CHECK_OPEN_SSL(RSA_sign(p_rsa->hashMode, digest, get_digest_length(p_rsa->hashMode), (unsigned char*) signature, &signature_length, p_rsa->rsa)); - RETVAL = newSVpvn(signature, signature_length); +#endif + RETVAL = newSVpvn((const char* )signature, signature_length); Safefree(signature); } OUTPUT: @@ -741,18 +1014,35 @@ PPCODE: STRLEN sig_length; sig = (unsigned char*) SvPV(sig_SV, sig_length); - if (RSA_size(p_rsa->rsa) < sig_length) + if (EVP_PKEY_get_size(p_rsa->rsa) < sig_length) { croak("Signature longer than key"); } CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */); + CHECK_OPEN_SSL(ctx); + CHECK_OPEN_SSL(EVP_PKEY_verify_init(ctx) == 1); + /* FIXME: Issue setting padding in some cases */ + EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + + EVP_MD* md = get_md_bynid(p_rsa->hashMode); + CHECK_OPEN_SSL(md != NULL); + + int md_status; + CHECK_OPEN_SSL((md_status = EVP_PKEY_CTX_set_signature_md(ctx, md)) > 0); + + switch (EVP_PKEY_verify(ctx, sig, sig_length, digest, get_digest_length(p_rsa->hashMode))) +#else switch(RSA_verify(p_rsa->hashMode, digest, get_digest_length(p_rsa->hashMode), sig, sig_length, p_rsa->rsa)) +#endif { case 0: ERR_clear_error(); diff --git a/t/rsa.t b/t/rsa.t index e97c15d..4bd1f01 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -3,6 +3,7 @@ use Test::More; use Crypt::OpenSSL::Random; use Crypt::OpenSSL::RSA; +use Crypt::OpenSSL::Guess qw(openssl_version); BEGIN { plan tests => 43 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + @@ -147,9 +148,16 @@ if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) { _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); } -$rsa->use_ripemd160_hash(); -$rsa_pub->use_ripemd160_hash(); -_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +my ($major, $minor, $patch) = openssl_version(); + +SKIP: { + skip "ripemd160 in legacy provider between 3.02 and 3.07", 5 if $major eq '3.0' && + ($minor ge '2' && $minor le '6'); + + $rsa->use_ripemd160_hash(); + $rsa_pub->use_ripemd160_hash(); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +} if (UNIVERSAL::can("Crypt::OpenSSL::RSA", "use_whirlpool_hash")) { $rsa->use_whirlpool_hash(); From eaac603d47dcb297550e00d17ec8ec1bfb745b70 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Fri, 2 May 2025 13:39:19 +0000 Subject: [PATCH 15/49] Run on multiple ubuntu versions to test different openssl --- .github/workflows/testsuite.yml | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 71c00f3..bc3edb1 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -22,7 +22,10 @@ jobs: AUTOMATED_TESTING: 1 RELEASE_TESTING: 1 - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest + + strategy: + fail-fast: false steps: - uses: actions/checkout@v4 @@ -36,12 +39,50 @@ jobs: run: perl -I$(pwd) Makefile.PL - run: make && ( make test || prove -wbvm t/*.t ) + openssl-matrix: + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 1 + AUTOMATED_TESTING: 1 + RELEASE_TESTING: 1 + + runs-on: ubuntu-latest + needs: [ubuntu] + name: "OpenSSL ${{ matrix.os-version }}" + + strategy: + fail-fast: false + matrix: + os-version: + - debian:buster # OpenSSL 1.1.1 + - debian:bullseye # OpenSSL 1.1.1 + - debian:bookworm # OpenSSL 3.0.x + - ubuntu:20.04 # OpenSSL 1.1.1 + + container: ${{ matrix.os-version }} + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + apt-get update && + apt-get install -y openssl perl make gcc libssl-dev perl sudo curl + - run: openssl version + - run: perl -V + - name: uses install-with-cpm + uses: perl-actions/install-with-cpm@v1 + with: + cpanfile: "cpanfile" + - name: Makefile.PL + run: perl -I$(pwd) Makefile.PL + - run: make && ( make test || prove -wbvm t/*.t ) + # # List of Perl Versions available # perl-versions: runs-on: ubuntu-latest + needs: [openssl-matrix] name: List Perl versions outputs: perl-versions: ${{ steps.action.outputs.perl-versions }} @@ -64,7 +105,7 @@ jobs: RELEASE_TESTING: 1 runs-on: ubuntu-latest - needs: [ubuntu,perl-versions] + needs: [openssl-matrix,perl-versions] name: "Perl ${{ matrix.perl-version }}" strategy: @@ -76,6 +117,7 @@ jobs: steps: - uses: actions/checkout@v4 + - run: openssl version - run: perl -V - name: Deps for testing run: | @@ -97,7 +139,7 @@ jobs: AUTOMATED_TESTING: 1 RELEASE_TESTING: 0 - needs: [ubuntu] + needs: [openssl-matrix, perl-versions] runs-on: windows-latest strategy: @@ -119,6 +161,7 @@ jobs: C:\strawberry\perl\bin "@ | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - run: openssl version - run: perl -V - name: Deps for testing run: cpanm --notest Crypt::OpenSSL::Random Crypt::OpenSSL::Guess From 20dfb87444f2b6a02a8c7c0ab33cf2c20e5e3a55 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 13:29:20 +0000 Subject: [PATCH 16/49] Tolerate Crypto policies on redhat 9+ --- t/rsa.t | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/t/rsa.t b/t/rsa.t index 4bd1f01..1078f93 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -32,9 +32,11 @@ sub _Test_Encrypt_And_Decrypt { } sub _Test_Sign_And_Verify { - my ( $plaintext, $rsa, $rsa_pub ) = @_; + my ( $plaintext, $rsa, $rsa_pub, $hash ) = @_; - my $sig = $rsa->sign($plaintext); + 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 ) ); my $false_sig = unpack "H*", $sig; @@ -45,6 +47,7 @@ sub _Test_Sign_And_Verify { my $sig_of_other = $rsa->sign("different"); ok( !$rsa_pub->verify( $plaintext, $sig_of_other ) ); ok( !$rsa->verify( $plaintext, $sig_of_other ) ); + } } sub _check_for_croak { @@ -124,28 +127,28 @@ $plaintext .= $plaintext x 5; # check signature algorithms $rsa->use_md5_hash(); $rsa_pub->use_md5_hash(); -_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "md5" ); $rsa->use_sha1_hash(); $rsa_pub->use_sha1_hash(); -_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); +_Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha1" ); 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 ); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha224" ); $rsa->use_sha256_hash(); $rsa_pub->use_sha256_hash(); - _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha256" ); $rsa->use_sha384_hash(); $rsa_pub->use_sha384_hash(); - _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha384" ); $rsa->use_sha512_hash(); $rsa_pub->use_sha512_hash(); - _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512" ); } my ($major, $minor, $patch) = openssl_version(); @@ -156,13 +159,13 @@ SKIP: { $rsa->use_ripemd160_hash(); $rsa_pub->use_ripemd160_hash(); - _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub ); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "ripemd160" ); } if (UNIVERSAL::can("Crypt::OpenSSL::RSA", "use_whirlpool_hash")) { $rsa->use_whirlpool_hash(); $rsa_pub->use_whirlpool_hash(); - _Test_Sign_And_Verify($plaintext, $rsa, $rsa_pub); + _Test_Sign_And_Verify($plaintext, $rsa, $rsa_pub, "whirlpool"); } # check subclassing From 7f2b3af45153083af6ca644d2817d5d8ce88997a Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 13:30:05 +0000 Subject: [PATCH 17/49] Tidy --- t/bignum.t | 2 +- t/format.t | 12 ++++++------ t/rsa.t | 47 ++++++++++++++++++++++++----------------------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/t/bignum.t b/t/bignum.t index 77691db..68776d9 100644 --- a/t/bignum.t +++ b/t/bignum.t @@ -48,7 +48,7 @@ sub check_key_parameters # runs 8 tests $rsa->use_no_padding(); - my $plaintext = pack( 'C*', 100, 100, 100, 12 ); + my $plaintext = pack( 'C*', 100, 100, 100, 12 ); my $ciphertext = Crypt::OpenSSL::Bignum->new_from_bin($plaintext)->mod_exp( $e, $n, $ctx )->to_bin(); check_key_parameters( $rsa, $n, $e, $d, $p, $q, $dmp1, $dmq1, $iqmp ); diff --git a/t/format.t b/t/format.t index 214302f..ec3cbda 100644 --- a/t/format.t +++ b/t/format.t @@ -79,12 +79,12 @@ ok( $PUBLIC_KEY_PKCS1_STRING eq $public_key->get_public_key_string() ); ok( $PUBLIC_KEY_X509_STRING eq $public_key->get_public_key_x509_string() ); my $passphase = '123456'; -ok( $private_key = Crypt::OpenSSL::RSA->new_private_key($ENCRYPT_PRIVATE_KEY_STRING, $passphase) ); +ok( $private_key = Crypt::OpenSSL::RSA->new_private_key( $ENCRYPT_PRIVATE_KEY_STRING, $passphase ) ); ok( $DECRYPT_PRIVATE_KEY_STRING eq $private_key->get_private_key_string() ); -ok( $private_key = Crypt::OpenSSL::RSA->new_private_key($DECRYPT_PRIVATE_KEY_STRING) ); -ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key($private_key->get_private_key_string($passphase), $passphase) ); +ok( $private_key = Crypt::OpenSSL::RSA->new_private_key($DECRYPT_PRIVATE_KEY_STRING) ); +ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key( $private_key->get_private_key_string($passphase), $passphase ) ); ok( $DECRYPT_PRIVATE_KEY_STRING eq $private_key2->get_private_key_string() ); -ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key($private_key->get_private_key_string($passphase, 'des3'), $passphase) ); +ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key( $private_key->get_private_key_string( $passphase, 'des3' ), $passphase ) ); +ok( $DECRYPT_PRIVATE_KEY_STRING eq $private_key2->get_private_key_string() ); +ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key( $private_key->get_private_key_string( $passphase, 'aes-128-cbc' ), $passphase ) ); ok( $DECRYPT_PRIVATE_KEY_STRING eq $private_key2->get_private_key_string() ); -ok( $private_key2 = Crypt::OpenSSL::RSA->new_private_key($private_key->get_private_key_string($passphase, 'aes-128-cbc'), $passphase) ); -ok( $DECRYPT_PRIVATE_KEY_STRING eq $private_key2->get_private_key_string() ); \ No newline at end of file diff --git a/t/rsa.t b/t/rsa.t index 1078f93..d8a5967 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -5,9 +5,9 @@ use Crypt::OpenSSL::Random; use Crypt::OpenSSL::RSA; use Crypt::OpenSSL::Guess qw(openssl_version); -BEGIN { plan tests => 43 + - ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + - ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ? 1 * 5 : 0 ) } +BEGIN { + plan tests => 43 + ( 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 { my ( $p_plaintext_length, $p_rsa, $p_check_private_encrypt ) = @_; @@ -34,20 +34,20 @@ sub _Test_Encrypt_And_Decrypt { sub _Test_Sign_And_Verify { my ( $plaintext, $rsa, $rsa_pub, $hash ) = @_; - 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 ) ); + 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 ) ); - 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 ) ) ); + 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 ) ) ); - my $sig_of_other = $rsa->sign("different"); - ok( !$rsa_pub->verify( $plaintext, $sig_of_other ) ); - ok( !$rsa->verify( $plaintext, $sig_of_other ) ); - } + my $sig_of_other = $rsa->sign("different"); + ok( !$rsa_pub->verify( $plaintext, $sig_of_other ) ); + ok( !$rsa->verify( $plaintext, $sig_of_other ) ); + } } sub _check_for_croak { @@ -151,21 +151,22 @@ if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ) { _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "sha512" ); } -my ($major, $minor, $patch) = openssl_version(); +my ( $major, $minor, $patch ) = openssl_version(); SKIP: { - skip "ripemd160 in legacy provider between 3.02 and 3.07", 5 if $major eq '3.0' && - ($minor ge '2' && $minor le '6'); + skip "ripemd160 in legacy provider between 3.02 and 3.07", 5 + if $major eq '3.0' + && ( $minor ge '2' && $minor le '6' ); - $rsa->use_ripemd160_hash(); - $rsa_pub->use_ripemd160_hash(); - _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "ripemd160" ); + $rsa->use_ripemd160_hash(); + $rsa_pub->use_ripemd160_hash(); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "ripemd160" ); } -if (UNIVERSAL::can("Crypt::OpenSSL::RSA", "use_whirlpool_hash")) { +if ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ) { $rsa->use_whirlpool_hash(); $rsa_pub->use_whirlpool_hash(); - _Test_Sign_And_Verify($plaintext, $rsa, $rsa_pub, "whirlpool"); + _Test_Sign_And_Verify( $plaintext, $rsa, $rsa_pub, "whirlpool" ); } # check subclassing From 94263c545c65356c125cb4d18b1a6c26b0910af2 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 13:33:39 +0000 Subject: [PATCH 18/49] Almalinux 9 testing --- .github/workflows/testsuite.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index bc3edb1..8a286af 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -57,15 +57,16 @@ jobs: - debian:buster # OpenSSL 1.1.1 - debian:bullseye # OpenSSL 1.1.1 - debian:bookworm # OpenSSL 3.0.x - - ubuntu:20.04 # OpenSSL 1.1.1 + - almalinux:9 # OpenSSL with new crypto policies (RHEL-compatible) container: ${{ matrix.os-version }} steps: - uses: actions/checkout@v4 - name: Install dependencies run: | - apt-get update && - apt-get install -y openssl perl make gcc libssl-dev perl sudo curl + (apt-get update && + apt-get install -y openssl perl make gcc libssl-dev perl sudo curl) || + (yum install --skip-broken -y openssl perl make gcc openssl-devel perl sudo curl) - run: openssl version - run: perl -V - name: uses install-with-cpm @@ -74,7 +75,7 @@ jobs: cpanfile: "cpanfile" - name: Makefile.PL run: perl -I$(pwd) Makefile.PL - - run: make && ( make test || prove -wbvm t/*.t ) + - run: make && prove -wbvm t/*.t # # List of Perl Versions available From 4d54dfa189aa8ff236ca25a5706e94ddeb2beb3d Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 13:45:01 +0000 Subject: [PATCH 19/49] Test build for 0.34_02 --- Changes | 5 ++++- RSA.pm | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 2154e5e..ee880f8 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,9 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. -0.34 TBD +0.34_02 May 4 2025 + - t/rsa.t needs to tolerate sha1 being disabled on rhel. + +0.34_01 May 3 2025 - docs - plaintext = decrypt(cyphertext) - #44 - Fix issue when libz is not linked on AIX - #50 - Correct openssl version may not be found diff --git a/RSA.pm b/RSA.pm index 93506ee..4bf9a96 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.33'; +our $VERSION = '0.34_02'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From 25fec76fc16d1877d21a497adaeb8f8fbfc2883b Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 14:11:57 +0000 Subject: [PATCH 20/49] Pass NULL to EVP_PKEY_CTX_new_from_pkey not a random var value --- RSA.xs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/RSA.xs b/RSA.xs index a3f2ea9..d60804b 100644 --- a/RSA.xs +++ b/RSA.xs @@ -324,9 +324,8 @@ SV* rsa_crypt(rsaData* p_rsa, SV* p_from, EVP_PKEY_CTX *ctx; OSSL_LIB_CTX *ossllibctx = OSSL_LIB_CTX_new(); - const char* propquery; if (public) { - ctx = EVP_PKEY_CTX_new_from_pkey(ossllibctx, (EVP_PKEY* )p_rsa->rsa, propquery); + ctx = EVP_PKEY_CTX_new_from_pkey(ossllibctx, (EVP_PKEY* )p_rsa->rsa, NULL); } else { ctx = EVP_PKEY_CTX_new((EVP_PKEY* )p_rsa->rsa, NULL); } From 048b92cef157afb983d559d609d6dd7cbb7bfdeb Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 4 May 2025 14:14:56 +0000 Subject: [PATCH 21/49] Bump to 0.34_03 for testing --- Changes | 3 +++ RSA.pm | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index ee880f8..ec9c85e 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. +0.34_03 May 4 2025 + - Fix bug in rsa_crypt. Need to pass NULL + 0.34_02 May 4 2025 - t/rsa.t needs to tolerate sha1 being disabled on rhel. diff --git a/RSA.pm b/RSA.pm index 4bf9a96..009a09f 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.34_02'; +our $VERSION = '0.34_03'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From 8c7f14ffd48977a139d2b36fce8ac579ba86e755 Mon Sep 17 00:00:00 2001 From: "Nicolas R." Date: Sun, 4 May 2025 16:42:04 +0200 Subject: [PATCH 22/49] Remove duplicate perl package --- .github/workflows/testsuite.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 8a286af..1b2670b 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -65,8 +65,8 @@ jobs: - name: Install dependencies run: | (apt-get update && - apt-get install -y openssl perl make gcc libssl-dev perl sudo curl) || - (yum install --skip-broken -y openssl perl make gcc openssl-devel perl sudo curl) + apt-get install -y openssl perl make gcc libssl-dev sudo curl) || + (yum install --skip-broken -y openssl perl make gcc openssl-devel sudo curl) - run: openssl version - run: perl -V - name: uses install-with-cpm From af951623616febe4e8e53e013a43da5a239b22fd Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Mon, 5 May 2025 13:38:59 +0000 Subject: [PATCH 23/49] Bump for production release of 0.34 --- Changes | 3 +++ RSA.pm | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index ec9c85e..d196c8f 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. +0.34 May 5 2025 + - Production release. + 0.34_03 May 4 2025 - Fix bug in rsa_crypt. Need to pass NULL diff --git a/RSA.pm b/RSA.pm index 009a09f..dda5bc6 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.34_03'; +our $VERSION = '0.34'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From f986c31575f41107bfe66610cdf922d6858a36be Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Tue, 6 May 2025 21:54:07 -0300 Subject: [PATCH 24/49] Disable PKCS#1 v1.5 padding --- RSA.pm | 14 ++++++++++++-- RSA.xs | 2 +- t/rsa.t | 5 +---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/RSA.pm b/RSA.pm index dda5bc6..4ca0b44 100644 --- a/RSA.pm +++ b/RSA.pm @@ -80,6 +80,13 @@ Crypt::OpenSSL::RSA - RSA encoding and decoding, using the openSSL libraries $signature = $rsa_priv->sign($plaintext); print "Signed correctly\n" if ($rsa->verify($plaintext, $signature)); +=head1 SECURITY + +Version 0.35 makes the use of PKCS#1 v1.5 padding a fatal error. It is +very difficult to implement PKCS#1 v1.5 padding securely. If you are still +using RSA in in general, you should be looking at alternative encryption +algorithms. + =head1 DESCRIPTION C provides the ability to RSA encrypt strings which are @@ -236,8 +243,11 @@ Encrypting user data directly with RSA is insecure. =item use_pkcs1_padding -Use PKCS #1 v1.5 padding. This currently is the most widely used mode -of padding. +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. + +L =item use_pkcs1_oaep_padding diff --git a/RSA.xs b/RSA.xs index d60804b..775ae3e 100644 --- a/RSA.xs +++ b/RSA.xs @@ -925,7 +925,7 @@ void use_pkcs1_padding(p_rsa) rsaData* p_rsa; CODE: - p_rsa->padding = RSA_PKCS1_PADDING; + croak("PKCS#1 1.5 is disabled as it is known to be vulnerable to marvin attacks."); void use_pkcs1_oaep_padding(p_rsa) diff --git a/t/rsa.t b/t/rsa.t index d8a5967..05b2550 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 => 43 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ) + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_whirlpool_hash" ) ? 1 * 5 : 0 ); + 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 ); } sub _Test_Encrypt_And_Decrypt { @@ -76,9 +76,6 @@ ok( $rsa->check_key() ); $rsa->use_no_padding(); _Test_Encrypt_And_Decrypt( $rsa->size(), $rsa, 1 ); -$rsa->use_pkcs1_padding(); -_Test_Encrypt_And_Decrypt( $rsa->size() - 11, $rsa, 1 ); - $rsa->use_pkcs1_oaep_padding(); # private_encrypt does not work with pkcs1_oaep_padding From 5b76ae34d2c26557e61440856616d2ea7a35dd94 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Wed, 7 May 2025 16:05:17 +0000 Subject: [PATCH 25/49] Bump changelog for release of 0.35 to CPAN --- Changes | 4 ++++ RSA.pm | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index d196c8f..38882d6 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,9 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. +0.35 May 7 2025 + - Disable PKCS#1 v1.5 padding. It's not practical to mitigate marvin attacks so we will instead disable this and require alternatives to address the issue. + - Resolves #42 - CVE-2024-2467. + 0.34 May 5 2025 - Production release. diff --git a/RSA.pm b/RSA.pm index 4ca0b44..1390852 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.34'; +our $VERSION = '0.35'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From 666db05d5b72c3de0da07b5b46da93996f295534 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Thu, 8 May 2025 08:20:28 -0300 Subject: [PATCH 26/49] Fix old openssl on strawberry does not include whrlpool.h --- Changes | 2 ++ RSA.xs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 38882d6..a69f8fa 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,7 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. + - Fix old openssl on strawberry does not include whrlpool.h + 0.35 May 7 2025 - Disable PKCS#1 v1.5 padding. It's not practical to mitigate marvin attacks so we will instead disable this and require alternatives to address the issue. - Resolves #42 - CVE-2024-2467. diff --git a/RSA.xs b/RSA.xs index 775ae3e..066ee00 100644 --- a/RSA.xs +++ b/RSA.xs @@ -10,7 +10,7 @@ #include #include #include -#if OPENSSL_VERSION_NUMBER < 0x30000000 +#if OPENSSL_VERSION_NUMBER >= 0x10000000 & OPENSSL_VERSION_NUMBER < 0x30000000 #include #endif #include From b2a8f0a950d57a81f5b11bf292dc5a1459739e09 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 9 May 2025 20:14:09 -0300 Subject: [PATCH 27/49] libressl message digest functions md cannot be NULL --- RSA.xs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/RSA.xs b/RSA.xs index 066ee00..7cc548a 100644 --- a/RSA.xs +++ b/RSA.xs @@ -200,10 +200,10 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method) { STRLEN text_length; unsigned char* text; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - static unsigned char md[EVP_MAX_MD_SIZE]; -#endif + unsigned char *md; + static unsigned char m[EVP_MAX_MD_SIZE]; text = (unsigned char*) SvPV(text_SV, text_length); + md = m; switch(hash_method) { @@ -211,36 +211,36 @@ unsigned char* get_message_digest(SV* text_SV, int hash_method) #if OPENSSL_VERSION_NUMBER >= 0x30000000L return EVP_Q_digest(NULL, "MD5", NULL, text, text_length, md, NULL) ? md : NULL; #else - return MD5(text, text_length, NULL); + return MD5(text, text_length, md); #endif break; case NID_sha1: - return SHA1(text, text_length, NULL); + return SHA1(text, text_length, md); break; #ifdef SHA512_DIGEST_LENGTH case NID_sha224: - return SHA224(text, text_length, NULL); + return SHA224(text, text_length, md); break; case NID_sha256: - return SHA256(text, text_length, NULL); + return SHA256(text, text_length, md); break; case NID_sha384: - return SHA384(text, text_length, NULL); + return SHA384(text, text_length, md); break; case NID_sha512: - return SHA512(text, text_length, NULL); + return SHA512(text, text_length, md); break; #endif case NID_ripemd160: #if OPENSSL_VERSION_NUMBER >= 0x30000000L return EVP_Q_digest(NULL, "RIPEMD160", NULL, text, text_length, md, NULL) ? md : NULL; #else - return RIPEMD160(text, text_length, NULL); + return RIPEMD160(text, text_length, md); #endif break; #ifdef WHIRLPOOL_DIGEST_LENGTH case NID_whirlpool: - return WHIRLPOOL(text, text_length, NULL); + return WHIRLPOOL(text, text_length, md); break; #endif default: From c7b51914ad849a7e85faae5e24091d91c29ed6c9 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 9 May 2025 20:19:12 -0300 Subject: [PATCH 28/49] Don't support whirlpool in libressl --- RSA.xs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RSA.xs b/RSA.xs index 7cc548a..aa8094c 100644 --- a/RSA.xs +++ b/RSA.xs @@ -11,8 +11,10 @@ #include #include #if OPENSSL_VERSION_NUMBER >= 0x10000000 & OPENSSL_VERSION_NUMBER < 0x30000000 +#ifndef LIBRESSL_VERSION_NUMBER #include #endif +#endif #include #include #include From fc7aa1d55f9ebc9c626e9391c0ce6071fca1ec02 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Mon, 14 Jul 2025 23:35:43 -0300 Subject: [PATCH 29/49] Don't ignore the set padding return code --- RSA.xs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RSA.xs b/RSA.xs index 066ee00..8300686 100644 --- a/RSA.xs +++ b/RSA.xs @@ -968,7 +968,7 @@ sign(p_rsa, text_SV) CHECK_OPEN_SSL(ctx); CHECK_OPEN_SSL(EVP_PKEY_sign_init(ctx)); /* FIXME: Issue setting padding in some cases */ - EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); EVP_MD* md = get_md_bynid(p_rsa->hashMode); CHECK_OPEN_SSL(md != NULL); @@ -1025,7 +1025,7 @@ PPCODE: CHECK_OPEN_SSL(ctx); CHECK_OPEN_SSL(EVP_PKEY_verify_init(ctx) == 1); /* FIXME: Issue setting padding in some cases */ - EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding); + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); EVP_MD* md = get_md_bynid(p_rsa->hashMode); CHECK_OPEN_SSL(md != NULL); From 985a5c42fe95daa9f12cf5261d623f31bc1dcdea Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Tue, 28 Oct 2025 23:45:17 -0300 Subject: [PATCH 30/49] Add support for use_pkcs1_pss_padding This change effectively reverses the fatal failure if use_pkcs1_padding is called and sets the padding to default to RSA_PKCS1_PSS_PADDING which is the recommended replacement for RSA_PKCS1_PADDING This will allow modules to continue to call use_pkcs1_padding but effectively replace it with the recommended alternative This may avoid changes to other modules but might not be what the user wants It should alos be noted that RSA_PKCS1_PSS_PADDING (and use_pkcs1_pss_padding should only be used for signing/verification operations --- RSA.pm | 11 ++++++++++- RSA.xs | 17 +++++++++++++++-- t/rsa.t | 47 +++++++++++++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/RSA.pm b/RSA.pm index 1390852..f2f3c09 100644 --- a/RSA.pm +++ b/RSA.pm @@ -245,7 +245,9 @@ 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() now sets the padding method to use_pkcs1_pss_padding. L @@ -256,6 +258,13 @@ 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. + =item use_sslv23_padding Use C padding with an SSL-specific modification that diff --git a/RSA.xs b/RSA.xs index aa8094c..29a445f 100644 --- a/RSA.xs +++ b/RSA.xs @@ -927,7 +927,7 @@ void use_pkcs1_padding(p_rsa) rsaData* p_rsa; CODE: - croak("PKCS#1 1.5 is disabled as it is known to be vulnerable to marvin attacks."); + p_rsa->padding = RSA_PKCS1_PSS_PADDING; void use_pkcs1_oaep_padding(p_rsa) @@ -935,6 +935,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 +983,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 +1043,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..5259865 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 => 97 + ( 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,16 @@ 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 ) ); + 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 +69,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 +121,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 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(); From 0ea9c522b19138e4ba43b635285237d39bf6be2d Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Tue, 28 Oct 2025 23:57:45 -0300 Subject: [PATCH 31/49] Fatal error if RSA-PSS is used for encryption operations --- RSA.pm | 4 +++- RSA.xs | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/RSA.pm b/RSA.pm index f2f3c09..e7f5b05 100644 --- a/RSA.pm +++ b/RSA.pm @@ -246,10 +246,12 @@ 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. +L use_pkcs1_padding() now sets the padding method to use_pkcs1_pss_padding. -L +B: RSA-PSS cannot be used for encryption/decryption and results in a +fatal error. Call C for encryption operations. =item use_pkcs1_oaep_padding diff --git a/RSA.xs b/RSA.xs index 29a445f..9aa8ed7 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(); From cb6435eb7fee930a4a41c7e6df72b6becd379068 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Wed, 29 Oct 2025 17:44:50 -0300 Subject: [PATCH 32/49] Fix test for sha1 digest issue and croak on use_pkcs1_padding --- RSA.pm | 11 +++++------ RSA.xs | 2 +- t/rsa.t | 5 +++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/RSA.pm b/RSA.pm index e7f5b05..22ddc09 100644 --- a/RSA.pm +++ b/RSA.pm @@ -245,13 +245,9 @@ 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. -L - -use_pkcs1_padding() now sets the padding method to use_pkcs1_pss_padding. +based side channel attacks. use_pkcs1_padding() results in a fatal error. -B: RSA-PSS cannot be used for encryption/decryption and results in a -fatal error. Call C for encryption operations. +L =item use_pkcs1_oaep_padding @@ -267,6 +263,9 @@ 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 9aa8ed7..d42c812 100644 --- a/RSA.xs +++ b/RSA.xs @@ -931,7 +931,7 @@ void use_pkcs1_padding(p_rsa) rsaData* p_rsa; CODE: - p_rsa->padding = RSA_PKCS1_PSS_PADDING; + croak("PKCS#1 1.5 is disabled as it is known to be vulnerable to marvin attacks."); void use_pkcs1_oaep_padding(p_rsa) diff --git a/t/rsa.t b/t/rsa.t index 5259865..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 => 97 + ( 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,6 +37,7 @@ 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; + 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; @@ -121,7 +122,7 @@ _check_for_croak( $plaintext .= $plaintext x 5; -my @paddings = qw/pkcs1 pkcs1_oaep pkcs1_pss/; +my @paddings = qw/pkcs1_oaep pkcs1_pss/; foreach my $padding (@paddings) { my $p = "use_$padding\_padding"; From 2f47d457d29af6f2a3e25fe67b45c6e5bf68c1ff Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Wed, 29 Oct 2025 21:17:05 +0000 Subject: [PATCH 33/49] Bump changelog for release of 0.36 to CPAN~ --- Changes | 6 +++++- RSA.pm | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index a69f8fa..3d3ccdb 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,10 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. - - Fix old openssl on strawberry does not include whrlpool.h +0.36 Oct 29 2025 + - Fix old openssl on strawberry does not include whrlpool.h + - libressl message digest functions md cannot be NULL + - Don't support whirlpool in libressl + - Add support for use_pkcs1_pss_padding with fatal error if RSA-PSS is used for encryption operations 0.35 May 7 2025 - Disable PKCS#1 v1.5 padding. It's not practical to mitigate marvin attacks so we will instead disable this and require alternatives to address the issue. diff --git a/RSA.pm b/RSA.pm index 22ddc09..6293d58 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.35'; +our $VERSION = '0.36'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From 7a4047a46983e646dc391096af40d833ff2f9bd9 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Wed, 29 Oct 2025 21:36:43 +0000 Subject: [PATCH 34/49] Fix libressl bitwise logic error in RSA.xs --- RSA.xs | 2 +- t/rsa.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/RSA.xs b/RSA.xs index 1dd5680..e3b3c27 100644 --- a/RSA.xs +++ b/RSA.xs @@ -10,7 +10,7 @@ #include #include #include -#if OPENSSL_VERSION_NUMBER >= 0x10000000 & OPENSSL_VERSION_NUMBER < 0x30000000 +#if OPENSSL_VERSION_NUMBER >= 0x10000000 && OPENSSL_VERSION_NUMBER < 0x30000000 #ifndef LIBRESSL_VERSION_NUMBER #include #endif diff --git a/t/rsa.t b/t/rsa.t index 2448825..83942f9 100644 --- a/t/rsa.t +++ b/t/rsa.t @@ -124,7 +124,7 @@ $plaintext .= $plaintext x 5; my @paddings = qw/pkcs1_oaep pkcs1_pss/; foreach my $padding (@paddings) { - my $p = "use_$padding\_padding"; + my $p = "use_${padding}_padding"; $rsa->$p; $rsa_pub->$p; From bb6cf944f6b303ff9d192733584185ba861a92f5 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Wed, 29 Oct 2025 21:38:41 +0000 Subject: [PATCH 35/49] Bump changelog for release of 0.37 to CPAN --- Changes | 3 +++ RSA.pm | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 3d3ccdb..73b3acb 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension Crypt::OpenSSL::RSA. +0.37 Oct 29 2025 + - Fix libressl bitwise logic error in RSA.xs + 0.36 Oct 29 2025 - Fix old openssl on strawberry does not include whrlpool.h - libressl message digest functions md cannot be NULL diff --git a/RSA.pm b/RSA.pm index 6293d58..b9d8d06 100644 --- a/RSA.pm +++ b/RSA.pm @@ -5,7 +5,7 @@ use warnings; use Carp; # Removing carp will break the XS code. -our $VERSION = '0.36'; +our $VERSION = '0.37'; use XSLoader; XSLoader::load 'Crypt::OpenSSL::RSA', $VERSION; From 5e50ed0f13878f5ba7c1d18f210274a432ad6323 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 31 Oct 2025 22:48:53 -0300 Subject: [PATCH 36/49] Change the default hash mode to sha256 sha1 is problematic especially since RedHat disabled it's usage --- RSA.xs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RSA.xs b/RSA.xs index e3b3c27..7b18f81 100644 --- a/RSA.xs +++ b/RSA.xs @@ -114,7 +114,11 @@ SV* make_rsa_obj(SV* p_proto, EVP_PKEY* p_rsa) CHECK_NEW(rsa, 1, rsaData); rsa->rsa = p_rsa; +#ifdef SHA512_DIGEST_LENGTH + rsa->hashMode = NID_sha256; +#else rsa->hashMode = NID_sha1; +#endif rsa->padding = RSA_PKCS1_OAEP_PADDING; return sv_bless( newRV_noinc(newSViv((IV) rsa)), From b24e1c087a0c8fb997b4671b298a77874a774864 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 31 Oct 2025 21:36:39 -0300 Subject: [PATCH 37/49] Make padding selection clearer and update documentation Also add t/padding.t that attempts to test the paddingi combinations more thoroughly or possible more clearly? --- RSA.pm | 32 ++++++++++- RSA.xs | 19 +++++-- t/padding.t | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 6 deletions(-) create mode 100644 t/padding.t diff --git a/RSA.pm b/RSA.pm index b9d8d06..346d609 100644 --- a/RSA.pm +++ b/RSA.pm @@ -85,7 +85,9 @@ Crypt::OpenSSL::RSA - RSA encoding and decoding, using the openSSL libraries Version 0.35 makes the use of PKCS#1 v1.5 padding a fatal error. It is very difficult to implement PKCS#1 v1.5 padding securely. If you are still using RSA in in general, you should be looking at alternative encryption -algorithms. +algorithms. Version 0.36 implements RSA-PSS padding (PKCS#1 v2.1) and makes +setting an invalid padding a fatal error. Note, PKCS1_OAEP can only be used +for encryption and PKCS1_PSS can only be used for signing. =head1 DESCRIPTION @@ -112,6 +114,10 @@ C<-----BEGIN...-----> and C<-----END...-----> lines. The padding is set to PKCS1_OAEP, but can be changed with the C methods. +Note, PKCS1_OAEP can only be used for encryption. You must specifically +call use_pkcs1_pss_padding (or use_pkcs1_pss_padding) prior to signing +operations. + =item new_private_key Create a new C object by loading a private key in @@ -235,6 +241,22 @@ Sign a string using the secret (portion of the) key. Check the signature on a text. +=back + +=head1 Padding Methods + +Versions prior to 0.35 allowed using pkcs1 padding for both encryption +and signature operations but has been disabled for security reasons. + +While B can be used for encryption or signature operations +B is used for signature operations and +B is used for encryption operations. + +Version 0.38 sets the appropriate padding for each operation unless +B is called before either operation. + +=over + =item use_no_padding Use raw RSA encryption. This mode should only be used to implement @@ -254,7 +276,7 @@ L padding as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding parameter. This mode of padding is recommended for all new applications. It is the default mode used by -C. +C but is only valid for encryption/decryption. =item use_pkcs1_pss_padding @@ -273,6 +295,12 @@ denotes that the server is SSL3 capable. Not available since OpenSSL 3. +=back + +=head1 Hash/Digest Methods + +=over + =item use_md5_hash Use the RFC 1321 MD5 hashing algorithm by Ron Rivest when signing and diff --git a/RSA.xs b/RSA.xs index e3b3c27..7b2ba3e 100644 --- a/RSA.xs +++ b/RSA.xs @@ -339,7 +339,11 @@ SV* rsa_crypt(rsaData* p_rsa, SV* p_from, CHECK_OPEN_SSL(ctx); CHECK_OPEN_SSL(init_crypt(ctx) == 1); - CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); + int crypt_pad = p_rsa->padding; + if (p_rsa->padding != RSA_NO_PADDING) { + crypt_pad = RSA_PKCS1_OAEP_PADDING; + } + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_pad) > 0); CHECK_OPEN_SSL(p_crypt(ctx, NULL, &to_length, from, from_length) == 1); CHECK_OPEN_SSL(p_crypt(ctx, to, &to_length, from, from_length) == 1); @@ -980,7 +984,11 @@ sign(p_rsa, text_SV) CHECK_OPEN_SSL(ctx); CHECK_OPEN_SSL(EVP_PKEY_sign_init(ctx)); /* FIXME: Issue setting padding in some cases */ - CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); + int sign_pad = p_rsa->padding; + if (p_rsa->padding != RSA_NO_PADDING) { + sign_pad = RSA_PKCS1_PSS_PADDING; + } + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, sign_pad) > 0); EVP_MD* md = get_md_bynid(p_rsa->hashMode); CHECK_OPEN_SSL(md != NULL); @@ -1040,8 +1048,11 @@ PPCODE: CHECK_OPEN_SSL(ctx); CHECK_OPEN_SSL(EVP_PKEY_verify_init(ctx) == 1); /* FIXME: Issue setting padding in some cases */ - CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, p_rsa->padding) > 0); - + int verify_pad = p_rsa->padding; + if (p_rsa->padding != RSA_NO_PADDING) { + verify_pad = RSA_PKCS1_PSS_PADDING; + } + CHECK_OPEN_SSL(EVP_PKEY_CTX_set_rsa_padding(ctx, verify_pad) > 0); EVP_MD* md = get_md_bynid(p_rsa->hashMode); CHECK_OPEN_SSL(md != NULL); diff --git a/t/padding.t b/t/padding.t new file mode 100644 index 0000000..092f50c --- /dev/null +++ b/t/padding.t @@ -0,0 +1,160 @@ +use strict; +use Test::More; + +use Crypt::OpenSSL::Random; +use Crypt::OpenSSL::RSA; +use Crypt::OpenSSL::Guess qw(openssl_version); + +my ($major, $minor, $patch) = openssl_version; + +BEGIN { + plan tests => 87 + ( UNIVERSAL::can( "Crypt::OpenSSL::RSA", "use_sha512_hash" ) ? 4 * 5 : 0 ); +} + +sub _Test_Encrypt_And_Decrypt { + my ( $p_plaintext_length, $p_rsa, $p_check_private_encrypt, $padding, $hash ) = @_; + + my ( $ciphertext, $decoded_text ); + my $plaintext = pack( + "C${p_plaintext_length}", + ( + 1, 255, 0, 128, 4, # Make sure these characters work + map { int( rand 256 ) } ( 1 .. $p_plaintext_length - 5 ) + ) + ); + ok( $ciphertext = $p_rsa->encrypt($plaintext), "Padding method $padding is valid for encrypting with $hash" ); + ok( $decoded_text = $p_rsa->decrypt($ciphertext), "Padding method $padding is valid for decrypting with $hash" ); + ok( $decoded_text eq $plaintext ); + + if ($p_check_private_encrypt) { + ok( $ciphertext = $p_rsa->private_encrypt($plaintext), "Padding method $padding is valid for private_encrypt with $hash" ); + ok( $decoded_text = $p_rsa->public_decrypt($ciphertext), "Padding method $padding is valid for private_decrypt with $hash" ); + ok( $decoded_text eq $plaintext ); + } +} + +sub _Test_Sign_And_Verify { + my ( $p_plaintext_length, $rsa, $rsa_pub, $padding, $hash ) = @_; + + my $plaintext = pack( + "C${p_plaintext_length}", + ( + 1, 255, 0, 128, 4, # Make sure these characters work + map { int( rand 256 ) } ( 1 .. $p_plaintext_length - 5 ) + ) + ); + + my $sig = eval { $rsa->sign($plaintext) }; + + SKIP: { + skip "OpenSSL error: illegal or unsupported padding mode - $hash", 6 if $@ =~ /illegal or unsupported padding mode/i; + skip "OpenSSL error: invalid digest - $hash", 6 if $@ =~ /invalid digest/i; + ok(!$@, "Padding method $padding is valid for signing with $hash"); + ok( $rsa_pub->verify( $plaintext, $sig ), "Padding method $padding is valid for verifying with $hash"); + + my $false_sig = unpack "H*", $sig; + $false_sig =~ tr/[a-f]/[0a-d]/; + ok( !$rsa_pub->verify( $plaintext, pack( "H*", $false_sig )), "rsa_pub: False signature does not verify"); + ok( !$rsa->verify( $plaintext, pack( "H*", $false_sig )), "rsa: False signature does not verify"); + + my $sig_of_other = $rsa->sign("different"); + ok( !$rsa_pub->verify( $plaintext, $sig_of_other ), "rsa_pub: plaintext does not match signature" ); + ok( !$rsa->verify( $plaintext, $sig_of_other ), "rsa: plaintext does not match signature"); + } +} + +Crypt::OpenSSL::Random::random_seed("OpenSSL needs at least 32 bytes."); +Crypt::OpenSSL::RSA->import_random_seed(); + +my $rsa = Crypt::OpenSSL::RSA->generate_key(2048); +ok( $rsa->size() * 8 == 2048); +ok( $rsa->check_key() ); + +my $private_key_string = $rsa->get_private_key_string(); +my $public_key_string = $rsa->get_public_key_string(); + +ok( $private_key_string and $public_key_string ); + +my $plaintext = "The quick brown fox jumped over the lazy dog"; +my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key_string); +ok( $plaintext eq $rsa_priv->decrypt( $rsa_priv->encrypt($plaintext) ) ); + +my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($public_key_string); + +my @unsupported_paddings = qw/pkcs1 sslv23/; + +$plaintext .= $plaintext x 5; +# pkcs1 sslv23 are unsupported methods +foreach my $pad (@unsupported_paddings) { + my $method = "use_${pad}_padding"; + SKIP: { + skip "OpenSSL version less than 3.0 supports sslv23", 1 + if $major lt '3.0' && $pad eq 'sslv23'; + eval { + $rsa->$method; + }; + ok($@, "Padding method $pad unsupported"); + } +} + +my @supported_paddings = qw/no pkcs1_pss pkcs1_oaep/; +# no pkcs1_pss pkcs1_oaep are supported methods +foreach my $pad (@supported_paddings) { + my $method = "use_${pad}_padding"; + eval { + $rsa->$method; + }; + ok(!$@, "Padding method $pad supported"); +} + +my @hashes = qw/md5 sha1 sha224 sha256 sha384 sha512 ripemd160/; # whirlpool/; + +my %padding_methods = ( + 'no' => {'sign' => 1, 'encrypt' => 1, 'pad' => 0}, + 'pkcs1_pss' => {'sign' => 1, 'encrypt' => 0, 'pad' => 1}, + 'pkcs1_oaep' => {'sign' => 0, 'encrypt' => 1, 'pad' => 42}, + 'pkcs1' => {'sign' => 0, 'encrypt' => 0, 'pad' => 11}, + #'sslv23' => {'sign' => 0, 'encrypt' => 0, 'pad' => 11}, + ); + + +foreach my $padding (keys %padding_methods) { + diag $padding; + foreach my $hash (@hashes) { + next if $hash ne 'sha256' && $padding eq 'x931'; + my $props = $padding_methods{$padding}; + my $sign = $props->{sign}; + my $encrypt = $props->{encrypt}; + my $pad = $props->{pad}; + + my $hash_mth = "use_${hash}_hash"; + $rsa->$hash_mth; + $rsa_pub->$hash_mth; + my $method = "use_${padding}_padding"; + if ($sign || $encrypt ) { + $rsa->$method; + $rsa_pub->$method; + } + # Valid signing methods + if ($sign && $pad) { + _Test_Sign_And_Verify( $rsa->size() - $pad, $rsa, $rsa_pub, $padding, $hash ); + } + + # Invalid signing methods + if ((!$sign) && $pad) { + eval { + $rsa->$method; + $rsa->sign($plaintext); + }; + ok(defined $@, "Padding $padding is invalid for signing"); + } + + # Valid encryption methods with padding + if ($encrypt) { + _Test_Encrypt_And_Decrypt( $rsa->size() - $pad, $rsa, 0, $padding, $hash ); + } + + } +} + +# Try From 60a4b569e53f5be801905ab7ac3d79fc8d79aa14 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Sat, 1 Nov 2025 21:09:34 -0300 Subject: [PATCH 38/49] Update README files to reflect pod updates --- README | 47 +++++++++++++++++++++++++++++++++++++++++++---- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/README b/README index 4fe1a46..0ed8661 100644 --- a/README +++ b/README @@ -13,7 +13,7 @@ SYNOPSIS $ciphertext = $rsa->encrypt($plaintext); $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($key_string); - $plaintext = $rsa->encrypt($ciphertext); + $plaintext = $rsa->decrypt($ciphertext); $rsa = Crypt::OpenSSL::RSA->generate_key(1024); # or $rsa = Crypt::OpenSSL::RSA->generate_key(1024, $prime); @@ -28,6 +28,15 @@ SYNOPSIS $signature = $rsa_priv->sign($plaintext); print "Signed correctly\n" if ($rsa->verify($plaintext, $signature)); +SECURITY + Version 0.35 makes the use of PKCS#1 v1.5 padding a fatal error. It is + very difficult to implement PKCS#1 v1.5 padding securely. If you are + still using RSA in in general, you should be looking at alternative + encryption algorithms. Version 0.36 implements RSA-PSS padding (PKCS#1 + v2.1) and makes setting an invalid padding a fatal error. Note, + PKCS1_OAEP can only be used for encryption and PKCS1_PSS can only be + used for signing. + DESCRIPTION "Crypt::OpenSSL::RSA" provides the ability to RSA encrypt strings which are somewhat shorter than the block size of a key. It also allows for @@ -48,6 +57,10 @@ Class Methods The padding is set to PKCS1_OAEP, but can be changed with the "use_xxx_padding" methods. + Note, PKCS1_OAEP can only be used for encryption. You must + specifically call use_pkcs1_pss_padding (or use_pkcs1_pss_padding) + prior to signing operations. + new_private_key Create a new "Crypt::OpenSSL::RSA" object by loading a private key in from an string containing the Base64/DER encoding of the PKCS1 @@ -140,20 +153,45 @@ Instance Methods verify Check the signature on a text. +Padding Methods + Versions prior to 0.35 allowed using pkcs1 padding for both encryption + and signature operations but has been disabled for security reasons. + + While use_no_padding can be used for encryption or signature operations + use_pkcs1_pss_padding is used for signature operations and + use_pkcs1_oaep_padding is used for encryption operations. + + Version 0.38 sets the appropriate padding for each operation unless + use_no_padding is called before either operation. + use_no_padding Use raw RSA encryption. This mode should only be used to implement cryptographically sound padding modes in the application code. Encrypting user data directly with RSA is insecure. use_pkcs1_padding - Use PKCS #1 v1.5 padding. This currently is the most widely used - mode of padding. + 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. + + Marvin Attack + use_pkcs1_oaep_padding Use "EME-OAEP" padding as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding parameter. This mode of padding is recommended for all new applications. It is the default mode used by - "Crypt::OpenSSL::RSA". + "Crypt::OpenSSL::RSA" but is only valid for encryption/decryption. + + use_pkcs1_pss_padding + Use 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. + + Note: RSA-PSS cannot be used for encryption/decryption and results in + a fatal error. Call use_pkcs1_oaep_padding for encryption operations. use_sslv23_padding Use "PKCS #1 v1.5" padding with an SSL-specific modification that @@ -161,6 +199,7 @@ Instance Methods Not available since OpenSSL 3. +Hash/Digest Methods use_md5_hash Use the RFC 1321 MD5 hashing algorithm by Ron Rivest when signing and verifying messages. diff --git a/README.md b/README.md index d0f37a8..4b85a6c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Crypt::OpenSSL::RSA - RSA encoding and decoding, using the openSSL libraries $ciphertext = $rsa->encrypt($plaintext); $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($key_string); - $plaintext = $rsa->encrypt($ciphertext); + $plaintext = $rsa->decrypt($ciphertext); $rsa = Crypt::OpenSSL::RSA->generate_key(1024); # or $rsa = Crypt::OpenSSL::RSA->generate_key(1024, $prime); @@ -31,6 +31,15 @@ Crypt::OpenSSL::RSA - RSA encoding and decoding, using the openSSL libraries $signature = $rsa_priv->sign($plaintext); print "Signed correctly\n" if ($rsa->verify($plaintext, $signature)); +# SECURITY + +Version 0.35 makes the use of PKCS#1 v1.5 padding a fatal error. It is +very difficult to implement PKCS#1 v1.5 padding securely. If you are still +using RSA in in general, you should be looking at alternative encryption +algorithms. Version 0.36 implements RSA-PSS padding (PKCS#1 v2.1) and makes +setting an invalid padding a fatal error. Note, PKCS1\_OAEP can only be used +for encryption and PKCS1\_PSS can only be used for signing. + # DESCRIPTION `Crypt::OpenSSL::RSA` provides the ability to RSA encrypt strings which are @@ -54,6 +63,10 @@ this (never documented) behavior is no longer the case. The padding is set to PKCS1\_OAEP, but can be changed with the `use_xxx_padding` methods. + Note, PKCS1\_OAEP can only be used for encryption. You must specifically + call use\_pkcs1\_pss\_padding (or use\_pkcs1\_pss\_padding) prior to signing + operations. + - new\_private\_key Create a new `Crypt::OpenSSL::RSA` object by loading a private key in @@ -165,6 +178,18 @@ this (never documented) behavior is no longer the case. Check the signature on a text. +# Padding Methods + +Versions prior to 0.35 allowed using pkcs1 padding for both encryption +and signature operations but has been disabled for security reasons. + +While **use\_no\_padding** can be used for encryption or signature operations +**use\_pkcs1\_pss\_padding** is used for signature operations and +**use\_pkcs1\_oaep\_padding** is used for encryption operations. + +Version 0.38 sets the appropriate padding for each operation unless +**use\_no\_padding** is called before either operation. + - use\_no\_padding Use raw RSA encryption. This mode should only be used to implement @@ -173,15 +198,28 @@ this (never documented) behavior is no longer the case. - use\_pkcs1\_padding - Use PKCS #1 v1.5 padding. This currently is the most widely used mode - of padding. + 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. + + [Marvin Attack](https://github.com/tomato42/marvin-toolkit/blob/master/README.md) - use\_pkcs1\_oaep\_padding Use `EME-OAEP` padding as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding parameter. This mode of padding is recommended for all new applications. It is the default mode used by - `Crypt::OpenSSL::RSA`. + `Crypt::OpenSSL::RSA` but is only valid for encryption/decryption. + +- use\_pkcs1\_pss\_padding + + Use `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. + + **Note**: RSA-PSS cannot be used for encryption/decryption and results in a + fatal error. Call `use_pkcs1_oaep_padding` for encryption operations. - use\_sslv23\_padding @@ -190,6 +228,8 @@ this (never documented) behavior is no longer the case. Not available since OpenSSL 3. +# Hash/Digest Methods + - use\_md5\_hash Use the RFC 1321 MD5 hashing algorithm by Ron Rivest when signing and From 06d12750b5bf4d0f7fb43644bad04628de6cc1fc Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Fri, 31 Oct 2025 22:21:18 -0300 Subject: [PATCH 39/49] Free openssl objects when done --- RSA.xs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/RSA.xs b/RSA.xs index 7b2ba3e..d6017ed 100644 --- a/RSA.xs +++ b/RSA.xs @@ -348,6 +348,7 @@ SV* rsa_crypt(rsaData* p_rsa, SV* p_from, CHECK_OPEN_SSL(p_crypt(ctx, to, &to_length, from, from_length) == 1); EVP_PKEY_CTX_free(ctx); + OSSL_LIB_CTX_free(ossllibctx); #else to_length = p_crypt( from_length, from, (unsigned char*) to, p_rsa->rsa, p_rsa->padding); @@ -1008,6 +1009,8 @@ sign(p_rsa, text_SV) CHECK_OPEN_SSL(EVP_PKEY_sign(ctx, signature, &signature_length, digest, get_digest_length(p_rsa->hashMode)) == 1); CHECK_OPEN_SSL(signature); + EVP_MD_free(md); + EVP_PKEY_CTX_free(ctx); #else CHECK_OPEN_SSL(RSA_sign(p_rsa->hashMode, digest, @@ -1084,6 +1087,10 @@ PPCODE: CHECK_OPEN_SSL(0); break; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD_free(md); + EVP_PKEY_CTX_free(ctx); +#endif } int From 4bfec6d5af26cbdcf4b1999d4cc24f9132d2a308 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Mon, 3 Nov 2025 20:07:38 -0400 Subject: [PATCH 40/49] Add blurb about JWTs for padding changes --- README | 5 +++++ README.md | 5 +++++ RSA.pm | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/README b/README index 0ed8661..a6587a3 100644 --- a/README +++ b/README @@ -164,6 +164,11 @@ Padding Methods Version 0.38 sets the appropriate padding for each operation unless use_no_padding is called before either operation. + Note: while "pkcs1-pss" is the effective replacement for "pkcs1" your + use case may require some additional steps. JSON Web Tokens (JWT) for + instance require the algorithm to be changed from "RS256" for "pkcs1" + (SHA1256) to "PS256" for "pkcs1-pss" (SHA-256 and MGF1 with SHA-256) + use_no_padding Use raw RSA encryption. This mode should only be used to implement cryptographically sound padding modes in the application code. diff --git a/README.md b/README.md index 4b85a6c..9d90808 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,11 @@ While **use\_no\_padding** can be used for encryption or signature operations Version 0.38 sets the appropriate padding for each operation unless **use\_no\_padding** is called before either operation. +**Note:** while "pkcs1-pss" is the effective replacement for "pkcs1" your +use case may require some additional steps. JSON Web Tokens (JWT) for +instance require the algorithm to be changed from "RS256" for "pkcs1" +(SHA1256) to "PS256" for "pkcs1-pss" (SHA-256 and MGF1 with SHA-256) + - use\_no\_padding Use raw RSA encryption. This mode should only be used to implement diff --git a/RSA.pm b/RSA.pm index 346d609..42a296e 100644 --- a/RSA.pm +++ b/RSA.pm @@ -255,6 +255,11 @@ B is used for encryption operations. Version 0.38 sets the appropriate padding for each operation unless B is called before either operation. +B while C is the effective replacement for your +use case may require some additional steps. JSON Web Tokens (JWT) for +instance require the algorithm to be changed from "RS256" for "pkcs1" +(SHA1256) to "PS256" for "pkcs1-pss" (SHA-256 and MGF1 with SHA-256) + =over =item use_no_padding From bb1907f96905637bfc3d688ebff096a4570d1881 Mon Sep 17 00:00:00 2001 From: Gabor Szabo Date: Fri, 30 Jan 2026 10:15:02 +0200 Subject: [PATCH 41/49] Remove debian:buster from the CI As it is not supported any more and thus apt-get is failing See also: https://www.debian.org/releases/buster/ --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 1b2670b..09251a9 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -54,7 +54,7 @@ jobs: fail-fast: false matrix: os-version: - - debian:buster # OpenSSL 1.1.1 + # - debian:buster # OpenSSL 1.1.1 - debian:bullseye # OpenSSL 1.1.1 - debian:bookworm # OpenSSL 3.0.x - almalinux:9 # OpenSSL with new crypto policies (RHEL-compatible) From f4f9b54cabff92dad1d8d873127a7557e983a895 Mon Sep 17 00:00:00 2001 From: Gabor Szabo Date: Fri, 30 Jan 2026 10:34:49 +0200 Subject: [PATCH 42/49] Add dependabot It will send PRs when newer versions of github actions are released. --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8ac6b8c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" From 9da97b1dfbe01083b82fccad45bcd57b25ebf7b6 Mon Sep 17 00:00:00 2001 From: Gabor Szabo Date: Fri, 30 Jan 2026 10:41:40 +0200 Subject: [PATCH 43/49] Separate the apt-get and the yum steps And protect them using if-statements --- .github/workflows/testsuite.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 1b2670b..16ea334 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -62,11 +62,15 @@ jobs: container: ${{ matrix.os-version }} steps: - uses: actions/checkout@v4 - - name: Install dependencies + - name: Install dependencies using apt-get + if: ${{ matrix.os-version == 'debian:bullseye' || matrix.os-version == 'debian:bookworm' }} run: | - (apt-get update && - apt-get install -y openssl perl make gcc libssl-dev sudo curl) || - (yum install --skip-broken -y openssl perl make gcc openssl-devel sudo curl) + apt-get update + apt-get install -y openssl perl make gcc libssl-dev sudo curl + - name: Install dependencies using yum + if: ${{ matrix.os-version == 'almalinux:9' }} + run: | + yum install --skip-broken -y openssl perl make gcc openssl-devel sudo curl - run: openssl version - run: perl -V - name: uses install-with-cpm From 2db8425d400e01914df1148c408ed50c5cbbde0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:12:41 +0000 Subject: [PATCH 44/49] Bump actions/checkout from 4 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/testsuite.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 09251a9..c555474 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -28,7 +28,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - run: openssl version - run: perl -V - name: uses install-with-cpm @@ -61,7 +61,7 @@ jobs: container: ${{ matrix.os-version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install dependencies run: | (apt-get update && @@ -117,7 +117,7 @@ jobs: container: perldocker/perl-tester:${{ matrix.perl-version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - run: openssl version - run: perl -V - name: Deps for testing @@ -149,7 +149,7 @@ jobs: perl-version: [latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Perl run: | # skip installing perl if it is already installed. From df0687de691e60bf4ff47e8e057a6bbc1374c153 Mon Sep 17 00:00:00 2001 From: Todd Rinaldo Date: Sun, 1 Feb 2026 12:17:11 -0600 Subject: [PATCH 45/49] Update checkout action version from v4 to v6 --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 45cde6d..141c75b 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -61,7 +61,7 @@ jobs: container: ${{ matrix.os-version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install dependencies using apt-get if: ${{ matrix.os-version == 'debian:bullseye' || matrix.os-version == 'debian:bookworm' }} run: | From 7ba5a5ea2b930dfda583f2e0e1c16d174f60626a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Sun, 8 Feb 2026 21:40:31 -0700 Subject: [PATCH 46/49] chore: fix META URLs, gitignore dupes, build_requires, add trixie CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - META_MERGE resources: http:// → https:// (license, homepage, repository) - META_MERGE build_requires: 'Test' → 'Test::More' (all tests use Test::More) - .gitignore: remove duplicate *.gcov and *.gcno entries - CI: add debian:trixie to OpenSSL matrix (3.4.x coverage) - CI: simplify apt-get condition with startsWith('debian:') Co-Authored-By: Claude Opus 4.6 --- .github/workflows/testsuite.yml | 3 ++- .gitignore | 2 -- Makefile.PL | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 141c75b..8433835 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -57,13 +57,14 @@ jobs: # - debian:buster # OpenSSL 1.1.1 - debian:bullseye # OpenSSL 1.1.1 - debian:bookworm # OpenSSL 3.0.x + - debian:trixie # OpenSSL 3.4.x (Debian 13) - almalinux:9 # OpenSSL with new crypto policies (RHEL-compatible) container: ${{ matrix.os-version }} steps: - uses: actions/checkout@v6 - name: Install dependencies using apt-get - if: ${{ matrix.os-version == 'debian:bullseye' || matrix.os-version == 'debian:bookworm' }} + if: ${{ startsWith(matrix.os-version, 'debian:') }} run: | apt-get update apt-get install -y openssl perl make gcc libssl-dev sudo curl diff --git a/.gitignore b/.gitignore index 433618c..b7a4352 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,5 @@ *.o *.gcov *.gcno -*.gcov *.gcda -*.gcno *.ERR diff --git a/Makefile.PL b/Makefile.PL index 588bd5b..7fb2978 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -47,13 +47,13 @@ WriteMakefile( 'Crypt::OpenSSL::Guess' => '0.11', }, build_requires => { - 'Test' => 0, # For testing + 'Test::More' => 0, }, resources => { - 'license' => 'http://dev.perl.org/licenses/', - 'homepage' => 'http://github.com/cpan-authors/Crypt-OpenSSL-RSA', + 'license' => 'https://dev.perl.org/licenses/', + 'homepage' => 'https://github.com/cpan-authors/Crypt-OpenSSL-RSA', 'bugtracker' => 'https://github.com/cpan-authors/Crypt-OpenSSL-RSA/issues', - 'repository' => 'http://github.com/cpan-authors/Crypt-OpenSSL-RSA', + 'repository' => 'https://github.com/cpan-authors/Crypt-OpenSSL-RSA', } } ); From fb5be11af9023f82ca7e5f1c127c74cfb3fc4a01 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Sat, 14 Feb 2026 23:08:17 -0400 Subject: [PATCH 47/49] Don't include whrlpool.h if whirlpool is disabled --- RSA.xs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RSA.xs b/RSA.xs index 6ff3a0d..35a41e1 100644 --- a/RSA.xs +++ b/RSA.xs @@ -12,9 +12,11 @@ #include #if OPENSSL_VERSION_NUMBER >= 0x10000000 && OPENSSL_VERSION_NUMBER < 0x30000000 #ifndef LIBRESSL_VERSION_NUMBER +#ifndef OPENSSL_NO_WHIRLPOOL #include #endif #endif +#endif #include #include #include From 1ff23f4ffa4d180a5278092e549732073b6b69ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Thu, 19 Feb 2026 00:18:01 -0700 Subject: [PATCH 48/49] fix: check_key() EVP_PKEY_CTX leak on OpenSSL 3.x EVP_PKEY_CTX allocated by EVP_PKEY_CTX_new_from_pkey() was never freed, leaking memory on every check_key() call. Also add a NULL check on the context allocation. Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RSA.xs b/RSA.xs index 6ff3a0d..7ef5655 100644 --- a/RSA.xs +++ b/RSA.xs @@ -842,7 +842,9 @@ check_key(p_rsa) } #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_pkey(NULL, p_rsa->rsa, NULL); + CHECK_OPEN_SSL(pctx); RETVAL = EVP_PKEY_private_check(pctx); + EVP_PKEY_CTX_free(pctx); #else RETVAL = RSA_check_key(p_rsa->rsa); #endif From d221f20a7d392146e295c2b2fab5ee2bdbc57d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Wed, 11 Mar 2026 06:08:10 -0600 Subject: [PATCH 49/49] fix: remove thread-unsafe static buffer in get_message_digest() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The static buffer `unsigned char m[EVP_MAX_MD_SIZE]` at file scope meant all calls shared the same memory — a data race in threaded Perl (ithread or multiplicity builds). Change the function to accept a caller-provided buffer instead. Each call site now declares its own stack-local `digest_buf[EVP_MAX_MD_SIZE]`, eliminating the shared mutable state without any heap allocation. Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/RSA.xs b/RSA.xs index ffb3325..3c4a084 100644 --- a/RSA.xs +++ b/RSA.xs @@ -204,14 +204,11 @@ EVP_MD *get_md_bynid(int hash_method) } } #endif -unsigned char* get_message_digest(SV* text_SV, int hash_method) +unsigned char* get_message_digest(SV* text_SV, int hash_method, unsigned char* md) { STRLEN text_length; unsigned char* text; - unsigned char *md; - static unsigned char m[EVP_MAX_MD_SIZE]; text = (unsigned char*) SvPV(text_SV, text_length); - md = m; switch(hash_method) { @@ -977,6 +974,7 @@ sign(p_rsa, text_SV) PREINIT: UNSIGNED_CHAR *signature; unsigned char* digest; + unsigned char digest_buf[EVP_MAX_MD_SIZE]; SIZE_T_UNSIGNED_INT signature_length; CODE: { @@ -986,7 +984,7 @@ sign(p_rsa, text_SV) } CHECK_NEW(signature, EVP_PKEY_get_size(p_rsa->rsa), UNSIGNED_CHAR); - CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); + CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode, digest_buf)); #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY_CTX *ctx; ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */); @@ -1044,6 +1042,7 @@ PPCODE: { unsigned char* sig; unsigned char* digest; + unsigned char digest_buf[EVP_MAX_MD_SIZE]; STRLEN sig_length; sig = (unsigned char*) SvPV(sig_SV, sig_length); @@ -1052,7 +1051,7 @@ PPCODE: croak("Signature longer than key"); } - CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode)); + CHECK_OPEN_SSL(digest = get_message_digest(text_SV, p_rsa->hashMode, digest_buf)); #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY_CTX *ctx; ctx = EVP_PKEY_CTX_new(p_rsa->rsa, NULL /* no engine */);