From: Vsevolod Stakhov Date: Mon, 11 Feb 2019 14:21:29 +0000 (+0000) Subject: [Minor] Move DKIM keys load to DKIM common code X-Git-Tag: 1.9.0~176 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ea07b601a62c68334e27a93c7b35e47e7fd16001;p=rspamd.git [Minor] Move DKIM keys load to DKIM common code --- diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index bbaa6b90f..2a66146ed 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -2604,29 +2604,83 @@ rspamd_dkim_get_dns_key (rspamd_dkim_context_t *ctx) return NULL; } +#define PEM_SIG "-----BEGIN" + rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_load (const gchar *key, gsize len, enum rspamd_dkim_key_format type, GError **err) { + guchar *map = NULL, *tmp = NULL; + gsize maplen; rspamd_dkim_sign_key_t *nkey; time_t mtime = time (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, - "invalid key type to load: %d", type); - return NULL; + if (type < 0 || type > RSPAMD_DKIM_KEY_UNKNOWN || len == 0 || key == NULL) { + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "invalid key type to load: %d", type); + return NULL; } nkey = g_malloc0 (sizeof (*nkey)); nkey->mtime = mtime; - msg_debug_dkim_taskless ("got public key with length %d and type %d", len, type); + msg_debug_dkim_taskless ("got public key with length %d and type %d", + len, type); + + /* Load key file if needed */ + if (type == RSPAMD_DKIM_KEY_FILE) { + struct stat st; + + if (stat (key, &st) != 0) { + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot stat key file: '%s' %s", key, strerror (errno)); + + return NULL; + } + + nkey->mtime = st.st_mtime; + map = rspamd_file_xmap (key, PROT_READ, &maplen, TRUE); + + if (map == NULL) { + g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL, + "cannot map key file: '%s' %s", key, strerror (errno)); + + return NULL; + } + + key = map; + len = maplen; + + if (maplen > sizeof (PEM_SIG) && + strncmp (map, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { + type = RSPAMD_DKIM_KEY_PEM; + } + else if (rspamd_cryptobox_base64_is_valid (map, maplen)) { + type = RSPAMD_DKIM_KEY_BASE64; + } + else { + type = RSPAMD_DKIM_KEY_RAW; + } + } + + if (type == RSPAMD_DKIM_KEY_UNKNOWN) { + if (len > sizeof (PEM_SIG) && + memcmp (key, PEM_SIG, sizeof (PEM_SIG) - 1) == 0) { + type = RSPAMD_DKIM_KEY_PEM; + } + else { + type = RSPAMD_DKIM_KEY_RAW; + } + } + + if (type == RSPAMD_DKIM_KEY_BASE64) { + type = RSPAMD_DKIM_KEY_RAW; + tmp = g_malloc (len); + rspamd_cryptobox_base64_decode (key, len, tmp, &len); + key = tmp; + } + if (type == RSPAMD_DKIM_KEY_RAW && len == 32) { unsigned char pk[32]; nkey->type = RSPAMD_DKIM_KEY_EDDSA; @@ -2645,8 +2699,9 @@ rspamd_dkim_sign_key_load (const gchar *key, gsize len, ERR_error_string (ERR_get_error (), NULL)); rspamd_dkim_sign_key_free (nkey); + nkey = NULL; - return NULL; + goto end; } } else { @@ -2655,8 +2710,9 @@ rspamd_dkim_sign_key_load (const gchar *key, gsize len, "cannot parse pem private key: %s", ERR_error_string (ERR_get_error (), NULL)); rspamd_dkim_sign_key_free (nkey); + nkey = NULL; - return NULL; + goto end; } } @@ -2667,17 +2723,31 @@ rspamd_dkim_sign_key_load (const gchar *key, gsize len, DKIM_SIGERROR_KEYFAIL, "cannot extract rsa key from evp key"); rspamd_dkim_sign_key_free (nkey); + nkey = NULL; - return NULL; + goto end; } nkey->type = RSPAMD_DKIM_KEY_RSA; } REF_INIT_RETAIN (nkey, rspamd_dkim_sign_key_free); +end: + + if (map != NULL) { + munmap (map, maplen); + } + + if (tmp != NULL) { + rspamd_explicit_memzero (tmp, len); + g_free (tmp); + } + return nkey; } +#undef PEM_SIG + gboolean rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key, time_t mtime) { diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c index 278a8e1e1..bb66e5ccc 100644 --- a/src/plugins/dkim_check.c +++ b/src/plugins/dkim_check.c @@ -641,58 +641,23 @@ 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 (struct rspamd_task *task, struct dkim_ctx *dkim_module_ctx, - const gchar *key, gsize keylen, enum rspamd_dkim_key_format key_format) +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; - 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); @@ -706,16 +671,19 @@ dkim_module_load_key_format (struct rspamd_task *task, struct dkim_ctx *dkim_mod */ if (key_format == RSPAMD_DKIM_KEY_UNKNOWN && (key[0] == '.' || key[0] == '/')) { - if (!is_valid_base64 (key, keylen)) + if (!rspamd_cryptobox_base64_is_valid (key, keylen)) { key_format = RSPAMD_DKIM_KEY_FILE; + } } 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"); /* @@ -729,43 +697,8 @@ dkim_module_load_key_format (struct rspamd_task *task, struct dkim_ctx *dkim_mod } /* found key; done */ - if (ret != NULL) + if (ret != NULL) { return ret; - - 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); @@ -779,16 +712,8 @@ dkim_module_load_key_format (struct rspamd_task *task, struct dkim_ctx *dkim_mod 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) @@ -844,10 +769,12 @@ lua_dkim_sign_handler (lua_State *L) if (key) { dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, key, keylen, RSPAMD_DKIM_KEY_UNKNOWN); - } else if(rawkey) { + } + else if(rawkey) { dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, rawkey, rawlen, RSPAMD_DKIM_KEY_UNKNOWN); - } else { + } + else { msg_err_task ("neither key nor rawkey are specified"); lua_pushboolean (L, FALSE);