2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-22 18:08:16 +00:00

[#1614] Checkpoint: ported HMAC to EVP

This commit is contained in:
Francis Dupont 2022-02-19 21:22:04 +01:00 committed by Tomek Mrugalski
parent 2991c87d57
commit d3ca06b7b6
4 changed files with 111 additions and 87 deletions

View File

@ -346,36 +346,27 @@ EOF
#CRYPTO_LDFLAGS="-ldl" #CRYPTO_LDFLAGS="-ldl"
CRYPTO_LDFLAGS="" CRYPTO_LDFLAGS=""
CRYPTO_RPATH="" CRYPTO_RPATH=""
dnl Check availability of SHA-2
AC_MSG_CHECKING([support of SHA-2]) AC_MSG_CHECKING([support of SHA-2])
LIBS_SAVED=${LIBS} LIBS_SAVED=${LIBS}
LIBS="$LIBS $CRYPTO_LIBS" LIBS="$LIBS $CRYPTO_LIBS"
CPPFLAGS_SAVED=${CPPFLAGS} CPPFLAGS_SAVED=${CPPFLAGS}
CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS" CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
AC_LINK_IFELSE( dnl Check availability of legacy hash
[AC_LANG_PROGRAM([#include <openssl/evp.h>], AC_CHECK_FUNC([EVP_md5],,[missing EVP entry for MD5])
[const EVP_MD* h224 = EVP_sha224(); AC_CHECK_FUNC([EVP_sha1],,[missing EVP entry for SHA1])
const EVP_MD* h256 = EVP_sha256(); dnl Check availability of SHA-2
const EVP_MD* h384 = EVP_sha384(); AC_CHECK_FUNC([EVP_sha224],,[missing EVP entry for SHA224])
const EVP_MD* h512 = EVP_sha512(); AC_CHECK_FUNC([EVP_sha256],,[missing EVP entry for SHA256])
])], AC_CHECK_FUNC([EVP_sha384],,[missing EVP entry for SHA384])
[AC_MSG_RESULT([yes])], AC_CHECK_FUNC([EVP_sha512],,[missing EVP entry for SHA512])
[AC_MSG_ERROR([missing EVP entry for SHA-2])]) dnl Two generations of EVP_MD_CTX functions
dnl Check HMAC API AC_CHECK_FUNCS([EVP_MD_CTX_new EVP_MD_CTX_free],,
AC_MSG_CHECKING([HMAC functions returning ints]) [AC_CHECK_FUNCS([EVP_MD_CTX_create EVP_MD_CTX_destroy],,
AC_LINK_IFELSE( [AC_MSG_ERROR([missing EVP MD CTX functions])])])
[AC_LANG_PROGRAM([#include <openssl/opensslv.h> dnl Same for EVP and HMAC
#include <openssl/hmac.h>], AC_CHECK_FUNCS([EVP_PKEY_new_raw_private_key],,
[#if OPENSSL_VERSION_NUMBER < 0x10100000L [AC_CHECK_FUNCS([EVP_PKEY_new_mac_key],,
HMAC_CTX ctx, tmp; [AC_MSG_ERROR([missing EVP PKEY new key function])])])
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])])
LIBS=${LIBS_SAVED} LIBS=${LIBS_SAVED}
CPPFLAGS=${CPPFLAGS_SAVED} CPPFLAGS=${CPPFLAGS_SAVED}
fi fi

View File

@ -4,52 +4,58 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // 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/. // 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 // This file is included by hash and hmac codes so KEA_H* macros
// avoid to define unused inlines. // avoid to define unused inlines.
#ifdef KEA_HASH #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() { inline EVP_MD_CTX* EVP_MD_CTX_new() {
return (EVP_MD_CTX_create()); 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) { inline void EVP_MD_CTX_free(EVP_MD_CTX* ctx) {
EVP_MD_CTX_destroy(ctx); EVP_MD_CTX_destroy(ctx);
} }
#else
#error have no EVP_MD_CTX_free() nor EVP_MD_CTX_destroy()
#endif
#endif
#endif #endif
#ifdef KEA_HMAC #ifdef KEA_HMAC
// HMAC_CTX_new() implementation for OpenSSL < 1.1 #ifndef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
#ifdef HAVE_EVP_PKEY_NEW_MAC_KEY
inline HMAC_CTX* HMAC_CTX_new() { // EVP_PKEY_new_raw_private_key(type, e, key, keylen) is
HMAC_CTX* ctx = static_cast<HMAC_CTX*>(OPENSSL_malloc(sizeof(HMAC_CTX))); // EVP_PKEY_new_mac_key(type, e, key, (int)keylen) in old OpenSSL
if (ctx != 0) {
HMAC_CTX_init(ctx); inline EVP_PKEY* EVP_PKEY_new_raw_private_key(int type, ENGINE* e,
} const unsigned char *key,
return (ctx); size_t keylen) {
} return (EVP_PKEY_new_mac_key(type, e, key, static_cast<int>(keylen)));
// HMAC_CTX_free() implementation for OpenSSL < 1.1
inline void HMAC_CTX_free(HMAC_CTX* ctx) {
if (ctx != 0) {
HMAC_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
} }
#else
#error have no EVP_PKEY_new_raw_private_key() nor EVP_PKEY_new_mac_key()
#endif
#endif #endif
#endif #endif

View 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 // 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 // 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 <boost/scoped_ptr.hpp>
#include <openssl/hmac.h> #include <openssl/evp.h>
#include <cryptolink/openssl_common.h> #include <cryptolink/openssl_common.h>
#define KEA_HASH
#define KEA_HMAC #define KEA_HMAC
#include <cryptolink/openssl_compat.h> #include <cryptolink/openssl_compat.h>
@ -46,22 +47,33 @@ public:
isc_throw(BadKey, "Bad HMAC secret length: 0"); isc_throw(BadKey, "Bad HMAC secret length: 0");
} }
md_ = HMAC_CTX_new(); md_ = EVP_MD_CTX_new();
if (md_ == 0) { 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, EVP_PKEY* pkey =
static_cast<int>(secret_len), EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
algo, NULL)) { reinterpret_cast<const unsigned char*>(secret),
isc_throw(LibraryError, "OpenSSL HMAC_Init_ex() failed"); 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 /// @brief Destructor
~HMACImpl() { ~HMACImpl() {
if (md_) { if (md_) {
HMAC_CTX_free(md_); EVP_MD_CTX_free(md_);
} }
md_ = 0; md_ = 0;
} }
@ -75,21 +87,19 @@ public:
/// ///
/// @return output size of the digest /// @return output size of the digest
size_t getOutputLength() const { size_t getOutputLength() const {
int size = HMAC_size(md_); return (EVP_MD_CTX_size(md_));
if (size < 0) {
isc_throw(LibraryError, "OpenSSL HMAC_size() failed");
}
return (static_cast<size_t>(size));
} }
/// @brief Add data to digest /// @brief Add data to digest
/// ///
/// See @ref isc::cryptolink::HMAC::update() for details. /// See @ref isc::cryptolink::HMAC::update() for details.
void update(const void* data, const size_t len) { void update(const void* data, const size_t len) {
if (!HMAC_Update(md_, if (len == 0) {
static_cast<const unsigned char*>(data), return;
len)) { }
isc_throw(LibraryError, "OpenSSLHMAC_Update() failed");
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) { void sign(isc::util::OutputBuffer& result, size_t len) {
size_t size = getOutputLength(); size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size); ossl::SecBuf<unsigned char> digest(size);
if (!HMAC_Final(md_, &digest[0], NULL)) { size_t digest_len = size;
isc_throw(LibraryError, "OpenSSL HMAC_Final() failed"); 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) { if (len > size) {
len = size; len = size;
@ -114,8 +128,12 @@ public:
void sign(void* result, size_t len) { void sign(void* result, size_t len) {
size_t size = getOutputLength(); size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size); ossl::SecBuf<unsigned char> digest(size);
if (!HMAC_Final(md_, &digest[0], NULL)) { size_t digest_len = size;
isc_throw(LibraryError, "OpenSSL HMAC_Final() failed"); 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) { if (len > size) {
len = size; len = size;
@ -129,8 +147,12 @@ public:
std::vector<uint8_t> sign(size_t len) { std::vector<uint8_t> sign(size_t len) {
size_t size = getOutputLength(); size_t size = getOutputLength();
ossl::SecBuf<unsigned char> digest(size); ossl::SecBuf<unsigned char> digest(size);
if (!HMAC_Final(md_, &digest[0], NULL)) { size_t digest_len = size;
isc_throw(LibraryError, "OpenSSL HMAC_Final() failed"); 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) { if (len < size) {
digest.resize(len); digest.resize(len);
@ -148,20 +170,25 @@ public:
return (false); return (false);
} }
// Get the digest from a copy of the context // 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) { 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_)) { if (!EVP_MD_CTX_copy(tmp, md_)) {
HMAC_CTX_free(tmp); EVP_MD_CTX_free(tmp);
isc_throw(LibraryError, "OpenSSL HMAC_CTX_copy() failed"); isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_copy() failed");
} }
ossl::SecBuf<unsigned char> digest(size); ossl::SecBuf<unsigned char> digest(size);
if (!HMAC_Final(tmp, &digest[0], NULL)) { size_t digest_len = size;
HMAC_CTX_free(tmp); if (!EVP_DigestSignFinal(tmp, &digest[0], &digest_len)) {
isc_throw(LibraryError, "OpenSSL HMAC_Final() failed"); EVP_MD_CTX_free(tmp);
isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
} }
HMAC_CTX_free(tmp); if (digest_len != size) {
EVP_MD_CTX_free(tmp);
isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
}
EVP_MD_CTX_free(tmp);
if (len > size) { if (len > size) {
len = size; len = size;
} }
@ -172,8 +199,8 @@ private:
/// @brief The hash algorithm /// @brief The hash algorithm
HashAlgorithm hash_algorithm_; HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the OpenSSL HMAC_CTX structure /// @brief The protected pointer to the OpenSSL EVP_MD_CTX structure
HMAC_CTX* md_; EVP_MD_CTX* md_;
}; };
HMAC::HMAC(const void* secret, size_t secret_length, HMAC::HMAC(const void* secret, size_t secret_length,

View 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 // 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 // License, v. 2.0. If a copy of the MPL was not distributed with this