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
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 "#define USE_CRYPTO_NATIVE 1" >>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 "$DEFAULT_CRYPTO" 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 "$USE_CRYPTO_NATIVE" = "1"; 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 "$DEFAULT_CRYPTO" 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 | ... | ... |