You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dkim.lua 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. --[[
  2. Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ]]--
  13. --[[[
  14. -- @module lua_ffi/dkim
  15. -- This module contains ffi interfaces to DKIM
  16. --]]
  17. local ffi = require 'ffi'
  18. ffi.cdef[[
  19. struct rspamd_dkim_sign_context_s;
  20. struct rspamd_dkim_key_s;
  21. struct rspamd_task;
  22. enum rspamd_dkim_key_format {
  23. RSPAMD_DKIM_KEY_FILE = 0,
  24. RSPAMD_DKIM_KEY_PEM,
  25. RSPAMD_DKIM_KEY_BASE64,
  26. RSPAMD_DKIM_KEY_RAW,
  27. };
  28. enum rspamd_dkim_type {
  29. RSPAMD_DKIM_NORMAL,
  30. RSPAMD_DKIM_ARC_SIG,
  31. RSPAMD_DKIM_ARC_SEAL
  32. };
  33. struct rspamd_dkim_sign_context_s*
  34. rspamd_create_dkim_sign_context (struct rspamd_task *task,
  35. struct rspamd_dkim_key_s *priv_key,
  36. int headers_canon,
  37. int body_canon,
  38. const char *dkim_headers,
  39. enum rspamd_dkim_type type,
  40. void *unused);
  41. struct rspamd_dkim_key_s* rspamd_dkim_sign_key_load (const char *what, size_t len,
  42. enum rspamd_dkim_key_format,
  43. void *err);
  44. void rspamd_dkim_key_unref (struct rspamd_dkim_key_s *k);
  45. struct GString *rspamd_dkim_sign (struct rspamd_task *task,
  46. const char *selector,
  47. const char *domain,
  48. unsigned long expire,
  49. size_t len,
  50. unsigned int idx,
  51. const char *arc_cv,
  52. struct rspamd_dkim_sign_context_s *ctx);
  53. ]]
  54. local function load_sign_key(what, format)
  55. if not format then
  56. format = ffi.C.RSPAMD_DKIM_KEY_PEM
  57. else
  58. if format == 'file' then
  59. format = ffi.C.RSPAMD_DKIM_KEY_FILE
  60. elseif format == 'base64' then
  61. format = ffi.C.RSPAMD_DKIM_KEY_BASE64
  62. elseif format == 'raw' then
  63. format = ffi.C.RSPAMD_DKIM_KEY_RAW
  64. else
  65. return nil,'unknown key format'
  66. end
  67. end
  68. return ffi.C.rspamd_dkim_sign_key_load(what, #what, format, nil)
  69. end
  70. local default_dkim_headers =
  71. "(o)from:(o)sender:(o)reply-to:(o)subject:(o)date:(o)message-id:" ..
  72. "(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:" ..
  73. "resent-to:resent-cc:resent-from:resent-sender:resent-message-id:" ..
  74. "(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:" ..
  75. "list-subscribe:list-post:(o)openpgp:(o)autocrypt"
  76. local function create_sign_context(task, privkey, dkim_headers, sign_type)
  77. if not task or not privkey then
  78. return nil,'invalid arguments'
  79. end
  80. if not dkim_headers then
  81. dkim_headers = default_dkim_headers
  82. end
  83. if not sign_type then
  84. sign_type = 'dkim'
  85. end
  86. if sign_type == 'dkim' then
  87. sign_type = ffi.C.RSPAMD_DKIM_NORMAL
  88. elseif sign_type == 'arc-sig' then
  89. sign_type = ffi.C.RSPAMD_DKIM_ARC_SIG
  90. elseif sign_type == 'arc-seal' then
  91. sign_type = ffi.C.RSPAMD_DKIM_ARC_SEAL
  92. else
  93. return nil,'invalid sign type'
  94. end
  95. return ffi.C.rspamd_create_dkim_sign_context(task:topointer(), privkey,
  96. 1, 1, dkim_headers, sign_type, nil)
  97. end
  98. local function do_sign(task, sign_context, selector, domain,
  99. expire, len, arc_idx)
  100. if not task or not sign_context or not selector or not domain then
  101. return nil,'invalid arguments'
  102. end
  103. if not expire then expire = 0 end
  104. if not len then len = 0 end
  105. if not arc_idx then arc_idx = 0 end
  106. local gstring = ffi.C.rspamd_dkim_sign(task:topointer(), selector, domain, expire, len, arc_idx, nil, sign_context)
  107. if not gstring then
  108. return nil,'cannot sign'
  109. end
  110. local ret = ffi.string(gstring.str, gstring.len)
  111. ffi.C.g_string_free(gstring, true)
  112. return ret
  113. end
  114. return {
  115. load_sign_key = load_sign_key,
  116. create_sign_context = create_sign_context,
  117. do_sign = do_sign
  118. }