diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7589be16..86b60fef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -750,7 +750,7 @@ set(COMMON_SRC stat_cache.c plugin.c http_etag.c array.c data_string.c data_array.c data_integer.c - algo_md5.c algo_sha1.c algo_splaytree.c + algo_hmac.c algo_md5.c algo_sha1.c algo_splaytree.c fdevent_select.c fdevent_libev.c fdevent_poll.c fdevent_linux_sysepoll.c fdevent_solaris_devpoll.c fdevent_solaris_port.c diff --git a/src/Makefile.am b/src/Makefile.am index 24915ae8..a9abc5fc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,7 +75,7 @@ common_src=base64.c buffer.c burl.c log.c \ stat_cache.c plugin.c http_etag.c array.c \ data_string.c data_array.c \ data_integer.c \ - algo_md5.c algo_sha1.c algo_splaytree.c \ + algo_hmac.c algo_md5.c algo_sha1.c algo_splaytree.c \ fdevent_select.c fdevent_libev.c \ fdevent_poll.c fdevent_linux_sysepoll.c \ fdevent_solaris_devpoll.c fdevent_solaris_port.c \ @@ -462,6 +462,7 @@ mod_wstunnel_la_LIBADD = $(common_libadd) $(CRYPTO_LIB) hdr = base64.h buffer.h burl.h network.h log.h http_kv.h keyvalue.h \ response.h request.h reqpool.h chunk.h h2.h \ first.h http_chunk.h \ + algo_hmac.h \ algo_md.h algo_md5.h algo_sha1.h algo_splaytree.h algo_xxhash.h \ http_auth.h http_date.h http_header.h http_vhostdb.h stream.h \ fdevent.h gw_backend.h connections.h base.h base_decls.h stat_cache.h \ diff --git a/src/SConscript b/src/SConscript index 40c8a104..21848a5c 100644 --- a/src/SConscript +++ b/src/SConscript @@ -61,7 +61,7 @@ common_src = Split("base64.c buffer.c burl.c log.c \ stat_cache.c plugin.c http_etag.c array.c \ data_string.c data_array.c \ data_integer.c \ - algo_md5.c algo_sha1.c algo_splaytree.c \ + algo_hmac.c algo_md5.c algo_sha1.c algo_splaytree.c \ fdevent_select.c fdevent_libev.c \ fdevent_poll.c fdevent_linux_sysepoll.c \ fdevent_solaris_devpoll.c fdevent_solaris_port.c \ diff --git a/src/algo_hmac.c b/src/algo_hmac.c new file mode 100644 index 00000000..262170aa --- /dev/null +++ b/src/algo_hmac.c @@ -0,0 +1,208 @@ +/* algo_hmac - hash-based message authentication code (HMAC) wrapper + * + * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com All rights reserved + * License: BSD 3-clause (same as lighttpd) + */ +#include "first.h" + +#include "algo_hmac.h" + +#include "sys-crypto-md.h" +#ifdef USE_LIB_CRYPTO +#if defined(USE_NETTLE_CRYPTO) +#include +#elif defined(USE_MBEDTLS_CRYPTO) +#include +#elif defined(USE_WOLFSSL_CRYPTO) +#include +#elif defined(USE_OPENSSL_CRYPTO) +#include +#include +#elif defined(USE_GNUTLS_CRYPTO) +#include +#elif defined(USE_NSS_CRYPTO) +#if 0 /*(nss/alghmac.h might not be present)*/ +#ifdef NSS_VER_INCLUDE +#include +#else +#include +#endif +#endif +#endif +#endif + +#if defined(USE_OPENSSL_CRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#define HMAC EVP_HMAC +static unsigned char * +EVP_HMAC (const EVP_MD *evp_md, const void *key, + int key_len, const unsigned char *d, int n, + unsigned char *md, size_t *md_len) +{ + EVP_PKEY * const pkey = + EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len); + if (NULL == pkey) return NULL; + + EVP_MD_CTX * const ctx = EVP_MD_CTX_new(); + if (NULL == ctx) { + EVP_PKEY_free(pkey); + return NULL; + } + + int rc = (1 == EVP_DigestSignInit(ctx, NULL, evp_md, NULL, pkey)) + && (1 == EVP_DigestSignUpdate(ctx, d, n)) + && (1 == EVP_DigestSignFinal(ctx, md, md_len)); + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + return (1 == rc) ? md : NULL; +} +#endif + + +int +li_hmac_md5 (unsigned char digest[MD5_DIGEST_LENGTH], + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen) +{ + li_MD5_CTX Md5Ctx; + li_MD5_Init(&Md5Ctx); + li_MD5_Update(&Md5Ctx, secret, slen); + li_MD5_Update(&Md5Ctx, msg, mlen); + li_MD5_Final(digest, &Md5Ctx); + return 1; +} + + +int +li_hmac_sha1 (unsigned char digest[SHA_DIGEST_LENGTH], + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen) +{ + #ifdef USE_LIB_CRYPTO + #if defined(USE_NETTLE_CRYPTO) + struct hmac_sha1_ctx ctx; + hmac_sha1_set_key(&ctx, slen, (const uint8_t *)secret); + hmac_sha1_update(&ctx, mlen, (const uint8_t *)msg); + hmac_sha1_digest(&ctx, SHA_DIGEST_LENGTH, (uint8_t *)digest); + return 1; + #elif defined(USE_MBEDTLS_CRYPTO) \ + && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA1_C) + return 0 == + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), + (const unsigned char *)secret, slen, + (const unsigned char *)msg, mlen, digest); + #elif defined(USE_WOLFSSL_CRYPTO) + Hmac hmac; + if (0 != wc_HmacInit(&hmac, NULL, INVALID_DEVID) + || wc_HmacSetKey(&hmac, WC_SHA, (const byte *)secret, (word32)slen) < 0 + || wc_HmacUpdate(&hmac, (const byte *)msg, (word32)mlen) < 0 + || wc_HmacFinal(&hmac, (byte *)digest) < 0) + return 0; + return 1; + #elif defined(USE_OPENSSL_CRYPTO) + return (NULL != HMAC(EVP_sha1(), + (const unsigned char *)secret, (int)slen, + (const unsigned char *)msg, mlen, + digest, NULL)); + #elif defined(USE_GNUTLS_CRYPTO) + return 0 == + gnutls_hmac_fast(GNUTLS_MAC_SHA1, + (const unsigned char *)secret, slen, + (const unsigned char *)msg, mlen, digest); + #elif defined(USE_NSS_CRYPTO) + /*(HMAC* funcs not public export of libfreebl3.so, + * even though nss3/alghmac.h is public (WTH?!))*/ + #if 0 + HMACContext *hmac = + HMAC_Create(HASH_GetHashObject(HASH_AlgSHA1), + (const unsigned char *)secret, slen, PR_FALSE); + if (NULL == hmac) + return 0; + HMAC_Begin(hmac); + HMAC_Update(hmac, (const unsigned char *)msg, mlen); + unsigned int dlen; + int rc = HMAC_Finish(hmac, digest, &dlen, SHA_DIGEST_LENGTH); + HMAC_Destroy(hmac, PR_TRUE); + return (SECSuccess == rc); + #else + return 0; + #endif + #else + #error "unexpected; crypto lib not configured for HMAC SHA1" + #endif + #else + UNUSED(digest); + UNUSED(secret); + UNUSED(slen); + UNUSED(msg); + UNUSED(mlen); + return 0; + #endif +} + + +int +li_hmac_sha256 (unsigned char digest[SHA256_DIGEST_LENGTH], + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen) +{ + #ifdef USE_LIB_CRYPTO + #if defined(USE_NETTLE_CRYPTO) + struct hmac_sha256_ctx ctx; + hmac_sha256_set_key(&ctx, slen, (const uint8_t *)secret); + hmac_sha256_update(&ctx, mlen, (const uint8_t *)msg); + hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, (uint8_t *)digest); + return 1; + #elif defined(USE_MBEDTLS_CRYPTO) \ + && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C) + return 0 == + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), + (const unsigned char *)secret, slen, + (const unsigned char *)msg, mlen, digest); + #elif defined(USE_WOLFSSL_CRYPTO) + Hmac hmac; + if (0 != wc_HmacInit(&hmac, NULL, INVALID_DEVID) + || wc_HmacSetKey(&hmac, WC_SHA256,(const byte *)secret,(word32)slen) < 0 + || wc_HmacUpdate(&hmac, (const byte *)msg, (word32)mlen) < 0 + || wc_HmacFinal(&hmac, (byte *)digest) < 0) + return 0; + return 1; + #elif defined(USE_OPENSSL_CRYPTO) + return (NULL != HMAC(EVP_sha256(), + (const unsigned char *)secret, (int)slen, + (const unsigned char *)msg, mlen, + digest, NULL)); + #elif defined(USE_GNUTLS_CRYPTO) + return 0 == + gnutls_hmac_fast(GNUTLS_MAC_SHA256, + (const unsigned char *)secret, slen, + (const unsigned char *)msg, mlen, digest); + #elif defined(USE_NSS_CRYPTO) + /*(HMAC* funcs not public export of libfreebl3.so, + * even though nss3/alghmac.h is public (WTH?!))*/ + #if 0 + HMACContext *hmac = + HMAC_Create(HASH_GetHashObject(HASH_AlgSHA256), + (const unsigned char *)secret, slen, PR_FALSE); + if (NULL == hmac) + return 0; + HMAC_Begin(hmac); + HMAC_Update(hmac, (const unsigned char *)msg, mlen); + unsigned int dlen; + int rc = HMAC_Finish(hmac, digest, &dlen, SHA256_DIGEST_LENGTH); + HMAC_Destroy(hmac, PR_TRUE); + return (SECSuccess == rc); + #else + return 0; + #endif + #else + #error "unexpected; crypto lib not configured for HMAC SHA256" + #endif + #else + UNUSED(digest); + UNUSED(secret); + UNUSED(slen); + UNUSED(msg); + UNUSED(mlen); + return 0; + #endif +} diff --git a/src/algo_hmac.h b/src/algo_hmac.h new file mode 100644 index 00000000..35187538 --- /dev/null +++ b/src/algo_hmac.h @@ -0,0 +1,26 @@ +/* algo_hmac - hash-based message authentication code (HMAC) wrapper + * + * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com All rights reserved + * License: BSD 3-clause (same as lighttpd) + */ +#ifndef INCLUDED_ALGO_HMAC_H +#define INCLUDED_ALGO_HMAC_H +#include "first.h" + +int +li_hmac_md5 (unsigned char digest[16], /* [MD5_DIGEST_LENGTH] */ + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen); + +int +li_hmac_sha1 (unsigned char digest[20], /* [SHA_DIGEST_LENGTH] */ + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen); + +int +li_hmac_sha256 (unsigned char digest[32], /* [SHA256_DIGEST_LENGTH] */ + const void * const secret, const uint32_t slen, + const unsigned char * const msg, const uint32_t mlen); + + +#endif /* INCLUDED_ALGO_HMAC_H */ diff --git a/src/meson.build b/src/meson.build index 474bbc35..3ec8c859 100644 --- a/src/meson.build +++ b/src/meson.build @@ -704,6 +704,7 @@ configure_file( ) common_src = [ + 'algo_hmac.c', 'algo_md5.c', 'algo_sha1.c', 'algo_splaytree.c',