diff options
author | John McKay <adenosine3p@gmail.com> | 2019-01-24 01:26:21 +0000 |
---|---|---|
committer | John McKay <adenosine3p@gmail.com> | 2019-02-02 05:41:41 +0000 |
commit | 875f80ee9aa1ff58463f32864ec5fcd57558b0a5 (patch) | |
tree | 9863ff43e6a10a08c31053690cfe00efe9d40c2b | |
parent | 04b5bfde88920f472516ebae5172b232e7ca37a0 (diff) | |
download | rspamd-875f80ee9aa1ff58463f32864ec5fcd57558b0a5.tar.gz rspamd-875f80ee9aa1ff58463f32864ec5fcd57558b0a5.zip |
Refactor dkim private key loads
-rw-r--r-- | src/libserver/dkim.c | 174 | ||||
-rw-r--r-- | src/libserver/dkim.h | 22 | ||||
-rw-r--r-- | src/plugins/dkim_check.c | 528 |
3 files changed, 302 insertions, 422 deletions
diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index d4c54b422..5144c0517 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -144,7 +144,7 @@ struct rspamd_dkim_context_s { struct rspamd_dkim_key_s { guint8 *keydata; - guint keylen; + gsize keylen; gsize decoded_len; guint ttl; union { @@ -155,6 +155,7 @@ struct rspamd_dkim_key_s { enum rspamd_dkim_key_type type; BIO *key_bio; EVP_PKEY *key_evp; + time_t mtime; ref_entry_t ref; }; @@ -163,22 +164,6 @@ struct rspamd_dkim_sign_context_s { rspamd_dkim_sign_key_t *key; }; -struct rspamd_dkim_sign_key_s { - enum rspamd_dkim_key_type type; - guint8 *keydata; - gpointer map; - gsize keylen; - union { - RSA *key_rsa; - guchar *key_eddsa; - } key; - BIO *key_bio; - EVP_PKEY *key_evp; - time_t mtime; - ref_entry_t ref; -}; - - struct rspamd_dkim_header { const gchar *name; guint count; @@ -1364,15 +1349,9 @@ rspamd_dkim_sign_key_free (rspamd_dkim_sign_key_t *key) BIO_free (key->key_bio); } - if (key->keydata && key->keylen > 0) { - - if (key->map) { - munmap (key->map, key->keylen); - } - else { - rspamd_explicit_memzero (key->keydata, key->keylen); - g_free (key->keydata); - } + if (key->type == RSPAMD_DKIM_KEY_EDDSA) { + rspamd_explicit_memzero (key->key.key_eddsa, key->keylen); + g_free (key->keydata); } g_free (key); @@ -2626,107 +2605,44 @@ rspamd_dkim_get_dns_key (rspamd_dkim_context_t *ctx) } rspamd_dkim_sign_key_t* -rspamd_dkim_sign_key_load (const gchar *what, gsize len, - enum rspamd_dkim_sign_key_type type, +rspamd_dkim_sign_key_load (const gchar *key, gsize len, + enum rspamd_dkim_key_format type, GError **err) { - gpointer map; - gsize map_len = 0; rspamd_dkim_sign_key_t *nkey; - struct stat st; - time_t mtime = 0; - - if (type == RSPAMD_DKIM_SIGN_KEY_FILE) { - gchar fpath[PATH_MAX]; + time_t mtime = time (NULL); - rspamd_snprintf (fpath, sizeof (fpath), "%*s", (gint)len, what); - - if (stat (fpath, &st) == -1) { - g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot stat private key %s: %s", - fpath, strerror (errno)); - - return NULL; - } - - mtime = st.st_mtime; - map = rspamd_file_xmap (fpath, PROT_READ, &map_len, TRUE); - - if (map == NULL) { + switch (type) { + case RSPAMD_DKIM_KEY_PEM: + /* fallthrough */ + case RSPAMD_DKIM_KEY_RAW: + break; + default: g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot map private key %s: %s", - fpath, strerror (errno)); - + "invalid key type to load: %d", type); return NULL; - } } nkey = g_malloc0 (sizeof (*nkey)); - nkey->type = type; nkey->mtime = mtime; - switch (type) { - case RSPAMD_DKIM_SIGN_KEY_FILE: - (void)mlock (map, len); - nkey->map = map; - nkey->keydata = map; - nkey->keylen = map_len; - break; - case RSPAMD_DKIM_SIGN_KEY_BASE64: - nkey->keydata = g_malloc (len); - nkey->keylen = len; - rspamd_cryptobox_base64_decode (what, len, nkey->keydata, - &nkey->keylen); - break; - case RSPAMD_DKIM_SIGN_KEY_DER: - case RSPAMD_DKIM_SIGN_KEY_PEM: - nkey->keydata = g_malloc (len); - memcpy (nkey->keydata, what, len); - nkey->keylen = len; - } - - msg_debug2_dkim("got public key with length %d and type %d", nkey->keylen, type); - (void)mlock (nkey->keydata, nkey->keylen); - if (type == RSPAMD_DKIM_SIGN_KEY_FILE && nkey->keylen == ED25519_B64_BYTES) { - unsigned char seed[32]; + msg_debug2_dkim("got public key with length %d and type %d", len, type); + if (type == RSPAMD_DKIM_KEY_RAW && len == 32) { unsigned char pk[32]; nkey->type = RSPAMD_DKIM_KEY_EDDSA; - nkey->keydata = g_malloc (rspamd_cryptobox_sk_sig_bytes (RSPAMD_CRYPTOBOX_MODE_25519)); - rspamd_cryptobox_base64_decode (nkey->map, ED25519_B64_BYTES, seed, &nkey->keylen); - ed25519_seed_keypair (pk, nkey->keydata, seed); - nkey->key.key_eddsa = nkey->keydata; - nkey->keylen = rspamd_cryptobox_sk_sig_bytes (RSPAMD_CRYPTOBOX_MODE_25519); - rspamd_explicit_memzero (seed, 32); - munmap (nkey->map, ED25519_B64_BYTES); - nkey->map = NULL; - } - else if (type == RSPAMD_DKIM_SIGN_KEY_BASE64 && nkey->keylen == ED25519_BYTES) { - unsigned char pk[32]; - nkey->type = RSPAMD_DKIM_KEY_EDDSA; - nkey->key.key_eddsa = - g_malloc (rspamd_cryptobox_sk_sig_bytes (RSPAMD_CRYPTOBOX_MODE_25519)); - ed25519_seed_keypair (pk, nkey->key.key_eddsa, nkey->keydata); - rspamd_explicit_memzero (nkey->keydata, nkey->keylen); - g_free (nkey->keydata); - nkey->keydata = nkey->key.key_eddsa; + nkey->key.key_eddsa = g_malloc ( + rspamd_cryptobox_sk_sig_bytes (RSPAMD_CRYPTOBOX_MODE_25519)); + ed25519_seed_keypair (pk, nkey->key.key_eddsa, (char *)key); nkey->keylen = rspamd_cryptobox_sk_sig_bytes (RSPAMD_CRYPTOBOX_MODE_25519); } else { - nkey->key_bio = BIO_new_mem_buf (nkey->keydata, nkey->keylen); + nkey->key_bio = BIO_new_mem_buf (key, len); - if (type == RSPAMD_DKIM_SIGN_KEY_DER || type == RSPAMD_DKIM_SIGN_KEY_BASE64) { + if (type == RSPAMD_DKIM_KEY_RAW) { if (d2i_PrivateKey_bio (nkey->key_bio, &nkey->key_evp) == NULL) { - if (type == RSPAMD_DKIM_SIGN_KEY_FILE) { - g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot read private key from %*s: %s", - (gint)len, what, - ERR_error_string (ERR_get_error (), NULL)); - } - else { - g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot read private key from string: %s", - ERR_error_string (ERR_get_error (), NULL)); - } + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot parse raw private key: %s", + ERR_error_string (ERR_get_error (), NULL)); rspamd_dkim_sign_key_free (nkey); @@ -2735,18 +2651,9 @@ rspamd_dkim_sign_key_load (const gchar *what, gsize len, } else { if (!PEM_read_bio_PrivateKey (nkey->key_bio, &nkey->key_evp, NULL, NULL)) { - if (type == RSPAMD_DKIM_SIGN_KEY_FILE) { - g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot read private key from %*s: %s", - (gint)len, what, - ERR_error_string (ERR_get_error (), NULL)); - } - else { - g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, - "cannot read private key from string: %s", - ERR_error_string (ERR_get_error (), NULL)); - } - + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot parse pem private key: %s", + ERR_error_string (ERR_get_error (), NULL)); rspamd_dkim_sign_key_free (nkey); return NULL; @@ -2772,32 +2679,11 @@ rspamd_dkim_sign_key_load (const gchar *what, gsize len, } gboolean -rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key, - enum rspamd_dkim_sign_key_type type, - const gchar *what, gsize len) +rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key, time_t mtime) { - struct stat st; - - if (type == RSPAMD_DKIM_SIGN_KEY_FILE) { - gchar fpath[PATH_MAX]; - - if (len >= PATH_MAX) { - /* Bad thing */ + if (mtime > key->mtime) { return TRUE; - } - - rspamd_snprintf (fpath, sizeof (fpath), "%*s", (gint) len, what); - - if (stat (fpath, &st) == -1) { - /* Wrong: do NOT prefer to use cached key since it is absent on FS */ - return TRUE; - } - - if (st.st_mtime > key->mtime) { - return TRUE; - } } - return FALSE; } diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h index 46953a21c..d57c923bb 100644 --- a/src/libserver/dkim.h +++ b/src/libserver/dkim.h @@ -102,16 +102,17 @@ typedef struct rspamd_dkim_sign_context_s rspamd_dkim_sign_context_t; struct rspamd_dkim_key_s; typedef struct rspamd_dkim_key_s rspamd_dkim_key_t; -struct rspamd_dkim_sign_key_s; -typedef struct rspamd_dkim_sign_key_s rspamd_dkim_sign_key_t; +struct rspamd_dkim_key_s; +typedef struct rspamd_dkim_key_s rspamd_dkim_sign_key_t; struct rspamd_task; -enum rspamd_dkim_sign_key_type { - RSPAMD_DKIM_SIGN_KEY_FILE = 0, - RSPAMD_DKIM_SIGN_KEY_PEM, - RSPAMD_DKIM_SIGN_KEY_BASE64, - RSPAMD_DKIM_SIGN_KEY_DER +enum rspamd_dkim_key_format { + RSPAMD_DKIM_KEY_FILE = 0, + RSPAMD_DKIM_KEY_PEM, + RSPAMD_DKIM_KEY_BASE64, + RSPAMD_DKIM_KEY_RAW, + RSPAMD_DKIM_KEY_UNKNOWN }; enum rspamd_dkim_type { @@ -188,17 +189,16 @@ rspamd_dkim_sign_context_t * rspamd_create_dkim_sign_context (struct rspamd_task * @return */ rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_load (const gchar *what, gsize len, - enum rspamd_dkim_sign_key_type type, + enum rspamd_dkim_key_format type, GError **err); /** * Invalidate modified sign key * @param key * @return - */ +*/ gboolean rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key, - enum rspamd_dkim_sign_key_type type, - const gchar *what, gsize len); + time_t mtime); /** * Make DNS request for specified context and obtain and parse key diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c index 92354529f..06c039ea4 100644 --- a/src/plugins/dkim_check.c +++ b/src/plugins/dkim_check.c @@ -38,6 +38,7 @@ #include "libutil/map_helpers.h" #include "rspamd.h" #include "utlist.h" +#include "unix-std.h" #include "lua/lua_common.h" #include "libserver/mempool_vars_internal.h" @@ -634,16 +635,58 @@ dkim_module_config (struct rspamd_config *cfg) return res; } +/** + * helper to see if valid base64, minus newline + */ +static gboolean +is_valid_base64(const uint8_t *in, size_t len) { + int i; + if (in[len - 1] == '\n') + len--; + if (in[len - 1] == '\r') + len--; + if (len % 4 != 0) + return FALSE; + + if (in[len - 1] == '=') + len--; + if (in[len - 1] == '=') + len--; + + for (i = 0; i < len; i++) { + if ('a' <= in[i] && in[i] <= 'z') + continue; + if ('A' <= in[i] && in[i] <= 'Z') + continue; + if ('0' <= in[i] && in[i] <= '9') + continue; + if (in[i] == '/') + continue; + if (in[i] == '+') + continue; + return FALSE; + } + return TRUE; +} + + +#define PEM_SIG "-----BEGIN" +/** + * Grab a private key from the cache + * or from the key content provided + */ rspamd_dkim_sign_key_t * -dkim_module_load_key_format (lua_State *L, struct rspamd_task *task, - const gchar *key, gsize keylen, - enum rspamd_dkim_sign_key_type kt) +dkim_module_load_key_format (struct rspamd_task *task, struct dkim_ctx *dkim_module_ctx, + const gchar *key, gsize keylen, enum rspamd_dkim_key_format key_format) + { guchar h[rspamd_cryptobox_HASHBYTES], hex_hash[rspamd_cryptobox_HASHBYTES * 2 + 1]; rspamd_dkim_sign_key_t *ret; GError *err = NULL; - struct dkim_ctx *dkim_module_ctx = dkim_get_context (task->cfg); + gpointer map = NULL, tmp = NULL; + struct stat st; + ssize_t maplen; memset (hex_hash, 0, sizeof (hex_hash)); rspamd_cryptobox_hash (h, key, keylen, NULL, 0); @@ -651,23 +694,95 @@ dkim_module_load_key_format (lua_State *L, struct rspamd_task *task, ret = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash, hex_hash, time (NULL)); - if (ret == NULL) { - ret = rspamd_dkim_sign_key_load (key, keylen, kt, &err); + /* + * This fails for paths that are also valid base64. + * Maybe the caller should have specified a format. + */ + if (key_format == RSPAMD_DKIM_KEY_UNKNOWN && + (key[0] == '.' || key[0] == '/')) { + if (!is_valid_base64 (key, keylen)) + key_format = RSPAMD_DKIM_KEY_FILE; + } - if (ret == NULL) { - msg_err_task ("cannot load private key: %e", err); - g_error_free (err); + if (ret != NULL && key_format == RSPAMD_DKIM_KEY_FILE) { + msg_debug_task("checking for stale file key"); + if (stat (key, &st) != 0) { + msg_err_task("cannot stat key file: %s", strerror (errno)); + return NULL; + } + if (rspamd_dkim_sign_key_maybe_invalidate (ret, st.st_mtime)) { + msg_debug_task("removing stale file key"); + /* + * Invalidate DKIM key + * removal from lru cache also cleanup the key and value + */ + rspamd_lru_hash_remove (dkim_module_ctx->dkim_sign_hash, + hex_hash); + ret = NULL; + } + } - return NULL; - } + /* found key; done */ + if (ret != NULL) + return ret; - rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, - g_strdup (hex_hash), ret, - time (NULL), 0); + if (key_format == RSPAMD_DKIM_KEY_FILE) { + if (stat (key, &st) != 0) { + msg_err_task("cannot stat key file: %s", strerror (errno)); + return NULL; } + map = rspamd_file_xmap (key, PROT_READ, &maplen, TRUE); + if (map == NULL) { + msg_err_task("cannot open key file \'%s\'", key); + return NULL; + } + key = map; + keylen = maplen; + if (maplen > sizeof (PEM_SIG) && + strncmp (map, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { + key_format = RSPAMD_DKIM_KEY_PEM; + } else if (is_valid_base64 ((uint8_t *)map, maplen)) { + key_format = RSPAMD_DKIM_KEY_BASE64; + } else { + key_format = RSPAMD_DKIM_KEY_RAW; + } + } + if (key_format == RSPAMD_DKIM_KEY_UNKNOWN) { + if (keylen > sizeof (PEM_SIG) && + strncmp (key, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { + key_format = RSPAMD_DKIM_KEY_PEM; + } else { + key_format = RSPAMD_DKIM_KEY_RAW; + } + } + if (key_format == RSPAMD_DKIM_KEY_BASE64) { + key_format = RSPAMD_DKIM_KEY_RAW; + tmp = g_malloc (keylen); + rspamd_cryptobox_base64_decode (key, keylen, tmp, &keylen); + key = tmp; + } + + ret = rspamd_dkim_sign_key_load (key, keylen, key_format, &err); + + if (ret == NULL) { + msg_err_task ("cannot load dkim key %s: %e", + key, err); + g_error_free (err); + } else { + rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, + g_strdup (hex_hash), ret, time (NULL), 0); + } + + if (map != NULL) + munmap (map, maplen); + if (tmp != NULL) { + rspamd_explicit_memzero (tmp, keylen); + g_free (tmp); + } return ret; } +#undef PEM_SIG static gint lua_dkim_sign_handler (lua_State *L) @@ -718,86 +833,24 @@ lua_dkim_sign_handler (lua_State *L) (GDestroyNotify)rspamd_dkim_sign_key_unref); } -#define PEM_SIG "-----BEGIN" if (key) { - if (key[0] == '.' || key[0] == '/') { - /* Likely raw path */ - dkim_key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash, - key, time (NULL)); - - if (dkim_key == NULL) { - dkim_key = rspamd_dkim_sign_key_load (key, strlen (key), - RSPAMD_DKIM_SIGN_KEY_FILE, &err); - - if (dkim_key == NULL) { - msg_err_task ("cannot load dkim key %s: %e", - key, err); - g_error_free (err); - - lua_pushboolean (L, FALSE); - return 1; - } - - rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, - g_strdup (key), dkim_key, - time (NULL), 0); - } - } - else if (keylen > sizeof (PEM_SIG) && - strncmp (key, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { - /* Pem header found */ - dkim_key = dkim_module_load_key_format (L, task, key, keylen, - RSPAMD_DKIM_SIGN_KEY_PEM); - - if (dkim_key == NULL) { - lua_pushboolean (L, FALSE); - return 1; - } - } - else { - dkim_key = dkim_module_load_key_format (L, task, key, keylen, - RSPAMD_DKIM_SIGN_KEY_BASE64); - - if (dkim_key == NULL) { - lua_pushboolean (L, FALSE); - return 1; - } - } - } - else if (rawkey) { - key = rawkey; - keylen = rawlen; - - if (keylen > sizeof (PEM_SIG) && - strncmp (key, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { - /* Pem header found */ - dkim_key = dkim_module_load_key_format (L, task, key, keylen, - RSPAMD_DKIM_SIGN_KEY_PEM); - - if (dkim_key == NULL) { - lua_pushboolean (L, FALSE); - return 1; - } - } - else { - dkim_key = dkim_module_load_key_format (L, task, key, keylen, - RSPAMD_DKIM_SIGN_KEY_BASE64); - - if (dkim_key == NULL) { - lua_pushboolean (L, FALSE); - return 1; - } - } - } - else { + dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, key, + keylen, RSPAMD_DKIM_KEY_UNKNOWN); + } else if(rawkey) { + dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, rawkey, + rawlen, RSPAMD_DKIM_KEY_UNKNOWN); + } else { msg_err_task ("neither key nor rawkey are specified"); lua_pushboolean (L, FALSE); return 1; } -#undef PEM_SIG + if (dkim_key == NULL) { + lua_pushboolean (L, FALSE); + return 1; + } if (sign_type_str) { if (strcmp (sign_type_str, "dkim") == 0) { @@ -1311,226 +1364,167 @@ dkim_sign_callback (struct rspamd_task *task, GString *tb, *hdr; GError *err = NULL; const gchar *selector = NULL, *domain = NULL, *key = NULL, *key_type = NULL, - *sign_type_str = NULL, *lru_key, *arc_cv = NULL; + *sign_type_str = NULL, *arc_cv = NULL; rspamd_dkim_sign_context_t *ctx; - rspamd_dkim_sign_key_t *dkim_key; - enum rspamd_dkim_sign_key_type key_sign_type = RSPAMD_DKIM_SIGN_KEY_FILE; + rspamd_dkim_key_t *dkim_key; + enum rspamd_dkim_key_format key_format = RSPAMD_DKIM_KEY_FILE; enum rspamd_dkim_type sign_type = RSPAMD_DKIM_NORMAL; - guchar h[rspamd_cryptobox_HASHBYTES], - hex_hash[rspamd_cryptobox_HASHBYTES * 2 + 1]; struct dkim_ctx *dkim_module_ctx = dkim_get_context (task->cfg); - if (dkim_module_ctx->sign_condition_ref != -1) { - sign = FALSE; - L = task->cfg->lua_state; - lua_pushcfunction (L, &rspamd_lua_traceback); - err_idx = lua_gettop (L); - - lua_rawgeti (L, LUA_REGISTRYINDEX, dkim_module_ctx->sign_condition_ref); - ptask = lua_newuserdata (L, sizeof (struct rspamd_task *)); - *ptask = task; - rspamd_lua_setclass (L, "rspamd{task}", -1); - - if (lua_pcall (L, 1, 1, err_idx) != 0) { - tb = lua_touserdata (L, -1); - msg_err_task ("call to user extraction script failed: %v", tb); - g_string_free (tb, TRUE); - } - else { - if (lua_istable (L, -1)) { - /* - * Get the following elements: - * - selector - * - domain - * - key - */ - if (!rspamd_lua_parse_table_arguments (L, -1, &err, - "*key=V;*domain=S;*selector=S;type=S;key_type=S;" - "sign_type=S;arc_cv=S;arc_idx=I", - &len, &key, &domain, &selector, - &key_type, &key_type, &sign_type_str, &arc_cv, - &arc_idx)) { - msg_err_task ("invalid return value from sign condition: %e", - err); - g_error_free (err); - rspamd_symcache_finalize_item (task, item); + if (dkim_module_ctx->sign_condition_ref == -1) { + rspamd_symcache_finalize_item (task, item); + return; + } - return; - } + sign = FALSE; + L = task->cfg->lua_state; + lua_pushcfunction (L, &rspamd_lua_traceback); + err_idx = lua_gettop (L); - if (key_type) { - if (strcmp (key_type, "file") == 0) { - key_sign_type = RSPAMD_DKIM_SIGN_KEY_FILE; - } - else if (strcmp (key_type, "base64") == 0) { - key_sign_type = RSPAMD_DKIM_SIGN_KEY_BASE64; - } - else if (strcmp (key_type, "pem") == 0) { - key_sign_type = RSPAMD_DKIM_SIGN_KEY_PEM; - } - else if (strcmp (key_type, "der") == 0 || - strcmp (key_type, "raw") == 0) { - key_sign_type = RSPAMD_DKIM_SIGN_KEY_DER; - } - else { - lua_settop (L, 0); - luaL_error (L, "unknown key type: %s", - key_type); - rspamd_symcache_finalize_item (task, item); + lua_rawgeti (L, LUA_REGISTRYINDEX, dkim_module_ctx->sign_condition_ref); + ptask = lua_newuserdata (L, sizeof (struct rspamd_task *)); + *ptask = task; + rspamd_lua_setclass (L, "rspamd{task}", -1); - return; - } - } + if (lua_pcall (L, 1, 1, err_idx) != 0) { + tb = lua_touserdata (L, -1); + msg_err_task ("call to user extraction script failed: %v", tb); + g_string_free (tb, TRUE); + } + else { + if (lua_istable (L, -1)) { + /* + * Get the following elements: + * - selector + * - domain + * - key + */ + if (!rspamd_lua_parse_table_arguments (L, -1, &err, + "*key=V;*domain=S;*selector=S;type=S;key_type=S;" + "sign_type=S;arc_cv=S;arc_idx=I", + &len, &key, &domain, &selector, + &key_type, &key_type, &sign_type_str, &arc_cv, + &arc_idx)) { + msg_err_task ("invalid return value from sign condition: %e", + err); + g_error_free (err); + rspamd_symcache_finalize_item (task, item); - if (sign_type_str) { - if (strcmp (sign_type_str, "dkim") == 0) { - sign_type = RSPAMD_DKIM_NORMAL; - } - else if (strcmp (sign_type_str, "arc-sign") == 0) { - sign_type = RSPAMD_DKIM_ARC_SIG; - if (arc_idx == 0) { - lua_settop (L, 0); - luaL_error (L, "no arc idx specified"); - rspamd_symcache_finalize_item (task, item); - - return; - } - } - else if (strcmp (sign_type_str, "arc-seal") == 0) { - sign_type = RSPAMD_DKIM_ARC_SEAL; - if (arc_cv == NULL) { - lua_settop (L, 0); - luaL_error (L, "no arc cv specified"); - rspamd_symcache_finalize_item (task, item); - - return; - } - if (arc_idx == 0) { - lua_settop (L, 0); - luaL_error (L, "no arc idx specified"); - rspamd_symcache_finalize_item (task, item); - - return; - } - } - else { - lua_settop (L, 0); - luaL_error (L, "unknown sign type: %s", - sign_type_str); - rspamd_symcache_finalize_item (task, item); + return; + } - return; - } + if (key_type) { + if (strcmp (key_type, "file") == 0) { + key_format = RSPAMD_DKIM_KEY_FILE; } - - if (key_sign_type == RSPAMD_DKIM_SIGN_KEY_FILE) { - - dkim_key = rspamd_lru_hash_lookup ( - dkim_module_ctx->dkim_sign_hash, - key, time (NULL)); - lru_key = key; + else if (strcmp (key_type, "base64") == 0) { + key_format = RSPAMD_DKIM_KEY_BASE64; } - else { - /* Prehash */ - memset (hex_hash, 0, sizeof (hex_hash)); - rspamd_cryptobox_hash (h, key, len, NULL, 0); - rspamd_encode_hex_buf (h, sizeof (h), - hex_hash, sizeof (hex_hash)); - dkim_key = rspamd_lru_hash_lookup ( - dkim_module_ctx->dkim_sign_hash, - hex_hash, time (NULL)); - lru_key = hex_hash; + else if (strcmp (key_type, "pem") == 0) { + key_format = RSPAMD_DKIM_KEY_PEM; } + else if (strcmp (key_type, "der") == 0 || + strcmp (key_type, "raw") == 0) { + key_format = RSPAMD_DKIM_KEY_RAW; + } + else { + lua_settop (L, 0); + luaL_error (L, "unknown key type: %s", + key_type); + rspamd_symcache_finalize_item (task, item); - if (dkim_key == NULL) { - dkim_key = rspamd_dkim_sign_key_load (key, len, - key_sign_type, &err); + return; + } + } - if (dkim_key == NULL) { - msg_err_task ("cannot load dkim key %s: %e", - lru_key, err); - g_error_free (err); + if (sign_type_str) { + if (strcmp (sign_type_str, "dkim") == 0) { + sign_type = RSPAMD_DKIM_NORMAL; + } + else if (strcmp (sign_type_str, "arc-sign") == 0) { + sign_type = RSPAMD_DKIM_ARC_SIG; + if (arc_idx == 0) { + lua_settop (L, 0); + luaL_error (L, "no arc idx specified"); rspamd_symcache_finalize_item (task, item); return; } - else { - rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, - g_strdup (lru_key), dkim_key, - time (NULL), 0); - } } - else if (rspamd_dkim_sign_key_maybe_invalidate (dkim_key, - key_sign_type, key, len)) { - /* - * Invalidate and reload DKIM key, - * removal from lru cache also cleanup the key and value - */ - - rspamd_lru_hash_remove (dkim_module_ctx->dkim_sign_hash, - lru_key); - dkim_key = rspamd_dkim_sign_key_load (key, len, - key_sign_type, &err); - - if (dkim_key == NULL) { - msg_err_task ("cannot load dkim key %s: %e", - lru_key, err); - g_error_free (err); + else if (strcmp (sign_type_str, "arc-seal") == 0) { + sign_type = RSPAMD_DKIM_ARC_SEAL; + if (arc_cv == NULL) { + lua_settop (L, 0); + luaL_error (L, "no arc cv specified"); rspamd_symcache_finalize_item (task, item); return; } - else { - rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, - g_strdup (lru_key), dkim_key, - time (NULL), 0); + if (arc_idx == 0) { + lua_settop (L, 0); + luaL_error (L, "no arc idx specified"); + rspamd_symcache_finalize_item (task, item); + + return; } } - - ctx = rspamd_create_dkim_sign_context (task, dkim_key, - DKIM_CANON_RELAXED, DKIM_CANON_RELAXED, - dkim_module_ctx->sign_headers, - sign_type, - &err); - - if (ctx == NULL) { - msg_err_task ("cannot create sign context: %e", - err); - g_error_free (err); + else { + lua_settop (L, 0); + luaL_error (L, "unknown sign type: %s", + sign_type_str); rspamd_symcache_finalize_item (task, item); return; } + } - hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, - arc_idx, arc_cv, - ctx); - - if (hdr) { - rspamd_mempool_set_variable (task->task_pool, - "dkim-signature", - hdr, rspamd_gstring_free_hard); - } + dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, + key, len, key_format); - sign = TRUE; + if (dkim_key == NULL) { + rspamd_symcache_finalize_item (task, item); + return; } - else { - sign = FALSE; + + ctx = rspamd_create_dkim_sign_context (task, dkim_key, + DKIM_CANON_RELAXED, DKIM_CANON_RELAXED, + dkim_module_ctx->sign_headers, + sign_type, + &err); + + if (ctx == NULL) { + msg_err_task ("cannot create sign context: %e", + err); + g_error_free (err); + rspamd_symcache_finalize_item (task, item); + + return; } - } - /* Result + error function */ - lua_settop (L, 0); + hdr = rspamd_dkim_sign (task, selector, domain, 0, 0, + arc_idx, arc_cv, + ctx); - if (!sign) { - msg_debug_task ("skip signing as dkim condition callback returned" - " false"); - rspamd_symcache_finalize_item (task, item); + if (hdr) { + rspamd_mempool_set_variable (task->task_pool, + "dkim-signature", + hdr, rspamd_gstring_free_hard); + } - return; + sign = TRUE; + } + else { + sign = FALSE; } } + /* Result + error function */ + lua_settop (L, 0); + + if (!sign) { + msg_debug_task ("skip signing as dkim condition callback returned" + " false"); + } rspamd_symcache_finalize_item (task, item); } |