aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rspamd.com>2024-09-24 22:09:51 +0600
committerGitHub <noreply@github.com>2024-09-24 22:09:51 +0600
commitf8700e56ec5659f331f0aca0b28eec43a4e7cb33 (patch)
tree999c6c7bd2ea52fc5352ed03275f4cef0cfa80c7
parent3dda59641af8826d50dd07bc82d67c9ffecef403 (diff)
parent464045f814b78b2d4f9ca20cc9e0a0a1b323ad8e (diff)
downloadrspamd-f8700e56ec5659f331f0aca0b28eec43a4e7cb33.tar.gz
rspamd-f8700e56ec5659f331f0aca0b28eec43a4e7cb33.zip
Merge branch 'master' into vstakhov-utf8-mimevstakhov-utf8-mime
-rw-r--r--.github/workflows/ci.yml18
-rw-r--r--.github/workflows/ci_rspamd_build.yml53
-rw-r--r--CMakeLists.txt11
-rw-r--r--config.h.in1
-rw-r--r--lualib/lua_util.lua11
-rw-r--r--lualib/rspamadm/secretbox.lua157
-rw-r--r--src/fuzzy_storage.c9
-rw-r--r--src/libcryptobox/cryptobox.c55
-rw-r--r--src/libcryptobox/keypair.c151
-rw-r--r--src/libcryptobox/keypair.h51
-rw-r--r--src/libserver/http/http_connection.c6
-rw-r--r--src/libserver/maps/map.c6
-rw-r--r--src/lua/lua_cryptobox.c49
-rw-r--r--src/lua/lua_map.c4
-rw-r--r--src/lua/lua_rsa.c20
-rw-r--r--src/plugins/lua/dmarc.lua12
-rw-r--r--src/rspamadm/signtool.c3
-rw-r--r--test/functional/cases/150_rspamadm.robot47
-rw-r--r--test/lua/unit/lua_util.maybe_encrypt_decrypt_header.lua11
-rw-r--r--utils/encrypt_decrypt_header.py97
20 files changed, 649 insertions, 123 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d92d5105e..07c4cc4d0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,3 +23,21 @@ jobs:
with:
image: ghcr.io/rspamd/rspamd-build-docker:ubuntu-ci
name: ubuntu-ci
+
+ ubuntu-focal:
+ uses: ./.github/workflows/ci_rspamd_build.yml
+ with:
+ image: ghcr.io/rspamd/rspamd-build-docker:ubuntu-focal
+ name: ubuntu-focal
+
+ centos-8:
+ uses: ./.github/workflows/ci_rspamd_build.yml
+ with:
+ image: ghcr.io/rspamd/rspamd-build-docker:centos-8
+ name: centos-8
+
+ centos-9:
+ uses: ./.github/workflows/ci_rspamd_build.yml
+ with:
+ image: ghcr.io/rspamd/rspamd-build-docker:centos-9
+ name: centos-9
diff --git a/.github/workflows/ci_rspamd_build.yml b/.github/workflows/ci_rspamd_build.yml
new file mode 100644
index 000000000..9503f1974
--- /dev/null
+++ b/.github/workflows/ci_rspamd_build.yml
@@ -0,0 +1,53 @@
+name: rspamd_build
+
+on:
+ workflow_call:
+ inputs:
+ image:
+ required: true
+ type: string
+ name:
+ required: true
+ type: string
+
+jobs:
+ test:
+ runs-on: [ "ubuntu-latest" ]
+ container:
+ image: ${{ inputs.image }}
+ options: --user root
+ steps:
+ - name: Create directories
+ run: |
+ sudo mkdir -p ${GITHUB_WORKSPACE}
+
+ - name: Check out source code
+ uses: actions/checkout@v4
+ with:
+ path: src
+
+ - name: Set variables on ARM64
+ if: runner.arch == 'ARM64'
+ run: echo "HYPERSCAN_ALTROOT=-DHYPERSCAN_ROOT_DIR=/vectorscan" >> "$GITHUB_ENV"
+
+ - name: Run cmake
+ run: |
+ mkdir ${GITHUB_WORKSPACE}/build
+ cd ${GITHUB_WORKSPACE}/build
+ if [[ -f /opt/rh/gcc-toolset-10/enable ]] ; then source /opt/rh/gcc-toolset-10/enable ; fi
+ cmake -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/install -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DENABLE_COVERAGE=ON -DENABLE_LIBUNWIND=ON -DENABLE_LUAJIT=ON -DLUA_ROOT=/luajit-build -DENABLE_HYPERSCAN=ON ${{ env.HYPERSCAN_ALTROOT }} ${GITHUB_WORKSPACE}/src
+
+ - name: Build rspamd
+ run: |
+ if [[ -f /opt/rh/gcc-toolset-10/enable ]] ; then source /opt/rh/gcc-toolset-10/enable ; fi
+ cd ${GITHUB_WORKSPACE}/build
+ ncpu=$(getconf _NPROCESSORS_ONLN)
+ make -j $ncpu install
+ make -j $ncpu rspamd-test
+ make -j $ncpu rspamd-test-cxx
+
+ - name: Run unit tests
+ if: "!(inputs.name == 'ubuntu-ci' && runner.arch == 'ARM64')"
+ run: |
+ cd ${GITHUB_WORKSPACE}/build
+ make test
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9bb50642..8028e170e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,8 +8,8 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12 FATAL_ERROR)
SET(RSPAMD_VERSION_MAJOR 3)
-SET(RSPAMD_VERSION_MINOR 9)
-SET(RSPAMD_VERSION_PATCH 2)
+SET(RSPAMD_VERSION_MINOR 10)
+SET(RSPAMD_VERSION_PATCH 0)
# Keep two digits all the time
SET(RSPAMD_VERSION_MAJOR_NUM ${RSPAMD_VERSION_MAJOR}0)
@@ -472,6 +472,13 @@ int main(int argc, char **argv) {
}
" HAVE_ATOMIC_BUILTINS)
+CHECK_C_SOURCE_RUNS("#include <stdio.h>
+int main() {
+ __builtin_cpu_init();
+ printf(\"%d\", __builtin_cpu_supports(\"avx\"));
+ return 0;
+}" HAVE_BUILTIN_CPU_SUPPORTS)
+
IF (NOT HAVE_ATOMIC_BUILTINS)
MESSAGE(STATUS "atomic builtins are -NOT- supported")
ELSE ()
diff --git a/config.h.in b/config.h.in
index 59c70c67c..9aff90783 100644
--- a/config.h.in
+++ b/config.h.in
@@ -115,6 +115,7 @@
#cmakedefine WITH_LUA_REPL 1
#cmakedefine WITH_FASTTEXT 1
#cmakedefine BACKWARD_ENABLE 1
+#cmakedefine HAVE_BUILTIN_CPU_SUPPORTS 1
#cmakedefine DISABLE_PTHREAD_MUTEX 1
diff --git a/lualib/lua_util.lua b/lualib/lua_util.lua
index ffc07842e..62b38c87e 100644
--- a/lualib/lua_util.lua
+++ b/lualib/lua_util.lua
@@ -1305,12 +1305,12 @@ exports.maybe_encrypt_header = function(header, settings, prefix)
local rspamd_secretbox = require "rspamd_cryptobox_secretbox"
if not header or header == '' then
- logger.errx(rspamd_config, "Header: %s is empty or nil", header)
+ logger.errx(rspamd_config, "Header is empty or nil. Header: %s", header)
return nil
elseif settings[prefix .. '_encrypt'] then
local key = settings[prefix .. '_key']
if not key or key == '' then
- logger.errx(rspamd_config, "Key: %s is empty or nil", key)
+ logger.errx(rspamd_config, "Key is empty or nil. Key: %s", key)
return header
end
local cryptobox = rspamd_secretbox.create(key)
@@ -1322,7 +1322,8 @@ exports.maybe_encrypt_header = function(header, settings, prefix)
else
encrypted_header = cryptobox:encrypt(header, nonce)
end
- return encrypted_header, nonce
+ encrypted_header = nonce .. encrypted_header
+ return encrypted_header
end
end
@@ -1342,12 +1343,12 @@ exports.maybe_decrypt_header = function(encrypted_header, settings, prefix, nonc
local rspamd_secretbox = require "rspamd_cryptobox_secretbox"
if not encrypted_header or encrypted_header == '' then
- logger.errx(rspamd_config, "Encoded header: %s is empty or nil")
+ logger.errx(rspamd_config, "Encrypted header is empty or nil. Encrypted header: %s", encrypted_header)
return nil
elseif settings[prefix .. '_encrypt'] then
local key = settings[prefix .. '_key']
if not key or key == '' then
- logger.errx(rspamd_config, "Key: %s is empty or nil")
+ logger.errx(rspamd_config, "Key is empty or nil. Key: %s", key)
return encrypted_header
end
local cryptobox = rspamd_secretbox.create(key)
diff --git a/lualib/rspamadm/secretbox.lua b/lualib/rspamadm/secretbox.lua
new file mode 100644
index 000000000..3ab10cee0
--- /dev/null
+++ b/lualib/rspamadm/secretbox.lua
@@ -0,0 +1,157 @@
+local util = require 'lua_util'
+local rspamd_util = require 'rspamd_util'
+local argparse = require 'argparse'
+
+local parser = argparse()
+ :name "secretbox"
+ :description "Encrypt/decrypt given text with given key and nonce"
+ :help_description_margin(32)
+ :command_target('command')
+ :require_command(true)
+
+parser:mutex(
+ parser:flag '-R --raw'
+ :description('Encrypted text(and nonce if it is there) will be given in raw'),
+ parser:flag '-H --hex'
+ :description('Encrypted text(and nonce if it is there) will be given in hex'),
+ parser:flag '-b --base32'
+ :description('Encrypted text(and nonce if it is there) will be given in base32'),
+ parser:flag '-B --base64'
+ :description('Encrypted text(and nonce if it is there) will be given in base64')
+)
+
+local decrypt = parser:command 'decrypt'
+ :description 'Decrypt text with given key and nonce'
+
+decrypt:option "-t --text"
+ :description("Encrypted text(Base 64)")
+ :argname("<text>")
+decrypt:option "-k --key"
+ :description("Key used to encrypt text")
+ :argname("<key>")
+decrypt:option "-n --nonce"
+ :description("Nonce used to encrypt text(Base 64)")
+ :argname("<nonce>")
+ :default(nil)
+
+local encrypt = parser:command 'encrypt'
+ :description 'Encrypt text with given key'
+
+encrypt:option "-t --text"
+ :description("Text to encrypt")
+ :argname("<text>")
+encrypt:option "-k --key"
+ :description("Key to encrypt text")
+ :argname("<key>")
+encrypt:option "-n --nonce"
+ :description("Nonce to encrypt text(Base 64)")
+ :argname("<nonce>")
+ :default(nil)
+
+local function set_up_encoding(args, type, text)
+ local function fromhex(str)
+ return (str:gsub('..', function (cc)
+ return string.char(tonumber(cc, 16))
+ end))
+ end
+
+ local function tohex(str)
+ return (str:gsub('.', function (c)
+ return string.format('%02X', string.byte(c))
+ end))
+ end
+
+ local output = text
+
+ if type == 'encode' then
+ if args.hex then
+ output = tohex(text)
+ elseif args.base32 then
+ output = rspamd_util.encode_base32(text)
+ elseif args.base64 then
+ output = rspamd_util.encode_base64(text)
+ end
+ elseif type == 'decode' then
+ if args.hex then
+ output = fromhex(text)
+ elseif args.base32 then
+ output = rspamd_util.decode_base32(text)
+ elseif args.base64 then
+ output = rspamd_util.decode_base64(text)
+ end
+ end
+
+ return output
+end
+
+local function decryption_handler(args)
+ local settings = {
+ prefix = 'dec',
+ dec_encrypt = true,
+ dec_key = args.key
+ }
+
+ local decrypted_header = ''
+ if(args.nonce ~= nil) then
+ local decoded_text = set_up_encoding(args, 'decode', tostring(args.text))
+ local decoded_nonce = set_up_encoding(args, 'decode', tostring(args.nonce))
+
+ decrypted_header = util.maybe_decrypt_header(decoded_text, settings, settings.prefix, decoded_nonce)
+ else
+ local text_with_nonce = set_up_encoding(args, 'decode', tostring(args.text))
+ local nonce = string.sub(tostring(text_with_nonce), 1, 24)
+ local text = string.sub(tostring(text_with_nonce), 25)
+
+ decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix, nonce)
+ end
+
+ if decrypted_header ~= nil then
+ print(decrypted_header)
+ else
+ print('The decryption failed. Please check the correctness of the arguments given.')
+ end
+end
+
+local function encryption_handler(args)
+ local settings = {
+ prefix = 'dec',
+ dec_encrypt = true,
+ dec_key = args.key,
+ }
+
+ if args.nonce ~= nil then
+ settings.dec_nonce = set_up_encoding(args, 'decode', tostring(args.nonce))
+ end
+
+ local encrypted_text = util.maybe_encrypt_header(args.text, settings, settings.prefix)
+
+ if encrypted_text ~= nil then
+ print(set_up_encoding(args, 'encode', tostring(encrypted_text)))
+ else
+ print('The encryption failed. Please check the correctness of the arguments given.')
+ end
+end
+
+local command_handlers = {
+ decrypt = decryption_handler,
+ encrypt = encryption_handler,
+}
+
+local function handler(args)
+ local cmd_opts = parser:parse(args)
+
+ local f = command_handlers[cmd_opts.command]
+ if not f then
+ parser:error(string.format("command isn't implemented: %s",
+ cmd_opts.command))
+ end
+ f(cmd_opts)
+end
+
+
+return {
+ name = 'secret_box',
+ aliases = { 'secretbox', 'secret_box' },
+ handler = handler,
+ description = parser._description
+} \ No newline at end of file
diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c
index 841d040b2..f21992a94 100644
--- a/src/fuzzy_storage.c
+++ b/src/fuzzy_storage.c
@@ -2453,7 +2453,8 @@ rspamd_fuzzy_key_stat_iter(const unsigned char *pk_iter, struct fuzzy_key *fuzzy
ucl_object_insert_key(elt, flags_ucl, "flags", 0, false);
ucl_object_insert_key(elt,
- rspamd_keypair_to_ucl(fuzzy_key->key, RSPAMD_KEYPAIR_DUMP_NO_SECRET | RSPAMD_KEYPAIR_DUMP_FLATTENED),
+ rspamd_keypair_to_ucl(fuzzy_key->key, RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_DUMP_NO_SECRET | RSPAMD_KEYPAIR_DUMP_FLATTENED),
"keypair", 0, false);
ucl_object_insert_key(keys_obj, elt, keyname, 0, true);
}
@@ -2474,6 +2475,12 @@ rspamd_fuzzy_stat_to_ucl(struct rspamd_fuzzy_storage_ctx *ctx, gboolean ip_stat)
rspamd_fuzzy_key_stat_iter(pk_iter, fuzzy_key, keys_obj, ip_stat);
});
+ if (ctx->dynamic_keys) {
+ kh_foreach(ctx->dynamic_keys, pk_iter, fuzzy_key, {
+ rspamd_fuzzy_key_stat_iter(pk_iter, fuzzy_key, keys_obj, ip_stat);
+ });
+ }
+
ucl_object_insert_key(obj, keys_obj, "keys", 0, false);
/* Now generic stats */
diff --git a/src/libcryptobox/cryptobox.c b/src/libcryptobox/cryptobox.c
index eeeed020c..a976653df 100644
--- a/src/libcryptobox/cryptobox.c
+++ b/src/libcryptobox/cryptobox.c
@@ -86,6 +86,60 @@ rspamd_cryptobox_cpuid(int cpu[4], int info)
#endif
}
+#ifdef HAVE_BUILTIN_CPU_SUPPORTS
+RSPAMD_CONSTRUCTOR(cryptobox_cpu_init)
+{
+ __builtin_cpu_init();
+}
+static gboolean
+rspamd_cryptobox_test_instr(int instr)
+{
+ gboolean ret = FALSE;
+ switch (instr) {
+#if defined HAVE_SSE2 && defined(__x86_64__)
+ case CPUID_SSE2:
+ ret = __builtin_cpu_supports("sse2");
+ break;
+ case CPUID_RDRAND:
+ /* XXX: no check to test for rdrand, but all avx2 cpus are def. capable of rdrand */
+ ret = __builtin_cpu_supports("avx2");
+ break;
+#endif
+#ifdef HAVE_SSE3
+ case CPUID_SSE3:
+ ret = __builtin_cpu_supports("sse3");
+ break;
+#endif
+#ifdef HAVE_SSSE3
+ case CPUID_SSSE3:
+ ret = __builtin_cpu_supports("ssse3");
+ break;
+#endif
+#ifdef HAVE_SSE41
+ case CPUID_SSE41:
+ ret = __builtin_cpu_supports("sse4.1");
+ break;
+#endif
+#if defined HAVE_SSE42 && defined(__x86_64__)
+ case CPUID_SSE42:
+ ret = __builtin_cpu_supports("sse4.2");
+ break;
+#endif
+#ifdef HAVE_AVX
+ case CPUID_AVX:
+ ret = __builtin_cpu_supports("avx");
+ break;
+#endif
+#ifdef HAVE_AVX2
+ case CPUID_AVX2:
+ ret = __builtin_cpu_supports("avx2");
+ break;
+#endif
+ }
+
+ return ret;
+}
+#else
static sig_atomic_t ok = 0;
static jmp_buf j;
@@ -171,6 +225,7 @@ rspamd_cryptobox_test_instr(int instr)
/* We actually never return here if SIGILL has been caught */
return ok == 1;
}
+#endif /* HAVE_BUILTIN_CPU_SUPPORTS */
struct rspamd_cryptobox_library_ctx *
rspamd_cryptobox_init(void)
diff --git a/src/libcryptobox/keypair.c b/src/libcryptobox/keypair.c
index d3f81ee2d..3556e188f 100644
--- a/src/libcryptobox/keypair.c
+++ b/src/libcryptobox/keypair.c
@@ -34,7 +34,7 @@ rspamd_keypair_quark(void)
*/
static void *
rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp,
- unsigned int *len)
+ size_t *len)
{
g_assert(kp != NULL);
@@ -50,7 +50,7 @@ rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp,
static void *
rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp,
- unsigned int *len)
+ size_t *len)
{
g_assert(kp != NULL);
@@ -66,7 +66,7 @@ rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp,
static void *
rspamd_cryptobox_pubkey_pk(const struct rspamd_cryptobox_pubkey *kp,
- unsigned int *len)
+ size_t *len)
{
g_assert(kp != NULL);
@@ -139,7 +139,7 @@ void rspamd_cryptobox_nm_dtor(struct rspamd_cryptobox_nm *nm)
void rspamd_cryptobox_keypair_dtor(struct rspamd_cryptobox_keypair *kp)
{
void *sk;
- unsigned int len = 0;
+ size_t len = 0;
sk = rspamd_cryptobox_keypair_sk(kp, &len);
g_assert(sk != NULL && len > 0);
@@ -168,7 +168,7 @@ rspamd_keypair_new(enum rspamd_cryptobox_keypair_type type)
{
struct rspamd_cryptobox_keypair *kp;
void *pk, *sk;
- unsigned int size;
+ size_t size;
kp = rspamd_cryptobox_keypair_alloc(type);
kp->type = type;
@@ -241,7 +241,7 @@ rspamd_pubkey_from_base32(const char *b32,
{
unsigned char *decoded;
gsize dlen, expected_len;
- unsigned int pklen;
+ size_t pklen;
struct rspamd_cryptobox_pubkey *pk;
unsigned char *pk_data;
@@ -283,7 +283,7 @@ rspamd_pubkey_from_hex(const char *hex,
{
unsigned char *decoded;
gsize dlen, expected_len;
- unsigned int pklen;
+ size_t pklen;
struct rspamd_cryptobox_pubkey *pk;
unsigned char *pk_data;
@@ -325,7 +325,7 @@ rspamd_pubkey_from_bin(const unsigned char *raw,
gsize len,
enum rspamd_cryptobox_keypair_type type)
{
- unsigned int pklen;
+ size_t pklen;
struct rspamd_cryptobox_pubkey *pk;
unsigned char *pk_data;
@@ -421,7 +421,7 @@ rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk,
unsigned int *len)
{
unsigned char *ret = NULL;
- unsigned int rlen;
+ size_t rlen;
ret = rspamd_cryptobox_pubkey_pk(pk, &rlen);
@@ -434,7 +434,8 @@ rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk,
static void
rspamd_keypair_print_component(unsigned char *data, gsize datalen,
- GString *res, unsigned int how, const char *description)
+ GString *res, unsigned int how, const char *description,
+ enum rspamd_cryptobox_keypair_encoding encoding)
{
int olen, b32_len;
@@ -442,7 +443,7 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen,
rspamd_printf_gstring(res, "%s: ", description);
}
- if (how & RSPAMD_KEYPAIR_BASE32) {
+ if (encoding == RSPAMD_KEYPAIR_ENCODING_ZBASE32) {
b32_len = (datalen * 8 / 5) + 2;
g_string_set_size(res, res->len + b32_len);
res->len -= b32_len;
@@ -454,9 +455,12 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen,
res->str[res->len] = '\0';
}
}
- else if (how & RSPAMD_KEYPAIR_HEX) {
+ else if (encoding == RSPAMD_KEYPAIR_ENCODING_HEX) {
rspamd_printf_gstring(res, "%*xs", (int) datalen, data);
}
+ else if (encoding == RSPAMD_KEYPAIR_ENCODING_BASE64) {
+ rspamd_printf_gstring(res, "%*Bs", (int) datalen, data);
+ }
else {
g_string_append_len(res, data, datalen);
}
@@ -467,10 +471,12 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen,
}
GString *
-rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, unsigned int how)
+rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp,
+ enum rspamd_cryptobox_keypair_encoding encoding,
+ unsigned int how)
{
GString *res;
- unsigned int len;
+ size_t len;
gpointer p;
g_assert(kp != NULL);
@@ -479,28 +485,30 @@ rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, unsigned int how)
if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
p = rspamd_cryptobox_keypair_pk(kp, &len);
- rspamd_keypair_print_component(p, len, res, how, "Public key");
+ rspamd_keypair_print_component(p, len, res, how, "Public key", encoding);
}
if ((how & RSPAMD_KEYPAIR_PRIVKEY)) {
p = rspamd_cryptobox_keypair_sk(kp, &len);
- rspamd_keypair_print_component(p, len, res, how, "Private key");
+ rspamd_keypair_print_component(p, len, res, how, "Private key", encoding);
}
if ((how & RSPAMD_KEYPAIR_ID_SHORT)) {
rspamd_keypair_print_component(kp->id, RSPAMD_KEYPAIR_SHORT_ID_LEN,
- res, how, "Short key ID");
+ res, how, "Short key ID", encoding);
}
if ((how & RSPAMD_KEYPAIR_ID)) {
- rspamd_keypair_print_component(kp->id, sizeof(kp->id), res, how, "Key ID");
+ rspamd_keypair_print_component(kp->id, sizeof(kp->id), res, how, "Key ID", encoding);
}
return res;
}
GString *
-rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, unsigned int how)
+rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk,
+ enum rspamd_cryptobox_keypair_encoding encoding,
+ unsigned int how)
{
GString *res;
- unsigned int len;
+ size_t len;
gpointer p;
g_assert(pk != NULL);
@@ -509,15 +517,15 @@ rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, unsigned int how)
if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
p = rspamd_cryptobox_pubkey_pk(pk, &len);
- rspamd_keypair_print_component(p, len, res, how, "Public key");
+ rspamd_keypair_print_component(p, len, res, how, "Public key", encoding);
}
if ((how & RSPAMD_KEYPAIR_ID_SHORT)) {
rspamd_keypair_print_component(pk->id, RSPAMD_KEYPAIR_SHORT_ID_LEN,
- res, how, "Short key ID");
+ res, how, "Short key ID", encoding);
}
if ((how & RSPAMD_KEYPAIR_ID)) {
rspamd_keypair_print_component(pk->id, sizeof(pk->id), res, how,
- "Key ID");
+ "Key ID", encoding);
}
return res;
@@ -527,7 +535,7 @@ const unsigned char *
rspamd_keypair_component(struct rspamd_cryptobox_keypair *kp,
unsigned int ncomp, unsigned int *len)
{
- unsigned int rlen = 0;
+ size_t rlen = 0;
const unsigned char *ret = NULL;
g_assert(kp != NULL);
@@ -558,11 +566,11 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj)
const ucl_object_t *privkey, *pubkey, *elt;
const char *str;
enum rspamd_cryptobox_keypair_type type = RSPAMD_KEYPAIR_KEX;
- gboolean is_hex = FALSE;
+ enum rspamd_cryptobox_keypair_encoding encoding = RSPAMD_KEYPAIR_ENCODING_DEFAULT;
struct rspamd_cryptobox_keypair *kp;
- unsigned int len;
- gsize ucl_len;
- int dec_len;
+ size_t len;
+ size_t ucl_len;
+ size_t dec_len;
gpointer target;
if (ucl_object_type(obj) != UCL_OBJECT) {
@@ -605,7 +613,10 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj)
str = ucl_object_tostring(elt);
if (g_ascii_strcasecmp(str, "hex") == 0) {
- is_hex = TRUE;
+ encoding = RSPAMD_KEYPAIR_ENCODING_HEX;
+ }
+ else if (g_ascii_strcasecmp(str, "base64") == 0) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_BASE64;
}
/* TODO: handle errors */
}
@@ -618,13 +629,29 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj)
target = rspamd_cryptobox_keypair_sk(kp, &len);
str = ucl_object_tolstring(privkey, &ucl_len);
- if (is_hex) {
+ switch (encoding) {
+ case RSPAMD_KEYPAIR_ENCODING_HEX:
dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len);
- }
- else {
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_ZBASE32:
dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT);
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_BASE64:
+ dec_len = rspamd_cryptobox_base64_decode(str, ucl_len, target, &len);
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_BINARY:
+ if (len >= ucl_len) {
+ memcpy(target, str, ucl_len);
+ dec_len = ucl_len;
+ }
+ else {
+ memcpy(target, str, len);
+ dec_len = len;
+ }
+ break;
}
+
if (dec_len != (int) len) {
rspamd_keypair_unref(kp);
@@ -634,11 +661,26 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj)
target = rspamd_cryptobox_keypair_pk(kp, &len);
str = ucl_object_tolstring(pubkey, &ucl_len);
- if (is_hex) {
+ switch (encoding) {
+ case RSPAMD_KEYPAIR_ENCODING_HEX:
dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len);
- }
- else {
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_ZBASE32:
dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT);
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_BASE64:
+ dec_len = rspamd_cryptobox_base64_decode(str, ucl_len, target, &len);
+ break;
+ case RSPAMD_KEYPAIR_ENCODING_BINARY:
+ if (len >= ucl_len) {
+ memcpy(target, str, ucl_len);
+ dec_len = ucl_len;
+ }
+ else {
+ memcpy(target, str, len);
+ dec_len = len;
+ }
+ break;
}
if (dec_len != (int) len) {
@@ -660,24 +702,15 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj)
ucl_object_t *
rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
+ enum rspamd_cryptobox_keypair_encoding encoding,
enum rspamd_keypair_dump_flags flags)
{
ucl_object_t *ucl_out, *elt;
- int how = 0;
GString *keypair_out;
- const char *encoding;
+ const char *encoding_str = NULL;
g_assert(kp != NULL);
- if (flags & RSPAMD_KEYPAIR_DUMP_HEX) {
- how |= RSPAMD_KEYPAIR_HEX;
- encoding = "hex";
- }
- else {
- how |= RSPAMD_KEYPAIR_BASE32;
- encoding = "base32";
- }
-
if (flags & RSPAMD_KEYPAIR_DUMP_FLATTENED) {
ucl_out = ucl_object_typed_new(UCL_OBJECT);
elt = ucl_out;
@@ -688,10 +721,17 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
ucl_object_insert_key(ucl_out, elt, "keypair", 0, false);
}
+ if (encoding == RSPAMD_KEYPAIR_ENCODING_HEX) {
+ encoding_str = "hex";
+ }
+ else if (encoding == RSPAMD_KEYPAIR_ENCODING_BASE64) {
+ encoding_str = "base64";
+ }
+ /* XXX: maybe support binary here ? */
/* pubkey part */
- keypair_out = rspamd_keypair_print(kp,
- RSPAMD_KEYPAIR_PUBKEY | how);
+ keypair_out = rspamd_keypair_print(kp, encoding,
+ RSPAMD_KEYPAIR_PUBKEY | flags);
ucl_object_insert_key(elt,
ucl_object_fromlstring(keypair_out->str, keypair_out->len),
"pubkey", 0, false);
@@ -699,8 +739,8 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
if (!(flags & RSPAMD_KEYPAIR_DUMP_NO_SECRET)) {
/* privkey part */
- keypair_out = rspamd_keypair_print(kp,
- RSPAMD_KEYPAIR_PRIVKEY | how);
+ keypair_out = rspamd_keypair_print(kp, encoding,
+ RSPAMD_KEYPAIR_PRIVKEY | flags);
ucl_object_insert_key(elt,
ucl_object_fromlstring(keypair_out->str, keypair_out->len),
"privkey", 0, false);
@@ -708,15 +748,18 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
}
keypair_out = rspamd_keypair_print(kp,
- RSPAMD_KEYPAIR_ID | how);
+ encoding,
+ RSPAMD_KEYPAIR_ID | flags);
ucl_object_insert_key(elt,
ucl_object_fromlstring(keypair_out->str, keypair_out->len),
"id", 0, false);
g_string_free(keypair_out, TRUE);
- ucl_object_insert_key(elt,
- ucl_object_fromstring(encoding),
- "encoding", 0, false);
+ if (encoding_str) {
+ ucl_object_insert_key(elt,
+ ucl_object_fromstring(encoding_str),
+ "encoding", 0, false);
+ }
ucl_object_insert_key(elt,
ucl_object_fromstring("curve25519"),
diff --git a/src/libcryptobox/keypair.h b/src/libcryptobox/keypair.h
index 97b46cbf5..80f4c4bd7 100644
--- a/src/libcryptobox/keypair.h
+++ b/src/libcryptobox/keypair.h
@@ -181,29 +181,8 @@ const unsigned char *rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk,
#define RSPAMD_KEYPAIR_ID 0x4
/** Print short key id */
#define RSPAMD_KEYPAIR_ID_SHORT 0x8
-/** Encode output with base 32 */
-#define RSPAMD_KEYPAIR_BASE32 0x10
/** Human readable output */
#define RSPAMD_KEYPAIR_HUMAN 0x20
-#define RSPAMD_KEYPAIR_HEX 0x40
-
-/**
- * Print keypair encoding it if needed
- * @param key key to print
- * @param how flags that specifies printing behaviour
- * @return newly allocated string with keypair
- */
-GString *rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp,
- unsigned int how);
-
-/**
- * Print pubkey encoding it if needed
- * @param key key to print
- * @param how flags that specifies printing behaviour
- * @return newly allocated string with keypair
- */
-GString *rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk,
- unsigned int how);
/** Get keypair pubkey ID */
#define RSPAMD_KEYPAIR_COMPONENT_ID 0
@@ -232,17 +211,45 @@ struct rspamd_cryptobox_keypair *rspamd_keypair_from_ucl(const ucl_object_t *obj
enum rspamd_keypair_dump_flags {
RSPAMD_KEYPAIR_DUMP_DEFAULT = 0,
- RSPAMD_KEYPAIR_DUMP_HEX = 1u << 0u,
RSPAMD_KEYPAIR_DUMP_NO_SECRET = 1u << 1u,
RSPAMD_KEYPAIR_DUMP_FLATTENED = 1u << 2u,
};
+enum rspamd_cryptobox_keypair_encoding {
+ RSPAMD_KEYPAIR_ENCODING_ZBASE32 = 0,
+ RSPAMD_KEYPAIR_ENCODING_HEX = 1,
+ RSPAMD_KEYPAIR_ENCODING_BASE64 = 2,
+ RSPAMD_KEYPAIR_ENCODING_BINARY = 3,
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT = RSPAMD_KEYPAIR_ENCODING_ZBASE32,
+};
+
+
+/**
+ * Print pubkey encoding it if needed
+ * @param key key to print
+ * @param how flags that specifies printing behaviour
+ * @return newly allocated string with keypair
+ */
+GString *rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk,
+ enum rspamd_cryptobox_keypair_encoding encoding,
+ unsigned int how);
+/**
+ * Print keypair encoding it if needed
+ * @param key key to print
+ * @param how flags that specifies printing behaviour
+ * @return newly allocated string with keypair
+ */
+GString *rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp,
+ enum rspamd_cryptobox_keypair_encoding encoding,
+ unsigned int how);
/**
* Converts keypair to ucl object
* @param kp
* @return
*/
+
ucl_object_t *rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
+ enum rspamd_cryptobox_keypair_encoding encoding,
enum rspamd_keypair_dump_flags flags);
diff --git a/src/libserver/http/http_connection.c b/src/libserver/http/http_connection.c
index 1ae9bb034..baf37a385 100644
--- a/src/libserver/http/http_connection.c
+++ b/src/libserver/http/http_connection.c
@@ -1987,9 +1987,11 @@ int rspamd_http_message_write_header(const char *mime_type, gboolean encrypted,
GString *b32_key, *b32_id;
b32_key = rspamd_keypair_print(priv->local_key,
- RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32);
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_PUBKEY);
b32_id = rspamd_pubkey_print(peer_key,
- RSPAMD_KEYPAIR_ID_SHORT | RSPAMD_KEYPAIR_BASE32);
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_ID_SHORT);
/* XXX: add some fuzz here */
rspamd_printf_fstring(&*buf, "Key: %v=%v\r\n", b32_id, b32_key);
g_string_free(b32_key, TRUE);
diff --git a/src/libserver/maps/map.c b/src/libserver/maps/map.c
index 631455755..43a9d5d86 100644
--- a/src/libserver/maps/map.c
+++ b/src/libserver/maps/map.c
@@ -685,7 +685,8 @@ rspamd_map_check_sig_pk_mem(const unsigned char *sig,
if (ret) {
b32_key = rspamd_pubkey_print(pk,
- RSPAMD_KEYPAIR_BASE32 | RSPAMD_KEYPAIR_PUBKEY);
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_PUBKEY);
msg_info_map("verified signature for %s using trusted key %v",
map->name, b32_key);
g_string_free(b32_key, TRUE);
@@ -728,7 +729,8 @@ rspamd_map_check_file_sig(const char *fname,
/* We just check pk against the trusted db of keys */
b32_key = rspamd_pubkey_print(pk,
- RSPAMD_KEYPAIR_BASE32 | RSPAMD_KEYPAIR_PUBKEY);
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_PUBKEY);
g_assert(b32_key != NULL);
if (g_hash_table_lookup(map->cfg->trusted_keys, b32_key->str) == NULL) {
diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
index c9cac1562..9600a4732 100644
--- a/src/lua/lua_cryptobox.c
+++ b/src/lua/lua_cryptobox.c
@@ -503,7 +503,7 @@ lua_cryptobox_keypair_gc(lua_State *L)
}
/***
- * @method keypair:totable([hex=false]])
+ * @method keypair:totable([encoding="zbase32"])
* Converts keypair to table (not very safe due to memory leftovers)
*/
static int
@@ -512,16 +512,39 @@ lua_cryptobox_keypair_totable(lua_State *L)
LUA_TRACE_POINT;
struct rspamd_cryptobox_keypair *kp = lua_check_cryptobox_keypair(L, 1);
ucl_object_t *obj;
- gboolean hex = FALSE;
+ enum rspamd_cryptobox_keypair_encoding encoding = RSPAMD_KEYPAIR_ENCODING_DEFAULT;
int ret = 1;
if (kp != NULL) {
if (lua_isboolean(L, 2)) {
- hex = lua_toboolean(L, 2);
+ if (lua_toboolean(L, 2)) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_HEX;
+ }
}
+ else if (lua_isstring(L, 2)) {
+ const char *enc = lua_tostring(L, 2);
- obj = rspamd_keypair_to_ucl(kp, hex ? RSPAMD_KEYPAIR_DUMP_HEX : RSPAMD_KEYPAIR_DUMP_DEFAULT);
+ if (g_ascii_strcasecmp(enc, "hex") == 0) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_HEX;
+ }
+ else if (g_ascii_strcasecmp(enc, "zbase32") == 0 ||
+ g_ascii_strcasecmp(enc, "default") == 0 ||
+ g_ascii_strcasecmp(enc, "base32") == 0) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_ZBASE32;
+ }
+ else if (g_ascii_strcasecmp(enc, "base64") == 0) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_BASE64;
+ }
+ else if (g_ascii_strcasecmp(enc, "binary") == 0) {
+ encoding = RSPAMD_KEYPAIR_ENCODING_BINARY;
+ }
+ else {
+ return luaL_error(L, "unknown encoding (known are: hex, zbase32/default, base64, binary: %s", enc);
+ }
+ }
+
+ obj = rspamd_keypair_to_ucl(kp, encoding, RSPAMD_KEYPAIR_DUMP_DEFAULT);
ret = ucl_object_push_lua(L, obj, true);
ucl_object_unref(obj);
@@ -1415,7 +1438,11 @@ lua_cryptobox_hash_reset(lua_State *L)
rspamd_cryptobox_hash_init(h->content.h, NULL, 0);
break;
case LUA_CRYPTOBOX_HASH_SSL:
+#if OPENSSL_VERSION_MAJOR >= 3
EVP_DigestInit(h->content.c, EVP_MD_CTX_get0_md(h->content.c));
+#else
+ EVP_DigestInit(h->content.c, EVP_MD_CTX_md(h->content.c));
+#endif
break;
case LUA_CRYPTOBOX_HASH_HMAC:
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
@@ -2508,31 +2535,20 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L)
}
if (strcmp(alg_str, "rsa") == 0) {
- BIGNUM *e;
EVP_PKEY *pk;
- e = BN_new();
pk = EVP_PKEY_new();
- if (BN_set_word(e, RSA_F4) != 1) {
- BN_free(e);
- EVP_PKEY_free(pk);
-
- return luaL_error(L, "BN_set_word failed");
- }
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (EVP_PKEY_keygen_init(pctx) != 1) {
- BN_free(e);
EVP_PKEY_free(pk);
EVP_PKEY_CTX_free(pctx);
return luaL_error(L, "EVP_PKEY_keygen_init failed");
}
EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, nbits);
- EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pctx, e);
if (EVP_PKEY_keygen(pctx, &pk) != 1) {
- BN_free(e);
EVP_PKEY_free(pk);
EVP_PKEY_CTX_free(pctx);
@@ -2552,7 +2568,6 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L)
if (rc == 0) {
BIO_free(mbio);
- BN_free(e);
EVP_PKEY_free(pk);
return luaL_error(L, "i2d_RSAPrivateKey_bio failed");
@@ -2574,7 +2589,6 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L)
if (rc == 0) {
BIO_free(mbio);
- BN_free(e);
EVP_PKEY_free(pk);
return luaL_error(L, "i2d_RSA_PUBKEY_bio failed");
@@ -2590,7 +2604,6 @@ lua_cryptobox_gen_dkim_keypair(lua_State *L)
pub_out->len = b64_len;
pub_out->flags = RSPAMD_TEXT_FLAG_OWN;
- BN_free(e);
EVP_PKEY_free(pk);
BIO_free(mbio);
}
diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c
index 1cc2ce1bd..062613bd7 100644
--- a/src/lua/lua_map.c
+++ b/src/lua/lua_map.c
@@ -1256,8 +1256,8 @@ lua_map_get_sign_key(lua_State *L)
bk = g_ptr_array_index(map->map->backends, i);
if (bk->trusted_pubkey) {
- ret = rspamd_pubkey_print(bk->trusted_pubkey,
- RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32);
+ ret = rspamd_pubkey_print(bk->trusted_pubkey, RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_PUBKEY);
}
else {
ret = NULL;
diff --git a/src/lua/lua_rsa.c b/src/lua/lua_rsa.c
index b7be612b0..4b9aa0354 100644
--- a/src/lua/lua_rsa.c
+++ b/src/lua/lua_rsa.c
@@ -261,6 +261,7 @@ lua_rsa_pubkey_gc(lua_State *L)
EVP_PKEY *pkey = lua_check_rsa_pubkey(L, 1);
if (pkey != NULL) {
+ /* It's actually EVP_PKEY_unref, thanks for that API */
EVP_PKEY_free(pkey);
}
@@ -522,6 +523,7 @@ lua_rsa_privkey_gc(lua_State *L)
EVP_PKEY *pkey = lua_check_rsa_privkey(L, 1);
if (pkey != NULL) {
+ /* It's actually EVP_PKEY_unref, thanks for that API */
EVP_PKEY_free(pkey);
}
@@ -758,7 +760,7 @@ lua_rsa_sign_memory(lua_State *L)
data = luaL_checklstring(L, 2, &sz);
if (pkey != NULL && data != NULL) {
- signature = rspamd_fstring_sized_new(EVP_PKEY_get_size(pkey));
+ signature = rspamd_fstring_sized_new(EVP_PKEY_size(pkey));
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
g_assert(pctx != NULL);
@@ -791,7 +793,6 @@ lua_rsa_sign_memory(lua_State *L)
static int
lua_rsa_keypair(lua_State *L)
{
- BIGNUM *e;
EVP_PKEY *pkey = NULL, *pub_pkey, *priv_pkey, **ppkey;
int bits = lua_gettop(L) > 0 ? lua_tointeger(L, 1) : 1024;
@@ -799,32 +800,31 @@ lua_rsa_keypair(lua_State *L)
return luaL_error(L, "invalid bits count");
}
- e = BN_new();
-
- g_assert(BN_set_word(e, RSA_F4) == 1);
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
g_assert(pctx != NULL);
g_assert(EVP_PKEY_keygen_init(pctx) == 1);
g_assert(EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, bits) == 1);
- g_assert(EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pctx, e) == 1);
-
g_assert(EVP_PKEY_keygen(pctx, &pkey) == 1);
g_assert(pkey != NULL);
- priv_pkey = EVP_PKEY_dup(pkey);
+ /* Increase refcount and share */
+ g_assert(EVP_PKEY_up_ref(pkey) == 1);
+ priv_pkey = pkey;
+
ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *));
rspamd_lua_setclass(L, rspamd_rsa_privkey_classname, -1);
*ppkey = priv_pkey;
- pub_pkey = EVP_PKEY_dup(pkey);
+ /* Increase refcount and share */
+ g_assert(EVP_PKEY_up_ref(pkey) == 1);
+ pub_pkey = pkey;
ppkey = lua_newuserdata(L, sizeof(EVP_PKEY *));
rspamd_lua_setclass(L, rspamd_rsa_pubkey_classname, -1);
*ppkey = pub_pkey;
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(pctx);
- BN_free(e);
return 2;
}
diff --git a/src/plugins/lua/dmarc.lua b/src/plugins/lua/dmarc.lua
index 792672bd0..28b3db867 100644
--- a/src/plugins/lua/dmarc.lua
+++ b/src/plugins/lua/dmarc.lua
@@ -264,6 +264,13 @@ local function dmarc_validate_policy(task, policy, hdrfromdom, dmarc_esld)
end
if policy.rua and redis_params and settings.reporting.enabled then
+ if settings.reporting.only_domains then
+ if not (settings.reporting.only_domains:get_key(policy.domain) or
+ settings.reporting.only_domains:get_key(rspamd_util.get_tld(policy.domain))) then
+ rspamd_logger.info(task, 'DMARC reporting suppressed for sender domain %s', policy.domain)
+ return
+ end
+ end
if settings.reporting.exclude_domains then
if settings.reporting.exclude_domains:get_key(policy.domain) or
settings.reporting.exclude_domains:get_key(rspamd_util.get_tld(policy.domain)) then
@@ -527,6 +534,11 @@ if type(settings.reporting) == 'table' then
type = 'map',
description = 'Recipients not to store DMARC reports for'
},
+ only_domains = {
+ optional = true,
+ type = 'map',
+ description = 'Domains to store DMARC reports about'
+ },
})
end
diff --git a/src/rspamadm/signtool.c b/src/rspamadm/signtool.c
index ddc3d45df..6d60e6700 100644
--- a/src/rspamadm/signtool.c
+++ b/src/rspamadm/signtool.c
@@ -366,7 +366,8 @@ rspamadm_sign_file(const char *fname, struct rspamd_cryptobox_keypair *kp)
}
else {
b32_pk = rspamd_keypair_print(kp,
- RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32);
+ RSPAMD_KEYPAIR_ENCODING_DEFAULT,
+ RSPAMD_KEYPAIR_PUBKEY);
if (b32_pk) {
rspamd_fprintf(pub_fp, "%v", b32_pk);
diff --git a/test/functional/cases/150_rspamadm.robot b/test/functional/cases/150_rspamadm.robot
index 6bff14b2e..257b0b501 100644
--- a/test/functional/cases/150_rspamadm.robot
+++ b/test/functional/cases/150_rspamadm.robot
@@ -4,6 +4,13 @@ Suite Teardown Rspamadm Teardown
Library ${RSPAMD_TESTDIR}/lib/rspamd.py
Resource ${RSPAMD_TESTDIR}/lib/rspamd.robot
+*** Variables ***
+${TEXT} text
+${KEY} 12345678901234567890123456789012
+${NONCE} 9pyeEd986hrjcpozCIZ41jEo6dCDbgjg
+${ENCRYPTED_TEXT} 8KGF6VLI7vnweUdR8FuQZuT+ID8=
+${PYTHON_SCRIPT} ${RSPAMD_TESTDIR}/../../utils/encrypt_decrypt_header.py
+
*** Test Cases ***
Config Test
${result} = Rspamadm configtest
@@ -46,3 +53,43 @@ Verbose mode
Should Match Regexp ${result.stderr} ^$
Should Match Regexp ${result.stdout} hello world\n
Should Be Equal As Integers ${result.rc} 0
+
+SecretBox rspamadm encrypt/decrypt
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result.stdout} ${NONCE}${ENCRYPTED_TEXT}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${ENCRYPTED_TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result1.stdout} ${TEXT}
+
+SecretBox python encrypt/decrypt
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result.stdout} ${NONCE}${ENCRYPTED_TEXT}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${NONCE}${ENCRYPTED_TEXT} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result1.stdout} ${TEXT}
+
+SecretBox encrypt python with nonce decrypt rspamadm
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt python without nonce decrypt rspamadm
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt rspamadm with nonce decrypt python
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt rspamadm without nonce decrypt python
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
diff --git a/test/lua/unit/lua_util.maybe_encrypt_decrypt_header.lua b/test/lua/unit/lua_util.maybe_encrypt_decrypt_header.lua
index 613101068..ef31f5e9b 100644
--- a/test/lua/unit/lua_util.maybe_encrypt_decrypt_header.lua
+++ b/test/lua/unit/lua_util.maybe_encrypt_decrypt_header.lua
@@ -15,7 +15,8 @@ context("Lua util - maybe encrypt/decrypt header", function()
assert_true(false, 'Failed to encrypt header')
end
- local decrypted_header = util.maybe_decrypt_header(encrypted_header, settings, settings.prefix)
+ local text = string.sub(tostring(encrypted_header), 6)
+ local decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix)
if decrypted_header == encrypted_header or decrypted_header == nil then
assert_true(false, 'Failed to decrypt header')
end
@@ -36,13 +37,15 @@ context("Lua util - maybe encrypt/decrypt header", function()
prefix_key = 'key'
}
- local encrypted_header, nonce = util.maybe_encrypt_header(header, settings, settings.prefix)
+ local encrypted_header = util.maybe_encrypt_header(header, settings, settings.prefix)
if encrypted_header == header or encrypted_header == nil then
assert_true(false, 'Failed to encrypt header')
end
- local decrypted_header = util.maybe_decrypt_header(encrypted_header, settings,
- settings.prefix, nonce)
+ local nonce = string.sub(tostring(encrypted_header), 1, 24)
+ local text = string.sub(tostring(encrypted_header), 25)
+ local decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix, nonce)
+
if decrypted_header == encrypted_header or decrypted_header == nil then
assert_true(false, 'Failed to decrypt header')
end
diff --git a/utils/encrypt_decrypt_header.py b/utils/encrypt_decrypt_header.py
new file mode 100644
index 000000000..5f2ea755e
--- /dev/null
+++ b/utils/encrypt_decrypt_header.py
@@ -0,0 +1,97 @@
+import argparse
+import base64
+
+import nacl.encoding
+from nacl.secret import SecretBox
+from nacl.hash import blake2b
+
+
+def create_secret_box(key):
+ key = blake2b(key, encoder=nacl.encoding.RawEncoder)
+ box = SecretBox(key)
+ return box
+
+def encrypt_text(header, key, nonce):
+ box = create_secret_box(key)
+ if nonce is not None:
+ encrypted_header = box.encrypt(header, nonce=nonce)
+ else:
+ encrypted_header = box.encrypt(header)
+ return encrypted_header
+
+def decrypt_text(encrypted_header, key):
+ box = create_secret_box(key)
+ decrypted_header = box.decrypt(encrypted_header)
+ return decrypted_header
+
+def set_encoding(args, type_, text):
+ output = text
+ if type_ == 'encode':
+ if args.hex:
+ output = base64.b16encode(text)
+ elif args.base32:
+ output = base64.b32encode(text)
+ elif args.base64:
+ output = base64.b64encode(text)
+ elif type_ == 'decode':
+ if args.hex:
+ output = base64.b16decode(text)
+ elif args.base32:
+ output = base64.b32decode(text)
+ elif args.base64:
+ output = base64.b64decode(text)
+ return output
+
+def set_up_parser_args():
+ new_parser = argparse.ArgumentParser(description="Encrypt or Decrypt a text.")
+ enc_group = new_parser.add_mutually_exclusive_group()
+
+ enc_group.add_argument("-r", "--raw", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in raw")
+ enc_group.add_argument("-H", "--hex", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in hex")
+ enc_group.add_argument("-b", "--base32", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in base32")
+ enc_group.add_argument("-B", "--base64", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in base64")
+
+ subparsers = new_parser.add_subparsers(dest="command", help="encrypt or decrypt")
+
+ encrypt_parser = subparsers.add_parser("encrypt", help="Encrypt a text")
+ encrypt_parser.add_argument("-t", "--text", type=str, required=True, help="Text to encrypt")
+ encrypt_parser.add_argument("-k", "--key", type=str, required=True, help="Encryption key")
+ encrypt_parser.add_argument("-n", "--nonce", type=str, required=False, help="Encryption nonce")
+
+ decrypt_parser = subparsers.add_parser("decrypt", help="Decrypt a text")
+ decrypt_parser.add_argument("-t", "--encrypted_text", type=str, required=True, help="Encrypted text")
+ decrypt_parser.add_argument("-k", "--key", type=str, required=True, help="Decryption key")
+
+ args = new_parser.parse_args()
+ return args
+
+def main():
+ args = set_up_parser_args()
+
+ if args.command == "encrypt":
+ text = args.text.encode()
+ key = args.key.encode()
+ if args.nonce is not None:
+ nonce = set_encoding(args, 'decode', args.nonce)
+ else:
+ nonce = None
+
+ encrypted_text = encrypt_text(text, key, nonce)
+ if args.raw:
+ print(set_encoding(args, 'encode', encrypted_text))
+ else:
+ print(set_encoding(args, 'encode', encrypted_text).decode())
+
+ elif args.command == "decrypt":
+ encrypted_text = set_encoding(args, 'decode', args.encrypted_text)
+ key = args.key.encode()
+
+ decrypted_text = decrypt_text(encrypted_text, key)
+ print(decrypted_text.decode())
+
+if __name__ == "__main__":
+ main() \ No newline at end of file