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