]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5382a] Code done, need more check
authorFrancis Dupont <fdupont@isc.org>
Mon, 28 May 2018 15:00:03 +0000 (17:00 +0200)
committerFrancis Dupont <fdupont@isc.org>
Mon, 28 May 2018 15:00:03 +0000 (17:00 +0200)
m4macros/ax_crypto.m4
src/lib/cryptolink/Makefile.am
src/lib/cryptolink/botan1_hash.cc [new file with mode: 0644]
src/lib/cryptolink/botan1_hmac.cc [new file with mode: 0644]
src/lib/cryptolink/botan1_link.cc [new file with mode: 0644]
src/lib/cryptolink/botan_hash.cc
src/lib/cryptolink/botan_hmac.cc
src/lib/cryptolink/botan_link.cc

index 622ee68166aef2314fe2641364feb5c723480fe2..4052e67f0657995facc42dd81fb5223abce2cadd 100644 (file)
@@ -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 <botan/botan.h>
+                                  #include <botan/init.h>
+                                  #include <botan/hash.h>
+                                 ],
+                                 [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 <botan/botan.h>
-                                  #include <botan/init.h>
-                                  #include <botan/hash.h>
-                                 ],
+                [AC_LANG_PROGRAM([#include <botan/lookup.h>],
                                  [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 <botan/version.h>
+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 <botan/lookup.h>],
+                         [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)
 ]
 )
index 2fb2093ec156c88943e22f8ac7c33fe0d2a1504d..1effdc8bd60f70c2f8f17cf1e835f28399ead873 100644 (file)
@@ -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 (file)
index 0000000..222aa45
--- /dev/null
@@ -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 <config.h>
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_hash.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/version.h>
+#include <botan/botan.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+#include <cryptolink/botan_common.h>
+
+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<int>(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<const Botan::byte*>(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<Botan::byte> 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<Botan::byte> 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<uint8_t> final(size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hash_->final());
+            if (len > b_result.size()) {
+                len = b_result.size();
+            }
+            return (std::vector<uint8_t>(&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<Botan::HashFunction> 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<uint8_t>
+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 (file)
index 0000000..cebf23f
--- /dev/null
@@ -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 <config.h>
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <botan/version.h>
+#include <botan/botan.h>
+#include <botan/hmac.h>
+#include <botan/hash.h>
+#include <botan/types.h>
+
+#include <cryptolink/botan_common.h>
+
+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<int>(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<Botan::byte> hashed_key =
+                    hash->process(static_cast<const Botan::byte*>(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<const Botan::byte*>(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<const Botan::byte*>(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<Botan::byte> 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<Botan::byte> 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<uint8_t> sign(size_t len) {
+        try {
+            Botan::SecureVector<Botan::byte> b_result(hmac_->final());
+            if (len > b_result.size()) {
+                len = b_result.size();
+            }
+            return (std::vector<uint8_t>(&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<const unsigned char*>(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<Botan::HMAC> hmac_;
+
+    /// @brief The digest cache for multiple verify
+    Botan::SecureVector<Botan::byte> 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<uint8_t>
+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 (file)
index 0000000..a367c4e
--- /dev/null
@@ -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 <config.h>
+
+#include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_hash.h>
+#include <cryptolink/crypto_hmac.h>
+
+#include <botan/botan.h>
+#include <botan/init.h>
+
+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
+
index 65bae22d831f82258ed40dc3f8e9d3c7f0aeacf4..8a1e37bb4f1887f5159bc6aa50b2716211a3afa5 100644 (file)
@@ -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
 
 #include <boost/scoped_ptr.hpp>
 
-#include <botan/version.h>
-#include <botan/botan.h>
-#include <botan/hash.h>
-#include <botan/types.h>
+#include <botan/lookup.h>
 
 #include <cryptolink/botan_common.h>
 
-#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
index b344de5b1019b6fa3a620439d4a06d7c4485ec7d..c7175d6b94d353c9cbb5c2a8923e415ea11d352b 100644 (file)
@@ -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
 
 #include <boost/scoped_ptr.hpp>
 
-#include <botan/version.h>
-#include <botan/botan.h>
 #include <botan/hmac.h>
-#include <botan/hash.h>
-#include <botan/types.h>
+#include <botan/lookup.h>
 
 #include <cryptolink/botan_common.h>
 
-#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<Botan::HashFunction> 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<Botan::byte> hashed_key =
                     hash->process(static_cast<const Botan::byte*>(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
index f57cb45dd3731c67e9c0d66fc7a799d69c9aacad..c7f40cb18244fe26782c35812bb85a676d8070f6 100644 (file)
@@ -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
 #include <cryptolink/crypto_hash.h>
 #include <cryptolink/crypto_hmac.h>
 
-#define BOTAN_NO_DEPRECATED_WARNINGS
-
-#include <botan/botan.h>
-#include <botan/init.h>
+#include <botan/exceptn.h>
+#include <botan/version.h>
 
 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() {