]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1614] Checkpoint: ported HMAC to EVP
authorFrancis Dupont <fdupont@isc.org>
Sat, 19 Feb 2022 20:22:04 +0000 (21:22 +0100)
committerTomek Mrugalski <tomek@isc.org>
Fri, 24 Jun 2022 15:37:29 +0000 (17:37 +0200)
m4macros/ax_crypto.m4
src/lib/cryptolink/openssl_compat.h
src/lib/cryptolink/openssl_hmac.cc
src/lib/cryptolink/tests/hmac_unittests.cc

index 6786bac1ef781f04ede9c314ddf0ec5ed3b68cec..c075aba8401205df1166a3302a9e05dfdfee1fa0 100644 (file)
@@ -346,36 +346,27 @@ EOF
     #CRYPTO_LDFLAGS="-ldl"
     CRYPTO_LDFLAGS=""
     CRYPTO_RPATH=""
-    dnl Check availability of SHA-2
     AC_MSG_CHECKING([support of SHA-2])
     LIBS_SAVED=${LIBS}
     LIBS="$LIBS $CRYPTO_LIBS"
     CPPFLAGS_SAVED=${CPPFLAGS}
     CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
-    AC_LINK_IFELSE(
-        [AC_LANG_PROGRAM([#include <openssl/evp.h>],
-                         [const EVP_MD* h224 = EVP_sha224();
-                          const EVP_MD* h256 = EVP_sha256();
-                          const EVP_MD* h384 = EVP_sha384();
-                          const EVP_MD* h512 = EVP_sha512();
-                          ])],
-        [AC_MSG_RESULT([yes])],
-        [AC_MSG_ERROR([missing EVP entry for SHA-2])])
-    dnl Check HMAC API
-    AC_MSG_CHECKING([HMAC functions returning ints])
-    AC_LINK_IFELSE(
-         [AC_LANG_PROGRAM([#include <openssl/opensslv.h>
-                           #include <openssl/hmac.h>],
-                          [#if OPENSSL_VERSION_NUMBER < 0x10100000L
-                           HMAC_CTX ctx, tmp;
-                           int n = HMAC_Init(&ctx, NULL, 0, NULL);
-                           n += HMAC_Update(&ctx, NULL, 0);
-                           n += HMAC_CTX_copy(&tmp, &ctx);
-                           n += HMAC_Final(&tmp, NULL, NULL);
-                           #endif
-                           ])],
-         [AC_MSG_RESULT([yes])],
-         [AC_MSG_ERROR([HMAC functions return void: please use OpenSSL version 1.0.1 or later])])
+    dnl Check availability of legacy hash
+    AC_CHECK_FUNC([EVP_md5],,[missing EVP entry for MD5])
+    AC_CHECK_FUNC([EVP_sha1],,[missing EVP entry for SHA1])
+    dnl Check availability of SHA-2
+    AC_CHECK_FUNC([EVP_sha224],,[missing EVP entry for SHA224])
+    AC_CHECK_FUNC([EVP_sha256],,[missing EVP entry for SHA256])
+    AC_CHECK_FUNC([EVP_sha384],,[missing EVP entry for SHA384])
+    AC_CHECK_FUNC([EVP_sha512],,[missing EVP entry for SHA512])
+    dnl Two generations of EVP_MD_CTX functions
+    AC_CHECK_FUNCS([EVP_MD_CTX_new EVP_MD_CTX_free],,
+        [AC_CHECK_FUNCS([EVP_MD_CTX_create EVP_MD_CTX_destroy],,
+        [AC_MSG_ERROR([missing EVP MD CTX functions])])])
+    dnl Same for EVP and HMAC
+    AC_CHECK_FUNCS([EVP_PKEY_new_raw_private_key],,
+        [AC_CHECK_FUNCS([EVP_PKEY_new_mac_key],,
+        [AC_MSG_ERROR([missing EVP PKEY new key function])])])
     LIBS=${LIBS_SAVED}
     CPPFLAGS=${CPPFLAGS_SAVED}
 fi
index 992fe031f10c46802dc8aab52bc12d09f9e3b14d..33b85e1a22aba0955bb1604a0459659dae0829b2 100644 (file)
@@ -4,52 +4,58 @@
 // 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 <openssl/opensslv.h>
-
-#if (defined(LIBRESSL_VERSION_NUMBER) && \
-     (LIBRESSL_VERSION_NUMBER < 0x3050200fL)) || \
-    (OPENSSL_VERSION_NUMBER < 0x10100000L)
-
 // This file is included by hash and hmac codes so KEA_H* macros
 // avoid to define unused inlines.
 
 #ifdef KEA_HASH
 
-// EVP_MD_CTX_new() is EVP_MD_CTX_create() in OpenSSL < 1.1
+#ifndef HAVE_EVP_MD_CTX_NEW
+#ifdef HAVE_EVP_MD_CTX_CREATE
+
+// EVP_MD_CTX_new() is EVP_MD_CTX_create() in old OpenSSL
 
 inline EVP_MD_CTX* EVP_MD_CTX_new() {
     return (EVP_MD_CTX_create());
 }
 
-// EVP_MD_CTX_free(ctx) is EVP_MD_CTX_destroy(ctx) in OpenSSL < 1.1
+#else
+#error have no EVP_MD_CTX_new() nor EVP_MD_CTX_create()
+#endif
+#endif
+
+#ifndef HAVE_EVP_MD_CTX_FREE
+#ifdef HAVE_EVP_MD_CTX_DESTROY
+
+// EVP_MD_CTX_free(ctx) is EVP_MD_CTX_destroy(ctx) in old OpenSSL
 
 inline void EVP_MD_CTX_free(EVP_MD_CTX* ctx) {
     EVP_MD_CTX_destroy(ctx);
 }
 
+#else
+#error have no EVP_MD_CTX_free() nor EVP_MD_CTX_destroy()
+#endif
 #endif
 
-#ifdef KEA_HMAC
+#endif
 
-// HMAC_CTX_new() implementation for OpenSSL < 1.1
+#ifdef KEA_HMAC
 
-inline HMAC_CTX* HMAC_CTX_new() {
-    HMAC_CTX* ctx = static_cast<HMAC_CTX*>(OPENSSL_malloc(sizeof(HMAC_CTX)));
-    if (ctx != 0) {
-        HMAC_CTX_init(ctx);
-    }
-    return (ctx);
-}
+#ifndef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
+#ifdef HAVE_EVP_PKEY_NEW_MAC_KEY
 
-// HMAC_CTX_free() implementation for OpenSSL < 1.1
+// EVP_PKEY_new_raw_private_key(type, e, key, keylen) is
+// EVP_PKEY_new_mac_key(type, e, key, (int)keylen) in old OpenSSL
 
-inline void HMAC_CTX_free(HMAC_CTX* ctx) {
-    if (ctx != 0) {
-        HMAC_CTX_cleanup(ctx);
-        OPENSSL_free(ctx);
-    }
+inline EVP_PKEY* EVP_PKEY_new_raw_private_key(int type, ENGINE* e,
+                                              const unsigned char *key,
+                                              size_t keylen) {
+    return (EVP_PKEY_new_mac_key(type, e, key, static_cast<int>(keylen)));
 }
 
+#else
+#error have no EVP_PKEY_new_raw_private_key() nor EVP_PKEY_new_mac_key()
+#endif
 #endif
 
 #endif
index 7d046858890efc4c534d0894ad92f2ff68e58ae2..29850f79a82c51eb5cb21e39d2956394465972d9 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2022 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 <openssl/hmac.h>
+#include <openssl/evp.h>
 
 #include <cryptolink/openssl_common.h>
+#define KEA_HASH
 #define KEA_HMAC
 #include <cryptolink/openssl_compat.h>
 
@@ -35,7 +36,7 @@ public:
     /// @param hash_algorithm The hash algorithm
     explicit HMACImpl(const void* secret, size_t secret_len,
                       const HashAlgorithm hash_algorithm)
-    : hash_algorithm_(hash_algorithm), md_() {
+      : hash_algorithm_(hash_algorithm), md_() {
         const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
         if (algo == 0) {
             isc_throw(UnsupportedAlgorithm,
@@ -46,22 +47,33 @@ public:
             isc_throw(BadKey, "Bad HMAC secret length: 0");
         }
 
-        md_ = HMAC_CTX_new();
+        md_ = EVP_MD_CTX_new();
         if (md_ == 0) {
-            isc_throw(LibraryError, "OpenSSL HMAC_CTX_new() failed");
+            isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_new() failed");
         }
 
-        if (!HMAC_Init_ex(md_, secret,
-                          static_cast<int>(secret_len),
-                          algo, NULL)) {
-            isc_throw(LibraryError, "OpenSSL HMAC_Init_ex() failed");
+        EVP_PKEY* pkey =
+            EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
+                                         reinterpret_cast<const unsigned char*>(secret),
+                                         secret_len);
+
+        if (pkey == 0) {
+            isc_throw(LibraryError,
+                      "OpenSSL EVP_PKEY_new_raw_private_key() failed");
+        }
+
+        if (!EVP_DigestSignInit(md_, NULL, algo, NULL, pkey)) {
+            EVP_PKEY_free(pkey);
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignInit() failed");
         }
+
+        EVP_PKEY_free(pkey);
     }
 
     /// @brief Destructor
     ~HMACImpl() {
         if (md_) {
-            HMAC_CTX_free(md_);
+            EVP_MD_CTX_free(md_);
         }
         md_ = 0;
     }
@@ -75,21 +87,19 @@ public:
     ///
     /// @return output size of the digest
     size_t getOutputLength() const {
-        int size = HMAC_size(md_);
-        if (size < 0) {
-            isc_throw(LibraryError, "OpenSSL HMAC_size() failed");
-        }
-        return (static_cast<size_t>(size));
+        return (EVP_MD_CTX_size(md_));
     }
 
     /// @brief Add data to digest
     ///
     /// See @ref isc::cryptolink::HMAC::update() for details.
     void update(const void* data, const size_t len) {
-        if (!HMAC_Update(md_,
-                         static_cast<const unsigned char*>(data),
-                         len)) {
-            isc_throw(LibraryError, "OpenSSLHMAC_Update() failed");
+        if (len == 0) {
+            return;
+        }
+
+        if (!EVP_DigestSignUpdate(md_, data, len)) {
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignUpdate() failed");
         }
     }
 
@@ -99,8 +109,12 @@ public:
     void sign(isc::util::OutputBuffer& result, size_t len) {
         size_t size = getOutputLength();
         ossl::SecBuf<unsigned char> digest(size);
-        if (!HMAC_Final(md_, &digest[0], NULL)) {
-            isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
+        size_t digest_len = size;
+        if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
+        }
+        if (digest_len != size) {
+            isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
         }
         if (len > size) {
             len = size;
@@ -114,8 +128,12 @@ public:
     void sign(void* result, size_t len) {
         size_t size = getOutputLength();
         ossl::SecBuf<unsigned char> digest(size);
-        if (!HMAC_Final(md_, &digest[0], NULL)) {
-            isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
+        size_t digest_len = size;
+        if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
+        }
+        if (digest_len != size) {
+            isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
         }
         if (len > size) {
             len = size;
@@ -129,8 +147,12 @@ public:
     std::vector<uint8_t> sign(size_t len) {
         size_t size = getOutputLength();
         ossl::SecBuf<unsigned char> digest(size);
-        if (!HMAC_Final(md_, &digest[0], NULL)) {
-            isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
+        size_t digest_len = size;
+        if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
+        }
+        if (digest_len != size) {
+            isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
         }
         if (len < size) {
             digest.resize(len);
@@ -148,20 +170,25 @@ public:
             return (false);
         }
         // Get the digest from a copy of the context
-        HMAC_CTX* tmp = HMAC_CTX_new();
+        EVP_MD_CTX* tmp = EVP_MD_CTX_new();
         if (tmp == 0) {
-            isc_throw(LibraryError, "OpenSSL HMAC_CTX_new() failed");
+            isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_new() failed");
         }
-        if (!HMAC_CTX_copy(tmp, md_)) {
-            HMAC_CTX_free(tmp);
-            isc_throw(LibraryError, "OpenSSL HMAC_CTX_copy() failed");
+        if (!EVP_MD_CTX_copy(tmp, md_)) {
+            EVP_MD_CTX_free(tmp);
+            isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_copy() failed");
         }
         ossl::SecBuf<unsigned char> digest(size);
-        if (!HMAC_Final(tmp, &digest[0], NULL)) {
-            HMAC_CTX_free(tmp);
-            isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
+        size_t digest_len = size;
+        if (!EVP_DigestSignFinal(tmp, &digest[0], &digest_len)) {
+            EVP_MD_CTX_free(tmp);
+            isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
+        }
+        if (digest_len != size) {
+            EVP_MD_CTX_free(tmp);
+            isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
         }
-        HMAC_CTX_free(tmp);
+        EVP_MD_CTX_free(tmp);
         if (len > size) {
             len = size;
         }
@@ -172,8 +199,8 @@ private:
     /// @brief The hash algorithm
     HashAlgorithm hash_algorithm_;
 
-    /// @brief The protected pointer to the OpenSSL HMAC_CTX structure
-    HMAC_CTX* md_;
+    /// @brief The protected pointer to the OpenSSL EVP_MD_CTX structure
+    EVP_MD_CTX* md_;
 };
 
 HMAC::HMAC(const void* secret, size_t secret_length,
index 340c033611a7e5115fc7c800d62e1e1d5d0d10bb..d0c5cd9b45311e260d6bb20c0a1f70016402e2d9 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2022 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
@@ -462,7 +462,7 @@ doRFC4231Tests(HashAlgorithm hash_algorithm,
         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
         0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
         0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
-        0x19 
+        0x19
     };
     secret_list.push_back(std::string(secret_array,
                                       secret_array + sizeof(secret_array)));