Commit 3794f8e2ad536db93ce780ae11f55d86a683c536

Authored by Jay Berkenbilt
1 parent 04377918

Support OpenSSL 3 (fixes #568)

ChangeLog
1 1 2021-11-04 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Add support for OpenSSL 3. Fixes #568.
  4 +
  5 + The OpenSSL version is detected at compile-time. If you want to
  6 + build with OpenSSL 3 on a system that has OpenSSL 1 installed, you
  7 + can run configure like this (or similar to this depending on how
  8 + you installed openssl3):
  9 +
  10 + pc_openssl_CFLAGS=-I/path/to/openssl3/include \
  11 + pc_openssl_LIBS='-L/path/to/openssl3/lib64 -lssl -lcrypto' \
  12 + ./configure
  13 +
  14 + where /path/to/openssl3 is wherever your OpenSSL 3 distribution is
  15 + installed. You may also need to set the LD_LIBRARY_PATH
  16 + environment variable if it's not installed in a standard location.
  17 +
3 18 * Add range check in QPDFNumberTreeObjectHelper (fuzz issue 37740).
4 19  
5 20 * Add QIntC::range_check_substract to do range checking on
... ...
libqpdf/QPDFCrypto_openssl.cc
... ... @@ -4,11 +4,20 @@
4 4 #include <stdexcept>
5 5 #include <string>
6 6  
  7 +#if (defined(__GNUC__) || defined(__clang__))
  8 +# pragma GCC diagnostic push
  9 +# pragma GCC diagnostic ignored "-Wold-style-cast"
  10 +#endif
7 11 #include <openssl/err.h>
  12 +#ifndef QPDF_OPENSSL_1
  13 +# include <openssl/provider.h>
  14 +#endif
  15 +#if (defined(__GNUC__) || defined(__clang__))
  16 +# pragma GCC diagnostic pop
  17 +#endif
8 18  
9 19 #include <qpdf/QIntC.hh>
10 20  
11   -
12 21 static void
13 22 bad_bits(int bits)
14 23 {
... ... @@ -33,8 +42,35 @@ check_openssl(int status)
33 42 }
34 43  
35 44 QPDFCrypto_openssl::QPDFCrypto_openssl() :
36   - md_ctx(EVP_MD_CTX_new()), cipher_ctx(EVP_CIPHER_CTX_new())
  45 +#ifdef QPDF_OPENSSL_1
  46 + rc4(EVP_rc4()),
  47 +#endif
  48 + md_ctx(EVP_MD_CTX_new()),
  49 + cipher_ctx(EVP_CIPHER_CTX_new())
37 50 {
  51 +#ifndef QPDF_OPENSSL_1
  52 + libctx = OSSL_LIB_CTX_new();
  53 + if (libctx == nullptr)
  54 + {
  55 + throw std::runtime_error("unable to create openssl library context");
  56 + return;
  57 + }
  58 + legacy = OSSL_PROVIDER_load(libctx, "legacy");
  59 + if (legacy == nullptr)
  60 + {
  61 + OSSL_LIB_CTX_free(libctx);
  62 + throw std::runtime_error("unable to load openssl legacy provider");
  63 + return;
  64 + }
  65 + rc4 = EVP_CIPHER_fetch(libctx, "RC4", nullptr);
  66 + if (rc4 == nullptr)
  67 + {
  68 + OSSL_PROVIDER_unload(legacy);
  69 + OSSL_LIB_CTX_free(libctx);
  70 + throw std::runtime_error("unable to load openssl rc4 algorithm");
  71 + return;
  72 + }
  73 +#endif
38 74 memset(md_out, 0, sizeof(md_out));
39 75 EVP_MD_CTX_init(md_ctx);
40 76 EVP_CIPHER_CTX_init(cipher_ctx);
... ... @@ -45,6 +81,11 @@ QPDFCrypto_openssl::~QPDFCrypto_openssl()
45 81 EVP_MD_CTX_reset(md_ctx);
46 82 EVP_CIPHER_CTX_reset(cipher_ctx);
47 83 EVP_CIPHER_CTX_free(cipher_ctx);
  84 +#ifndef QPDF_OPENSSL_1
  85 + EVP_CIPHER_free(rc4);
  86 + OSSL_PROVIDER_unload(legacy);
  87 + OSSL_LIB_CTX_free(libctx);
  88 +#endif
48 89 EVP_MD_CTX_free(md_ctx);
49 90 }
50 91  
... ... @@ -100,7 +141,12 @@ QPDFCrypto_openssl::SHA2_update(unsigned char const* data, size_t len)
100 141 void
101 142 QPDFCrypto_openssl::MD5_finalize()
102 143 {
103   - if (EVP_MD_CTX_md(md_ctx))
  144 +#ifdef QPDF_OPENSSL_1
  145 + auto md = EVP_MD_CTX_md(md_ctx);
  146 +#else
  147 + auto md = EVP_MD_CTX_get0_md(md_ctx);
  148 +#endif
  149 + if (md)
104 150 {
105 151 check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr));
106 152 }
... ... @@ -109,7 +155,12 @@ QPDFCrypto_openssl::MD5_finalize()
109 155 void
110 156 QPDFCrypto_openssl::SHA2_finalize()
111 157 {
112   - if (EVP_MD_CTX_md(md_ctx))
  158 +#ifdef QPDF_OPENSSL_1
  159 + auto md = EVP_MD_CTX_md(md_ctx);
  160 +#else
  161 + auto md = EVP_MD_CTX_get0_md(md_ctx);
  162 +#endif
  163 + if (md)
113 164 {
114 165 check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr));
115 166 }
... ... @@ -137,7 +188,7 @@ QPDFCrypto_openssl::RC4_init(unsigned char const* key_data, int key_len)
137 188 strlen(reinterpret_cast<const char*>(key_data)));
138 189 }
139 190 check_openssl(
140   - EVP_EncryptInit_ex(cipher_ctx, EVP_rc4(), nullptr, nullptr, nullptr));
  191 + EVP_EncryptInit_ex(cipher_ctx, rc4, nullptr, nullptr, nullptr));
141 192 check_openssl(EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len));
142 193 check_openssl(
143 194 EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, key_data, nullptr));
... ...
libqpdf/qpdf/QPDFCrypto_openssl.hh
... ... @@ -3,6 +3,14 @@
3 3  
4 4 #include <qpdf/QPDFCryptoImpl.hh>
5 5 #include <string>
  6 +#if (defined(__GNUC__) || defined(__clang__))
  7 +# pragma GCC diagnostic push
  8 +# pragma GCC diagnostic ignored "-Wold-style-cast"
  9 +#endif
  10 +#include <openssl/opensslv.h>
  11 +#if !defined(OPENSSL_VERSION_MAJOR) || OPENSSL_VERSION_MAJOR < 3
  12 +# define QPDF_OPENSSL_1
  13 +#endif
6 14 #include <openssl/rand.h>
7 15 #ifdef OPENSSL_IS_BORINGSSL
8 16 #include <openssl/cipher.h>
... ... @@ -10,6 +18,9 @@
10 18 #else
11 19 #include <openssl/evp.h>
12 20 #endif
  21 +#if (defined(__GNUC__) || defined(__clang__))
  22 +# pragma GCC diagnostic pop
  23 +#endif
13 24  
14 25 class QPDFCrypto_openssl: public QPDFCryptoImpl
15 26 {
... ... @@ -44,6 +55,13 @@ class QPDFCrypto_openssl: public QPDFCryptoImpl
44 55 void rijndael_finalize() override;
45 56  
46 57 private:
  58 +#ifdef QPDF_OPENSSL_1
  59 + EVP_CIPHER const* rc4;
  60 +#else
  61 + OSSL_LIB_CTX* libctx;
  62 + OSSL_PROVIDER* legacy;
  63 + EVP_CIPHER* rc4;
  64 +#endif
47 65 EVP_MD_CTX* const md_ctx;
48 66 EVP_CIPHER_CTX* const cipher_ctx;
49 67 uint8_t md_out[EVP_MAX_MD_SIZE];
... ...