Files
wolfssl/wolfcrypt/src/hmac.c
Hayden Roche 3bf21b5a05 Expand error queue usage with new macro WOLFSSL_ERROR_VERBOSE.
We have users who need to debug errors coming out of libwolfssl in production,
where --enable-debug isn't an option. Our error queue implementation is the
solution, but our usage of WOLFSSL_ERROR isn't consistent. This commit greatly
expands our usage of WOLFSSL_ERROR. There are too many error cases to tackle
all at once, and not all error cases are particularly meaningful or likely to be
hit in regular operation of the library. I've tried to focus on errors that
users are likely to hit, and I've chosen to ignore things like the mountain of
BUFFER_E and BAD_FUNC_ARG cases (for the most part). I've also tried to expand
WOLFSSL_ERROR usage in files where we haven't been using it historically
(e.g. aes.c), so the pattern is now there for other developers to follow. In
order to prevent these additions from exploding the size of libwolfssl, they're
all behind a new macro, WOLFSSL_ERROR_VERBOSE. If WOLFSSL_VERBOSE_ERRORS is
defined, WOLFSSL_ERROR_VERBOSE just maps to WOLFSSL_ERROR.
2022-08-05 10:32:18 -07:00

1317 lines
38 KiB
C

/* hmac.c
*
* Copyright (C) 2006-2022 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/wc_port.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifndef NO_HMAC
#if defined(HAVE_FIPS) && \
defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
/* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
#define FIPS_NO_WRAPPERS
#ifdef USE_WINDOWS_API
#pragma code_seg(".fipsA$b")
#pragma const_seg(".fipsB$b")
#endif
#endif
#include <wolfssl/wolfcrypt/hmac.h>
#ifdef WOLF_CRYPTO_CB
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#ifdef WOLFSSL_KCAPI_HMAC
#include <wolfssl/wolfcrypt/port/kcapi/kcapi_hmac.h>
/* map the _Software calls used by kcapi_hmac.c */
#define wc_HmacSetKey wc_HmacSetKey_Software
#define wc_HmacUpdate wc_HmacUpdate_Software
#define wc_HmacFinal wc_HmacFinal_Software
#endif
/* fips wrapper calls, user can call direct */
/* If building for old FIPS. */
#if defined(HAVE_FIPS) && \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
/* does init */
int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 keySz)
{
if (hmac == NULL || (key == NULL && keySz != 0) ||
!(type == WC_MD5 || type == WC_SHA || type == WC_SHA256 ||
type == WC_SHA384 || type == WC_SHA512)) {
return BAD_FUNC_ARG;
}
return HmacSetKey_fips(hmac, type, key, keySz);
}
int wc_HmacUpdate(Hmac* hmac, const byte* in, word32 sz)
{
if (hmac == NULL || (in == NULL && sz > 0)) {
return BAD_FUNC_ARG;
}
return HmacUpdate_fips(hmac, in, sz);
}
int wc_HmacFinal(Hmac* hmac, byte* out)
{
if (hmac == NULL) {
return BAD_FUNC_ARG;
}
return HmacFinal_fips(hmac, out);
}
int wolfSSL_GetHmacMaxSize(void)
{
return CyaSSL_GetHmacMaxSize();
}
int wc_HmacInit(Hmac* hmac, void* heap, int devId)
{
#ifndef WOLFSSL_KCAPI_HMAC
(void)hmac;
(void)heap;
(void)devId;
return 0;
#else
return HmacInit(hmac, heap, devId);
#endif
}
void wc_HmacFree(Hmac* hmac)
{
#ifndef WOLFSSL_KCAPI_HMAC
(void)hmac;
#else
HmacFree(hmac);
#endif
}
#ifdef HAVE_HKDF
int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
const byte* salt, word32 saltSz,
const byte* info, word32 infoSz,
byte* out, word32 outSz)
{
return HKDF(type, inKey, inKeySz, salt, saltSz,
info, infoSz, out, outSz);
}
#endif /* HAVE_HKDF */
#else /* else build without fips, or for new fips */
int wc_HmacSizeByType(int type)
{
int ret;
if (!(type == WC_MD5 || type == WC_SHA ||
type == WC_SHA224 || type == WC_SHA256 ||
type == WC_SHA384 || type == WC_SHA512 ||
type == WC_SHA3_224 || type == WC_SHA3_256 ||
type == WC_SHA3_384 || type == WC_SHA3_512)) {
return BAD_FUNC_ARG;
}
switch (type) {
#ifndef NO_MD5
case WC_MD5:
ret = WC_MD5_DIGEST_SIZE;
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
ret = WC_SHA_DIGEST_SIZE;
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
ret = WC_SHA224_DIGEST_SIZE;
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
ret = WC_SHA256_DIGEST_SIZE;
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
ret = WC_SHA384_DIGEST_SIZE;
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
ret = WC_SHA512_DIGEST_SIZE;
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
case WC_SHA3_224:
ret = WC_SHA3_224_DIGEST_SIZE;
break;
case WC_SHA3_256:
ret = WC_SHA3_256_DIGEST_SIZE;
break;
case WC_SHA3_384:
ret = WC_SHA3_384_DIGEST_SIZE;
break;
case WC_SHA3_512:
ret = WC_SHA3_512_DIGEST_SIZE;
break;
#endif
default:
ret = BAD_FUNC_ARG;
break;
}
return ret;
}
int _InitHmac(Hmac* hmac, int type, void* heap)
{
int ret = 0;
#ifdef WOLF_CRYPTO_CB
int devId = hmac->devId;
#else
int devId = INVALID_DEVID;
#endif
switch (type) {
#ifndef NO_MD5
case WC_MD5:
ret = wc_InitMd5_ex(&hmac->hash.md5, heap, devId);
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
ret = wc_InitSha_ex(&hmac->hash.sha, heap, devId);
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
ret = wc_InitSha224_ex(&hmac->hash.sha224, heap, devId);
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
ret = wc_InitSha256_ex(&hmac->hash.sha256, heap, devId);
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
ret = wc_InitSha384_ex(&hmac->hash.sha384, heap, devId);
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
ret = wc_InitSha512_ex(&hmac->hash.sha512, heap, devId);
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
ret = wc_InitSha3_224(&hmac->hash.sha3, heap, devId);
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
ret = wc_InitSha3_256(&hmac->hash.sha3, heap, devId);
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
ret = wc_InitSha3_384(&hmac->hash.sha3, heap, devId);
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
ret = wc_InitSha3_512(&hmac->hash.sha3, heap, devId);
break;
#endif
#endif
default:
ret = BAD_FUNC_ARG;
break;
}
/* default to NULL heap hint or test value */
#ifdef WOLFSSL_HEAP_TEST
hmac->heap = (void*)WOLFSSL_HEAP_TEST;
#else
hmac->heap = heap;
#endif /* WOLFSSL_HEAP_TEST */
return ret;
}
int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
{
byte* ip;
byte* op;
word32 i, hmac_block_size = 0;
int ret = 0;
void* heap = NULL;
if (hmac == NULL || (key == NULL && length != 0) ||
!(type == WC_MD5 || type == WC_SHA ||
type == WC_SHA224 || type == WC_SHA256 ||
type == WC_SHA384 || type == WC_SHA512 ||
type == WC_SHA3_224 || type == WC_SHA3_256 ||
type == WC_SHA3_384 || type == WC_SHA3_512)) {
return BAD_FUNC_ARG;
}
#ifndef HAVE_FIPS
/* if set key has already been run then make sure and free existing */
/* This is for async and PIC32MZ situations, and just normally OK,
provided the user calls wc_HmacInit() first. That function is not
available in FIPS builds. In current FIPS builds, the hashes are
not allocating resources. */
if (hmac->macType != WC_HASH_TYPE_NONE) {
wc_HmacFree(hmac);
}
#endif
hmac->innerHashKeyed = 0;
hmac->macType = (byte)type;
ret = _InitHmac(hmac, type, heap);
if (ret != 0)
return ret;
#ifdef HAVE_FIPS
if (length < HMAC_FIPS_MIN_KEY) {
WOLFSSL_ERROR_VERBOSE(HMAC_MIN_KEYLEN_E);
return HMAC_MIN_KEYLEN_E;
}
#endif
#ifdef WOLF_CRYPTO_CB
hmac->keyRaw = key; /* use buffer directly */
hmac->keyLen = length;
#endif
ip = (byte*)hmac->ipad;
op = (byte*)hmac->opad;
switch (hmac->macType) {
#ifndef NO_MD5
case WC_MD5:
hmac_block_size = WC_MD5_BLOCK_SIZE;
if (length <= WC_MD5_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Md5Update(&hmac->hash.md5, key, length);
if (ret != 0)
break;
ret = wc_Md5Final(&hmac->hash.md5, ip);
if (ret != 0)
break;
length = WC_MD5_DIGEST_SIZE;
}
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
hmac_block_size = WC_SHA_BLOCK_SIZE;
if (length <= WC_SHA_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_ShaUpdate(&hmac->hash.sha, key, length);
if (ret != 0)
break;
ret = wc_ShaFinal(&hmac->hash.sha, ip);
if (ret != 0)
break;
length = WC_SHA_DIGEST_SIZE;
}
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
hmac_block_size = WC_SHA224_BLOCK_SIZE;
if (length <= WC_SHA224_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha224Update(&hmac->hash.sha224, key, length);
if (ret != 0)
break;
ret = wc_Sha224Final(&hmac->hash.sha224, ip);
if (ret != 0)
break;
length = WC_SHA224_DIGEST_SIZE;
}
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
hmac_block_size = WC_SHA256_BLOCK_SIZE;
if (length <= WC_SHA256_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha256Update(&hmac->hash.sha256, key, length);
if (ret != 0)
break;
ret = wc_Sha256Final(&hmac->hash.sha256, ip);
if (ret != 0)
break;
length = WC_SHA256_DIGEST_SIZE;
}
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
hmac_block_size = WC_SHA384_BLOCK_SIZE;
if (length <= WC_SHA384_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha384Update(&hmac->hash.sha384, key, length);
if (ret != 0)
break;
ret = wc_Sha384Final(&hmac->hash.sha384, ip);
if (ret != 0)
break;
length = WC_SHA384_DIGEST_SIZE;
}
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
hmac_block_size = WC_SHA512_BLOCK_SIZE;
if (length <= WC_SHA512_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha512Update(&hmac->hash.sha512, key, length);
if (ret != 0)
break;
ret = wc_Sha512Final(&hmac->hash.sha512, ip);
if (ret != 0)
break;
length = WC_SHA512_DIGEST_SIZE;
}
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
hmac_block_size = WC_SHA3_224_BLOCK_SIZE;
if (length <= WC_SHA3_224_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha3_224_Update(&hmac->hash.sha3, key, length);
if (ret != 0)
break;
ret = wc_Sha3_224_Final(&hmac->hash.sha3, ip);
if (ret != 0)
break;
length = WC_SHA3_224_DIGEST_SIZE;
}
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
hmac_block_size = WC_SHA3_256_BLOCK_SIZE;
if (length <= WC_SHA3_256_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha3_256_Update(&hmac->hash.sha3, key, length);
if (ret != 0)
break;
ret = wc_Sha3_256_Final(&hmac->hash.sha3, ip);
if (ret != 0)
break;
length = WC_SHA3_256_DIGEST_SIZE;
}
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
hmac_block_size = WC_SHA3_384_BLOCK_SIZE;
if (length <= WC_SHA3_384_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha3_384_Update(&hmac->hash.sha3, key, length);
if (ret != 0)
break;
ret = wc_Sha3_384_Final(&hmac->hash.sha3, ip);
if (ret != 0)
break;
length = WC_SHA3_384_DIGEST_SIZE;
}
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
hmac_block_size = WC_SHA3_512_BLOCK_SIZE;
if (length <= WC_SHA3_512_BLOCK_SIZE) {
if (key != NULL) {
XMEMCPY(ip, key, length);
}
}
else {
ret = wc_Sha3_512_Update(&hmac->hash.sha3, key, length);
if (ret != 0)
break;
ret = wc_Sha3_512_Final(&hmac->hash.sha3, ip);
if (ret != 0)
break;
length = WC_SHA3_512_DIGEST_SIZE;
}
break;
#endif
#endif /* WOLFSSL_SHA3 */
default:
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) {
#if defined(HAVE_INTEL_QA) || defined(HAVE_CAVIUM)
#ifdef HAVE_INTEL_QA
if (IntelQaHmacGetType(hmac->macType, NULL) == 0)
#endif
{
if (length > hmac_block_size)
length = hmac_block_size;
/* update key length */
hmac->keyLen = (word16)length;
return ret;
}
/* no need to pad below */
#endif
}
#endif
if (ret == 0) {
if (length < hmac_block_size)
XMEMSET(ip + length, 0, hmac_block_size - length);
for(i = 0; i < hmac_block_size; i++) {
op[i] = ip[i] ^ OPAD;
ip[i] ^= IPAD;
}
}
return ret;
}
static int HmacKeyInnerHash(Hmac* hmac)
{
int ret = 0;
switch (hmac->macType) {
#ifndef NO_MD5
case WC_MD5:
ret = wc_Md5Update(&hmac->hash.md5, (byte*)hmac->ipad,
WC_MD5_BLOCK_SIZE);
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
ret = wc_ShaUpdate(&hmac->hash.sha, (byte*)hmac->ipad,
WC_SHA_BLOCK_SIZE);
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
ret = wc_Sha224Update(&hmac->hash.sha224, (byte*)hmac->ipad,
WC_SHA224_BLOCK_SIZE);
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
ret = wc_Sha256Update(&hmac->hash.sha256, (byte*)hmac->ipad,
WC_SHA256_BLOCK_SIZE);
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
ret = wc_Sha384Update(&hmac->hash.sha384, (byte*)hmac->ipad,
WC_SHA384_BLOCK_SIZE);
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
ret = wc_Sha512Update(&hmac->hash.sha512, (byte*)hmac->ipad,
WC_SHA512_BLOCK_SIZE);
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
WC_SHA3_224_BLOCK_SIZE);
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
WC_SHA3_256_BLOCK_SIZE);
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
WC_SHA3_384_BLOCK_SIZE);
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->ipad,
WC_SHA3_512_BLOCK_SIZE);
break;
#endif
#endif /* WOLFSSL_SHA3 */
default:
break;
}
if (ret == 0)
hmac->innerHashKeyed = WC_HMAC_INNER_HASH_KEYED_SW;
return ret;
}
int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
{
int ret = 0;
if (hmac == NULL || (msg == NULL && length > 0)) {
return BAD_FUNC_ARG;
}
#ifdef WOLF_CRYPTO_CB
if (hmac->devId != INVALID_DEVID) {
ret = wc_CryptoCb_Hmac(hmac, hmac->macType, msg, length, NULL);
if (ret != CRYPTOCB_UNAVAILABLE)
return ret;
/* fall-through when unavailable */
ret = 0; /* reset error code */
}
#endif
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) {
#if defined(HAVE_CAVIUM)
return NitroxHmacUpdate(hmac, msg, length);
#elif defined(HAVE_INTEL_QA)
if (IntelQaHmacGetType(hmac->macType, NULL) == 0) {
return IntelQaHmac(&hmac->asyncDev, hmac->macType,
(byte*)hmac->ipad, hmac->keyLen, NULL, msg, length);
}
#endif
}
#endif /* WOLFSSL_ASYNC_CRYPT */
if (!hmac->innerHashKeyed) {
ret = HmacKeyInnerHash(hmac);
if (ret != 0)
return ret;
}
switch (hmac->macType) {
#ifndef NO_MD5
case WC_MD5:
ret = wc_Md5Update(&hmac->hash.md5, msg, length);
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
ret = wc_ShaUpdate(&hmac->hash.sha, msg, length);
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
ret = wc_Sha224Update(&hmac->hash.sha224, msg, length);
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
ret = wc_Sha256Update(&hmac->hash.sha256, msg, length);
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
ret = wc_Sha384Update(&hmac->hash.sha384, msg, length);
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
ret = wc_Sha512Update(&hmac->hash.sha512, msg, length);
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
ret = wc_Sha3_224_Update(&hmac->hash.sha3, msg, length);
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
ret = wc_Sha3_256_Update(&hmac->hash.sha3, msg, length);
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
ret = wc_Sha3_384_Update(&hmac->hash.sha3, msg, length);
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
ret = wc_Sha3_512_Update(&hmac->hash.sha3, msg, length);
break;
#endif
#endif /* WOLFSSL_SHA3 */
default:
break;
}
return ret;
}
int wc_HmacFinal(Hmac* hmac, byte* hash)
{
int ret;
if (hmac == NULL || hash == NULL) {
return BAD_FUNC_ARG;
}
#ifdef WOLF_CRYPTO_CB
if (hmac->devId != INVALID_DEVID) {
ret = wc_CryptoCb_Hmac(hmac, hmac->macType, NULL, 0, hash);
if (ret != CRYPTOCB_UNAVAILABLE)
return ret;
/* fall-through when unavailable */
}
#endif
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
if (hmac->asyncDev.marker == WOLFSSL_ASYNC_MARKER_HMAC) {
int hashLen = wc_HmacSizeByType(hmac->macType);
if (hashLen <= 0)
return hashLen;
#if defined(HAVE_CAVIUM)
return NitroxHmacFinal(hmac, hash, hashLen);
#elif defined(HAVE_INTEL_QA)
if (IntelQaHmacGetType(hmac->macType, NULL) == 0) {
return IntelQaHmac(&hmac->asyncDev, hmac->macType,
(byte*)hmac->ipad, hmac->keyLen, hash, NULL, hashLen);
}
#endif
}
#endif /* WOLFSSL_ASYNC_CRYPT */
if (!hmac->innerHashKeyed) {
ret = HmacKeyInnerHash(hmac);
if (ret != 0)
return ret;
}
switch (hmac->macType) {
#ifndef NO_MD5
case WC_MD5:
ret = wc_Md5Final(&hmac->hash.md5, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Md5Update(&hmac->hash.md5, (byte*)hmac->opad,
WC_MD5_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Md5Update(&hmac->hash.md5, (byte*)hmac->innerHash,
WC_MD5_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Md5Final(&hmac->hash.md5, hash);
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
ret = wc_ShaFinal(&hmac->hash.sha, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_ShaUpdate(&hmac->hash.sha, (byte*)hmac->opad,
WC_SHA_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_ShaUpdate(&hmac->hash.sha, (byte*)hmac->innerHash,
WC_SHA_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_ShaFinal(&hmac->hash.sha, hash);
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
ret = wc_Sha224Final(&hmac->hash.sha224, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha224Update(&hmac->hash.sha224, (byte*)hmac->opad,
WC_SHA224_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha224Update(&hmac->hash.sha224, (byte*)hmac->innerHash,
WC_SHA224_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha224Final(&hmac->hash.sha224, hash);
if (ret != 0)
break;
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
ret = wc_Sha256Final(&hmac->hash.sha256, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha256Update(&hmac->hash.sha256, (byte*)hmac->opad,
WC_SHA256_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha256Update(&hmac->hash.sha256, (byte*)hmac->innerHash,
WC_SHA256_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha256Final(&hmac->hash.sha256, hash);
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
ret = wc_Sha384Final(&hmac->hash.sha384, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha384Update(&hmac->hash.sha384, (byte*)hmac->opad,
WC_SHA384_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha384Update(&hmac->hash.sha384, (byte*)hmac->innerHash,
WC_SHA384_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha384Final(&hmac->hash.sha384, hash);
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
ret = wc_Sha512Final(&hmac->hash.sha512, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha512Update(&hmac->hash.sha512, (byte*)hmac->opad,
WC_SHA512_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha512Update(&hmac->hash.sha512, (byte*)hmac->innerHash,
WC_SHA512_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha512Final(&hmac->hash.sha512, hash);
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
ret = wc_Sha3_224_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->opad,
WC_SHA3_224_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_224_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
WC_SHA3_224_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_224_Final(&hmac->hash.sha3, hash);
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
ret = wc_Sha3_256_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->opad,
WC_SHA3_256_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_256_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
WC_SHA3_256_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_256_Final(&hmac->hash.sha3, hash);
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
ret = wc_Sha3_384_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->opad,
WC_SHA3_384_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_384_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
WC_SHA3_384_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_384_Final(&hmac->hash.sha3, hash);
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
ret = wc_Sha3_512_Final(&hmac->hash.sha3, (byte*)hmac->innerHash);
if (ret != 0)
break;
ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->opad,
WC_SHA3_512_BLOCK_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_512_Update(&hmac->hash.sha3, (byte*)hmac->innerHash,
WC_SHA3_512_DIGEST_SIZE);
if (ret != 0)
break;
ret = wc_Sha3_512_Final(&hmac->hash.sha3, hash);
break;
#endif
#endif /* WOLFSSL_SHA3 */
default:
ret = BAD_FUNC_ARG;
break;
}
if (ret == 0) {
hmac->innerHashKeyed = 0;
}
return ret;
}
#ifdef WOLFSSL_KCAPI_HMAC
/* implemented in wolfcrypt/src/port/kcapi/kcapi_hmac.c */
/* unmap the _Software calls used by kcapi_hmac.c */
#undef wc_HmacSetKey
#undef wc_HmacUpdate
#undef wc_HmacFinal
#else
/* Initialize Hmac for use with async device */
int wc_HmacInit(Hmac* hmac, void* heap, int devId)
{
int ret = 0;
if (hmac == NULL)
return BAD_FUNC_ARG;
XMEMSET(hmac, 0, sizeof(Hmac));
hmac->macType = WC_HASH_TYPE_NONE;
hmac->heap = heap;
#ifdef WOLF_CRYPTO_CB
hmac->devId = devId;
hmac->devCtx = NULL;
#endif
#if defined(WOLFSSL_DEVCRYPTO_HMAC)
hmac->ctx.cfd = -1;
#endif
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
ret = wolfAsync_DevCtxInit(&hmac->asyncDev, WOLFSSL_ASYNC_MARKER_HMAC,
hmac->heap, devId);
#else
(void)devId;
#endif /* WOLFSSL_ASYNC_CRYPT */
return ret;
}
#ifdef WOLF_PRIVATE_KEY_ID
int wc_HmacInit_Id(Hmac* hmac, unsigned char* id, int len, void* heap,
int devId)
{
int ret = 0;
if (hmac == NULL)
ret = BAD_FUNC_ARG;
if (ret == 0 && (len < 0 || len > HMAC_MAX_ID_LEN))
ret = BUFFER_E;
if (ret == 0)
ret = wc_HmacInit(hmac, heap, devId);
if (ret == 0) {
XMEMCPY(hmac->id, id, len);
hmac->idLen = len;
}
return ret;
}
int wc_HmacInit_Label(Hmac* hmac, const char* label, void* heap, int devId)
{
int ret = 0;
int labelLen = 0;
if (hmac == NULL || label == NULL)
ret = BAD_FUNC_ARG;
if (ret == 0) {
labelLen = (int)XSTRLEN(label);
if (labelLen == 0 || labelLen > HMAC_MAX_LABEL_LEN)
ret = BUFFER_E;
}
if (ret == 0)
ret = wc_HmacInit(hmac, heap, devId);
if (ret == 0) {
XMEMCPY(hmac->label, label, labelLen);
hmac->labelLen = labelLen;
}
return ret;
}
#endif /* WOLF_PRIVATE_KEY_ID */
/* Free Hmac from use with async device */
void wc_HmacFree(Hmac* hmac)
{
if (hmac == NULL)
return;
#ifdef WOLF_CRYPTO_CB
/* handle cleanup case where final is not called */
if (hmac->devId != INVALID_DEVID && hmac->devCtx != NULL) {
int ret;
byte finalHash[WC_HMAC_BLOCK_SIZE];
ret = wc_CryptoCb_Hmac(hmac, hmac->macType, NULL, 0, finalHash);
(void)ret; /* must ignore return code here */
(void)finalHash;
}
#endif
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_HMAC)
wolfAsync_DevCtxFree(&hmac->asyncDev, WOLFSSL_ASYNC_MARKER_HMAC);
#endif /* WOLFSSL_ASYNC_CRYPT */
switch (hmac->macType) {
#ifndef NO_MD5
case WC_MD5:
wc_Md5Free(&hmac->hash.md5);
break;
#endif /* !NO_MD5 */
#ifndef NO_SHA
case WC_SHA:
wc_ShaFree(&hmac->hash.sha);
break;
#endif /* !NO_SHA */
#ifdef WOLFSSL_SHA224
case WC_SHA224:
wc_Sha224Free(&hmac->hash.sha224);
break;
#endif /* WOLFSSL_SHA224 */
#ifndef NO_SHA256
case WC_SHA256:
wc_Sha256Free(&hmac->hash.sha256);
break;
#endif /* !NO_SHA256 */
#ifdef WOLFSSL_SHA384
case WC_SHA384:
wc_Sha384Free(&hmac->hash.sha384);
break;
#endif /* WOLFSSL_SHA384 */
#ifdef WOLFSSL_SHA512
case WC_SHA512:
wc_Sha512Free(&hmac->hash.sha512);
break;
#endif /* WOLFSSL_SHA512 */
#ifdef WOLFSSL_SHA3
#ifndef WOLFSSL_NOSHA3_224
case WC_SHA3_224:
wc_Sha3_224_Free(&hmac->hash.sha3);
break;
#endif
#ifndef WOLFSSL_NOSHA3_256
case WC_SHA3_256:
wc_Sha3_256_Free(&hmac->hash.sha3);
break;
#endif
#ifndef WOLFSSL_NOSHA3_384
case WC_SHA3_384:
wc_Sha3_384_Free(&hmac->hash.sha3);
break;
#endif
#ifndef WOLFSSL_NOSHA3_512
case WC_SHA3_512:
wc_Sha3_512_Free(&hmac->hash.sha3);
break;
#endif
#endif /* WOLFSSL_SHA3 */
default:
break;
}
}
#endif /* WOLFSSL_KCAPI_HMAC */
int wolfSSL_GetHmacMaxSize(void)
{
return WC_MAX_DIGEST_SIZE;
}
#ifdef HAVE_HKDF
/* HMAC-KDF-Extract.
* RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
*
* type The hash algorithm type.
* salt The optional salt value.
* saltSz The size of the salt.
* inKey The input keying material.
* inKeySz The size of the input keying material.
* out The pseudorandom key with the length that of the hash.
* returns 0 on success, otherwise failure.
*/
int wc_HKDF_Extract(int type, const byte* salt, word32 saltSz,
const byte* inKey, word32 inKeySz, byte* out)
{
byte tmp[WC_MAX_DIGEST_SIZE]; /* localSalt helper */
Hmac myHmac;
int ret;
const byte* localSalt; /* either points to user input or tmp */
int hashSz;
ret = wc_HmacSizeByType(type);
if (ret < 0)
return ret;
hashSz = ret;
localSalt = salt;
if (localSalt == NULL) {
XMEMSET(tmp, 0, hashSz);
localSalt = tmp;
saltSz = hashSz;
}
ret = wc_HmacInit(&myHmac, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_HmacSetKey(&myHmac, type, localSalt, saltSz);
if (ret == 0)
ret = wc_HmacUpdate(&myHmac, inKey, inKeySz);
if (ret == 0)
ret = wc_HmacFinal(&myHmac, out);
wc_HmacFree(&myHmac);
}
return ret;
}
/* HMAC-KDF-Expand.
* RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
*
* type The hash algorithm type.
* inKey The input key.
* inKeySz The size of the input key.
* info The application specific information.
* infoSz The size of the application specific information.
* out The output keying material.
* returns 0 on success, otherwise failure.
*/
int wc_HKDF_Expand(int type, const byte* inKey, word32 inKeySz,
const byte* info, word32 infoSz, byte* out, word32 outSz)
{
byte tmp[WC_MAX_DIGEST_SIZE];
Hmac myHmac;
int ret = 0;
word32 outIdx = 0;
word32 hashSz = wc_HmacSizeByType(type);
byte n = 0x1;
/* RFC 5869 states that the length of output keying material in
octets must be L <= 255*HashLen or N = ceil(L/HashLen) */
if (out == NULL || ((outSz/hashSz) + ((outSz % hashSz) != 0)) > 255)
return BAD_FUNC_ARG;
ret = wc_HmacInit(&myHmac, NULL, INVALID_DEVID);
if (ret != 0)
return ret;
while (outIdx < outSz) {
int tmpSz = (n == 1) ? 0 : hashSz;
word32 left = outSz - outIdx;
ret = wc_HmacSetKey(&myHmac, type, inKey, inKeySz);
if (ret != 0)
break;
ret = wc_HmacUpdate(&myHmac, tmp, tmpSz);
if (ret != 0)
break;
ret = wc_HmacUpdate(&myHmac, info, infoSz);
if (ret != 0)
break;
ret = wc_HmacUpdate(&myHmac, &n, 1);
if (ret != 0)
break;
ret = wc_HmacFinal(&myHmac, tmp);
if (ret != 0)
break;
left = min(left, hashSz);
XMEMCPY(out+outIdx, tmp, left);
outIdx += hashSz;
n++;
}
wc_HmacFree(&myHmac);
return ret;
}
/* HMAC-KDF.
* RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
*
* type The hash algorithm type.
* inKey The input keying material.
* inKeySz The size of the input keying material.
* salt The optional salt value.
* saltSz The size of the salt.
* info The application specific information.
* infoSz The size of the application specific information.
* out The output keying material.
* returns 0 on success, otherwise failure.
*/
int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
const byte* salt, word32 saltSz,
const byte* info, word32 infoSz,
byte* out, word32 outSz)
{
byte prk[WC_MAX_DIGEST_SIZE];
int hashSz = wc_HmacSizeByType(type);
int ret;
if (hashSz < 0)
return BAD_FUNC_ARG;
ret = wc_HKDF_Extract(type, salt, saltSz, inKey, inKeySz, prk);
if (ret != 0)
return ret;
return wc_HKDF_Expand(type, prk, hashSz, info, infoSz, out, outSz);
}
#endif /* HAVE_HKDF */
#endif /* HAVE_FIPS */
#endif /* NO_HMAC */