2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-15 16:42:19 +00:00

Support OpenSSL 3 (fixes #568)

This commit is contained in:
Jay Berkenbilt 2021-11-04 17:21:34 -04:00
parent 043779187e
commit 3794f8e2ad
3 changed files with 89 additions and 5 deletions

View File

@ -1,5 +1,20 @@
2021-11-04 Jay Berkenbilt <ejb@ql.org> 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 range check in QPDFNumberTreeObjectHelper (fuzz issue 37740).
* Add QIntC::range_check_substract to do range checking on * Add QIntC::range_check_substract to do range checking on

View File

@ -4,11 +4,20 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#if (defined(__GNUC__) || defined(__clang__))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include <openssl/err.h> #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> #include <qpdf/QIntC.hh>
static void static void
bad_bits(int bits) bad_bits(int bits)
{ {
@ -33,8 +42,35 @@ check_openssl(int status)
} }
QPDFCrypto_openssl::QPDFCrypto_openssl() : 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)); memset(md_out, 0, sizeof(md_out));
EVP_MD_CTX_init(md_ctx); EVP_MD_CTX_init(md_ctx);
EVP_CIPHER_CTX_init(cipher_ctx); EVP_CIPHER_CTX_init(cipher_ctx);
@ -45,6 +81,11 @@ QPDFCrypto_openssl::~QPDFCrypto_openssl()
EVP_MD_CTX_reset(md_ctx); EVP_MD_CTX_reset(md_ctx);
EVP_CIPHER_CTX_reset(cipher_ctx); EVP_CIPHER_CTX_reset(cipher_ctx);
EVP_CIPHER_CTX_free(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); EVP_MD_CTX_free(md_ctx);
} }
@ -100,7 +141,12 @@ QPDFCrypto_openssl::SHA2_update(unsigned char const* data, size_t len)
void void
QPDFCrypto_openssl::MD5_finalize() 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)); check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr));
} }
@ -109,7 +155,12 @@ QPDFCrypto_openssl::MD5_finalize()
void void
QPDFCrypto_openssl::SHA2_finalize() 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)); 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))); strlen(reinterpret_cast<const char*>(key_data)));
} }
check_openssl( 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_CIPHER_CTX_set_key_length(cipher_ctx, key_len));
check_openssl( check_openssl(
EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr)); EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr));

View File

@ -3,6 +3,14 @@
#include <qpdf/QPDFCryptoImpl.hh> #include <qpdf/QPDFCryptoImpl.hh>
#include <string> #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> #include <openssl/rand.h>
#ifdef OPENSSL_IS_BORINGSSL #ifdef OPENSSL_IS_BORINGSSL
#include <openssl/cipher.h> #include <openssl/cipher.h>
@ -10,6 +18,9 @@
#else #else
#include <openssl/evp.h> #include <openssl/evp.h>
#endif #endif
#if (defined(__GNUC__) || defined(__clang__))
# pragma GCC diagnostic pop
#endif
class QPDFCrypto_openssl: public QPDFCryptoImpl class QPDFCrypto_openssl: public QPDFCryptoImpl
{ {
@ -44,6 +55,13 @@ class QPDFCrypto_openssl: public QPDFCryptoImpl
void rijndael_finalize() override; void rijndael_finalize() override;
private: 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_MD_CTX* const md_ctx;
EVP_CIPHER_CTX* const cipher_ctx; EVP_CIPHER_CTX* const cipher_ctx;
uint8_t md_out[EVP_MAX_MD_SIZE]; uint8_t md_out[EVP_MAX_MD_SIZE];