]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Lua_cryptobox: Add keyed ssl hash functions via HMAC
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 10 Aug 2021 10:18:33 +0000 (11:18 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 10 Aug 2021 10:18:33 +0000 (11:18 +0100)
src/lua/lua_cryptobox.c

index 788f2e1df4906a75375cdc65cb370009f0eb997d..f712fad0c8bdb32654112e872242a0476b98741a 100644 (file)
 #include "libutil/ref.h"
 
 #include <stdalign.h>
+#include <openssl/hmac.h>
 
 
 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: