diff options
author | Dean Scarff <deanscarff@google.com> | 2020-04-06 05:19:56 +0200 |
---|---|---|
committer | Jay Berkenbilt <jberkenbilt@users.noreply.github.com> | 2020-04-06 15:01:55 +0200 |
commit | 0f2507234fbe3bd305404b1267607b9900857523 (patch) | |
tree | 9484ca1d93d3def6125f94b512b6c5b8e390c9a4 /libqpdf | |
parent | 08379321645133ba74dad4ce130055c087130bab (diff) | |
download | qpdf-0f2507234fbe3bd305404b1267607b9900857523.tar.zst |
Add OpenSSL/BoringSSL crypto provider
Fixes qpdf/qpdf#417
Diffstat (limited to 'libqpdf')
-rw-r--r-- | libqpdf/QPDFCryptoProvider.cc | 6 | ||||
-rw-r--r-- | libqpdf/QPDFCrypto_openssl.cc | 193 | ||||
-rw-r--r-- | libqpdf/build.mk | 7 | ||||
-rw-r--r-- | libqpdf/qpdf/QPDFCrypto_openssl.hh | 50 | ||||
-rw-r--r-- | libqpdf/qpdf/qpdf-config.h.in | 3 |
5 files changed, 259 insertions, 0 deletions
diff --git a/libqpdf/QPDFCryptoProvider.cc b/libqpdf/QPDFCryptoProvider.cc index 5755fcca..b375498d 100644 --- a/libqpdf/QPDFCryptoProvider.cc +++ b/libqpdf/QPDFCryptoProvider.cc @@ -9,6 +9,9 @@ #ifdef USE_CRYPTO_GNUTLS # include <qpdf/QPDFCrypto_gnutls.hh> #endif +#ifdef USE_CRYPTO_OPENSSL +# include <qpdf/QPDFCrypto_openssl.hh> +#endif std::shared_ptr<QPDFCryptoImpl> QPDFCryptoProvider::getImpl() @@ -50,6 +53,9 @@ QPDFCryptoProvider::QPDFCryptoProvider() : #ifdef USE_CRYPTO_GNUTLS registerImpl_internal<QPDFCrypto_gnutls>("gnutls"); #endif +#ifdef USE_CRYPTO_OPENSSL + registerImpl_internal<QPDFCrypto_openssl>("openssl"); +#endif std::string default_crypto; if (! QUtil::get_env("QPDF_CRYPTO_PROVIDER", &default_crypto)) { diff --git a/libqpdf/QPDFCrypto_openssl.cc b/libqpdf/QPDFCrypto_openssl.cc new file mode 100644 index 00000000..c226fc9c --- /dev/null +++ b/libqpdf/QPDFCrypto_openssl.cc @@ -0,0 +1,193 @@ +#include <qpdf/QPDFCrypto_openssl.hh> + +#include <cstring> +#include <stdexcept> + +#include <qpdf/QIntC.hh> + + +static void +bad_bits(int bits) +{ + throw std::logic_error( + std::string("unsupported key length: ") + std::to_string(bits)); +} + +static void +check_openssl(int status) +{ + if (status != 1) + { + throw std::runtime_error("openssl error"); + } +} + +QPDFCrypto_openssl::QPDFCrypto_openssl() : + md_ctx(EVP_MD_CTX_new()), cipher_ctx(EVP_CIPHER_CTX_new()) +{ + memset(md_out, 0, sizeof(md_out)); + EVP_MD_CTX_init(md_ctx); + EVP_CIPHER_CTX_init(cipher_ctx); +} + +QPDFCrypto_openssl::~QPDFCrypto_openssl() +{ + EVP_MD_CTX_reset(md_ctx); + EVP_CIPHER_CTX_reset(cipher_ctx); + EVP_CIPHER_CTX_free(cipher_ctx); + EVP_MD_CTX_free(md_ctx); +} + +void +QPDFCrypto_openssl::MD5_init() +{ + check_openssl(EVP_MD_CTX_reset(md_ctx)); + check_openssl(EVP_DigestInit_ex(md_ctx, EVP_md5(), nullptr)); +} + +void +QPDFCrypto_openssl::SHA2_init(int bits) +{ + const EVP_MD* md = EVP_sha512(); + switch (bits) + { + case 256: + md = EVP_sha256(); + break; + case 384: + md = EVP_sha384(); + break; + case 512: + md = EVP_sha512(); + break; + default: + bad_bits(bits); + return; + } + sha2_bits = static_cast<size_t>(bits); + check_openssl(EVP_MD_CTX_reset(md_ctx)); + check_openssl(EVP_DigestInit_ex(md_ctx, md, nullptr)); +} + +void +QPDFCrypto_openssl::MD5_update(unsigned char const* data, size_t len) +{ + check_openssl(EVP_DigestUpdate(md_ctx, data, len)); +} + +void +QPDFCrypto_openssl::SHA2_update(unsigned char const* data, size_t len) +{ + check_openssl(EVP_DigestUpdate(md_ctx, data, len)); +} + +void +QPDFCrypto_openssl::MD5_finalize() +{ + if (EVP_MD_CTX_md(md_ctx)) + { + check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr)); + } +} + +void +QPDFCrypto_openssl::SHA2_finalize() +{ + if (EVP_MD_CTX_md(md_ctx)) + { + check_openssl(EVP_DigestFinal(md_ctx, md_out + 0, nullptr)); + } +} + +void +QPDFCrypto_openssl::MD5_digest(MD5_Digest d) +{ + memcpy(d, md_out, sizeof(QPDFCryptoImpl::MD5_Digest)); +} + +std::string +QPDFCrypto_openssl::SHA2_digest() +{ + return std::string(reinterpret_cast<char*>(md_out), sha2_bits / 8); +} + +void +QPDFCrypto_openssl::RC4_init(unsigned char const* key_data, int key_len) +{ + check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); + if (key_len == -1) + { + key_len = QIntC::to_int( + strlen(reinterpret_cast<const char*>(key_data))); + } + check_openssl( + EVP_EncryptInit_ex(cipher_ctx, EVP_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)); +} + +void +QPDFCrypto_openssl::rijndael_init( + bool encrypt, unsigned char const* key_data, size_t key_len, + bool cbc_mode, unsigned char* cbc_block) +{ + const EVP_CIPHER* cipher = nullptr; + switch (key_len) + { + case 32: + cipher = cbc_mode ? EVP_aes_256_cbc() : EVP_aes_256_ecb(); + break; + case 24: + cipher = cbc_mode ? EVP_aes_192_cbc() : EVP_aes_192_ecb(); + break; + default: + cipher = cbc_mode ? EVP_aes_128_cbc() : EVP_aes_128_ecb(); + break; + } + + check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); + check_openssl( + EVP_CipherInit_ex(cipher_ctx, cipher, nullptr, + key_data, cbc_block, encrypt)); + check_openssl(EVP_CIPHER_CTX_set_padding(cipher_ctx, 0)); +} + +void +QPDFCrypto_openssl::RC4_process( + unsigned char* in_data, size_t len, unsigned char* out_data) +{ + if (nullptr == out_data) + { + out_data = in_data; + } + int out_len = static_cast<int>(len); + check_openssl( + EVP_EncryptUpdate(cipher_ctx, out_data, &out_len, in_data, out_len)); +} + +void +QPDFCrypto_openssl::rijndael_process( + unsigned char* in_data, unsigned char* out_data) +{ + int len = QPDFCryptoImpl::rijndael_buf_size; + check_openssl(EVP_CipherUpdate(cipher_ctx, out_data, &len, in_data, len)); +} + +void +QPDFCrypto_openssl::RC4_finalize() +{ + if (EVP_CIPHER_CTX_cipher(cipher_ctx)) + { + check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); + } +} + +void +QPDFCrypto_openssl::rijndael_finalize() +{ + if (EVP_CIPHER_CTX_cipher(cipher_ctx)) + { + check_openssl(EVP_CIPHER_CTX_reset(cipher_ctx)); + } +} diff --git a/libqpdf/build.mk b/libqpdf/build.mk index ac904174..69b1693c 100644 --- a/libqpdf/build.mk +++ b/libqpdf/build.mk @@ -14,6 +14,9 @@ CRYPTO_NATIVE = \ libqpdf/sha2.c \ libqpdf/sha2big.c +CRYPTO_OPENSSL = \ + libqpdf/QPDFCrypto_openssl.cc + CRYPTO_GNUTLS = \ libqpdf/QPDFCrypto_gnutls.cc @@ -97,6 +100,10 @@ ifeq ($(USE_CRYPTO_NATIVE), 1) SRCS_libqpdf += $(CRYPTO_NATIVE) endif +ifeq ($(USE_CRYPTO_OPENSSL), 1) +SRCS_libqpdf += $(CRYPTO_OPENSSL) +endif + ifeq ($(USE_CRYPTO_GNUTLS), 1) SRCS_libqpdf += $(CRYPTO_GNUTLS) endif diff --git a/libqpdf/qpdf/QPDFCrypto_openssl.hh b/libqpdf/qpdf/QPDFCrypto_openssl.hh new file mode 100644 index 00000000..ff8c4831 --- /dev/null +++ b/libqpdf/qpdf/QPDFCrypto_openssl.hh @@ -0,0 +1,50 @@ +#ifndef QPDFCRYPTO_openssl_HH +#define QPDFCRYPTO_openssl_HH + +#include <qpdf/QPDFCryptoImpl.hh> +#include <string> +#ifdef OPENSSL_IS_BORINGSSL +#include <openssl/cipher.h> +#include <openssl/digest.h> +#else +#include <openssl/evp.h> +#endif + +class QPDFCrypto_openssl: public QPDFCryptoImpl +{ + public: + QPDFCrypto_openssl(); + + QPDF_DLL + ~QPDFCrypto_openssl() override; + + void MD5_init() override; + void MD5_update(unsigned char const* data, size_t len) override; + void MD5_finalize() override; + void MD5_digest(MD5_Digest) override; + + void RC4_init(unsigned char const* key_data, int key_len = -1) override; + void RC4_process(unsigned char* in_data, size_t len, + unsigned char* out_data = 0) override; + void RC4_finalize() override; + + void SHA2_init(int bits) override; + void SHA2_update(unsigned char const* data, size_t len) override; + void SHA2_finalize() override; + std::string SHA2_digest() override; + + void rijndael_init( + bool encrypt, unsigned char const* key_data, size_t key_len, + bool cbc_mode, unsigned char* cbc_block) override; + void rijndael_process( + unsigned char* in_data, unsigned char* out_data) override; + void rijndael_finalize() override; + + private: + EVP_MD_CTX* const md_ctx; + EVP_CIPHER_CTX* const cipher_ctx; + uint8_t md_out[EVP_MAX_MD_SIZE]; + size_t sha2_bits; +}; + +#endif // QPDFCRYPTO_openssl_HH diff --git a/libqpdf/qpdf/qpdf-config.h.in b/libqpdf/qpdf/qpdf-config.h.in index 75d34c66..c9886b57 100644 --- a/libqpdf/qpdf/qpdf-config.h.in +++ b/libqpdf/qpdf/qpdf-config.h.in @@ -90,6 +90,9 @@ /* Whether to use the native crypto provider */ #undef USE_CRYPTO_NATIVE +/* Whether to use the openssl crypto provider */ +#undef USE_CRYPTO_OPENSSL + /* Whether to use insecure random numbers */ #undef USE_INSECURE_RANDOM |