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>
* 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

View File

@ -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));

View File

@ -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];