rspamd_dkim_sign_context_t *ctx;
rspamd_dkim_sign_key_t *dkim_key;
gsize rawlen = 0, keylen = 0;
- gboolean no_cache = FALSE;
+ gboolean no_cache = FALSE, strict_pubkey_check = FALSE;
luaL_argcheck (L, lua_type (L, 2) == LUA_TTABLE, 2, "'table' expected");
/*
*/
if (!rspamd_lua_parse_table_arguments (L, 2, &err,
"key=V;rawkey=V;*domain=S;*selector=S;no_cache=B;headers=S;"
- "sign_type=S;arc_idx=I;arc_cv=S;expire=I;pubkey=S",
+ "sign_type=S;arc_idx=I;arc_cv=S;expire=I;pubkey=S;"
+ "strict_pubkey_check=B",
&keylen, &key, &rawlen, &rawkey, &domain,
&selector, &no_cache, &headers,
- &sign_type_str, &arc_idx, &arc_cv, &expire, &pubkey)) {
+ &sign_type_str, &arc_idx, &arc_cv, &expire, &pubkey,
+ &strict_pubkey_check)) {
msg_err_task ("cannot parse table arguments: %e",
err);
g_error_free (err);
pk = rspamd_dkim_parse_key (pubkey, &keylen, NULL);
if (pk == NULL) {
- msg_warn_task ("cannot parse pubkey from string: %s",
- pubkey);
+ if (strict_pubkey_check) {
+ msg_err_task ("cannot parse pubkey from string: %s, skip signing",
+ pubkey);
+ lua_pushboolean (L, FALSE);
+
+ return 1;
+ }
+ else {
+ msg_warn_task ("cannot parse pubkey from string: %s",
+ pubkey);
+ }
}
else {
GError *te = NULL;
/* We have parsed the key, so try to check keys */
if (!rspamd_dkim_match_keys (pk, dkim_key, &te)) {
- msg_warn_task ("public key for %s/%s does not match private key: %e",
- domain, selector, te);
- g_error_free (te);
+ if (strict_pubkey_check) {
+ msg_err_task ("public key for %s/%s does not match private "
+ "key: %e, skip signing",
+ domain, selector, te);
+ g_error_free (te);
+ lua_pushboolean (L, FALSE);
+ rspamd_dkim_key_unref (pk);
- /* TODO: add fatal failure possibility */
+ return 1;
+ }
+ else {
+ msg_warn_task ("public key for %s/%s does not match private "
+ "key: %e",
+ domain, selector, te);
+ g_error_free (te);
+ }
}
+
+ rspamd_dkim_key_unref (pk);
}
}
allow_hdrfrom_mismatch_sign_networks = false,
allow_hdrfrom_multiple = false,
allow_username_mismatch = false,
+ allow_pubkey_mismatch = true,
auth_only = true,
+ check_pubkey = false,
domain = {},
path = string.format('%s/%s/%s', rspamd_paths['DBDIR'], 'dkim', '$domain.$selector.key'),
sign_local = true,
return
end
+ local function do_sign()
+ if settings.check_pubkey then
+ local resolve_name = p.selector .. "._domainkey." .. p.domain
+ task:get_resolver():resolve_txt({
+ task = task,
+ name = resolve_name,
+ callback = function(_, _, results, err)
+ task:inc_dns_req()
+ if not err and results and results[1] then
+ p.pubkey = results[1]
+ p.strict_pubkey_check = not settings.allow_pubkey_mismatch
+ elseif not settings.allow_pubkey_mismatch then
+ rspamd_logger.errx('public key for domain %s/%s is not found: %s, skip signing',
+ p.domain, p.selector, err)
+ return
+ else
+ rspamd_logger.infox('public key for domain %s/%s is not found: %s',
+ p.domain, p.selector, err)
+ end
+
+ local sret, _ = sign_func(task, p)
+ if sret then
+ task:insert_result(settings.symbol, 1.0)
+ end
+ end,
+ forced = true
+ })
+ else
+ local sret, _ = sign_func(task, p)
+ if sret then
+ task:insert_result(settings.symbol, 1.0)
+ end
+ end
+ end
+
if settings.use_redis then
local function try_redis_key(selector)
p.key = nil
elseif type(data) ~= 'string' then
rspamd_logger.debugm(N, task, "missing DKIM key for %s", rk)
else
- p.rawkey = data
- local sret, _ = sign_func(task, p)
- if sret then
- task:insert_result(settings.symbol, 1.0)
- end
+ p.rawkey = data
+ do_sign()
end
end
local rret = rspamd_redis_make_request(task,
return false
end
- local sret, _ = sign_func(task, p)
- return sret
+ do_sign()
else
rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing')
return false