Commit 88bedb41fe82df312d62e364a5a216b62fc8807c

Authored by Jay Berkenbilt
1 parent cc145234

Implement gnutls crypto provider (fixes #218)

Thanks to Zdenek Dohnal <zdohnal@redhat.com> for contributing the code
used for the gnutls crypto provider.
autoconf.mk.in
... ... @@ -31,6 +31,7 @@ OBJDUMP=@OBJDUMP@
31 31 GENDEPS=@GENDEPS@
32 32 LIBTOOL=@LIBTOOL@
33 33 USE_CRYPTO_NATIVE=@USE_CRYPTO_NATIVE@
  34 +USE_CRYPTO_GNUTLS=@USE_CRYPTO_GNUTLS@
34 35 DOCBOOKX_DTD=@DOCBOOKX_DTD@
35 36 FOP=@FOP@
36 37 XSLTPROC=@XSLTPROC@
... ...
autofiles.sums
1   -2b5c5a808c353b8df9e28e8cfb1e7d37114a2cad37eaede5bfe4354acae804d0 configure.ac
  1 +97f3ed3cd8b491f0ceeb57baa40f4ed9c4be188692da1d13c93ef318c45cc4ae configure.ac
2 2 d3f9ee6f6f0846888d9a10fd3dad2e4b1258be84205426cf04d7cef02d61dad7 aclocal.m4
3   -7fc840fce5d372e92aa676e0040213a0f239cc8c01b6d6ef53c82043ceda571a libqpdf/qpdf/qpdf-config.h.in
  3 +2e4cd495837be1b8454a4d8aef541b000988634be89d9c05a9cf5de67dffef5e libqpdf/qpdf/qpdf-config.h.in
4 4 5297971a0ef90bcd5563eb3f7127a032bb76d3ae2af7258bf13479caf8983a60 m4/ax_cxx_compile_stdcxx.m4
5 5 35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4
6 6 37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4
... ...
configure
... ... @@ -643,6 +643,9 @@ DOCBOOK_XHTML
643 643 SHOW_FAILED_TEST_OUTPUT
644 644 QPDF_SKIP_TEST_COMPARE_IMAGES
645 645 DEFAULT_CRYPTO
  646 +USE_CRYPTO_GNUTLS
  647 +pc_gnutls_LIBS
  648 +pc_gnutls_CFLAGS
646 649 USE_CRYPTO_NATIVE
647 650 CXXWFLAGS
648 651 WFLAGS
... ... @@ -780,6 +783,7 @@ enable_werror
780 783 enable_int_warnings
781 784 enable_implicit_crypto
782 785 enable_crypto_native
  786 +enable_crypto_gnutls
783 787 with_default_crypto
784 788 enable_test_compare_images
785 789 enable_show_failed_test_output
... ... @@ -811,7 +815,9 @@ PKG_CONFIG_LIBDIR
811 815 pc_zlib_CFLAGS
812 816 pc_zlib_LIBS
813 817 pc_libjpeg_CFLAGS
814   -pc_libjpeg_LIBS'
  818 +pc_libjpeg_LIBS
  819 +pc_gnutls_CFLAGS
  820 +pc_gnutls_LIBS'
815 821  
816 822  
817 823 # Initialize some variables set by options.
... ... @@ -1466,6 +1472,8 @@ Optional Features:
1466 1472 are not explicitly requested; true by default
1467 1473 --enable-crypto-native whether to include support for native crypto
1468 1474 provider
  1475 + --enable-crypto-gnutls whether to include support for gnutls crypto
  1476 + provider
1469 1477 --enable-test-compare-images
1470 1478 whether to compare images in test suite; disabled by
1471 1479 default, enabling requires ghostscript and tiffcmp
... ... @@ -1535,6 +1543,10 @@ Some influential environment variables:
1535 1543 C compiler flags for pc_libjpeg, overriding pkg-config
1536 1544 pc_libjpeg_LIBS
1537 1545 linker flags for pc_libjpeg, overriding pkg-config
  1546 + pc_gnutls_CFLAGS
  1547 + C compiler flags for pc_gnutls, overriding pkg-config
  1548 + pc_gnutls_LIBS
  1549 + linker flags for pc_gnutls, overriding pkg-config
1538 1550  
1539 1551 Use these variables to override the choices made by `configure' or to help
1540 1552 it to find libraries and programs with nonstandard names/locations.
... ... @@ -17625,6 +17637,122 @@ $as_echo &quot;#define USE_CRYPTO_NATIVE 1&quot; &gt;&gt;confdefs.h
17625 17637 fi
17626 17638  
17627 17639  
  17640 +
  17641 +pkg_failed=no
  17642 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pc_gnutls" >&5
  17643 +$as_echo_n "checking for pc_gnutls... " >&6; }
  17644 +
  17645 +if test -n "$pc_gnutls_CFLAGS"; then
  17646 + pkg_cv_pc_gnutls_CFLAGS="$pc_gnutls_CFLAGS"
  17647 + elif test -n "$PKG_CONFIG"; then
  17648 + if test -n "$PKG_CONFIG" && \
  17649 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5
  17650 + ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5
  17651 + ac_status=$?
  17652 + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  17653 + test $ac_status = 0; }; then
  17654 + pkg_cv_pc_gnutls_CFLAGS=`$PKG_CONFIG --cflags "gnutls" 2>/dev/null`
  17655 + test "x$?" != "x0" && pkg_failed=yes
  17656 +else
  17657 + pkg_failed=yes
  17658 +fi
  17659 + else
  17660 + pkg_failed=untried
  17661 +fi
  17662 +if test -n "$pc_gnutls_LIBS"; then
  17663 + pkg_cv_pc_gnutls_LIBS="$pc_gnutls_LIBS"
  17664 + elif test -n "$PKG_CONFIG"; then
  17665 + if test -n "$PKG_CONFIG" && \
  17666 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls\""; } >&5
  17667 + ($PKG_CONFIG --exists --print-errors "gnutls") 2>&5
  17668 + ac_status=$?
  17669 + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  17670 + test $ac_status = 0; }; then
  17671 + pkg_cv_pc_gnutls_LIBS=`$PKG_CONFIG --libs "gnutls" 2>/dev/null`
  17672 + test "x$?" != "x0" && pkg_failed=yes
  17673 +else
  17674 + pkg_failed=yes
  17675 +fi
  17676 + else
  17677 + pkg_failed=untried
  17678 +fi
  17679 +
  17680 +
  17681 +
  17682 +if test $pkg_failed = yes; then
  17683 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
  17684 +$as_echo "no" >&6; }
  17685 +
  17686 +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
  17687 + _pkg_short_errors_supported=yes
  17688 +else
  17689 + _pkg_short_errors_supported=no
  17690 +fi
  17691 + if test $_pkg_short_errors_supported = yes; then
  17692 + pc_gnutls_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls" 2>&1`
  17693 + else
  17694 + pc_gnutls_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls" 2>&1`
  17695 + fi
  17696 + # Put the nasty error message in config.log where it belongs
  17697 + echo "$pc_gnutls_PKG_ERRORS" >&5
  17698 +
  17699 + GNUTLS_FOUND=0
  17700 +elif test $pkg_failed = untried; then
  17701 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
  17702 +$as_echo "no" >&6; }
  17703 + GNUTLS_FOUND=0
  17704 +else
  17705 + pc_gnutls_CFLAGS=$pkg_cv_pc_gnutls_CFLAGS
  17706 + pc_gnutls_LIBS=$pkg_cv_pc_gnutls_LIBS
  17707 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
  17708 +$as_echo "yes" >&6; }
  17709 + GNUTLS_FOUND=1
  17710 +fi
  17711 +
  17712 +IMPLICIT_GNUTLS=0
  17713 +USE_CRYPTO_GNUTLS=0
  17714 +
  17715 +# Check whether --enable-crypto-gnutls was given.
  17716 +if test "${enable_crypto_gnutls+set}" = set; then :
  17717 + enableval=$enable_crypto_gnutls; if test "$enableval" = "yes"; then
  17718 + USE_CRYPTO_GNUTLS=1
  17719 + else
  17720 + USE_CRYPTO_GNUTLS=0
  17721 + fi
  17722 +else
  17723 + IMPLICIT_GNUTLS=$IMPLICIT_CRYPTO
  17724 +fi
  17725 +
  17726 +
  17727 +if test "$IMPLICIT_GNUTLS" = "1"; then
  17728 + USE_CRYPTO_GNUTLS=$GNUTLS_FOUND
  17729 + if test "$USE_CRYPTO_GNUTLS" = "1"; then
  17730 + { $as_echo "$as_me:${as_lineno-$LINENO}: enabling gnutls crypto provider since gnutls is available" >&5
  17731 +$as_echo "$as_me: enabling gnutls crypto provider since gnutls is available" >&6;}
  17732 + else
  17733 + { $as_echo "$as_me:${as_lineno-$LINENO}: not enabling gnutls crypto provider since gnutls was not found" >&5
  17734 +$as_echo "$as_me: not enabling gnutls crypto provider since gnutls was not found" >&6;}
  17735 + fi
  17736 +fi
  17737 +
  17738 +if test "$USE_CRYPTO_GNUTLS" = "1" -a "$GNUTLS_FOUND" = "0"; then
  17739 + as_fn_error $? "unable to use requested gnutls crypto provider without gnutls" "$LINENO" 5
  17740 +fi
  17741 +
  17742 +if test "$USE_CRYPTO_GNUTLS" = "1"; then
  17743 + CFLAGS="$CFLAGS $pc_gnutls_CFLAGS"
  17744 + CXXFLAGS="$CXXFLAGS $pc_gnutls_CXXFLAGS"
  17745 + LIBS="$LIBS $pc_gnutls_LIBS"
  17746 +
  17747 +$as_echo "#define USE_CRYPTO_GNUTLS 1" >>confdefs.h
  17748 +
  17749 + DEFAULT_CRYPTO=gnutls
  17750 +elif test "$GNUTLS_FOUND" = "1"; then
  17751 + { $as_echo "$as_me:${as_lineno-$LINENO}: not linking with gnutls even though it is available" >&5
  17752 +$as_echo "$as_me: not linking with gnutls even though it is available" >&6;}
  17753 +fi
  17754 +
  17755 +
17628 17756 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which crypto to use by default" >&5
17629 17757 $as_echo_n "checking which crypto to use by default... " >&6; }
17630 17758  
... ... @@ -17650,6 +17778,11 @@ case &quot;$DEFAULT_CRYPTO&quot; in
17650 17778 bad_crypto=1
17651 17779 fi
17652 17780 ;;
  17781 + "gnutls")
  17782 + if test "$USE_CRYPTO_GNUTLS" != "1"; then
  17783 + bad_crypto=1
  17784 + fi
  17785 + ;;
17653 17786 *)
17654 17787 bad_crypto=1
17655 17788 ;;
... ...
configure.ac
... ... @@ -506,6 +506,49 @@ if test &quot;$USE_CRYPTO_NATIVE&quot; = &quot;1&quot;; then
506 506 DEFAULT_CRYPTO=native
507 507 fi
508 508  
  509 +dnl If the gnutls provider is explicitly requested, require gnutls. If
  510 +dnl the gnutls provider is not explicitly disabled, enable it if
  511 +dnl gnutls is available. If the gnutls provider is explicitly
  512 +dnl disabled, do not link with gnutls even if present.
  513 +
  514 +PKG_CHECK_MODULES([pc_gnutls], [gnutls], [GNUTLS_FOUND=1], [GNUTLS_FOUND=0])
  515 +
  516 +IMPLICIT_GNUTLS=0
  517 +USE_CRYPTO_GNUTLS=0
  518 +AC_SUBST(USE_CRYPTO_GNUTLS)
  519 +AC_ARG_ENABLE(crypto-gnutls,
  520 + AS_HELP_STRING([--enable-crypto-gnutls],
  521 + [whether to include support for gnutls crypto provider]),
  522 + [if test "$enableval" = "yes"; then
  523 + USE_CRYPTO_GNUTLS=1
  524 + else
  525 + USE_CRYPTO_GNUTLS=0
  526 + fi],
  527 + [IMPLICIT_GNUTLS=$IMPLICIT_CRYPTO])
  528 +
  529 +if test "$IMPLICIT_GNUTLS" = "1"; then
  530 + USE_CRYPTO_GNUTLS=$GNUTLS_FOUND
  531 + if test "$USE_CRYPTO_GNUTLS" = "1"; then
  532 + AC_MSG_NOTICE(enabling gnutls crypto provider since gnutls is available)
  533 + else
  534 + AC_MSG_NOTICE(not enabling gnutls crypto provider since gnutls was not found)
  535 + fi
  536 +fi
  537 +
  538 +if test "$USE_CRYPTO_GNUTLS" = "1" -a "$GNUTLS_FOUND" = "0"; then
  539 + AC_MSG_ERROR(unable to use requested gnutls crypto provider without gnutls)
  540 +fi
  541 +
  542 +if test "$USE_CRYPTO_GNUTLS" = "1"; then
  543 + CFLAGS="$CFLAGS $pc_gnutls_CFLAGS"
  544 + CXXFLAGS="$CXXFLAGS $pc_gnutls_CXXFLAGS"
  545 + LIBS="$LIBS $pc_gnutls_LIBS"
  546 + AC_DEFINE([USE_CRYPTO_GNUTLS], 1, [Whether to use the gnutls crypto provider])
  547 + DEFAULT_CRYPTO=gnutls
  548 +elif test "$GNUTLS_FOUND" = "1"; then
  549 + AC_MSG_NOTICE(not linking with gnutls even though it is available)
  550 +fi
  551 +
509 552 dnl Allow the default crypto provider to be specified explicitly.
510 553  
511 554 AC_MSG_CHECKING(which crypto to use by default)
... ... @@ -527,6 +570,11 @@ case &quot;$DEFAULT_CRYPTO&quot; in
527 570 bad_crypto=1
528 571 fi
529 572 ;;
  573 + "gnutls")
  574 + if test "$USE_CRYPTO_GNUTLS" != "1"; then
  575 + bad_crypto=1
  576 + fi
  577 + ;;
530 578 *)
531 579 bad_crypto=1
532 580 ;;
... ...
libqpdf/QPDFCryptoProvider.cc
... ... @@ -5,6 +5,9 @@
5 5 #ifdef USE_CRYPTO_NATIVE
6 6 # include <qpdf/QPDFCrypto_native.hh>
7 7 #endif
  8 +#ifdef USE_CRYPTO_GNUTLS
  9 +# include <qpdf/QPDFCrypto_gnutls.hh>
  10 +#endif
8 11  
9 12 std::shared_ptr<QPDFCryptoImpl>
10 13 QPDFCryptoProvider::getImpl()
... ... @@ -43,6 +46,9 @@ QPDFCryptoProvider::QPDFCryptoProvider() :
43 46 #ifdef USE_CRYPTO_NATIVE
44 47 registerImpl_internal<QPDFCrypto_native>("native");
45 48 #endif
  49 +#ifdef USE_CRYPTO_GNUTLS
  50 + registerImpl_internal<QPDFCrypto_gnutls>("gnutls");
  51 +#endif
46 52 setDefaultProvider_internal(DEFAULT_CRYPTO);
47 53 }
48 54  
... ...
libqpdf/QPDFCrypto_gnutls.cc 0 → 100644
  1 +#include <qpdf/QPDFCrypto_gnutls.hh>
  2 +#include <qpdf/QIntC.hh>
  3 +#include <qpdf/QUtil.hh>
  4 +#include <cstring>
  5 +
  6 +QPDFCrypto_gnutls::QPDFCrypto_gnutls() :
  7 + hash_ctx(nullptr),
  8 + cipher_ctx(nullptr),
  9 + sha2_bits(0),
  10 + encrypt(false),
  11 + cbc_mode(false),
  12 + aes_key_data(nullptr),
  13 + aes_key_len(0)
  14 +{
  15 + memset(digest, 0, sizeof(digest));
  16 +}
  17 +
  18 +QPDFCrypto_gnutls::~QPDFCrypto_gnutls()
  19 +{
  20 + if (this->hash_ctx)
  21 + {
  22 + gnutls_hash_deinit(this->hash_ctx, digest);
  23 + }
  24 + if (cipher_ctx)
  25 + {
  26 + gnutls_cipher_deinit(this->cipher_ctx);
  27 + }
  28 + this->aes_key_data = nullptr;
  29 + this->aes_key_len = 0;
  30 +}
  31 +
  32 +void
  33 +QPDFCrypto_gnutls::MD5_init()
  34 +{
  35 + MD5_finalize();
  36 + int code = gnutls_hash_init(&this->hash_ctx, GNUTLS_DIG_MD5);
  37 + if (code < 0)
  38 + {
  39 + this->hash_ctx = nullptr;
  40 + throw std::runtime_error(
  41 + std::string("gnutls: MD5 error: ") +
  42 + std::string(gnutls_strerror(code)));
  43 + }
  44 +}
  45 +
  46 +void
  47 +QPDFCrypto_gnutls::MD5_update(unsigned char const* data, size_t len)
  48 +{
  49 + gnutls_hash(this->hash_ctx, data, len);
  50 +}
  51 +
  52 +void
  53 +QPDFCrypto_gnutls::MD5_finalize()
  54 +{
  55 + if (this->hash_ctx)
  56 + {
  57 + gnutls_hash_deinit(this->hash_ctx, this->digest);
  58 + this->hash_ctx = nullptr;
  59 + }
  60 +}
  61 +
  62 +void
  63 +QPDFCrypto_gnutls::MD5_digest(MD5_Digest d)
  64 +{
  65 + memcpy(d, this->digest, sizeof(MD5_Digest));
  66 +}
  67 +
  68 +void
  69 +QPDFCrypto_gnutls::RC4_init(unsigned char const* key_data, int key_len)
  70 +{
  71 + RC4_finalize();
  72 + if (key_len == -1)
  73 + {
  74 + key_len = QIntC::to_int(
  75 + strlen(reinterpret_cast<char const*>(key_data)));
  76 + }
  77 + gnutls_datum_t key;
  78 + key.data = const_cast<unsigned char*>(key_data);
  79 + key.size = QIntC::to_uint(key_len);
  80 +
  81 + int code = gnutls_cipher_init(
  82 + &this->cipher_ctx, GNUTLS_CIPHER_ARCFOUR_128, &key, nullptr);
  83 + if (code < 0)
  84 + {
  85 + this->cipher_ctx = nullptr;
  86 + throw std::runtime_error(
  87 + std::string("gnutls: RC4 error: ") +
  88 + std::string(gnutls_strerror(code)));
  89 + }
  90 +}
  91 +
  92 +void
  93 +QPDFCrypto_gnutls::RC4_process(unsigned char* in_data, size_t len,
  94 + unsigned char* out_data)
  95 +{
  96 + if (nullptr == out_data)
  97 + {
  98 + out_data = in_data;
  99 + }
  100 + gnutls_cipher_encrypt2(this->cipher_ctx, in_data, len, out_data, len);
  101 +}
  102 +
  103 +void
  104 +QPDFCrypto_gnutls::RC4_finalize()
  105 +{
  106 + if (this->cipher_ctx)
  107 + {
  108 + gnutls_cipher_deinit(this->cipher_ctx);
  109 + this->cipher_ctx = nullptr;
  110 + }
  111 +}
  112 +
  113 +void
  114 +QPDFCrypto_gnutls::SHA2_init(int bits)
  115 +{
  116 + SHA2_finalize();
  117 + gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
  118 + switch (bits)
  119 + {
  120 + case 256:
  121 + alg = GNUTLS_DIG_SHA256;
  122 + break;
  123 + case 384:
  124 + alg = GNUTLS_DIG_SHA384;
  125 + break;
  126 + case 512:
  127 + alg = GNUTLS_DIG_SHA512;
  128 + break;
  129 + default:
  130 + badBits();
  131 + break;
  132 + }
  133 + this->sha2_bits = bits;
  134 + int code = gnutls_hash_init(&this->hash_ctx, alg);
  135 + if (code < 0)
  136 + {
  137 + this->hash_ctx = nullptr;
  138 + throw std::runtime_error(
  139 + std::string("gnutls: SHA") + QUtil::int_to_string(bits) +
  140 + " error: " + std::string(gnutls_strerror(code)));
  141 + }
  142 +}
  143 +
  144 +void
  145 +QPDFCrypto_gnutls::SHA2_update(unsigned char const* data, size_t len)
  146 +{
  147 + gnutls_hash(this->hash_ctx, data, len);
  148 +}
  149 +
  150 +void
  151 +QPDFCrypto_gnutls::SHA2_finalize()
  152 +{
  153 + if (this->hash_ctx)
  154 + {
  155 + gnutls_hash_deinit(this->hash_ctx, this->digest);
  156 + this->hash_ctx = nullptr;
  157 + }
  158 +}
  159 +
  160 +std::string
  161 +QPDFCrypto_gnutls::SHA2_digest()
  162 +{
  163 + std::string result;
  164 + switch (this->sha2_bits)
  165 + {
  166 + case 256:
  167 + result = std::string(reinterpret_cast<char*>(this->digest), 32);
  168 + break;
  169 + case 384:
  170 + result = std::string(reinterpret_cast<char*>(this->digest), 48);
  171 + break;
  172 + case 512:
  173 + result = std::string(reinterpret_cast<char*>(this->digest), 64);
  174 + break;
  175 + default:
  176 + badBits();
  177 + break;
  178 + }
  179 + return result;
  180 +}
  181 +
  182 +void
  183 +QPDFCrypto_gnutls::rijndael_init(
  184 + bool encrypt, unsigned char const* key_data, size_t key_len,
  185 + bool cbc_mode, unsigned char* cbc_block)
  186 +{
  187 + rijndael_finalize();
  188 + this->encrypt = encrypt;
  189 + this->cbc_mode = cbc_mode;
  190 + if (! cbc_mode)
  191 + {
  192 + // Save the key so we can re-initialize.
  193 + this->aes_key_data = key_data;
  194 + this->aes_key_len = key_len;
  195 + }
  196 +
  197 + gnutls_cipher_algorithm_t alg = GNUTLS_CIPHER_UNKNOWN;
  198 + gnutls_datum_t cipher_key;
  199 + gnutls_datum_t iv;
  200 +
  201 + cipher_key.data = const_cast<unsigned char*>(key_data);
  202 +
  203 + switch(key_len)
  204 + {
  205 + case 16:
  206 + alg = GNUTLS_CIPHER_AES_128_CBC;
  207 + break;
  208 + case 32:
  209 + alg = GNUTLS_CIPHER_AES_256_CBC;
  210 + break;
  211 + case 24:
  212 + alg = GNUTLS_CIPHER_AES_192_CBC;
  213 + break;
  214 + default:
  215 + alg = GNUTLS_CIPHER_AES_128_CBC;
  216 + break;
  217 + }
  218 +
  219 + cipher_key.size = QIntC::to_uint(gnutls_cipher_get_key_size(alg));
  220 +
  221 + iv.data = cbc_block;
  222 + iv.size = rijndael_buf_size;
  223 +
  224 + int code = gnutls_cipher_init(&this->cipher_ctx, alg, &cipher_key, &iv);
  225 + if (code < 0)
  226 + {
  227 + this->cipher_ctx = nullptr;
  228 + throw std::runtime_error(
  229 + std::string("gnutls: AES error: ") +
  230 + std::string(gnutls_strerror(code)));
  231 + }
  232 +}
  233 +
  234 +void
  235 +QPDFCrypto_gnutls::rijndael_process(unsigned char* in_data,
  236 + unsigned char* out_data)
  237 +{
  238 + if (this->encrypt)
  239 + {
  240 + gnutls_cipher_encrypt2(this->cipher_ctx,
  241 + in_data, rijndael_buf_size,
  242 + out_data, rijndael_buf_size);
  243 + }
  244 + else
  245 + {
  246 + gnutls_cipher_decrypt2(this->cipher_ctx,
  247 + in_data, rijndael_buf_size,
  248 + out_data, rijndael_buf_size);
  249 + }
  250 +
  251 + // Gnutls doesn't support AES in ECB (non-CBC) mode, but the
  252 + // result is the same as if you just reset the cbc block to all
  253 + // zeroes each time. We jump through a few hoops here to make this
  254 + // work.
  255 + if (! this->cbc_mode)
  256 + {
  257 + static unsigned char zeroes[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  258 + rijndael_init(this->encrypt, this->aes_key_data, this->aes_key_len,
  259 + false, zeroes);
  260 + }
  261 +}
  262 +
  263 +void
  264 +QPDFCrypto_gnutls::rijndael_finalize()
  265 +{
  266 + if (this->cipher_ctx)
  267 + {
  268 + gnutls_cipher_deinit(this->cipher_ctx);
  269 + this->cipher_ctx = nullptr;
  270 + }
  271 +}
  272 +
  273 +void
  274 +QPDFCrypto_gnutls::badBits()
  275 +{
  276 + throw std::logic_error("SHA2 (gnutls) has bits != 256, 384, or 512");
  277 +}
... ...
libqpdf/build.mk
... ... @@ -14,6 +14,9 @@ CRYPTO_NATIVE = \
14 14 libqpdf/sha2.c \
15 15 libqpdf/sha2big.c
16 16  
  17 +CRYPTO_GNUTLS = \
  18 + libqpdf/QPDFCrypto_gnutls.cc
  19 +
17 20 SRCS_libqpdf = \
18 21 libqpdf/BitStream.cc \
19 22 libqpdf/BitWriter.cc \
... ... @@ -94,6 +97,10 @@ ifeq ($(USE_CRYPTO_NATIVE), 1)
94 97 SRCS_libqpdf += $(CRYPTO_NATIVE)
95 98 endif
96 99  
  100 +ifeq ($(USE_CRYPTO_GNUTLS), 1)
  101 +SRCS_libqpdf += $(CRYPTO_GNUTLS)
  102 +endif
  103 +
97 104 # -----
98 105  
99 106 CCSRCS_libqpdf = $(filter %.cc,$(SRCS_libqpdf))
... ...
libqpdf/qpdf/QPDFCrypto_gnutls.hh 0 → 100644
  1 +#ifndef QPDFCRYPTO_GNUTLS_HH
  2 +#define QPDFCRYPTO_GNUTLS_HH
  3 +
  4 +#include <qpdf/DLL.h>
  5 +#include <qpdf/QPDFCryptoImpl.hh>
  6 +#include <memory>
  7 +#include <gnutls/gnutls.h>
  8 +#include <gnutls/crypto.h>
  9 +
  10 +class QPDFCrypto_gnutls: public QPDFCryptoImpl
  11 +{
  12 + public:
  13 + QPDFCrypto_gnutls();
  14 +
  15 + QPDF_DLL
  16 + virtual ~QPDFCrypto_gnutls();
  17 +
  18 + virtual void MD5_init();
  19 + virtual void MD5_update(unsigned char const* data, size_t len);
  20 + virtual void MD5_finalize();
  21 + virtual void MD5_digest(MD5_Digest);
  22 +
  23 + virtual void RC4_init(unsigned char const* key_data, int key_len = -1);
  24 + virtual void RC4_process(unsigned char* in_data, size_t len,
  25 + unsigned char* out_data = 0);
  26 + virtual void RC4_finalize();
  27 +
  28 + virtual void SHA2_init(int bits);
  29 + virtual void SHA2_update(unsigned char const* data, size_t len);
  30 + virtual void SHA2_finalize();
  31 + virtual std::string SHA2_digest();
  32 +
  33 + virtual void rijndael_init(
  34 + bool encrypt, unsigned char const* key_data, size_t key_len,
  35 + bool cbc_mode, unsigned char* cbc_block);
  36 + virtual void rijndael_process(
  37 + unsigned char* in_data, unsigned char* out_data);
  38 + virtual void rijndael_finalize();
  39 +
  40 + private:
  41 + void badBits();
  42 +
  43 + gnutls_hash_hd_t hash_ctx;
  44 + gnutls_cipher_hd_t cipher_ctx;
  45 + int sha2_bits;
  46 + bool encrypt;
  47 + bool cbc_mode;
  48 + char digest[64];
  49 + unsigned char const* aes_key_data;
  50 + size_t aes_key_len;
  51 +};
  52 +
  53 +#endif // QPDFCRYPTO_GNUTLS_HH
... ...
libqpdf/qpdf/qpdf-config.h.in
... ... @@ -84,6 +84,9 @@
84 84 /* Define to 1 if you have the ANSI C header files. */
85 85 #undef STDC_HEADERS
86 86  
  87 +/* Whether to use the gnutls crypto provider */
  88 +#undef USE_CRYPTO_GNUTLS
  89 +
87 90 /* Whether to use the native crypto provider */
88 91 #undef USE_CRYPTO_NATIVE
89 92  
... ...