local lua_util = require "lua_util"
local dkim_sign_tools = require "lua_dkim_tools"
local rspamd_util = require "rspamd_util"
-local rspamd_rsa_privkey = require "rspamd_rsa_privkey"
-local rspamd_rsa = require "rspamd_rsa"
local fun = require "fun"
local lua_auth_results = require "lua_auth_results"
-local hash = require "rspamd_cryptobox_hash"
local lua_mime = require "lua_mime"
if confighelp then
rspamd_config:register_dependency('ARC_CHECK', 'DKIM_CHECK')
local function arc_sign_seal(task, params, header)
- local arc_sigs = task:cache_get('arc-sigs')
local arc_seals = task:cache_get('arc-seals')
- local arc_auth_results = task:cache_get('arc-authres')
local cur_auth_results
- local privkey
-
- if params.rawkey then
- -- Distinguish between pem and base64
- if string.match(params.rawkey, '^-----BEGIN') then
- privkey = rspamd_rsa_privkey.load_pem(params.rawkey)
- else
- privkey = rspamd_rsa_privkey.load_base64(params.rawkey)
- end
- elseif params.key then
- privkey = rspamd_rsa_privkey.load_file(params.key)
- end
-
- if not privkey then
- rspamd_logger.errx(task, 'cannot load private key for signing')
- return
- end
if settings.reuse_auth_results then
local ar_header = task:get_header('Authentication-Results')
cur_auth_results = lua_auth_results.gen_auth_results(task, ar_settings) or ''
end
- local sha_ctx = hash.create_specific('sha256')
-
- -- Update using previous seals + sigs + AAR
local cur_idx = 1
if arc_seals then
cur_idx = #arc_seals + 1
- -- We use the cached version per each ARC-* header field individually, already sorted by instance
- -- value in ascending order
- for i = 1, #arc_seals, 1 do
- if arc_auth_results[i] then
- local s = dkim_canonicalize('ARC-Authentication-Results',
- arc_auth_results[i].raw_header)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'update signature with header: %s', s)
- end
- if arc_sigs[i] then
- local s = dkim_canonicalize('ARC-Message-Signature',
- arc_sigs[i].raw_header)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'update signature with header: %s', s)
- end
- if arc_seals[i] then
- local s = dkim_canonicalize('ARC-Seal', arc_seals[i].raw_header)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'update signature with header: %s', s)
- end
- end
end
header = lua_util.fold_header_with_encoding(task,
cur_auth_results,
{ stop_chars = ';', structured = true, encode = false })
- local s = dkim_canonicalize('ARC-Authentication-Results',
- cur_auth_results)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'update signature with header: %s', s)
- s = dkim_canonicalize('ARC-Message-Signature', header)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'update signature with header: %s', s)
-
- local cur_arc_seal = string.format('i=%d; s=%s; d=%s; t=%d; a=rsa-sha256; cv=%s; b=',
- cur_idx,
- params.selector,
- params.domain,
- math.floor(rspamd_util.get_time()), params.arc_cv)
- s = string.format('%s:%s', 'arc-seal', cur_arc_seal)
- sha_ctx:update(s)
- lua_util.debugm(N, task, 'initial update signature with header: %s', s)
-
- local nl_type
- if task:has_flag("milter") then
- nl_type = "lf"
- else
- nl_type = task:get_newlines_type()
- end
-
- local sig = rspamd_rsa.sign_memory(privkey, sha_ctx:bin())
- cur_arc_seal = string.format('%s%s', cur_arc_seal,
- sig:base64(70, nl_type))
-
+ -- Temporarily add AAR and AMS headers so they can be signed by the seal
lua_mime.modify_headers(task, {
add = {
['ARC-Authentication-Results'] = { order = 1, value = cur_auth_results },
['ARC-Message-Signature'] = { order = 1, value = header },
+ },
+ })
+
+ -- Create ARC-Seal using the native C dkim_sign function
+ -- This supports both RSA and ed25519 keys automatically
+ local seal_params = {
+ domain = params.domain,
+ selector = params.selector,
+ key = params.key,
+ rawkey = params.rawkey,
+ sign_type = 'arc-seal',
+ arc_idx = cur_idx,
+ arc_cv = params.arc_cv,
+ headers = 'arc-authentication-results:arc-message-signature' ..
+ string.rep(':arc-seal', cur_idx - 1), -- Include previous seals
+ }
+
+ local dret, seal_header = dkim_sign(task, seal_params)
+ if not dret then
+ rspamd_logger.errx(task, 'cannot create ARC seal signature')
+ return
+ end
+
+ lua_mime.modify_headers(task, {
+ add = {
['ARC-Seal'] = {
order = 1,
value = lua_util.fold_header_with_encoding(task,
- 'ARC-Seal', cur_arc_seal,
+ 'ARC-Seal', seal_header,
{ structured = true, encode = false })
}
},
end
local function do_sign(task, sign_params)
- if sign_params.alg and sign_params.alg ~= 'rsa' then
- -- No support for ed25519 keys
- return
- end
-
if not prepare_arc_selector(task, sign_params) then
-- Broken arc
return