summaryrefslogtreecommitdiffstats
path: root/lualib/lua_ffi/dkim.lua
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lualib/lua_ffi/dkim.lua144
1 files changed, 144 insertions, 0 deletions
diff --git a/lualib/lua_ffi/dkim.lua b/lualib/lua_ffi/dkim.lua
new file mode 100644
index 0000000..e4592c2
--- /dev/null
+++ b/lualib/lua_ffi/dkim.lua
@@ -0,0 +1,144 @@
+--[[
+Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+]]--
+
+--[[[
+-- @module lua_ffi/dkim
+-- This module contains ffi interfaces to DKIM
+--]]
+
+local ffi = require 'ffi'
+
+ffi.cdef [[
+struct rspamd_dkim_sign_context_s;
+struct rspamd_dkim_key_s;
+struct rspamd_task;
+enum rspamd_dkim_key_format {
+ RSPAMD_DKIM_KEY_FILE = 0,
+ RSPAMD_DKIM_KEY_PEM,
+ RSPAMD_DKIM_KEY_BASE64,
+ RSPAMD_DKIM_KEY_RAW,
+};
+enum rspamd_dkim_type {
+ RSPAMD_DKIM_NORMAL,
+ RSPAMD_DKIM_ARC_SIG,
+ RSPAMD_DKIM_ARC_SEAL
+};
+struct rspamd_dkim_sign_context_s*
+rspamd_create_dkim_sign_context (struct rspamd_task *task,
+ struct rspamd_dkim_key_s *priv_key,
+ int headers_canon,
+ int body_canon,
+ const char *dkim_headers,
+ enum rspamd_dkim_type type,
+ void *unused);
+struct rspamd_dkim_key_s* rspamd_dkim_sign_key_load (const char *what, size_t len,
+ enum rspamd_dkim_key_format,
+ void *err);
+void rspamd_dkim_key_unref (struct rspamd_dkim_key_s *k);
+struct GString *rspamd_dkim_sign (struct rspamd_task *task,
+ const char *selector,
+ const char *domain,
+ unsigned long expire,
+ size_t len,
+ unsigned int idx,
+ const char *arc_cv,
+ struct rspamd_dkim_sign_context_s *ctx);
+]]
+
+local function load_sign_key(what, format)
+ if not format then
+ format = ffi.C.RSPAMD_DKIM_KEY_PEM
+ else
+ if format == 'file' then
+ format = ffi.C.RSPAMD_DKIM_KEY_FILE
+ elseif format == 'base64' then
+ format = ffi.C.RSPAMD_DKIM_KEY_BASE64
+ elseif format == 'raw' then
+ format = ffi.C.RSPAMD_DKIM_KEY_RAW
+ else
+ return nil, 'unknown key format'
+ end
+ end
+
+ return ffi.C.rspamd_dkim_sign_key_load(what, #what, format, nil)
+end
+
+local default_dkim_headers = "(o)from:(o)sender:(o)reply-to:(o)subject:(o)date:(o)message-id:" ..
+ "(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:" ..
+ "resent-to:resent-cc:resent-from:resent-sender:resent-message-id:" ..
+ "(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:" ..
+ "list-subscribe:list-post:(o)openpgp:(o)autocrypt"
+
+local function create_sign_context(task, privkey, dkim_headers, sign_type)
+ if not task or not privkey then
+ return nil, 'invalid arguments'
+ end
+
+ if not dkim_headers then
+ dkim_headers = default_dkim_headers
+ end
+
+ if not sign_type then
+ sign_type = 'dkim'
+ end
+
+ if sign_type == 'dkim' then
+ sign_type = ffi.C.RSPAMD_DKIM_NORMAL
+ elseif sign_type == 'arc-sig' then
+ sign_type = ffi.C.RSPAMD_DKIM_ARC_SIG
+ elseif sign_type == 'arc-seal' then
+ sign_type = ffi.C.RSPAMD_DKIM_ARC_SEAL
+ else
+ return nil, 'invalid sign type'
+ end
+
+ return ffi.C.rspamd_create_dkim_sign_context(task:topointer(), privkey,
+ 1, 1, dkim_headers, sign_type, nil)
+end
+
+local function do_sign(task, sign_context, selector, domain,
+ expire, len, arc_idx)
+ if not task or not sign_context or not selector or not domain then
+ return nil, 'invalid arguments'
+ end
+
+ if not expire then
+ expire = 0
+ end
+ if not len then
+ len = 0
+ end
+ if not arc_idx then
+ arc_idx = 0
+ end
+
+ local gstring = ffi.C.rspamd_dkim_sign(task:topointer(), selector, domain, expire, len, arc_idx, nil, sign_context)
+
+ if not gstring then
+ return nil, 'cannot sign'
+ end
+
+ local ret = ffi.string(gstring.str, gstring.len)
+ ffi.C.g_string_free(gstring, true)
+
+ return ret
+end
+
+return {
+ load_sign_key = load_sign_key,
+ create_sign_context = create_sign_context,
+ do_sign = do_sign
+}