Commit 88bedb41fe82df312d62e364a5a216b62fc8807c
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.
Showing
9 changed files
with
531 additions
and
3 deletions
autoconf.mk.in
| @@ -31,6 +31,7 @@ OBJDUMP=@OBJDUMP@ | @@ -31,6 +31,7 @@ OBJDUMP=@OBJDUMP@ | ||
| 31 | GENDEPS=@GENDEPS@ | 31 | GENDEPS=@GENDEPS@ |
| 32 | LIBTOOL=@LIBTOOL@ | 32 | LIBTOOL=@LIBTOOL@ |
| 33 | USE_CRYPTO_NATIVE=@USE_CRYPTO_NATIVE@ | 33 | USE_CRYPTO_NATIVE=@USE_CRYPTO_NATIVE@ |
| 34 | +USE_CRYPTO_GNUTLS=@USE_CRYPTO_GNUTLS@ | ||
| 34 | DOCBOOKX_DTD=@DOCBOOKX_DTD@ | 35 | DOCBOOKX_DTD=@DOCBOOKX_DTD@ |
| 35 | FOP=@FOP@ | 36 | FOP=@FOP@ |
| 36 | XSLTPROC=@XSLTPROC@ | 37 | XSLTPROC=@XSLTPROC@ |
autofiles.sums
| 1 | -2b5c5a808c353b8df9e28e8cfb1e7d37114a2cad37eaede5bfe4354acae804d0 configure.ac | 1 | +97f3ed3cd8b491f0ceeb57baa40f4ed9c4be188692da1d13c93ef318c45cc4ae configure.ac |
| 2 | d3f9ee6f6f0846888d9a10fd3dad2e4b1258be84205426cf04d7cef02d61dad7 aclocal.m4 | 2 | d3f9ee6f6f0846888d9a10fd3dad2e4b1258be84205426cf04d7cef02d61dad7 aclocal.m4 |
| 3 | -7fc840fce5d372e92aa676e0040213a0f239cc8c01b6d6ef53c82043ceda571a libqpdf/qpdf/qpdf-config.h.in | 3 | +2e4cd495837be1b8454a4d8aef541b000988634be89d9c05a9cf5de67dffef5e libqpdf/qpdf/qpdf-config.h.in |
| 4 | 5297971a0ef90bcd5563eb3f7127a032bb76d3ae2af7258bf13479caf8983a60 m4/ax_cxx_compile_stdcxx.m4 | 4 | 5297971a0ef90bcd5563eb3f7127a032bb76d3ae2af7258bf13479caf8983a60 m4/ax_cxx_compile_stdcxx.m4 |
| 5 | 35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4 | 5 | 35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4 |
| 6 | 37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4 | 6 | 37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4 |
configure
| @@ -643,6 +643,9 @@ DOCBOOK_XHTML | @@ -643,6 +643,9 @@ DOCBOOK_XHTML | ||
| 643 | SHOW_FAILED_TEST_OUTPUT | 643 | SHOW_FAILED_TEST_OUTPUT |
| 644 | QPDF_SKIP_TEST_COMPARE_IMAGES | 644 | QPDF_SKIP_TEST_COMPARE_IMAGES |
| 645 | DEFAULT_CRYPTO | 645 | DEFAULT_CRYPTO |
| 646 | +USE_CRYPTO_GNUTLS | ||
| 647 | +pc_gnutls_LIBS | ||
| 648 | +pc_gnutls_CFLAGS | ||
| 646 | USE_CRYPTO_NATIVE | 649 | USE_CRYPTO_NATIVE |
| 647 | CXXWFLAGS | 650 | CXXWFLAGS |
| 648 | WFLAGS | 651 | WFLAGS |
| @@ -780,6 +783,7 @@ enable_werror | @@ -780,6 +783,7 @@ enable_werror | ||
| 780 | enable_int_warnings | 783 | enable_int_warnings |
| 781 | enable_implicit_crypto | 784 | enable_implicit_crypto |
| 782 | enable_crypto_native | 785 | enable_crypto_native |
| 786 | +enable_crypto_gnutls | ||
| 783 | with_default_crypto | 787 | with_default_crypto |
| 784 | enable_test_compare_images | 788 | enable_test_compare_images |
| 785 | enable_show_failed_test_output | 789 | enable_show_failed_test_output |
| @@ -811,7 +815,9 @@ PKG_CONFIG_LIBDIR | @@ -811,7 +815,9 @@ PKG_CONFIG_LIBDIR | ||
| 811 | pc_zlib_CFLAGS | 815 | pc_zlib_CFLAGS |
| 812 | pc_zlib_LIBS | 816 | pc_zlib_LIBS |
| 813 | pc_libjpeg_CFLAGS | 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 | # Initialize some variables set by options. | 823 | # Initialize some variables set by options. |
| @@ -1466,6 +1472,8 @@ Optional Features: | @@ -1466,6 +1472,8 @@ Optional Features: | ||
| 1466 | are not explicitly requested; true by default | 1472 | are not explicitly requested; true by default |
| 1467 | --enable-crypto-native whether to include support for native crypto | 1473 | --enable-crypto-native whether to include support for native crypto |
| 1468 | provider | 1474 | provider |
| 1475 | + --enable-crypto-gnutls whether to include support for gnutls crypto | ||
| 1476 | + provider | ||
| 1469 | --enable-test-compare-images | 1477 | --enable-test-compare-images |
| 1470 | whether to compare images in test suite; disabled by | 1478 | whether to compare images in test suite; disabled by |
| 1471 | default, enabling requires ghostscript and tiffcmp | 1479 | default, enabling requires ghostscript and tiffcmp |
| @@ -1535,6 +1543,10 @@ Some influential environment variables: | @@ -1535,6 +1543,10 @@ Some influential environment variables: | ||
| 1535 | C compiler flags for pc_libjpeg, overriding pkg-config | 1543 | C compiler flags for pc_libjpeg, overriding pkg-config |
| 1536 | pc_libjpeg_LIBS | 1544 | pc_libjpeg_LIBS |
| 1537 | linker flags for pc_libjpeg, overriding pkg-config | 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 | Use these variables to override the choices made by `configure' or to help | 1551 | Use these variables to override the choices made by `configure' or to help |
| 1540 | it to find libraries and programs with nonstandard names/locations. | 1552 | it to find libraries and programs with nonstandard names/locations. |
| @@ -17625,6 +17637,122 @@ $as_echo "#define USE_CRYPTO_NATIVE 1" >>confdefs.h | @@ -17625,6 +17637,122 @@ $as_echo "#define USE_CRYPTO_NATIVE 1" >>confdefs.h | ||
| 17625 | fi | 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 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking which crypto to use by default" >&5 | 17756 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking which crypto to use by default" >&5 |
| 17629 | $as_echo_n "checking which crypto to use by default... " >&6; } | 17757 | $as_echo_n "checking which crypto to use by default... " >&6; } |
| 17630 | 17758 | ||
| @@ -17650,6 +17778,11 @@ case "$DEFAULT_CRYPTO" in | @@ -17650,6 +17778,11 @@ case "$DEFAULT_CRYPTO" in | ||
| 17650 | bad_crypto=1 | 17778 | bad_crypto=1 |
| 17651 | fi | 17779 | fi |
| 17652 | ;; | 17780 | ;; |
| 17781 | + "gnutls") | ||
| 17782 | + if test "$USE_CRYPTO_GNUTLS" != "1"; then | ||
| 17783 | + bad_crypto=1 | ||
| 17784 | + fi | ||
| 17785 | + ;; | ||
| 17653 | *) | 17786 | *) |
| 17654 | bad_crypto=1 | 17787 | bad_crypto=1 |
| 17655 | ;; | 17788 | ;; |
configure.ac
| @@ -506,6 +506,49 @@ if test "$USE_CRYPTO_NATIVE" = "1"; then | @@ -506,6 +506,49 @@ if test "$USE_CRYPTO_NATIVE" = "1"; then | ||
| 506 | DEFAULT_CRYPTO=native | 506 | DEFAULT_CRYPTO=native |
| 507 | fi | 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 | dnl Allow the default crypto provider to be specified explicitly. | 552 | dnl Allow the default crypto provider to be specified explicitly. |
| 510 | 553 | ||
| 511 | AC_MSG_CHECKING(which crypto to use by default) | 554 | AC_MSG_CHECKING(which crypto to use by default) |
| @@ -527,6 +570,11 @@ case "$DEFAULT_CRYPTO" in | @@ -527,6 +570,11 @@ case "$DEFAULT_CRYPTO" in | ||
| 527 | bad_crypto=1 | 570 | bad_crypto=1 |
| 528 | fi | 571 | fi |
| 529 | ;; | 572 | ;; |
| 573 | + "gnutls") | ||
| 574 | + if test "$USE_CRYPTO_GNUTLS" != "1"; then | ||
| 575 | + bad_crypto=1 | ||
| 576 | + fi | ||
| 577 | + ;; | ||
| 530 | *) | 578 | *) |
| 531 | bad_crypto=1 | 579 | bad_crypto=1 |
| 532 | ;; | 580 | ;; |
libqpdf/QPDFCryptoProvider.cc
| @@ -5,6 +5,9 @@ | @@ -5,6 +5,9 @@ | ||
| 5 | #ifdef USE_CRYPTO_NATIVE | 5 | #ifdef USE_CRYPTO_NATIVE |
| 6 | # include <qpdf/QPDFCrypto_native.hh> | 6 | # include <qpdf/QPDFCrypto_native.hh> |
| 7 | #endif | 7 | #endif |
| 8 | +#ifdef USE_CRYPTO_GNUTLS | ||
| 9 | +# include <qpdf/QPDFCrypto_gnutls.hh> | ||
| 10 | +#endif | ||
| 8 | 11 | ||
| 9 | std::shared_ptr<QPDFCryptoImpl> | 12 | std::shared_ptr<QPDFCryptoImpl> |
| 10 | QPDFCryptoProvider::getImpl() | 13 | QPDFCryptoProvider::getImpl() |
| @@ -43,6 +46,9 @@ QPDFCryptoProvider::QPDFCryptoProvider() : | @@ -43,6 +46,9 @@ QPDFCryptoProvider::QPDFCryptoProvider() : | ||
| 43 | #ifdef USE_CRYPTO_NATIVE | 46 | #ifdef USE_CRYPTO_NATIVE |
| 44 | registerImpl_internal<QPDFCrypto_native>("native"); | 47 | registerImpl_internal<QPDFCrypto_native>("native"); |
| 45 | #endif | 48 | #endif |
| 49 | +#ifdef USE_CRYPTO_GNUTLS | ||
| 50 | + registerImpl_internal<QPDFCrypto_gnutls>("gnutls"); | ||
| 51 | +#endif | ||
| 46 | setDefaultProvider_internal(DEFAULT_CRYPTO); | 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,6 +14,9 @@ CRYPTO_NATIVE = \ | ||
| 14 | libqpdf/sha2.c \ | 14 | libqpdf/sha2.c \ |
| 15 | libqpdf/sha2big.c | 15 | libqpdf/sha2big.c |
| 16 | 16 | ||
| 17 | +CRYPTO_GNUTLS = \ | ||
| 18 | + libqpdf/QPDFCrypto_gnutls.cc | ||
| 19 | + | ||
| 17 | SRCS_libqpdf = \ | 20 | SRCS_libqpdf = \ |
| 18 | libqpdf/BitStream.cc \ | 21 | libqpdf/BitStream.cc \ |
| 19 | libqpdf/BitWriter.cc \ | 22 | libqpdf/BitWriter.cc \ |
| @@ -94,6 +97,10 @@ ifeq ($(USE_CRYPTO_NATIVE), 1) | @@ -94,6 +97,10 @@ ifeq ($(USE_CRYPTO_NATIVE), 1) | ||
| 94 | SRCS_libqpdf += $(CRYPTO_NATIVE) | 97 | SRCS_libqpdf += $(CRYPTO_NATIVE) |
| 95 | endif | 98 | endif |
| 96 | 99 | ||
| 100 | +ifeq ($(USE_CRYPTO_GNUTLS), 1) | ||
| 101 | +SRCS_libqpdf += $(CRYPTO_GNUTLS) | ||
| 102 | +endif | ||
| 103 | + | ||
| 97 | # ----- | 104 | # ----- |
| 98 | 105 | ||
| 99 | CCSRCS_libqpdf = $(filter %.cc,$(SRCS_libqpdf)) | 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,6 +84,9 @@ | ||
| 84 | /* Define to 1 if you have the ANSI C header files. */ | 84 | /* Define to 1 if you have the ANSI C header files. */ |
| 85 | #undef STDC_HEADERS | 85 | #undef STDC_HEADERS |
| 86 | 86 | ||
| 87 | +/* Whether to use the gnutls crypto provider */ | ||
| 88 | +#undef USE_CRYPTO_GNUTLS | ||
| 89 | + | ||
| 87 | /* Whether to use the native crypto provider */ | 90 | /* Whether to use the native crypto provider */ |
| 88 | #undef USE_CRYPTO_NATIVE | 91 | #undef USE_CRYPTO_NATIVE |
| 89 | 92 |