@@ -2255,7 +2255,7 @@ rspamd_dkim_check_bh_cached (struct rspamd_dkim_common_ctx *ctx, | |||
* @param task task to check | |||
* @return | |||
*/ | |||
enum rspamd_dkim_check_result | |||
struct rspamd_dkim_check_result * | |||
rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
rspamd_dkim_key_t *key, | |||
struct rspamd_task *task) | |||
@@ -2265,21 +2265,31 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
struct rspamd_dkim_cached_hash *cached_bh = NULL; | |||
EVP_MD_CTX *cpy_ctx = NULL; | |||
gsize dlen = 0; | |||
enum rspamd_dkim_check_result res = DKIM_CONTINUE; | |||
struct rspamd_dkim_check_result *res; | |||
guint i; | |||
struct rspamd_dkim_header *dh; | |||
gint nid; | |||
g_return_val_if_fail (ctx != NULL, DKIM_ERROR); | |||
g_return_val_if_fail (key != NULL, DKIM_ERROR); | |||
g_return_val_if_fail (task->msg.len > 0, DKIM_ERROR); | |||
g_return_val_if_fail (ctx != NULL, NULL); | |||
g_return_val_if_fail (key != NULL, NULL); | |||
g_return_val_if_fail (task->msg.len > 0, NULL); | |||
/* First of all find place of body */ | |||
body_end = task->msg.begin + task->msg.len; | |||
body_start = task->raw_headers_content.body_start; | |||
res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); | |||
res->ctx = ctx; | |||
res->selector = ctx->selector; | |||
res->domain = ctx->domain; | |||
res->fail_reason = NULL; | |||
res->short_b = rspamd_encode_base64 (ctx->b, 4, 0, NULL); | |||
res->rcode = DKIM_CONTINUE; | |||
rspamd_mempool_add_destructor (task->task_pool, g_free, (gpointer)res->short_b); | |||
if (!body_start) { | |||
return DKIM_RECORD_ERROR; | |||
res->rcode = DKIM_ERROR; | |||
return res; | |||
} | |||
if (ctx->common.type != RSPAMD_DKIM_ARC_SEAL) { | |||
@@ -2291,7 +2301,8 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
/* Start canonization of body part */ | |||
if (!rspamd_dkim_canonize_body (&ctx->common, body_start, body_end, | |||
FALSE)) { | |||
return DKIM_RECORD_ERROR; | |||
res->rcode = DKIM_RECORD_ERROR; | |||
return res; | |||
} | |||
} | |||
} | |||
@@ -2380,8 +2391,11 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
#else | |||
EVP_MD_CTX_reset (cpy_ctx); | |||
#endif | |||
res->fail_reason = "body hash did not verify"; | |||
res->rcode = DKIM_REJECT; | |||
EVP_MD_CTX_destroy (cpy_ctx); | |||
return DKIM_REJECT; | |||
return res; | |||
} | |||
} | |||
} | |||
@@ -2398,11 +2412,18 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
dlen, ctx->bh, | |||
dlen, cached_bh->digest_cr); | |||
return DKIM_REJECT; | |||
res->fail_reason = "body hash did not verify"; | |||
res->rcode = DKIM_REJECT; | |||
return res; | |||
} | |||
} | |||
else { | |||
return DKIM_REJECT; | |||
res->fail_reason = "body hash did not verify"; | |||
res->rcode = DKIM_REJECT; | |||
return res; | |||
} | |||
} | |||
} | |||
@@ -2411,8 +2432,10 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
"bh value mismatch: %*xs versus %*xs", | |||
dlen, ctx->bh, | |||
dlen, cached_bh->digest_normal); | |||
res->fail_reason = "body hash did not verify"; | |||
res->rcode = DKIM_REJECT; | |||
return DKIM_REJECT; | |||
return res; | |||
} | |||
} | |||
@@ -2452,21 +2475,24 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
if (RSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen, | |||
key->key.key_rsa) != 1) { | |||
msg_debug_dkim ("rsa verify failed"); | |||
res = DKIM_REJECT; | |||
res->rcode = DKIM_REJECT; | |||
res->fail_reason = "rsa verify failed"; | |||
} | |||
break; | |||
case RSPAMD_DKIM_KEY_ECDSA: | |||
if (ECDSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen, | |||
key->key.key_ecdsa) != 1) { | |||
msg_debug_dkim ("ecdsa verify failed"); | |||
res = DKIM_REJECT; | |||
res->rcode = DKIM_REJECT; | |||
res->fail_reason = "ecdsa verify failed"; | |||
} | |||
break; | |||
case RSPAMD_DKIM_KEY_EDDSA: | |||
if (!rspamd_cryptobox_verify (ctx->b, ctx->blen, raw_digest, dlen, | |||
key->key.key_eddsa, RSPAMD_CRYPTOBOX_MODE_25519)) { | |||
msg_debug_dkim ("eddsa verify failed"); | |||
res = DKIM_REJECT; | |||
res->rcode = DKIM_REJECT; | |||
res->fail_reason = "eddsa verify failed"; | |||
} | |||
break; | |||
} | |||
@@ -2476,11 +2502,13 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
switch (ctx->cv) { | |||
case RSPAMD_ARC_INVALID: | |||
msg_info_dkim ("arc seal is invalid i=%d", ctx->common.idx); | |||
res = DKIM_PERM_ERROR; | |||
res->rcode = DKIM_PERM_ERROR; | |||
res->fail_reason = "arc seal is invalid"; | |||
break; | |||
case RSPAMD_ARC_FAIL: | |||
msg_info_dkim ("arc seal failed i=%d", ctx->common.idx); | |||
res = DKIM_REJECT; | |||
res->rcode = DKIM_REJECT; | |||
res->fail_reason = "arc seal failed"; | |||
break; | |||
default: | |||
break; | |||
@@ -2490,6 +2518,24 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
return res; | |||
} | |||
struct rspamd_dkim_check_result * | |||
rspamd_dkim_create_result (rspamd_dkim_context_t *ctx, | |||
enum rspamd_dkim_check_rcode rcode, | |||
struct rspamd_task *task) | |||
{ | |||
struct rspamd_dkim_check_result *res; | |||
res = rspamd_mempool_alloc0 (task->task_pool, sizeof (*res)); | |||
res->ctx = ctx; | |||
res->selector = ctx->selector; | |||
res->domain = ctx->domain; | |||
res->fail_reason = NULL; | |||
res->short_b = rspamd_encode_base64 (ctx->b, 4, 0, NULL); | |||
rspamd_mempool_add_destructor (task->task_pool, g_free, (gpointer)res->short_b); | |||
return res; | |||
} | |||
rspamd_dkim_key_t * | |||
rspamd_dkim_key_ref (rspamd_dkim_key_t *k) | |||
{ |
@@ -81,7 +81,7 @@ | |||
#define DKIM_SIGERROR_EMPTY_V 45 /* v= tag empty */ | |||
/* Check results */ | |||
enum rspamd_dkim_check_result { | |||
enum rspamd_dkim_check_rcode { | |||
DKIM_CONTINUE = 0, | |||
DKIM_REJECT, | |||
DKIM_TRYAGAIN, | |||
@@ -137,6 +137,16 @@ enum rspamd_dkim_key_type { | |||
RSPAMD_DKIM_KEY_EDDSA | |||
}; | |||
struct rspamd_dkim_check_result { | |||
enum rspamd_dkim_check_rcode rcode; | |||
rspamd_dkim_context_t *ctx; | |||
/* Processed parts */ | |||
const gchar *selector; | |||
const gchar *domain; | |||
const gchar *short_b; | |||
const gchar *fail_reason; | |||
}; | |||
/* Err MUST be freed if it is not NULL, key is allocated by slice allocator */ | |||
typedef void (*dkim_key_handler_f)(rspamd_dkim_key_t *key, gsize keylen, | |||
@@ -209,13 +219,23 @@ gboolean rspamd_get_dkim_key (rspamd_dkim_context_t *ctx, | |||
* @param task task to check | |||
* @return | |||
*/ | |||
enum rspamd_dkim_check_result rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
rspamd_dkim_key_t *key, | |||
struct rspamd_task *task); | |||
GString *rspamd_dkim_sign (struct rspamd_task *task, const gchar *selector, | |||
const gchar *domain, time_t expire, gsize len, guint idx, | |||
const gchar *arc_cv, rspamd_dkim_sign_context_t *ctx); | |||
struct rspamd_dkim_check_result * rspamd_dkim_check (rspamd_dkim_context_t *ctx, | |||
rspamd_dkim_key_t *key, | |||
struct rspamd_task *task); | |||
struct rspamd_dkim_check_result * | |||
rspamd_dkim_create_result (rspamd_dkim_context_t *ctx, | |||
enum rspamd_dkim_check_rcode rcode, | |||
struct rspamd_task *task); | |||
GString *rspamd_dkim_sign (struct rspamd_task *task, | |||
const gchar *selector, | |||
const gchar *domain, | |||
time_t expire, | |||
gsize len, | |||
guint idx, | |||
const gchar *arc_cv, | |||
rspamd_dkim_sign_context_t *ctx); | |||
rspamd_dkim_key_t * rspamd_dkim_key_ref (rspamd_dkim_key_t *k); | |||
void rspamd_dkim_key_unref (rspamd_dkim_key_t *k); |
@@ -32,6 +32,7 @@ | |||
#define RSPAMD_MEMPOOL_DKIM_SIGNATURE "dkim-signature" | |||
#define RSPAMD_MEMPOOL_DMARC_CHECKS "dmarc_checks" | |||
#define RSPAMD_MEMPOOL_DKIM_BH_CACHE "dkim_bh_cache" | |||
#define RSPAMD_MEMPOOL_DKIM_CHECK_RESULTS "dkim_results" | |||
#define RSPAMD_MEMPOOL_DKIM_SIGN_KEY "dkim_key" | |||
#define RSPAMD_MEMPOOL_DKIM_SIGN_SELECTOR "dkim_selector" | |||
#define RSPAMD_MEMPOOL_ARC_SIGN_KEY "arc_key" |
@@ -85,7 +85,7 @@ struct dkim_check_result { | |||
rspamd_dkim_context_t *ctx; | |||
rspamd_dkim_key_t *key; | |||
struct rspamd_task *task; | |||
gint res; | |||
struct rspamd_dkim_check_result *res; | |||
gdouble mult_allow; | |||
gdouble mult_deny; | |||
struct rspamd_symcache_item *item; | |||
@@ -822,7 +822,7 @@ lua_dkim_sign_handler (lua_State *L) | |||
if (pubkey != NULL) { | |||
/* Also check if private and public keys match */ | |||
rspamd_dkim_key_t *pk; | |||
gsize keylen = strlen (pubkey); | |||
keylen = strlen (pubkey); | |||
pk = rspamd_dkim_parse_key (pubkey, &keylen, NULL); | |||
@@ -956,7 +956,7 @@ dkim_module_check (struct dkim_check_result *res) | |||
continue; | |||
} | |||
if (cur->key != NULL && cur->res == -1) { | |||
if (cur->key != NULL && cur->res == NULL) { | |||
cur->res = rspamd_dkim_check (cur->ctx, cur->key, cur->task); | |||
if (dkim_module_ctx->dkim_domains != NULL) { | |||
@@ -978,7 +978,7 @@ dkim_module_check (struct dkim_check_result *res) | |||
if (cur->ctx == NULL) { | |||
continue; | |||
} | |||
if (cur->res == -1) { | |||
if (cur->res == NULL) { | |||
/* Still need a key */ | |||
all_done = FALSE; | |||
} | |||
@@ -989,24 +989,25 @@ dkim_module_check (struct dkim_check_result *res) | |||
const gchar *symbol = NULL, *trace = NULL; | |||
gdouble symbol_weight = 1.0; | |||
if (cur->ctx == NULL) { | |||
if (cur->ctx == NULL || cur->res == NULL) { | |||
continue; | |||
} | |||
if (cur->res == DKIM_REJECT) { | |||
if (cur->res->rcode == DKIM_REJECT) { | |||
symbol = dkim_module_ctx->symbol_reject; | |||
trace = "-"; | |||
symbol_weight = cur->mult_deny * 1.0; | |||
} | |||
else if (cur->res == DKIM_CONTINUE) { | |||
else if (cur->res->rcode == DKIM_CONTINUE) { | |||
symbol = dkim_module_ctx->symbol_allow; | |||
trace = "+"; | |||
symbol_weight = cur->mult_allow * 1.0; | |||
} | |||
else if (cur->res == DKIM_PERM_ERROR) { | |||
else if (cur->res->rcode == DKIM_PERM_ERROR) { | |||
trace = "~"; | |||
symbol = dkim_module_ctx->symbol_permfail; | |||
} | |||
else if (cur->res == DKIM_TRYAGAIN) { | |||
else if (cur->res->rcode == DKIM_TRYAGAIN) { | |||
trace = "?"; | |||
symbol = dkim_module_ctx->symbol_tempfail; | |||
} | |||
@@ -1072,10 +1073,12 @@ dkim_module_key_handler (rspamd_dkim_key_t *key, | |||
if (err != NULL) { | |||
if (err->code == DKIM_SIGERROR_NOKEY) { | |||
res->res = DKIM_TRYAGAIN; | |||
res->res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task); | |||
res->res->fail_reason = "DNS error when getting key"; | |||
} | |||
else { | |||
res->res = DKIM_PERM_ERROR; | |||
res->res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task); | |||
res->res->fail_reason = "invalid DKIM record"; | |||
} | |||
} | |||
} | |||
@@ -1153,7 +1156,7 @@ dkim_symbol_callback (struct rspamd_task *task, | |||
cur = rspamd_mempool_alloc0 (task->task_pool, sizeof (*cur)); | |||
cur->first = res; | |||
cur->res = -1; | |||
cur->res = NULL; | |||
cur->task = task; | |||
cur->mult_allow = 1.0; | |||
cur->mult_deny = 1.0; | |||
@@ -1492,7 +1495,7 @@ struct rspamd_dkim_lua_verify_cbdata { | |||
static void | |||
dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd, | |||
gint code, GError *err) | |||
struct rspamd_dkim_check_result *res, GError *err) | |||
{ | |||
struct rspamd_task **ptask, *task; | |||
const gchar *error_str = "unknown error"; | |||
@@ -1500,7 +1503,7 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd, | |||
task = cbd->task; | |||
switch (code) { | |||
switch (res->rcode) { | |||
case DKIM_CONTINUE: | |||
error_str = NULL; | |||
success = TRUE; | |||
@@ -1556,13 +1559,19 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd, | |||
lua_pushstring (cbd->L, error_str); | |||
if (cbd->ctx) { | |||
lua_pushstring (cbd->L, rspamd_dkim_get_domain (cbd->ctx)); | |||
lua_pushstring (cbd->L, res->domain); | |||
lua_pushstring (cbd->L, res->selector); | |||
lua_pushstring (cbd->L, res->short_b); | |||
lua_pushstring (cbd->L, res->fail_reason); | |||
} | |||
else { | |||
lua_pushnil (cbd->L); | |||
lua_pushnil (cbd->L); | |||
lua_pushnil (cbd->L); | |||
lua_pushnil (cbd->L); | |||
} | |||
if (lua_pcall (cbd->L, 4, 0, 0) != 0) { | |||
if (lua_pcall (cbd->L, 7, 0, 0) != 0) { | |||
msg_err_task ("call to verify callback failed: %s", | |||
lua_tostring (cbd->L, -1)); | |||
lua_pop (cbd->L, 1); | |||
@@ -1573,14 +1582,14 @@ dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd, | |||
static void | |||
dkim_module_lua_on_key (rspamd_dkim_key_t *key, | |||
gsize keylen, | |||
rspamd_dkim_context_t *ctx, | |||
gpointer ud, | |||
GError *err) | |||
gsize keylen, | |||
rspamd_dkim_context_t *ctx, | |||
gpointer ud, | |||
GError *err) | |||
{ | |||
struct rspamd_dkim_lua_verify_cbdata *cbd = ud; | |||
struct rspamd_task *task; | |||
gint ret; | |||
struct rspamd_dkim_check_result *res; | |||
struct dkim_ctx *dkim_module_ctx; | |||
task = cbd->task; | |||
@@ -1607,16 +1616,22 @@ dkim_module_lua_on_key (rspamd_dkim_key_t *key, | |||
if (err != NULL) { | |||
if (err->code == DKIM_SIGERROR_NOKEY) { | |||
dkim_module_lua_push_verify_result (cbd, DKIM_TRYAGAIN, err); | |||
res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task); | |||
res->fail_reason = "DNS error when getting key"; | |||
} | |||
else { | |||
dkim_module_lua_push_verify_result (cbd, DKIM_PERM_ERROR, err); | |||
res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task); | |||
res->fail_reason = "invalid DKIM record"; | |||
} | |||
} | |||
else { | |||
dkim_module_lua_push_verify_result (cbd, DKIM_TRYAGAIN, NULL); | |||
res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task); | |||
res->fail_reason = "DNS error when getting key"; | |||
} | |||
dkim_module_lua_push_verify_result (cbd, res, err); | |||
if (err) { | |||
g_error_free (err); | |||
} | |||
@@ -1624,8 +1639,8 @@ dkim_module_lua_on_key (rspamd_dkim_key_t *key, | |||
return; | |||
} | |||
ret = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task); | |||
dkim_module_lua_push_verify_result (cbd, ret, NULL); | |||
res = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task); | |||
dkim_module_lua_push_verify_result (cbd, res, NULL); | |||
} | |||
static gint | |||
@@ -1636,7 +1651,7 @@ lua_dkim_verify_handler (lua_State *L) | |||
rspamd_dkim_context_t *ctx; | |||
struct rspamd_dkim_lua_verify_cbdata *cbd; | |||
rspamd_dkim_key_t *key; | |||
gint ret; | |||
struct rspamd_dkim_check_result *ret; | |||
GError *err = NULL; | |||
const gchar *type_str = NULL; | |||
enum rspamd_dkim_type type = RSPAMD_DKIM_NORMAL; |