From 8f70f5e4b465ace44590ad233a223639e5a5e861 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 10 Aug 2021 11:18:33 +0100 Subject: [PATCH] [Feature] Lua_cryptobox: Add keyed ssl hash functions via HMAC --- src/lua/lua_cryptobox.c | 184 +++++++++++++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 29 deletions(-) diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c index 788f2e1df..f712fad0c 100644 --- a/src/lua/lua_cryptobox.c +++ b/src/lua/lua_cryptobox.c @@ -36,11 +36,13 @@ #include "libutil/ref.h" #include +#include enum lua_cryptobox_hash_type { LUA_CRYPTOBOX_HASH_BLAKE2 = 0, LUA_CRYPTOBOX_HASH_SSL, + LUA_CRYPTOBOX_HASH_HMAC, LUA_CRYPTOBOX_HASH_XXHASH64, LUA_CRYPTOBOX_HASH_XXHASH32, LUA_CRYPTOBOX_HASH_MUM, @@ -51,6 +53,7 @@ struct rspamd_lua_cryptobox_hash { union { rspamd_cryptobox_hash_state_t *h; EVP_MD_CTX *c; + HMAC_CTX *hmac_c; rspamd_cryptobox_fast_hash_state_t *fh; } content; @@ -83,6 +86,7 @@ LUA_FUNCTION_DEF (cryptobox_signature, base64); LUA_FUNCTION_DEF (cryptobox_signature, bin); LUA_FUNCTION_DEF (cryptobox_hash, create); LUA_FUNCTION_DEF (cryptobox_hash, create_specific); +LUA_FUNCTION_DEF (cryptobox_hash, create_specific_keyed); LUA_FUNCTION_DEF (cryptobox_hash, create_keyed); LUA_FUNCTION_DEF (cryptobox_hash, update); LUA_FUNCTION_DEF (cryptobox_hash, reset); @@ -178,6 +182,7 @@ static const struct luaL_reg cryptoboxhashlib_f[] = { LUA_INTERFACE_DEF (cryptobox_hash, create), LUA_INTERFACE_DEF (cryptobox_hash, create_keyed), LUA_INTERFACE_DEF (cryptobox_hash, create_specific), + LUA_INTERFACE_DEF (cryptobox_hash, create_specific_keyed), {NULL, NULL} }; @@ -964,6 +969,9 @@ rspamd_lua_hash_update (struct rspamd_lua_cryptobox_hash *h, case LUA_CRYPTOBOX_HASH_SSL: EVP_DigestUpdate (h->content.c, p, len); break; + case LUA_CRYPTOBOX_HASH_HMAC: + HMAC_Update (h->content.hmac_c, p, len); + break; case LUA_CRYPTOBOX_HASH_XXHASH64: case LUA_CRYPTOBOX_HASH_XXHASH32: case LUA_CRYPTOBOX_HASH_MUM: @@ -987,6 +995,14 @@ lua_cryptobox_hash_dtor (struct rspamd_lua_cryptobox_hash *h) #endif EVP_MD_CTX_destroy (h->content.c); } + else if (h->type == LUA_CRYPTOBOX_HASH_HMAC) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + HMAC_CTX_cleanup (h->content.hmac_c); + g_free (h->content.hmac_c); +#else + HMAC_CTX_free (h->content.hmac_c); +#endif + } else if (h->type == LUA_CRYPTOBOX_HASH_BLAKE2) { rspamd_explicit_memzero (h->content.h, sizeof (*h->content.h)); free (h->content.h); /* Allocated by posix_memalign */ @@ -1013,6 +1029,50 @@ rspamd_lua_hash_init_default (struct rspamd_lua_cryptobox_hash *h, h->out_len = rspamd_cryptobox_HASHBYTES; } +static void +rspamd_lua_ssl_hash_create (struct rspamd_lua_cryptobox_hash *h, const EVP_MD *htype, + bool insecure) +{ + h->type = LUA_CRYPTOBOX_HASH_SSL; + h->content.c = EVP_MD_CTX_create (); + h->out_len = EVP_MD_size (htype); + + if (insecure) { + /* Should never ever be used for crypto/security purposes! */ +#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW + EVP_MD_CTX_set_flags(h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + } + + EVP_DigestInit_ex (h->content.c, htype, NULL); +} + +static void +rspamd_lua_ssl_hmac_create (struct rspamd_lua_cryptobox_hash *h, const EVP_MD *htype, + const gchar *key, gsize keylen, + bool insecure) +{ + h->type = LUA_CRYPTOBOX_HASH_HMAC; + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + h->content.hmac_c = g_malloc0 (sizeof(*h->content.hmac_c)); +#else + h->content.hmac_c = HMAC_CTX_new (); +#endif + h->out_len = EVP_MD_size (htype); + +#if OPENSSL_VERSION_NUMBER > 0x10100000L + if (insecure) { + /* Should never ever be used for crypto/security purposes! */ +#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW + HMAC_CTX_set_flags(h->content.hmac_c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + } +#endif + + HMAC_Init_ex (h->content.hmac_c, key, keylen, htype, NULL); +} + static struct rspamd_lua_cryptobox_hash * rspamd_lua_hash_create (const gchar *type, const gchar *key, gsize keylen) { @@ -1023,43 +1083,45 @@ rspamd_lua_hash_create (const gchar *type, const gchar *key, gsize keylen) if (type) { if (g_ascii_strcasecmp (type, "md5") == 0) { - h->type = LUA_CRYPTOBOX_HASH_SSL; - h->content.c = EVP_MD_CTX_create (); - h->out_len = EVP_MD_size (EVP_md5 ()); - /* Should never ever be used for crypto/security purposes! */ -#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW - EVP_MD_CTX_set_flags (h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); -#endif - EVP_DigestInit_ex (h->content.c, EVP_md5 (), NULL); + if (keylen > 0) { + rspamd_lua_ssl_hmac_create(h, EVP_md5(), key, keylen, true); + } + else { + rspamd_lua_ssl_hash_create(h, EVP_md5(), true); + } } else if (g_ascii_strcasecmp (type, "sha1") == 0 || g_ascii_strcasecmp (type, "sha") == 0) { - h->type = LUA_CRYPTOBOX_HASH_SSL; - h->content.c = EVP_MD_CTX_create (); - h->out_len = EVP_MD_size (EVP_sha1 ()); - /* Should never ever be used for crypto/security purposes! */ -#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW - EVP_MD_CTX_set_flags (h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); -#endif - EVP_DigestInit_ex (h->content.c, EVP_sha1 (), NULL); + if (keylen > 0) { + rspamd_lua_ssl_hmac_create(h, EVP_sha1(), key, keylen, true); + } + else { + rspamd_lua_ssl_hash_create(h, EVP_sha1(), true); + } } else if (g_ascii_strcasecmp (type, "sha256") == 0) { - h->type = LUA_CRYPTOBOX_HASH_SSL; - h->content.c = EVP_MD_CTX_create (); - h->out_len = EVP_MD_size (EVP_sha256 ()); - EVP_DigestInit (h->content.c, EVP_sha256 ()); + if (keylen > 0) { + rspamd_lua_ssl_hmac_create(h, EVP_sha256(), key, keylen, true); + } + else { + rspamd_lua_ssl_hash_create(h, EVP_sha256(), true); + } } else if (g_ascii_strcasecmp (type, "sha512") == 0) { - h->type = LUA_CRYPTOBOX_HASH_SSL; - h->content.c = EVP_MD_CTX_create (); - h->out_len = EVP_MD_size (EVP_sha512 ()); - EVP_DigestInit (h->content.c, EVP_sha512 ()); + if (keylen > 0) { + rspamd_lua_ssl_hmac_create(h, EVP_sha512(), key, keylen, true); + } + else { + rspamd_lua_ssl_hash_create(h, EVP_sha512(), true); + } } else if (g_ascii_strcasecmp (type, "sha384") == 0) { - h->type = LUA_CRYPTOBOX_HASH_SSL; - h->content.c = EVP_MD_CTX_create (); - h->out_len = EVP_MD_size (EVP_sha384 ()); - EVP_DigestInit (h->content.c, EVP_sha384 ()); + if (keylen > 0) { + rspamd_lua_ssl_hmac_create(h, EVP_sha384(), key, keylen, true); + } + else { + rspamd_lua_ssl_hash_create(h, EVP_sha384(), true); + } } else if (g_ascii_strcasecmp (type, "xxh64") == 0) { h->type = LUA_CRYPTOBOX_HASH_XXHASH64; @@ -1235,7 +1297,57 @@ lua_cryptobox_hash_create_keyed (lua_State *L) } if (s) { - rspamd_cryptobox_hash_update (h->content.h, s, len); + rspamd_lua_hash_update (h, s, len); + } + + ph = lua_newuserdata (L, sizeof (void *)); + *ph = h; + rspamd_lua_setclass (L, "rspamd{cryptobox_hash}", -1); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +/*** + * @function rspamd_cryptobox_hash.create_specific_keyed(key, type, [string]) + * Creates new hash context with specified key + * @param {string} key key + * @return {cryptobox_hash} hash object + */ +static gint +lua_cryptobox_hash_create_specific_keyed (lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_lua_cryptobox_hash *h, **ph; + const gchar *key, *s = NULL, *type = luaL_checkstring (L, 2); + struct rspamd_lua_text *t; + gsize len = 0; + gsize keylen; + + key = luaL_checklstring (L, 1, &keylen); + + if (key != NULL && type != NULL) { + h = rspamd_lua_hash_create (type, key, keylen); + + if (lua_type (L, 3) == LUA_TSTRING) { + s = lua_tolstring (L, 3, &len); + } + else if (lua_type (L, 3) == LUA_TUSERDATA) { + t = lua_check_text (L, 3); + + if (!t) { + return luaL_error (L, "invalid arguments"); + } + + s = t->start; + len = t->len; + } + + if (s) { + rspamd_lua_hash_update (h, s, len); } ph = lua_newuserdata (L, sizeof (void *)); @@ -1327,6 +1439,14 @@ lua_cryptobox_hash_reset (lua_State *L) case LUA_CRYPTOBOX_HASH_SSL: EVP_DigestInit (h->content.c, EVP_MD_CTX_md (h->content.c)); break; + case LUA_CRYPTOBOX_HASH_HMAC: +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + /* Old openssl is awesome... */ + HMAC_Init_ex (h->content.hmac_c, NULL, 0, h->content.hmac_c->md, NULL); +#else + HMAC_CTX_reset (h->content.hmac_c); +#endif + break; case LUA_CRYPTOBOX_HASH_XXHASH64: rspamd_cryptobox_fast_hash_init_specific (h->content.fh, RSPAMD_CRYPTOBOX_XXHASH64, 0); @@ -1378,6 +1498,12 @@ lua_cryptobox_hash_finish (struct rspamd_lua_cryptobox_hash *h) g_assert (ssl_outlen <= sizeof (h->out)); memcpy (h->out, out, ssl_outlen); break; + case LUA_CRYPTOBOX_HASH_HMAC: + HMAC_Final (h->content.hmac_c, out, &ssl_outlen); + h->out_len = ssl_outlen; + g_assert (ssl_outlen <= sizeof (h->out)); + memcpy (h->out, out, ssl_outlen); + break; case LUA_CRYPTOBOX_HASH_XXHASH64: case LUA_CRYPTOBOX_HASH_XXHASH32: case LUA_CRYPTOBOX_HASH_MUM: -- 2.39.5