aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_cryptobox.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/lua_cryptobox.c')
-rw-r--r--src/lua/lua_cryptobox.c100
1 files changed, 92 insertions, 8 deletions
diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
index b562c4778..2c2254920 100644
--- a/src/lua/lua_cryptobox.c
+++ b/src/lua/lua_cryptobox.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Vsevolod Stakhov
+ * Copyright 2025 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -121,6 +121,8 @@ LUA_FUNCTION_DEF(cryptobox_secretbox, encrypt);
LUA_FUNCTION_DEF(cryptobox_secretbox, decrypt);
LUA_FUNCTION_DEF(cryptobox_secretbox, gc);
+static void lua_cryptobox_hash_finish(struct rspamd_lua_cryptobox_hash *h);
+
static const struct luaL_reg cryptoboxlib_f[] = {
LUA_INTERFACE_DEF(cryptobox, verify_memory),
LUA_INTERFACE_DEF(cryptobox, verify_file),
@@ -402,7 +404,7 @@ lua_cryptobox_keypair_load(lua_State *L)
if (lua_type(L, 1) == LUA_TSTRING) {
buf = luaL_checklstring(L, 1, &len);
if (buf != NULL) {
- parser = ucl_parser_new(0);
+ parser = ucl_parser_new(UCL_PARSER_SAFE_FLAGS);
if (!ucl_parser_add_chunk(parser, buf, len)) {
msg_err("cannot open keypair from data: %s",
@@ -1306,6 +1308,19 @@ lua_cryptobox_hash_create_keyed(lua_State *L)
return 1;
}
+struct lua_hash_elt {
+ unsigned char key_hash[rspamd_cryptobox_HASHBYTES];
+ unsigned char value_hash[rspamd_cryptobox_HASHBYTES];
+};
+
+int lua_cryptobox_hash_elt_cmp(const void *a, const void *b)
+{
+ const struct lua_hash_elt *ha = (struct lua_hash_elt *) a,
+ *hb = (struct lua_hash_elt *) b;
+
+ return memcmp(ha->key_hash, hb->key_hash, sizeof(ha->key_hash));
+}
+
/***
* @function rspamd_cryptobox_hash.create_specific_keyed(key, type, [string])
* Creates new hash context with specified key
@@ -1362,13 +1377,60 @@ lua_cryptobox_hash_create_specific_keyed(lua_State *L)
return 1;
}
+static struct rspamd_lua_cryptobox_hash *
+lua_cryptobox_hash_copy(const struct rspamd_lua_cryptobox_hash *orig)
+{
+ struct rspamd_lua_cryptobox_hash *nhash = g_malloc(sizeof(struct rspamd_lua_cryptobox_hash));
+
+ memcpy(nhash, orig, sizeof(struct rspamd_lua_cryptobox_hash));
+ REF_INIT_RETAIN(nhash, lua_cryptobox_hash_dtor);
+
+ if (orig->type == LUA_CRYPTOBOX_HASH_SSL) {
+ EVP_MD_CTX_copy(nhash->content.c, orig->content.c);
+ }
+ else if (orig->type == LUA_CRYPTOBOX_HASH_HMAC) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000)
+ /* XXX: dunno what to do with this ancient crap */
+#else
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ nhash->content.hmac_c = EVP_MAC_CTX_dup(orig->content.hmac_c);
+#else
+ nhash->content.hmac_c = HMAC_CTX_new();
+ HMAC_CTX_copy(nhash->content.hmac_c, orig->content.hmac_c);
+#endif
+#endif
+ }
+ else if (orig->type == LUA_CRYPTOBOX_HASH_BLAKE2) {
+ if (posix_memalign((void **) &nhash->content.h,
+ RSPAMD_ALIGNOF(rspamd_cryptobox_hash_state_t),
+ sizeof(*nhash->content.h)) != 0) {
+ g_assert_not_reached();
+ }
+ memcpy(nhash->content.h, orig->content.h, sizeof(*nhash->content.h));
+ }
+ else {
+ nhash->content.fh = rspamd_cryptobox_fast_hash_new();
+ memcpy(nhash->content.fh, orig->content.fh, sizeof(*nhash->content.fh));
+ }
+
+ return nhash;
+}
+
+#define MAX_HASH_UPDATE_REC 16
+
static void
-lua_cryptobox_update_pos(lua_State *L, struct rspamd_lua_cryptobox_hash *h, int pos)
+lua_cryptobox_update_pos(lua_State *L, struct rspamd_lua_cryptobox_hash *h, int pos, int rec)
{
const char *data;
struct rspamd_lua_text *t;
gsize len;
+ if (rec > MAX_HASH_UPDATE_REC) {
+ /* Max recursion is reached, do nothing */
+ return;
+ }
+
/* Inverse pos if it is relative to the top of the stack */
if (pos < 0) {
pos = lua_gettop(L) + pos + 1;
@@ -1412,22 +1474,44 @@ lua_cryptobox_update_pos(lua_State *L, struct rspamd_lua_cryptobox_hash *h, int
for (gsize i = 1; i <= alen; i++) {
lua_rawgeti(L, pos, i);
- lua_cryptobox_update_pos(L, h, -1); /* Recurse */
+ lua_cryptobox_update_pos(L, h, -1, rec + 1); /* Recurse */
lua_pop(L, 1);
}
- /* Hash key-value pairs */
+ /* Hash key-value pairs and store all stuff in the array */
lua_pushnil(L);
+ GArray *tbl_digests = g_array_new(false, true, sizeof(struct lua_hash_elt));
while (lua_next(L, pos) != 0) {
+ struct rspamd_lua_cryptobox_hash *key_h = lua_cryptobox_hash_copy(h),
+ *value_h = lua_cryptobox_hash_copy(h);
+ struct lua_hash_elt he;
/* Hash key */
lua_pushvalue(L, -2);
- lua_cryptobox_update_pos(L, h, -1);
+ lua_cryptobox_update_pos(L, key_h, -1, rec + 1);
lua_pop(L, 1);
+ lua_cryptobox_hash_finish(key_h);
+ memcpy(he.key_hash, key_h->out, sizeof(he.key_hash));
+ REF_RELEASE(key_h);
/* Hash value */
- lua_cryptobox_update_pos(L, h, -1);
+ lua_cryptobox_update_pos(L, value_h, -1, rec + 1);
lua_pop(L, 1);
+ lua_cryptobox_hash_finish(value_h);
+ memcpy(he.value_hash, value_h->out, sizeof(he.value_hash));
+ REF_RELEASE(value_h);
+
+ g_array_append_val(tbl_digests, he);
+ }
+
+ /* Sort elements */
+ g_array_sort(tbl_digests, lua_cryptobox_hash_elt_cmp);
+ /* Now update the original hash context */
+ for (size_t i = 0; i < tbl_digests->len; i++) {
+ struct lua_hash_elt *he = &g_array_index(tbl_digests, struct lua_hash_elt, i);
+ rspamd_lua_hash_update(h, he->key_hash, sizeof(he->key_hash));
+ rspamd_lua_hash_update(h, he->value_hash, sizeof(he->value_hash));
}
+ g_array_free(tbl_digests, true);
break;
}
@@ -1464,7 +1548,7 @@ lua_cryptobox_hash_update(lua_State *L)
return luaL_error(L, "invalid arguments or hash is already finalized");
}
- lua_cryptobox_update_pos(L, h, 2);
+ lua_cryptobox_update_pos(L, h, 2, 0);
ph = lua_newuserdata(L, sizeof(void *));
*ph = h;