diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2017-01-28 13:36:32 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2017-01-28 13:36:32 +0000 |
commit | 02b3c524724a65ae8b8291ee28c0eb4d4cf72516 (patch) | |
tree | ff45aeb42a48eb615fc8517d6d7ed62e891613c4 | |
parent | 605a33e6216729383d6c0adbba1215ac805dc134 (diff) | |
download | rspamd-02b3c524724a65ae8b8291ee28c0eb4d4cf72516.tar.gz rspamd-02b3c524724a65ae8b8291ee28c0eb4d4cf72516.zip |
[Feature] Allow to pass sign key directly from Lua
-rw-r--r-- | src/libserver/dkim.c | 53 | ||||
-rw-r--r-- | src/libserver/dkim.h | 9 | ||||
-rw-r--r-- | src/plugins/dkim_check.c | 66 |
3 files changed, 113 insertions, 15 deletions
diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index 7e2dbec89..4ef2ad122 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -2025,6 +2025,59 @@ rspamd_dkim_sign_key_load (const gchar *path, GError **err) return nkey; } +rspamd_dkim_sign_key_t* +rspamd_dkim_sign_key_from_memory (const guchar *data, + gsize len, GError **err) +{ + rspamd_dkim_sign_key_t *nkey; + gpointer map; + + map = mmap (NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + + if (map == MAP_FAILED) { + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot map in-memory private key %s", + strerror (errno)); + + return NULL; + } + + /* Initialize memory and set the appropriate access mode */ + memcpy (map, data, len); + (void)mprotect (map, len, PROT_READ); + (void)mlock (map, len); + + nkey = g_slice_alloc0 (sizeof (*nkey)); + nkey->keydata = map; + nkey->keylen = len; + nkey->key_bio = BIO_new_mem_buf (map, len); + + if (!PEM_read_bio_PrivateKey (nkey->key_bio, &nkey->key_evp, NULL, NULL)) { + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot read private key from memory: %s", + ERR_error_string (ERR_get_error (), NULL)); + rspamd_dkim_sign_key_free (nkey); + + return NULL; + } + + nkey->key_rsa = EVP_PKEY_get1_RSA (nkey->key_evp); + if (nkey->key_rsa == NULL) { + g_set_error (err, + DKIM_ERROR, + DKIM_SIGERROR_KEYFAIL, + "cannot extract rsa key from evp key"); + rspamd_dkim_sign_key_free (nkey); + + return NULL; + } + + REF_INIT_RETAIN (nkey, rspamd_dkim_sign_key_free); + + return nkey; +} + rspamd_dkim_sign_context_t * rspamd_create_dkim_sign_context (struct rspamd_task *task, rspamd_dkim_sign_key_t *priv_key, diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h index b2ff151ad..ac3f04233 100644 --- a/src/libserver/dkim.h +++ b/src/libserver/dkim.h @@ -142,6 +142,15 @@ rspamd_dkim_sign_context_t * rspamd_create_dkim_sign_context (struct rspamd_task rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_load (const gchar *path, GError **err); /** + * Load dkim key from memory chunk + * @param path + * @param err + * @return + */ +rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_from_memory (const guchar *data, + gsize len, GError **err); + +/** * Make DNS request for specified context and obtain and parse key * @param ctx dkim context from signature * @param resolver dns resolver object diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c index aa2da3bfe..1023ce70b 100644 --- a/src/plugins/dkim_check.c +++ b/src/plugins/dkim_check.c @@ -553,9 +553,10 @@ lua_dkim_sign_handler (lua_State *L) GError *err = NULL; GString *hdr; - const gchar *selector = NULL, *domain = NULL, *key = NULL; + const gchar *selector = NULL, *domain = NULL, *key = NULL, *rawkey = NULL; rspamd_dkim_sign_context_t *ctx; rspamd_dkim_sign_key_t *dkim_key; + gsize rawlen = 0; /* * Get the following elements: * - selector @@ -563,8 +564,8 @@ lua_dkim_sign_handler (lua_State *L) * - key */ if (!rspamd_lua_parse_table_arguments (L, 2, &err, - "*key=S;*domain=S;*selector=S", - &key, &domain, &selector)) { + "key=S;rawkey=V;*domain=S;*selector=S", + &key, &rawlen, rawkey, &domain, &selector)) { msg_err_task ("invalid return value from sign condition: %e", err); g_error_free (err); @@ -580,24 +581,59 @@ lua_dkim_sign_handler (lua_State *L) (GDestroyNotify)rspamd_dkim_sign_key_unref); } - dkim_key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash, - key, time (NULL)); + if (key) { + 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, &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 (rawkey) { + guchar h[rspamd_cryptobox_HASHBYTES], + hex_hash[rspamd_cryptobox_HASHBYTES * 2 + 1]; - if (dkim_key == NULL) { - dkim_key = rspamd_dkim_sign_key_load (key, &err); + memset (hex_hash, 0, sizeof (hex_hash)); + rspamd_cryptobox_hash (h, rawkey, rawlen, 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)); if (dkim_key == NULL) { - msg_err_task ("cannot load dkim key %s: %e", - key, err); - g_error_free (err); + dkim_key = rspamd_dkim_sign_key_from_memory (rawkey, rawlen, &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; + } - lua_pushboolean (L, FALSE); - return 1; + rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, + g_strdup (hex_hash), dkim_key, + time (NULL), 0); } + } + else { + msg_err_task ("neither key nor rawkey are specified", err); + lua_pushboolean (L, FALSE); - rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash, - g_strdup (key), dkim_key, - time (NULL), 0); + return 1; } ctx = rspamd_create_dkim_sign_context (task, dkim_key, |