diff options
author | Francis Dupont <fdupont@isc.org> | 2022-02-19 21:22:04 +0100 |
---|---|---|
committer | Tomek Mrugalski <tomek@isc.org> | 2022-06-24 17:37:29 +0200 |
commit | d3ca06b7b6e930c68c911cb60d9219ac5ce945ce (patch) | |
tree | b5075bb3d917103971e2fa36470f6258bc44dcf8 | |
parent | [#2247] Spelling (diff) | |
download | kea-d3ca06b7b6e930c68c911cb60d9219ac5ce945ce.tar.xz kea-d3ca06b7b6e930c68c911cb60d9219ac5ce945ce.zip |
[#1614] Checkpoint: ported HMAC to EVP
-rw-r--r-- | m4macros/ax_crypto.m4 | 41 | ||||
-rw-r--r-- | src/lib/cryptolink/openssl_compat.h | 52 | ||||
-rw-r--r-- | src/lib/cryptolink/openssl_hmac.cc | 99 | ||||
-rw-r--r-- | src/lib/cryptolink/tests/hmac_unittests.cc | 4 |
4 files changed, 110 insertions, 86 deletions
diff --git a/m4macros/ax_crypto.m4 b/m4macros/ax_crypto.m4 index 6786bac1ef..c075aba840 100644 --- a/m4macros/ax_crypto.m4 +++ b/m4macros/ax_crypto.m4 @@ -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 diff --git a/src/lib/cryptolink/openssl_compat.h b/src/lib/cryptolink/openssl_compat.h index 992fe031f1..33b85e1a22 100644 --- a/src/lib/cryptolink/openssl_compat.h +++ b/src/lib/cryptolink/openssl_compat.h @@ -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 diff --git a/src/lib/cryptolink/openssl_hmac.cc b/src/lib/cryptolink/openssl_hmac.cc index 7d04685889..29850f79a8 100644 --- a/src/lib/cryptolink/openssl_hmac.cc +++ b/src/lib/cryptolink/openssl_hmac.cc @@ -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 @@ -11,9 +11,10 @@ #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, diff --git a/src/lib/cryptolink/tests/hmac_unittests.cc b/src/lib/cryptolink/tests/hmac_unittests.cc index 340c033611..d0c5cd9b45 100644 --- a/src/lib/cryptolink/tests/hmac_unittests.cc +++ b/src/lib/cryptolink/tests/hmac_unittests.cc @@ -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))); |