aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2021-11-04 22:21:34 +0100
committerJay Berkenbilt <ejb@ql.org>2021-11-04 23:24:54 +0100
commit3794f8e2ad536db93ce780ae11f55d86a683c536 (patch)
treeb7d3568d3fccfb24b7f126b135d4cd4fc6a4d726
parent043779187e8050673078683492dd9cbe33474cb7 (diff)
downloadqpdf-3794f8e2ad536db93ce780ae11f55d86a683c536.tar.zst
Support OpenSSL 3 (fixes #568)
-rw-r--r--ChangeLog15
-rw-r--r--libqpdf/QPDFCrypto_openssl.cc61
-rw-r--r--libqpdf/qpdf/QPDFCrypto_openssl.hh18
3 files changed, 89 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 45b70fea..a1319681 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2021-11-04 Jay Berkenbilt <ejb@ql.org>
+ * Add support for OpenSSL 3. Fixes #568.
+
+ The OpenSSL version is detected at compile-time. If you want to
+ build with OpenSSL 3 on a system that has OpenSSL 1 installed, you
+ can run configure like this (or similar to this depending on how
+ you installed openssl3):
+
+ pc_openssl_CFLAGS=-I/path/to/openssl3/include \
+ pc_openssl_LIBS='-L/path/to/openssl3/lib64 -lssl -lcrypto' \
+ ./configure
+
+ where /path/to/openssl3 is wherever your OpenSSL 3 distribution is
+ installed. You may also need to set the LD_LIBRARY_PATH
+ environment variable if it's not installed in a standard location.
+
* Add range check in QPDFNumberTreeObjectHelper (fuzz issue 37740).
* Add QIntC::range_check_substract to do range checking on
diff --git a/libqpdf/QPDFCrypto_openssl.cc b/libqpdf/QPDFCrypto_openssl.cc
index 358040d5..427ce5bb 100644
--- a/libqpdf/QPDFCrypto_openssl.cc
+++ b/libqpdf/QPDFCrypto_openssl.cc
@@ -4,11 +4,20 @@
#include <stdexcept>
#include <string>
+#if (defined(__GNUC__) || defined(__clang__))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
#include <openssl/err.h>
+#ifndef QPDF_OPENSSL_1
+# include <openssl/provider.h>
+#endif
+#if (defined(__GNUC__) || defined(__clang__))
+# pragma GCC diagnostic pop
+#endif
#include <qpdf/QIntC.hh>
-
static void
bad_bits(int bits)
{
@@ -33,8 +42,35 @@ check_openssl(int status)
}
QPDFCrypto_openssl::QPDFCrypto_openssl() :
- md_ctx(EVP_MD_CTX_new()), cipher_ctx(EVP_CIPHER_CTX_new())
+#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);
@@ -45,6 +81,11 @@ 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);
}
@@ -100,7 +141,12 @@ QPDFCrypto_openssl::SHA2_update(unsigned char const* data, size_t len)
void
QPDFCrypto_openssl::MD5_finalize()
{
- if (EVP_MD_CTX_md(md_ctx))
+#ifdef QPDF_OPENSSL_1
+ auto md = EVP_MD_CTX_md(md_ctx);
+#else
+ auto md = EVP_MD_CTX_get0_md(md_ctx);
+#endif
+ if (md)
{
check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr));
}
@@ -109,7 +155,12 @@ QPDFCrypto_openssl::MD5_finalize()
void
QPDFCrypto_openssl::SHA2_finalize()
{
- if (EVP_MD_CTX_md(md_ctx))
+#ifdef QPDF_OPENSSL_1
+ auto md = EVP_MD_CTX_md(md_ctx);
+#else
+ auto md = EVP_MD_CTX_get0_md(md_ctx);
+#endif
+ if (md)
{
check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr));
}
@@ -137,7 +188,7 @@ QPDFCrypto_openssl::RC4_init(unsigned char const* key_data, int key_len)
strlen(reinterpret_cast<const char*>(key_data)));
}
check_openssl(
- EVP_EncryptInit_ex(cipher_ctx, EVP_rc4(), nullptr, nullptr, nullptr));
+ EVP_EncryptInit_ex(cipher_ctx, rc4, nullptr, nullptr, nullptr));
check_openssl(EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len));
check_openssl(
EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr));
diff --git a/libqpdf/qpdf/QPDFCrypto_openssl.hh b/libqpdf/qpdf/QPDFCrypto_openssl.hh
index 58f54c3f..eb369c8a 100644
--- a/libqpdf/qpdf/QPDFCrypto_openssl.hh
+++ b/libqpdf/qpdf/QPDFCrypto_openssl.hh
@@ -3,6 +3,14 @@
#include <qpdf/QPDFCryptoImpl.hh>
#include <string>
+#if (defined(__GNUC__) || defined(__clang__))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+#include <openssl/opensslv.h>
+#if !defined(OPENSSL_VERSION_MAJOR) || OPENSSL_VERSION_MAJOR < 3
+# define QPDF_OPENSSL_1
+#endif
#include <openssl/rand.h>
#ifdef OPENSSL_IS_BORINGSSL
#include <openssl/cipher.h>
@@ -10,6 +18,9 @@
#else
#include <openssl/evp.h>
#endif
+#if (defined(__GNUC__) || defined(__clang__))
+# pragma GCC diagnostic pop
+#endif
class QPDFCrypto_openssl: public QPDFCryptoImpl
{
@@ -44,6 +55,13 @@ class QPDFCrypto_openssl: public QPDFCryptoImpl
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];