File qpdf-fix-openssl3.patch of Package qpdf

From b745920961bd44cbe3ded956c7b79f47c142b118 Mon Sep 17 00:00:00 2001
From: Jay Berkenbilt <ejb@ql.org>
Date: Sat, 8 Oct 2022 16:10:15 -0400
Subject: [PATCH 1/2] Allow specific performance tests to be run

---
 ChangeLog         |  5 +++++
 performance_check | 20 +++++++++++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

Index: qpdf-10.3.1/performance_check
===================================================================
--- qpdf-10.3.1.orig/performance_check
+++ qpdf-10.3.1/performance_check
@@ -41,16 +41,25 @@ my $default_maxtime = 20;
 
 sub usage
 {
-    die "
+    warn "
 Usage: $whoami [ args ]
   --dir dir           test on all files in dir (default: $default_test_dir)
   --file file         test only on the named file
   --executable qpdf   use the specified qpdf (default: $default_executable)
   --workdir           where to write output pdfs (default: $default_workdir)
   --maxtime           maximum time for a test; 0 means unlimited (default: $default_maxtime)
+  --test regexp       run only tests that match specified pattern
+
+Tests:
 ";
+    foreach my $t (@tests)
+    {
+        warn "  $t->[0]\n";
+    }
+    exit 2;
 }
 
+my $test_re = undef;
 while (@ARGV)
 {
     my $arg = shift(@ARGV);
@@ -81,6 +90,11 @@ while (@ARGV)
         usage() unless @ARGV;
         $maxtime = shift(@ARGV);
     }
+    elsif ('--test' eq $arg)
+    {
+        usage() unless @ARGV;
+        $test_re = shift(@ARGV);
+    }
     else
     {
         usage();
@@ -164,6 +178,11 @@ sub run_tests
     foreach my $test (@tests)
     {
         my ($name, $args) = @$test;
+        if ((defined $test_re) && $name !~ m/$test_re/)
+        {
+            print " skipping test $name\n";
+            next;
+        }
         print " test: $name\n";
         $args = filter_args($args);
         if (! defined $args)
Index: qpdf-10.3.1/libqpdf/QPDFCrypto_openssl.cc
===================================================================
--- qpdf-10.3.1.orig/libqpdf/QPDFCrypto_openssl.cc
+++ qpdf-10.3.1/libqpdf/QPDFCrypto_openssl.cc
@@ -1,6 +1,7 @@
 #include <qpdf/QPDFCrypto_openssl.hh>
 
 #include <cstring>
+#include <memory>
 #include <stdexcept>
 #include <string>
 
@@ -18,6 +19,60 @@
 
 #include <qpdf/QIntC.hh>
 
+#ifndef QPDF_OPENSSL_1
+namespace
+{
+    class RC4Loader
+    {
+      public:
+        static EVP_CIPHER const* getRC4();
+        ~RC4Loader();
+
+      private:
+        RC4Loader();
+        OSSL_PROVIDER* legacy;
+        OSSL_LIB_CTX* libctx;
+        EVP_CIPHER* rc4;
+    };
+} // namespace
+
+EVP_CIPHER const*
+RC4Loader::getRC4()
+{
+    static auto loader = std::shared_ptr<RC4Loader>(new RC4Loader());
+    return loader->rc4;
+}
+
+RC4Loader::RC4Loader()
+{
+    libctx = OSSL_LIB_CTX_new();
+    if (libctx == nullptr) {
+        throw std::runtime_error("unable to create openssl library context");
+        return;
+    }
+    legacy = OSSL_PROVIDER_load(libctx, "legacy");
+    if (legacy == nullptr) {
+        OSSL_LIB_CTX_free(libctx);
+        throw std::runtime_error("unable to load openssl legacy provider");
+        return;
+    }
+    rc4 = EVP_CIPHER_fetch(libctx, "RC4", nullptr);
+    if (rc4 == nullptr) {
+        OSSL_PROVIDER_unload(legacy);
+        OSSL_LIB_CTX_free(libctx);
+        throw std::runtime_error("unable to load openssl rc4 algorithm");
+        return;
+    }
+}
+
+RC4Loader::~RC4Loader()
+{
+    EVP_CIPHER_free(rc4);
+    OSSL_PROVIDER_unload(legacy);
+    OSSL_LIB_CTX_free(libctx);
+}
+#endif // not QPDF_OPENSSL_1
+
 static void
 bad_bits(int bits)
 {
@@ -42,35 +97,9 @@ check_openssl(int status)
 }
 
 QPDFCrypto_openssl::QPDFCrypto_openssl() :
-#ifdef QPDF_OPENSSL_1
-    rc4(EVP_rc4()),
-#endif
     md_ctx(EVP_MD_CTX_new()),
     cipher_ctx(EVP_CIPHER_CTX_new())
 {
-#ifndef QPDF_OPENSSL_1
-    libctx = OSSL_LIB_CTX_new();
-    if (libctx == nullptr)
-    {
-        throw std::runtime_error("unable to create openssl library context");
-        return;
-    }
-    legacy = OSSL_PROVIDER_load(libctx, "legacy");
-    if (legacy == nullptr)
-    {
-        OSSL_LIB_CTX_free(libctx);
-        throw std::runtime_error("unable to load openssl legacy provider");
-        return;
-    }
-    rc4 = EVP_CIPHER_fetch(libctx, "RC4", nullptr);
-    if (rc4 == nullptr)
-    {
-        OSSL_PROVIDER_unload(legacy);
-        OSSL_LIB_CTX_free(libctx);
-        throw std::runtime_error("unable to load openssl rc4 algorithm");
-        return;
-    }
-#endif
     memset(md_out, 0, sizeof(md_out));
     EVP_MD_CTX_init(md_ctx);
     EVP_CIPHER_CTX_init(cipher_ctx);
@@ -81,11 +110,6 @@ QPDFCrypto_openssl::~QPDFCrypto_openssl(
     EVP_MD_CTX_reset(md_ctx);
     EVP_CIPHER_CTX_reset(cipher_ctx);
     EVP_CIPHER_CTX_free(cipher_ctx);
-#ifndef QPDF_OPENSSL_1
-    EVP_CIPHER_free(rc4);
-    OSSL_PROVIDER_unload(legacy);
-    OSSL_LIB_CTX_free(libctx);
-#endif
     EVP_MD_CTX_free(md_ctx);
 }
 
@@ -105,7 +129,7 @@ QPDFCrypto_openssl::MD5_init()
 void
 QPDFCrypto_openssl::SHA2_init(int bits)
 {
-    const EVP_MD* md = EVP_sha512();
+    static const EVP_MD* md = EVP_sha512();
     switch (bits)
     {
       case 256:
@@ -181,6 +205,11 @@ QPDFCrypto_openssl::SHA2_digest()
 void
 QPDFCrypto_openssl::RC4_init(unsigned char const* key_data, int key_len)
 {
+#ifdef QPDF_OPENSSL_1
+    static auto const rc4 = EVP_rc4();
+#else
+    static auto const rc4 = RC4Loader::getRC4();
+#endif
     check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx));
     if (key_len == -1)
     {
Index: qpdf-10.3.1/libqpdf/qpdf/QPDFCrypto_openssl.hh
===================================================================
--- qpdf-10.3.1.orig/libqpdf/qpdf/QPDFCrypto_openssl.hh
+++ qpdf-10.3.1/libqpdf/qpdf/QPDFCrypto_openssl.hh
@@ -55,13 +55,6 @@ class QPDFCrypto_openssl: public QPDFCry
     void rijndael_finalize() override;
 
   private:
-#ifdef QPDF_OPENSSL_1
-    EVP_CIPHER const* rc4;
-#else
-    OSSL_LIB_CTX* libctx;
-    OSSL_PROVIDER* legacy;
-    EVP_CIPHER* rc4;
-#endif
     EVP_MD_CTX* const md_ctx;
     EVP_CIPHER_CTX* const cipher_ctx;
     uint8_t md_out[EVP_MAX_MD_SIZE];
Index: qpdf-10.3.1/ChangeLog
===================================================================
--- qpdf-10.3.1.orig/ChangeLog
+++ qpdf-10.3.1/ChangeLog
@@ -1,5 +1,10 @@
 2021-03-11  Jay Berkenbilt  <ejb@ql.org>
 
+	* Fix major performance bug with the openssl crypto provider when
+	using OpenSSL 3. The legacy loader and rc4 algorithm was being
+	loaded with every call to the crypto provider instead of once in
+	the life of the program. Fixes #798.
+
 	* Add support for OpenSSL 3. Fixes #568.
 
 	The OpenSSL version is detected at compile-time. If you want to
openSUSE Build Service is sponsored by