From: Francis Dupont Date: Mon, 28 May 2018 15:00:03 +0000 (+0200) Subject: [5382a] Code done, need more check X-Git-Tag: trac5631_base~3^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99676db43c21a886ac941618e8f7686dccfc8b4f;p=thirdparty%2Fkea.git [5382a] Code done, need more check --- diff --git a/m4macros/ax_crypto.m4 b/m4macros/ax_crypto.m4 index 622ee68166..4052e67f06 100644 --- a/m4macros/ax_crypto.m4 +++ b/m4macros/ax_crypto.m4 @@ -24,6 +24,49 @@ AC_DEFUN([ACX_CHECK_PROG_NONCACHE], [ IFS="$IFS_SAVED" ]) +AC_DEFUN([ACX_TRY_BOTAN1_TOOL], [ + TOOL=$1 + TOOL_ARG=$2 + BOTAN1_TOOL="" + ACX_CHECK_PROG_NONCACHE([BOTAN1_TOOL], [${TOOL}]) + AC_MSG_CHECKING([usability of ${TOOL} ${TOOL_ARG}]) + if test "$BOTAN1_TOOL" != "" ; then + if test -x ${BOTAN1_TOOL}; then + CRYPTO_LIBS=`$BOTAN1_TOOL $TOOL_ARG --libs` + LIBS_SAVED=${LIBS} + LIBS="$LIBS $CRYPTO_LIBS" + CRYPTO_INCLUDES=`$BOTAN1_TOOL $TOOL_ARG --cflags` + CPPFLAGS_SAVED=${CPPFLAGS} + CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS" + #AC_MSG_RESULT([found]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include + #include + #include + ], + [using namespace Botan; + LibraryInitializer::initialize(); + HashFunction *h = get_hash("MD5"); + ])], + [ AC_MSG_RESULT([ok]) + $3 + ], + [ AC_MSG_RESULT([not usable]) ] + ) + LIBS=${LIBS_SAVED} + CPPFLAGS=${CPPFLAGS_SAVED} + else + AC_MSG_RESULT([not executable]) + fi + else + AC_MSG_RESULT([not found]) + fi + BOTAN1_TOOL="" + AC_SUBST(BOTAN1_TOOL) + ] +) +# End of ACX_TRY_BOTAN1_TOOL + AC_DEFUN([ACX_TRY_BOTAN_TOOL], [ TOOL=$1 TOOL_ARG=$2 @@ -40,13 +83,9 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [ CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS" #AC_MSG_RESULT([found]) AC_LINK_IFELSE( - [AC_LANG_PROGRAM([#include - #include - #include - ], + [AC_LANG_PROGRAM([#include ], [using namespace Botan; - LibraryInitializer::initialize(); - HashFunction *h = get_hash("MD5"); + HashFunction *h = HashFunction::create("MD5").release(); ])], [ AC_MSG_RESULT([ok]) $3 @@ -74,7 +113,7 @@ AC_DEFUN([AX_CRYPTO], [ # Unless --with-botan-config is given, we first try to find these config # scripts ourselves. Unfortunately, on some systems, these scripts do not # provide the correct implementation, so for each script found, we try -# a compilation test (ACX_TRY_BOTAN_TOOL). If none are found, or none of +# a compilation test (ACX_TRY_BOTAN[1]_TOOL). If none are found, or none of # them work, we see if pkg-config is available. If so, we try the several # potential pkg-config .pc files. Again, on some systems, these can return # incorrect information as well, so the try-compile test is repeated for @@ -111,45 +150,73 @@ elif test "${botan_config}" != "yes" ; then if test -d "${botan_config}" ; then AC_MSG_ERROR([${botan_config} is a directory]) else - BOTAN_CONFIG="${botan_config}" + BOTAN1_CONFIG="${botan_config}" fi else AC_MSG_ERROR([--with-botan-config should point to a botan-config program and not a directory (${botan_config})]) fi + # determine Botan major version + BOTAN_CONFIG="${BOTAN1_CONFIG}" + cat > conftest.cpp << EOF +#include +MAJOR_VERSION=BOTAN_VERSION_MAJOR +EOF + CRYPTO_INCLUDES=`$BOTAN1_CONFIG --cflags` + MAJOR_VERSION=`$CXX -E $CXXFLAGS $CRYPTO_INCLUDES conftest.cpp | grep '^MAJOR_VERSION=' | $SED -e 's/MAJOR_VERSION=//' -e 's/[[ ]]//g' -e 's/"//g' 2> /dev/null` + if test "x${MAJOR_VERSION}" = "x2"; then + BOTAN1_CONFIG="" + fi + $RM -f conftest.cpp else BOTAN_CONFIG="" + BOTAN1_CONFIG="" # first try several possible names of the config script - # (botan-config-1.8 is there just in case, the official name change + # (botan-config-1.9 is there just in case, the official name change # came later) - BOTAN_CONFIG_VERSIONS="botan-config-1.10 botan-config-1.9 botan-config-1.8 botan-config" - for botan_config in $BOTAN_CONFIG_VERSIONS; do - ACX_TRY_BOTAN_TOOL([$botan_config],, - [ BOTAN_CONFIG="$botan_config" ] - ) - if test "$BOTAN_CONFIG" != "" ; then + BOTAN1_CONFIG_VERSIONS="botan-config-1.11 botan-config-1.10 botan-config-1.9 botan-config" + for botan1_config in $BOTAN1_CONFIG_VERSIONS; do + ACX_TRY_BOTAN1_TOOL([$botan1_config],, + [ BOTAN1_CONFIG="$botan1_config" ] + ) + if test "$BOTAN1_CONFIG" != "" ; then + BOTAN_CONFIG="${BOTAN1_CONFIG}" break fi done - if test "$BOTAN_CONFIG" = "" ; then - AC_PATH_PROG([PKG_CONFIG], [pkg-config]) - if test "$PKG_CONFIG" != "" ; then + AC_PATH_PROG([PKG_CONFIG], [pkg-config]) + if test "$PKG_CONFIG" != "" ; then + if test "$BOTAN1_CONFIG" = "" ; then # Ok so no script found, see if pkg-config knows of it. # Unfortunately, the botan.pc files also have their minor version # in their name, so we need to try them one by one - BOTAN_VERSIONS="botan-2 botan-1.11 botan-1.10 botan-1.9 botan-1.8" + BOTAN1_VERSIONS="botan-1.11 botan-1.10 botan-1.9 botan-1.8" + for version in $BOTAN1_VERSIONS; do + ACX_TRY_BOTAN1_TOOL([pkg-config], + ["$version --silence-errors"], + [ BOTAN1_CONFIG="$PKG_CONFIG $version" ] + ) + if test "$BOTAN1_CONFIG" != "" ; then + BOTAN_CONFIG="${BOTAN1_CONFIG}" + break + fi + done + fi + if test "$BOTAN_CONFIG" = "" ; then + # Retry with Botan2 + BOTAN_VERSIONS="botan-2" for version in $BOTAN_VERSIONS; do ACX_TRY_BOTAN_TOOL([pkg-config], ["$version --silence-errors"], [ BOTAN_CONFIG="$PKG_CONFIG $version" ] ) - if test "$BOTAN_CONFIG" != "" ; then - break - fi + if test "$BOTAN_CONFIG" != "" ; then + break + fi done fi fi fi -if test "x${BOTAN_CONFIG}" != "x" +if test "$BOTAN_CONFIG" != "" then CRYPTO_LIBS=`${BOTAN_CONFIG} --libs` CRYPTO_INCLUDES=`${BOTAN_CONFIG} --cflags` @@ -175,7 +242,7 @@ then AUTOCONF_BOTAN_VERSION=BOTAN_VERSION_MAJOR . BOTAN_VERSION_MINOR . BOTAN_VERSION_PATCH EOF - CRYPTO_VERSION=`$CPPP $CPPFLAGS $CRYPTO_INCLUDES conftest.cpp | grep '^AUTOCONF_BOTAN_VERSION=' | $SED -e 's/^AUTOCONF_BOTAN_VERSION=//' -e 's/[[ ]]//g' -e 's/"//g' 2> /dev/null` + CRYPTO_VERSION=`$CPPP $CPPFLAGS $CRYPTO_INCLUDES conftest.cpp | grep '^AUTOCONF_BOTAN_VERSION=' | $SED -e 's/^AUTOCONF_BOTAN_VERSION=//' -e 's/[[ ]]//g' -e 's/"//g' 2> /dev/null` if test -z "$CRYPTO_VERSION"; then CRYPTO_VERSION="unknown" fi @@ -222,14 +289,18 @@ EOF # failure handler we can detect the difference between a header not existing # (or not even passing the pre-processor phase) and a header file resulting # in compilation failures. - AC_CHECK_HEADERS([botan/botan.h],,[ + HEADER_TO_CHECK=botan/botan.h + if test "BOTAN1_CONFIG" = ""; then + HEADER_TO_CHECK=botan/lookup.h + fi + AC_CHECK_HEADERS([${HEADER_TO_CHECK}],,[ CRYPTO_INCLUDES="" CRYPTO_LIBS="" CRYPTO_LDFLAGS="" CRYPTO_RPATH="" if test "x$ac_header_preproc" = "xyes"; then - AC_MSG_RESULT([ -botan/botan.h was found but is unusable. The most common cause of this problem + AC_MSG_RESULT([${HEADER_TO_CHECK} +was found but is unusable. The most common cause of this problem is attempting to use an updated C++ compiler with older C++ libraries, such as the version of Botan that comes with your distribution. If you have updated your C++ compiler we highly recommend that you use support libraries such as @@ -242,7 +313,7 @@ Boost and Botan that were compiled with the same compiler version.]) LIBS=$LIBS_SAVED fi -if test "x${CRYPTO_LIBS}" != "x" +if test "x${BOTAN1_CONFIG}" != "x" then CPPFLAGS_SAVED=$CPPFLAGS CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS" @@ -257,13 +328,41 @@ then LibraryInitializer::initialize(); HashFunction *h = get_hash("MD5"); ])], + [AC_MSG_RESULT([checking for Botan1 library... yes])], + [AC_MSG_RESULT([checking for Botan1 library... no]) + CRYPTO_INCLUDES="" + CRYPTO_LIBS="" + CRYPTO_LDFLAGS="" + CRYPTO_RPATH="" + AC_MSG_RESULT([Needs Botan library 1.9 or higher. On some systems, + the botan package has a few missing dependencies (libbz2 and + libgmp), if libbotan has been installed and you see this message, + try upgrading to a higher version of botan or installing libbz2 + and libgmp.])] + ) + CPPFLAGS=$CPPFLAGS_SAVED + LIBS=$LIBS_SAVED + CRYPTO_NAME="Botan1" + CRYPTO_PACKAGE="botan-1.11" +elif test "x${CRYPTO_LIBS}" != "x" +then + CPPFLAGS_SAVED=$CPPFLAGS + CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS" + LIBS_SAVED="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], + [using namespace Botan; + HashFunction *h = HashFunction::create("MD5") +.release(); + ])], [AC_MSG_RESULT([checking for Botan library... yes])], [AC_MSG_RESULT([checking for Botan library... no]) CRYPTO_INCLUDES="" CRYPTO_LIBS="" CRYPTO_LDFLAGS="" CRYPTO_RPATH="" - AC_MSG_RESULT([Needs Botan library 1.8 or higher. On some systems, + AC_MSG_RESULT([Needs Botan library 2.0 or higher. On some systems, the botan package has a few missing dependencies (libbz2 and libgmp), if libbotan has been installed and you see this message, try upgrading to a higher version of botan or installing libbz2 @@ -271,20 +370,20 @@ then ) CPPFLAGS=$CPPFLAGS_SAVED LIBS=$LIBS_SAVED + CRYPTO_NAME="Botan" + CRYPTO_PACKAGE="botan-2" fi if test "x${CRYPTO_LIBS}" != "x" then - CRYPTO_NAME="Botan" DISABLED_CRYPTO="OpenSSL" - CRYPTO_PACKAGE="botan-1.8" CRYPTO_CFLAGS="" DISTCHECK_CRYPTO_CONFIGURE_FLAG="$distcheck_botan" AC_DEFINE_UNQUOTED([WITH_BOTAN], [], [Compile with Botan crypto]) else CRYPTO_NAME="OpenSSL" DISABLED_CRYPTO="Botan" - CRYPTO_PACKAGE="openssl-1.0.2" + CRYPTO_PACKAGE="openssl-1.1.0" AC_DEFINE_UNQUOTED([WITH_OPENSSL], [], [Compile with OpenSSL crypto]) AC_MSG_CHECKING(for OpenSSL library) # from bind9 @@ -314,6 +413,7 @@ else else CRYPTO_CFLAGS="" CRYPTO_INCLUDES="-I${use_openssl}/include" + OPENSSL_LIBDIR="${use_openssl}/lib" DISTCHECK_CRYPTO_CONFIGURE_FLAG="--with-openssl=${use_openssl}" case $host in *-solaris*) @@ -386,6 +486,7 @@ EOF CPPFLAGS=${CPPFLAGS_SAVED} fi +AM_CONDITIONAL(HAVE_BOTAN1, test "$CRYPTO_NAME" = "Botan1") AM_CONDITIONAL(HAVE_BOTAN, test "$CRYPTO_NAME" = "Botan") AM_CONDITIONAL(HAVE_OPENSSL, test "$CRYPTO_NAME" = "OpenSSL") AC_SUBST(CRYPTO_INCLUDES) @@ -395,5 +496,6 @@ AC_SUBST(CRYPTO_LDFLAGS) AC_SUBST(CRYPTO_PACKAGE) AC_SUBST(CRYPTO_RPATH) AC_SUBST(DISTCHECK_CRYPTO_CONFIGURE_FLAG) +AC_SUBST(OPENSSL_LIBDIR) ] ) diff --git a/src/lib/cryptolink/Makefile.am b/src/lib/cryptolink/Makefile.am index 2fb2093ec1..1effdc8bd6 100644 --- a/src/lib/cryptolink/Makefile.am +++ b/src/lib/cryptolink/Makefile.am @@ -11,6 +11,12 @@ lib_LTLIBRARIES = libkea-cryptolink.la libkea_cryptolink_la_SOURCES = cryptolink.h cryptolink.cc libkea_cryptolink_la_SOURCES += crypto_hash.h crypto_hash.cc libkea_cryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc +if HAVE_BOTAN1 +libkea_cryptolink_la_SOURCES += botan1_link.cc +libkea_cryptolink_la_SOURCES += botan_common.h +libkea_cryptolink_la_SOURCES += botan1_hash.cc +libkea_cryptolink_la_SOURCES += botan1_hmac.cc +endif if HAVE_BOTAN libkea_cryptolink_la_SOURCES += botan_link.cc libkea_cryptolink_la_SOURCES += botan_common.h @@ -38,6 +44,11 @@ libkea_cryptolink_include_HEADERS = \ crypto_hmac.h \ cryptolink.h +if HAVE_BOTAN1 +libkea_cryptolink_include_HEADERS += \ + botan_common.h +endif + if HAVE_BOTAN libkea_cryptolink_include_HEADERS += \ botan_common.h diff --git a/src/lib/cryptolink/botan1_hash.cc b/src/lib/cryptolink/botan1_hash.cc new file mode 100644 index 0000000000..222aa45349 --- /dev/null +++ b/src/lib/cryptolink/botan1_hash.cc @@ -0,0 +1,209 @@ +// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +namespace isc { +namespace cryptolink { + +/// @brief Decode the HashAlgorithm enum into a name usable by Botan +/// +/// @param algorithm algorithm to be converted +/// @return text representation of the algorithm name +const std::string +btn::getHashAlgorithmName(HashAlgorithm algorithm) { + switch (algorithm) { + case isc::cryptolink::MD5: + return ("MD5"); + case isc::cryptolink::SHA1: + return ("SHA-1"); + case isc::cryptolink::SHA256: + return ("SHA-256"); + case isc::cryptolink::SHA224: + return ("SHA-224"); + case isc::cryptolink::SHA384: + return ("SHA-384"); + case isc::cryptolink::SHA512: + return ("SHA-512"); + case isc::cryptolink::UNKNOWN_HASH: + return ("Unknown"); + } + // compiler should have prevented us to reach this, since we have + // no default. But we need a return value anyway + return ("Unknown"); +} + +/// @brief Botan implementation of Hash. Each method is the counterpart +/// of the Hash corresponding method. +class HashImpl { +public: + + /// @brief Constructor for specific hash algorithm + /// + /// @param hash_algorithm The hash algorithm + explicit HashImpl(const HashAlgorithm hash_algorithm) + : hash_algorithm_(hash_algorithm), hash_() { + Botan::HashFunction* hash; + try { + const std::string& name = + btn::getHashAlgorithmName(hash_algorithm); + hash = Botan::get_hash(name); + } catch (const Botan::Algorithm_Not_Found&) { + isc_throw(isc::cryptolink::UnsupportedAlgorithm, + "Unknown hash algorithm: " << + static_cast(hash_algorithm)); + } catch (const Botan::Exception& exc) { + isc_throw(isc::cryptolink::LibraryError, + "Botan error: " << exc.what()); + } + + hash_.reset(hash); + } + + /// @brief Destructor + ~HashImpl() { } + + /// @brief Returns the HashAlgorithm of the object + HashAlgorithm getHashAlgorithm() const { + return (hash_algorithm_); + } + + /// @brief Returns the output size of the digest + /// + /// @return output size of the digest + size_t getOutputLength() const { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) + return (hash_->output_length()); +#else +#error "Unsupported Botan version (need 1.9 or higher)" + // added to suppress irrelevant compiler errors + return 0; +#endif + } + + /// @brief Adds data to the digest + /// + /// See @ref isc::cryptolink::Hash::update() for details. + void update(const void* data, const size_t len) { + try { + hash_->update(static_cast(data), len); + } catch (const Botan::Exception& exc) { + isc_throw(isc::cryptolink::LibraryError, + "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final digest + /// + /// See @ref isc::cryptolink::Hash::final() for details. + void final(isc::util::OutputBuffer& result, size_t len) { + try { + Botan::SecureVector b_result(hash_->final()); + + if (len > b_result.size()) { + len = b_result.size(); + } + result.writeData(&b_result[0], len); + } catch (const Botan::Exception& exc) { + isc_throw(isc::cryptolink::LibraryError, + "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final digest + /// + /// See @ref isc::cryptolink::Hash::final() for details. + void final(void* result, size_t len) { + try { + Botan::SecureVector b_result(hash_->final()); + size_t output_size = getOutputLength(); + if (output_size > len) { + output_size = len; + } + std::memcpy(result, &b_result[0], output_size); + } catch (const Botan::Exception& exc) { + isc_throw(isc::cryptolink::LibraryError, + "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final digest + /// + /// See @ref isc::cryptolink::Hash::final() for details. + std::vector final(size_t len) { + try { + Botan::SecureVector b_result(hash_->final()); + if (len > b_result.size()) { + len = b_result.size(); + } + return (std::vector(&b_result[0], &b_result[len])); + } catch (const Botan::Exception& exc) { + isc_throw(isc::cryptolink::LibraryError, + "Botan error: " << exc.what()); + } + } + +private: + /// @brief The hash algorithm + HashAlgorithm hash_algorithm_; + + /// @brief The protected pointer to the Botan HashFunction object + boost::scoped_ptr hash_; +}; + +Hash::Hash(const HashAlgorithm hash_algorithm) +{ + impl_ = new HashImpl(hash_algorithm); +} + +Hash::~Hash() { + delete impl_; +} + +HashAlgorithm +Hash::getHashAlgorithm() const { + return (impl_->getHashAlgorithm()); +} + +size_t +Hash::getOutputLength() const { + return (impl_->getOutputLength()); +} + +void +Hash::update(const void* data, const size_t len) { + impl_->update(data, len); +} + +void +Hash::final(isc::util::OutputBuffer& result, size_t len) { + impl_->final(result, len); +} + +void +Hash::final(void* result, size_t len) { + impl_->final(result, len); +} + +std::vector +Hash::final(size_t len) { + return impl_->final(len); +} + +} // namespace cryptolink +} // namespace isc diff --git a/src/lib/cryptolink/botan1_hmac.cc b/src/lib/cryptolink/botan1_hmac.cc new file mode 100644 index 0000000000..cebf23f037 --- /dev/null +++ b/src/lib/cryptolink/botan1_hmac.cc @@ -0,0 +1,251 @@ +// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace isc { +namespace cryptolink { + +/// @brief Botan implementation of HMAC. Each method is the counterpart +/// of the HMAC corresponding method. +class HMACImpl { +public: + /// @brief Constructor from a secret and a hash algorithm + /// + /// See constructor of the @ref isc::cryptolink::HMAC class for details. + /// + /// @param secret The secret to sign with + /// @param secret_len The length of the secret + /// @param hash_algorithm The hash algorithm + explicit HMACImpl(const void* secret, size_t secret_len, + const HashAlgorithm hash_algorithm) + : hash_algorithm_(hash_algorithm), hmac_() { + Botan::HashFunction* hash; + try { + const std::string& name = + btn::getHashAlgorithmName(hash_algorithm); + hash = Botan::get_hash(name); + } catch (const Botan::Algorithm_Not_Found&) { + isc_throw(UnsupportedAlgorithm, + "Unknown hash algorithm: " << + static_cast(hash_algorithm)); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + + hmac_.reset(new Botan::HMAC(hash)); + + // If the key length is larger than the block size, we hash the + // key itself first. + try { + // use a temp var so we don't have blocks spanning + // preprocessor directives +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) + size_t block_length = hash->hash_block_size(); +#else +#error "Unsupported Botan version (need 1.9 or higher)" + // added to suppress irrelevant compiler errors + size_t block_length = 0; +#endif + if (secret_len > block_length) { + Botan::SecureVector hashed_key = + hash->process(static_cast(secret), + secret_len); + hmac_->set_key(&hashed_key[0], hashed_key.size()); + } else { + // Botan 1.8 considers len 0 a bad key. 1.9 does not, + // but we won't accept it anyway, and fail early + if (secret_len == 0) { + isc_throw(BadKey, "Bad HMAC secret length: 0"); + } + hmac_->set_key(static_cast(secret), + secret_len); + } + } catch (const Botan::Invalid_Key_Length& ikl) { + isc_throw(BadKey, ikl.what()); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + + /// @brief Destructor + ~HMACImpl() { + } + + /// @brief Returns the HashAlgorithm of the object + HashAlgorithm getHashAlgorithm() const { + return (hash_algorithm_); + } + + /// @brief Returns the output size of the digest + /// + /// @return output size of the digest + size_t getOutputLength() const { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) + return (hmac_->output_length()); +#else +#error "Unsupported Botan version (need 1.9 or higher)" + // added to suppress irrelevant compiler errors + return 0; +#endif + } + + /// @brief Add data to digest + /// + /// See @ref isc::cryptolink::HMAC::update() for details. + void update(const void* data, const size_t len) { + try { + hmac_->update(static_cast(data), len); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final signature + /// + /// See @ref isc::cryptolink::HMAC::sign() for details. + void sign(isc::util::OutputBuffer& result, size_t len) { + try { + Botan::SecureVector b_result(hmac_->final()); + + if (len > b_result.size()) { + len = b_result.size(); + } + result.writeData(&b_result[0], len); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final signature + /// + /// See @ref isc::cryptolink::HMAC::sign() for details. + void sign(void* result, size_t len) { + try { + Botan::SecureVector b_result(hmac_->final()); + size_t output_size = getOutputLength(); + if (output_size > len) { + output_size = len; + } + std::memcpy(result, &b_result[0], output_size); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + + /// @brief Calculate the final signature + /// + /// See @ref isc::cryptolink::HMAC::sign() for details. + std::vector sign(size_t len) { + try { + Botan::SecureVector b_result(hmac_->final()); + if (len > b_result.size()) { + len = b_result.size(); + } + return (std::vector(&b_result[0], &b_result[len])); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + + + /// @brief Verify an existing signature + /// + /// See @ref isc::cryptolink::HMAC::verify() for details. + bool verify(const void* sig, size_t len) { + // Botan's verify_mac checks if len matches the output_length, + // which causes it to fail for truncated signatures, so we do + // the check ourselves + try { + size_t size = getOutputLength(); + if (len < 10 || len < size / 2) { + return (false); + } + if (len > size) { + len = size; + } + if (digest_.size() == 0) { + digest_ = hmac_->final(); + } + return (Botan::same_mem(&digest_[0], + static_cast(sig), + len)); + } catch (const Botan::Exception& exc) { + isc_throw(LibraryError, "Botan error: " << exc.what()); + } + } + +private: + /// @brief The hash algorithm + HashAlgorithm hash_algorithm_; + + /// @brief The protected pointer to the Botan HMAC object + boost::scoped_ptr hmac_; + + /// @brief The digest cache for multiple verify + Botan::SecureVector digest_; +}; + +HMAC::HMAC(const void* secret, size_t secret_length, + const HashAlgorithm hash_algorithm) +{ + impl_ = new HMACImpl(secret, secret_length, hash_algorithm); +} + +HMAC::~HMAC() { + delete impl_; +} + +HashAlgorithm +HMAC::getHashAlgorithm() const { + return (impl_->getHashAlgorithm()); +} + +size_t +HMAC::getOutputLength() const { + return (impl_->getOutputLength()); +} + +void +HMAC::update(const void* data, const size_t len) { + impl_->update(data, len); +} + +void +HMAC::sign(isc::util::OutputBuffer& result, size_t len) { + impl_->sign(result, len); +} + +void +HMAC::sign(void* result, size_t len) { + impl_->sign(result, len); +} + +std::vector +HMAC::sign(size_t len) { + return impl_->sign(len); +} + +bool +HMAC::verify(const void* sig, const size_t len) { + return (impl_->verify(sig, len)); +} + +} // namespace cryptolink +} // namespace isc diff --git a/src/lib/cryptolink/botan1_link.cc b/src/lib/cryptolink/botan1_link.cc new file mode 100644 index 0000000000..a367c4ea6e --- /dev/null +++ b/src/lib/cryptolink/botan1_link.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include + +#include +#include + +namespace isc { +namespace cryptolink { + +// For Botan, we use the CryptoLink class object in RAII style +class CryptoLinkImpl { +private: + Botan::LibraryInitializer botan_init_; +}; + +CryptoLink::~CryptoLink() { + delete impl_; +} + +void +CryptoLink::initialize() { + CryptoLink& c = getCryptoLinkInternal(); + if (c.impl_ == NULL) { + try { + c.impl_ = new CryptoLinkImpl(); + } catch (const Botan::Exception& ex) { + isc_throw(InitializationError, "Botan error: " << ex.what()); + } + } +} + +std::string +CryptoLink::getVersion() { + return (Botan::version_string()); +} + +} // namespace cryptolink +} // namespace isc + diff --git a/src/lib/cryptolink/botan_hash.cc b/src/lib/cryptolink/botan_hash.cc index 65bae22d83..8a1e37bb4f 100644 --- a/src/lib/cryptolink/botan_hash.cc +++ b/src/lib/cryptolink/botan_hash.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,17 +11,10 @@ #include -#include -#include -#include -#include +#include #include -#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,0) -#define secure_vector SecureVector -#endif - namespace isc { namespace cryptolink { @@ -66,11 +59,7 @@ public: try { const std::string& name = btn::getHashAlgorithmName(hash_algorithm); -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) hash = Botan::HashFunction::create(name).release(); -#else - hash = Botan::get_hash(name); -#endif } catch (const Botan::Algorithm_Not_Found&) { isc_throw(isc::cryptolink::UnsupportedAlgorithm, "Unknown hash algorithm: " << @@ -95,15 +84,7 @@ public: /// /// @return output size of the digest size_t getOutputLength() const { -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) return (hash_->output_length()); -#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0) - return (hash_->OUTPUT_LENGTH); -#else -#error "Unsupported Botan version (need 1.8 or higher)" - // added to suppress irrelevant compiler errors - return 0; -#endif } /// @brief Adds data to the digest diff --git a/src/lib/cryptolink/botan_hmac.cc b/src/lib/cryptolink/botan_hmac.cc index b344de5b10..c7175d6b94 100644 --- a/src/lib/cryptolink/botan_hmac.cc +++ b/src/lib/cryptolink/botan_hmac.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,18 +11,11 @@ #include -#include -#include #include -#include -#include +#include #include -#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,0) -#define secure_vector SecureVector -#endif - namespace isc { namespace cryptolink { @@ -44,7 +37,6 @@ public: try { const std::string& name = btn::getHashAlgorithmName(hash_algorithm); -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,0) std::unique_ptr hash_ptr = Botan::HashFunction::create(name); if (hash_ptr) { @@ -52,9 +44,6 @@ public: } else { throw Botan::Algorithm_Not_Found(name); } -#else - hash = Botan::get_hash(name); -#endif } catch (const Botan::Algorithm_Not_Found&) { isc_throw(UnsupportedAlgorithm, "Unknown hash algorithm: " << @@ -70,15 +59,7 @@ public: try { // use a temp var so we don't have blocks spanning // preprocessor directives -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) size_t block_length = hash->hash_block_size(); -#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0) - size_t block_length = hash->HASH_BLOCK_SIZE; -#else -#error "Unsupported Botan version (need 1.8 or higher)" - // added to suppress irrelevant compiler errors - size_t block_length = 0; -#endif if (secret_len > block_length) { Botan::secure_vector hashed_key = hash->process(static_cast(secret), @@ -113,15 +94,7 @@ public: /// /// @return output size of the digest size_t getOutputLength() const { -#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0) return (hmac_->output_length()); -#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0) - return (hmac_->OUTPUT_LENGTH); -#else -#error "Unsupported Botan version (need 1.8 or higher)" - // added to suppress irrelevant compiler errors - return 0; -#endif } /// @brief Add data to digest diff --git a/src/lib/cryptolink/botan_link.cc b/src/lib/cryptolink/botan_link.cc index f57cb45dd3..c7f40cb182 100644 --- a/src/lib/cryptolink/botan_link.cc +++ b/src/lib/cryptolink/botan_link.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2015,2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -10,18 +10,15 @@ #include #include -#define BOTAN_NO_DEPRECATED_WARNINGS - -#include -#include +#include +#include namespace isc { namespace cryptolink { // For Botan, we use the CryptoLink class object in RAII style class CryptoLinkImpl { -private: - Botan::LibraryInitializer botan_init_; + // empty class }; CryptoLink::~CryptoLink() {